]> git.cworth.org Git - apitrace/blobdiff - common/os_win32.cpp
Use skiplist-based FastCallSet within trace::CallSet
[apitrace] / common / os_win32.cpp
index 4e48da5089992c594615018eabd37bc9957d3e8f..e9306cdc6dfa0168b3bca328d5511b66bb551932 100644 (file)
 #include <string.h>
 #include <stdio.h>
 
+#include <string>
+
 #include "os.hpp"
+#include "os_string.hpp"
 
 
 namespace os {
 
 
-/* 
- * Trick from http://locklessinc.com/articles/pthreads_on_windows/
- */
-static CRITICAL_SECTION
-CriticalSection = {
-    (PCRITICAL_SECTION_DEBUG)-1, -1, 0, 0, 0, 0
-};
+String
+getProcessName(void)
+{
+    String path;
+    size_t size = MAX_PATH;
+    char *buf = path.buf(size);
 
+    DWORD nWritten = GetModuleFileNameA(NULL, buf, size);
+    (void)nWritten;
 
-void
-AcquireMutex(void)
-{
-    EnterCriticalSection(&CriticalSection); 
+    path.truncate();
+
+    return path;
 }
 
+String
+getCurrentDir(void)
+{
+    String path;
+    size_t size = MAX_PATH;
+    char *buf = path.buf(size);
+    
+    DWORD ret = GetCurrentDirectoryA(size, buf);
+    (void)ret;
+    
+    buf[size - 1] = 0;
+    path.truncate();
+
+    return path;
+}
 
-void
-ReleaseMutex(void)
+bool
+String::exists(void) const
 {
-    LeaveCriticalSection(&CriticalSection); 
+    DWORD attrs = GetFileAttributesA(str());
+    return attrs != INVALID_FILE_ATTRIBUTES;
 }
 
+bool
+copyFile(const String &srcFileName, const String &dstFileName, bool override)
+{
+    return CopyFileA(srcFileName, dstFileName, !override);
+}
 
 bool
-GetProcessName(char *str, size_t size)
+removeFile(const String &srcFilename)
+{
+    return DeleteFileA(srcFilename);
+}
+
+/**
+ * Determine whether an argument should be quoted.
+ */
+static bool
+needsQuote(const char *arg)
 {
-    char szProcessPath[PATH_MAX];
-    char *lpProcessName;
-    char *lpProcessExt;
+    char c;
+    while (true) {
+        c = *arg++;
+        if (c == '\0') {
+            break;
+        }
+        if (c == ' ' || c == '\t' || c == '\"') {
+            return true;
+        }
+        if (c == '\\') {
+            c = *arg++;
+            if (c == '\0') {
+                break;
+            }
+            if (c == '"') {
+                return true;
+            }
+        }
+    }
+    return false;
+}
 
-    GetModuleFileNameA(NULL, szProcessPath, sizeof(szProcessPath)/sizeof(szProcessPath[0]));
+static void
+quoteArg(std::string &s, const char *arg)
+{
+    char c;
+    unsigned backslashes = 0;
+    
+    s.push_back('"');
+    while (true) {
+        c = *arg++;
+        if (c == '\0') {
+            break;
+        } else if (c == '"') {
+            while (backslashes) {
+                s.push_back('\\');
+                --backslashes;
+            }
+            s.push_back('\\');
+        } else {
+            if (c == '\\') {
+                ++backslashes;
+            } else {
+                backslashes = 0;
+            }
+        }
+        s.push_back(c);
+    }
+    s.push_back('"');
+}
 
-    lpProcessName = strrchr(szProcessPath, '\\');
-    lpProcessName = lpProcessName ? lpProcessName + 1 : szProcessPath;
+int execute(char * const * args)
+{
+    std::string commandLine;
+   
+    const char *arg0 = *args;
+    const char *arg;
+    char sep = 0;
+    while ((arg = *args++) != NULL) {
+        if (sep) {
+            commandLine.push_back(sep);
+        }
+
+        if (needsQuote(arg)) {
+            quoteArg(commandLine, arg);
+        } else {
+            commandLine.append(arg);
+        }
+
+        sep = ' ';
+    }
 
-    lpProcessExt = strrchr(lpProcessName, '.');
-    if (lpProcessExt) {
-        *lpProcessExt = '\0';
+    STARTUPINFO startupInfo;
+    memset(&startupInfo, 0, sizeof(startupInfo));
+    startupInfo.cb = sizeof(startupInfo);
+
+    PROCESS_INFORMATION processInformation;
+
+    if (!CreateProcessA(NULL,
+                        const_cast<char *>(commandLine.c_str()), // only modified by CreateProcessW
+                        0, // process attributes
+                        0, // thread attributes
+                        FALSE, // inherit handles
+                        0, // creation flags,
+                        NULL, // environment
+                        NULL, // current directory
+                        &startupInfo,
+                        &processInformation
+                        )) {
+        log("error: failed to execute %s\n", arg0);
+        return -1;
     }
 
-    strncpy(str, lpProcessName, size);
+    WaitForSingleObject(processInformation.hProcess, INFINITE);
 
-    return true;
-}
+    DWORD exitCode = ~0UL;
+    GetExitCodeProcess(processInformation.hProcess, &exitCode);
 
-bool
-GetCurrentDir(char *str, size_t size)
-{
-    DWORD ret;
-    ret = GetCurrentDirectoryA(size, str);
-    str[size - 1] = 0;
-    return ret == 0 ? false : true;
+    CloseHandle(processInformation.hProcess);
+    CloseHandle(processInformation.hThread);
+
+    return (int)exitCode;
 }
 
 void
-DebugMessage(const char *format, ...)
+log(const char *format, ...)
 {
     char buf[4096];
 
@@ -115,18 +224,10 @@ DebugMessage(const char *format, ...)
 #endif
 }
 
-long long GetTime(void)
-{
-    static LARGE_INTEGER frequency;
-    LARGE_INTEGER counter;
-    if (!frequency.QuadPart)
-        QueryPerformanceFrequency(&frequency);
-    QueryPerformanceCounter(&counter);
-    return counter.QuadPart*1000000LL/frequency.QuadPart;
-}
+long long timeFrequency = 0LL;
 
 void
-Abort(void)
+abort(void)
 {
 #ifndef NDEBUG
     DebugBreak();
@@ -136,24 +237,82 @@ Abort(void)
 }
 
 
-static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter = NULL;
+#ifndef DBG_PRINTEXCEPTION_C
+#define DBG_PRINTEXCEPTION_C 0x40010006
+#endif
+
+static PVOID prevExceptionFilter = NULL;
 static void (*gCallback)(void) = NULL;
 
-static LONG WINAPI UnhandledExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo)
+static LONG CALLBACK
+unhandledExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
 {
-    if (gCallback) {
-        gCallback();
+    PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
+
+    /*
+     * Ignore OutputDebugStringA exception.
+     */
+    if (pExceptionRecord->ExceptionCode == DBG_PRINTEXCEPTION_C) {
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
+
+    /*
+     * Ignore C++ exceptions
+     *
+     * http://support.microsoft.com/kb/185294
+     * http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx
+     */
+    if (pExceptionRecord->ExceptionCode == 0xe06d7363) {
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
+
+    /*
+     * Ignore thread naming exception.
+     *
+     * http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
+     */
+    if (pExceptionRecord->ExceptionCode == 0x406d1388) {
+        return EXCEPTION_CONTINUE_SEARCH;
     }
 
-       if (prevExceptionFilter) {
-               return prevExceptionFilter(pExceptionInfo);
+    /*
+     * Ignore .NET exception.
+     *
+     * http://ig2600.blogspot.co.uk/2011/01/why-do-i-keep-getting-exception-code.html
+     */
+    if (pExceptionRecord->ExceptionCode == 0xe0434352) {
+        return EXCEPTION_CONTINUE_SEARCH;
+    }
+
+    // Clear direction flag
+#ifdef _MSC_VER
+#ifndef _WIN64
+    __asm {
+        cld
+    };
+#endif
+#else
+    asm("cld");
+#endif
+
+    log("apitrace: warning: caught exception 0x%08lx\n", pExceptionRecord->ExceptionCode);
+
+    static int recursion_count = 0;
+    if (recursion_count) {
+        fprintf(stderr, "apitrace: warning: recursion handling exception\n");
     } else {
-               return EXCEPTION_CONTINUE_SEARCH;
+        if (gCallback) {
+            ++recursion_count;
+            gCallback();
+            --recursion_count;
+        }
     }
+
+    return EXCEPTION_CONTINUE_SEARCH;
 }
 
 void
-SetExceptionCallback(void (*callback)(void))
+setExceptionCallback(void (*callback)(void))
 {
     assert(!gCallback);
 
@@ -162,19 +321,17 @@ SetExceptionCallback(void (*callback)(void))
 
         assert(!prevExceptionFilter);
 
-        /*
-         * TODO: Unfortunately it seems that the CRT will reset the exception
-         * handler in certain circumnstances.  See
-         * http://www.codeproject.com/KB/winsdk/crash_hook.aspx
-         */
-        prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionFilter);
+        prevExceptionFilter = AddVectoredExceptionHandler(0, unhandledExceptionHandler);
     }
 }
 
 void
-ResetExceptionCallback(void)
+resetExceptionCallback(void)
 {
-    gCallback = NULL;
+    if (gCallback) {
+        RemoveVectoredExceptionHandler(prevExceptionFilter);
+        gCallback = NULL;
+    }
 }