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