]> git.cworth.org Git - apitrace/blob - common/os_win32.cpp
Make os::getTime() inline and make time frequency OS-dependent variable.
[apitrace] / common / os_win32.cpp
1 /**************************************************************************
2  *
3  * Copyright 2010 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 #include <windows.h>
27
28 #include <assert.h>
29 #include <string.h>
30 #include <stdio.h>
31
32 #include <string>
33
34 #include "os.hpp"
35 #include "os_string.hpp"
36
37
38 namespace os {
39
40
41 String
42 getProcessName(void)
43 {
44     String path;
45     size_t size = MAX_PATH;
46     char *buf = path.buf(size);
47
48     DWORD nWritten = GetModuleFileNameA(NULL, buf, size);
49     (void)nWritten;
50
51     path.truncate();
52
53     return path;
54 }
55
56 String
57 getCurrentDir(void)
58 {
59     String path;
60     size_t size = MAX_PATH;
61     char *buf = path.buf(size);
62     
63     DWORD ret = GetCurrentDirectoryA(size, buf);
64     (void)ret;
65     
66     buf[size - 1] = 0;
67     path.truncate();
68
69     return path;
70 }
71
72 bool
73 String::exists(void) const
74 {
75     DWORD attrs = GetFileAttributesA(str());
76     return attrs != INVALID_FILE_ATTRIBUTES;
77 }
78
79 /**
80  * Determine whether an argument should be quoted.
81  */
82 static bool
83 needsQuote(const char *arg)
84 {
85     char c;
86     while (true) {
87         c = *arg++;
88         if (c == '\0') {
89             break;
90         }
91         if (c == ' ' || c == '\t' || c == '\"') {
92             return true;
93         }
94         if (c == '\\') {
95             c = *arg++;
96             if (c == '\0') {
97                 break;
98             }
99             if (c == '"') {
100                 return true;
101             }
102         }
103     }
104     return false;
105 }
106
107 static void
108 quoteArg(std::string &s, const char *arg)
109 {
110     char c;
111     unsigned backslashes = 0;
112     
113     s.push_back('"');
114     while (true) {
115         c = *arg++;
116         switch (c)
117         if (c == '\0') {
118             break;
119         } else if (c == '"') {
120             while (backslashes) {
121                 s.push_back('\\');
122                 --backslashes;
123             }
124             s.push_back('\\');
125         } else {
126             if (c == '\\') {
127                 ++backslashes;
128             } else {
129                 backslashes = 0;
130             }
131         }
132         s.push_back(c);
133     }
134     s.push_back('"');
135 }
136
137 int execute(char * const * args)
138 {
139     std::string commandLine;
140    
141     const char *arg0 = *args;
142     const char *arg;
143     char sep = 0;
144     while ((arg = *args++) != NULL) {
145         if (sep) {
146             commandLine.push_back(sep);
147         }
148
149         if (needsQuote(arg)) {
150             quoteArg(commandLine, arg);
151         } else {
152             commandLine.append(arg);
153         }
154
155         sep = ' ';
156     }
157
158     STARTUPINFO startupInfo;
159     memset(&startupInfo, 0, sizeof(startupInfo));
160     startupInfo.cb = sizeof(startupInfo);
161
162     PROCESS_INFORMATION processInformation;
163
164     if (!CreateProcessA(NULL,
165                         const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
166                         0, // process attributes
167                         0, // thread attributes
168                         FALSE, // inherit handles
169                         0, // creation flags,
170                         NULL, // environment
171                         NULL, // current directory
172                         &startupInfo,
173                         &processInformation
174                         )) {
175         log("error: failed to execute %s\n", arg0);
176         return -1;
177     }
178
179     WaitForSingleObject(processInformation.hProcess, INFINITE);
180
181     DWORD exitCode = ~0;
182     GetExitCodeProcess(processInformation.hProcess, &exitCode);
183
184     CloseHandle(processInformation.hProcess);
185     CloseHandle(processInformation.hThread);
186
187     return (int)exitCode;
188 }
189
190 void
191 log(const char *format, ...)
192 {
193     char buf[4096];
194
195     va_list ap;
196     va_start(ap, format);
197     fflush(stdout);
198     vsnprintf(buf, sizeof buf, format, ap);
199     va_end(ap);
200
201     OutputDebugStringA(buf);
202
203     /*
204      * Also write the message to stderr, when a debugger is not present (to
205      * avoid duplicate messages in command line debuggers).
206      */
207 #if _WIN32_WINNT > 0x0400
208     if (!IsDebuggerPresent()) {
209         fflush(stdout);
210         fputs(buf, stderr);
211         fflush(stderr);
212     }
213 #endif
214 }
215
216 long long timeFrequency = 0LL;
217
218 void
219 abort(void)
220 {
221 #ifndef NDEBUG
222     DebugBreak();
223 #else
224     ExitProcess(0);
225 #endif
226 }
227
228
229 #ifndef DBG_PRINTEXCEPTION_C
230 #define DBG_PRINTEXCEPTION_C 0x40010006
231 #endif
232
233 static PVOID prevExceptionFilter = NULL;
234 static void (*gCallback)(void) = NULL;
235
236 static LONG CALLBACK
237 unhandledExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
238 {
239     PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
240
241     /*
242      * Ignore OutputDebugStringA exception.
243      */
244     if (pExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) {
245         return EXCEPTION_CONTINUE_SEARCH;
246     }
247
248     /*
249      * Ignore C++ exceptions
250      *
251      * http://support.microsoft.com/kb/185294
252      * http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
253      */
254     if (pExceptionRecord->ExceptionCode == 0xe06d7363) {
255         return EXCEPTION_CONTINUE_SEARCH;
256     }
257
258     // Clear direction flag
259 #ifdef _MSC_VER
260 #ifndef _WIN64
261     __asm {
262         cld
263     };
264 #endif
265 #else
266     asm("cld");
267 #endif
268
269     log("apitrace: warning: caught exception 0x%08lx\n", pExceptionRecord->ExceptionCode);
270
271     static int recursion_count = 0;
272     if (recursion_count) {
273         fprintf(stderr, "apitrace: warning: recursion handling exception\n");
274     } else {
275         if (gCallback) {
276             ++recursion_count;
277             gCallback();
278             --recursion_count;
279         }
280     }
281
282     return EXCEPTION_CONTINUE_SEARCH;
283 }
284
285 void
286 setExceptionCallback(void (*callback)(void))
287 {
288     assert(!gCallback);
289
290     if (!gCallback) {
291         gCallback = callback;
292
293         assert(!prevExceptionFilter);
294
295         prevExceptionFilter = AddVectoredExceptionHandler(0, unhandledExceptionHandler);
296     }
297 }
298
299 void
300 resetExceptionCallback(void)
301 {
302     if (gCallback) {
303         RemoveVectoredExceptionHandler(prevExceptionFilter);
304         gCallback = NULL;
305     }
306 }
307
308
309 } /* namespace os */