]> git.cworth.org Git - apitrace/blob - common/os_posix.cpp
Implement getTime for OS X
[apitrace] / common / os_posix.cpp
1 /**************************************************************************
2  *
3  * Copyright 2010-2011 VMware, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26
27 #include <assert.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #include <unistd.h>
33 #include <sys/wait.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <signal.h>
37
38 #if defined(__linux__)
39 #include <linux/limits.h> // PATH_MAX
40 #endif
41
42 #ifdef __APPLE__
43 #include <sys/syslimits.h> // PATH_MAX
44 #include <mach-o/dyld.h>
45 #endif
46
47 #ifndef PATH_MAX
48 #warning PATH_MAX undefined
49 #define PATH_MAX 4096
50 #endif
51
52 #include "os.hpp"
53 #include "os_string.hpp"
54
55
56 namespace os {
57
58
59 String
60 getProcessName(void)
61 {
62     String path;
63     size_t size = PATH_MAX;
64     char *buf = path.buf(size);
65
66     // http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
67 #ifdef __APPLE__
68     uint32_t len = size;
69     if (_NSGetExecutablePath(buf, &len) != 0) {
70         *buf = 0;
71         return path;
72     }
73     len = strlen(buf);
74 #else
75     ssize_t len;
76     len = readlink("/proc/self/exe", buf, size - 1);
77     if (len == -1) {
78         // /proc/self/exe is not available on setuid processes, so fallback to
79         // /proc/self/cmdline.
80         int fd = open("/proc/self/cmdline", O_RDONLY);
81         if (fd >= 0) {
82             len = read(fd, buf, size - 1);
83             close(fd);
84         }
85     }
86     if (len <= 0) {
87         snprintf(buf, size, "%i", (int)getpid());
88         return path;
89     }
90 #endif
91     path.truncate(len);
92
93     return path;
94 }
95
96 String
97 getCurrentDir(void)
98 {
99     String path;
100     size_t size = PATH_MAX;
101     char *buf = path.buf(size);
102
103     getcwd(buf, size);
104     buf[size - 1] = 0;
105     
106     path.truncate();
107     return path;
108 }
109
110 bool
111 String::exists(void) const
112 {
113     struct stat st;
114     int err;
115
116     err = stat(str(), &st);
117     if (err) {
118         return false;
119     }
120
121     if (!S_ISREG(st.st_mode))
122         return false;
123
124     return true;
125 }
126
127 int execute(char * const * args)
128 {
129     pid_t pid = fork();
130     if (pid == 0) {
131         // child
132         execvp(args[0], args);
133         fprintf(stderr, "error: failed to execute %s\n", args[0]);
134         exit(-1);
135     } else {
136         // parent
137         if (pid == -1) {
138             fprintf(stderr, "error: failed to fork\n");
139             return -1;
140         }
141         int status = -1;
142         waitpid(pid, &status, 0);
143         return status;
144     }
145 }
146
147 static volatile bool logging = false;
148
149 void
150 log(const char *format, ...)
151 {
152     logging = true;
153     va_list ap;
154     va_start(ap, format);
155     fflush(stdout);
156     vfprintf(stderr, format, ap);
157     va_end(ap);
158     logging = false;
159 }
160
161 #if defined(__APPLE__)
162 long long timeFrequency = 0LL;
163 #endif
164
165 void
166 abort(void)
167 {
168     exit(0);
169 }
170
171
172 static void (*gCallback)(void) = NULL;
173
174 #define NUM_SIGNALS 16
175
176 struct sigaction old_actions[NUM_SIGNALS];
177
178
179 /*
180  * See also:
181  * - http://sourceware.org/git/?p=glibc.git;a=blob;f=debug/segfault.c
182  * - http://ggi.cvs.sourceforge.net/viewvc/ggi/ggi-core/libgg/gg/cleanup.c?view=markup
183  */
184 static void
185 signalHandler(int sig, siginfo_t *info, void *context)
186 {
187     /*
188      * There are several signals that can happen when logging to stdout/stderr.
189      * For example, SIGPIPE will be emitted if stderr is a pipe with no
190      * readers.  Therefore ignore any signal while logging by returning
191      * immediately, to prevent deadlocks.
192      */
193     if (logging) {
194         return;
195     }
196
197     static int recursion_count = 0;
198
199     log("apitrace: warning: caught signal %i\n", sig);
200
201     if (recursion_count) {
202         log("apitrace: warning: recursion handling signal %i\n", sig);
203     } else {
204         if (gCallback) {
205             ++recursion_count;
206             gCallback();
207             --recursion_count;
208         }
209     }
210
211     struct sigaction *old_action;
212     if (sig >= NUM_SIGNALS) {
213         /* This should never happen */
214         log("error: unexpected signal %i\n", sig);
215         raise(SIGKILL);
216     }
217     old_action = &old_actions[sig];
218
219     if (old_action->sa_flags & SA_SIGINFO) {
220         // Handler is in sa_sigaction
221         old_action->sa_sigaction(sig, info, context);
222     } else {
223         if (old_action->sa_handler == SIG_DFL) {
224             log("apitrace: info: taking default action for signal %i\n", sig);
225
226 #if 1
227             struct sigaction dfl_action;
228             dfl_action.sa_handler = SIG_DFL;
229             sigemptyset (&dfl_action.sa_mask);
230             dfl_action.sa_flags = 0;
231             sigaction(sig, &dfl_action, NULL);
232
233             raise(sig);
234 #else
235             raise(SIGKILL);
236 #endif
237         } else if (old_action->sa_handler == SIG_IGN) {
238             /* ignore */
239         } else {
240             /* dispatch to handler */
241             old_action->sa_handler(sig);
242         }
243     }
244 }
245
246 void
247 setExceptionCallback(void (*callback)(void))
248 {
249     assert(!gCallback);
250     if (!gCallback) {
251         gCallback = callback;
252
253         struct sigaction new_action;
254         new_action.sa_sigaction = signalHandler;
255         sigemptyset(&new_action.sa_mask);
256         new_action.sa_flags = SA_SIGINFO | SA_RESTART;
257
258
259         for (int sig = 1; sig < NUM_SIGNALS; ++sig) {
260             // SIGKILL and SIGSTOP can't be handled.
261             if (sig == SIGKILL || sig == SIGSTOP) {
262                 continue;
263             }
264
265             /*
266              * SIGPIPE can be emitted when writing to stderr that is redirected
267              * to a pipe without readers.  It is also very unlikely to ocurr
268              * inside graphics APIs, and most applications where it can occur
269              * normally already ignore it.  In summary, it is unlikely that a
270              * SIGPIPE will cause abnormal termination, which it is likely that
271              * intercepting here will cause problems, so simple don't intercept
272              * it here.
273              */
274             if (sig == SIGPIPE) {
275                 continue;
276             }
277
278             if (sigaction(sig,  NULL, &old_actions[sig]) >= 0) {
279                 sigaction(sig,  &new_action, NULL);
280             }
281         }
282     }
283 }
284
285 void
286 resetExceptionCallback(void)
287 {
288     gCallback = NULL;
289 }
290
291 } /* namespace os */
292