OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "chrome/browser/sync/util/pthread_helpers.h" |
| 6 |
| 7 #if (defined(OS_LINUX) || defined(OS_MACOSX)) |
| 8 #include <sys/time.h> |
| 9 #endif // (defined(OS_LINUX) || defined(OS_MACOSX)) |
| 10 |
| 11 #include "base/atomicops.h" |
| 12 #include "base/logging.h" |
| 13 #include "base/port.h" |
| 14 #include "base/scoped_ptr.h" |
| 15 #include "chrome/browser/sync/protocol/service_constants.h" |
| 16 |
| 17 #ifdef OS_WINDOWS |
| 18 |
| 19 namespace { |
| 20 |
| 21 // Ensure that we don't bug the user more than once about the process being |
| 22 // terminated. |
| 23 base::subtle::AtomicWord g_process_terminating = 0; |
| 24 |
| 25 struct ThreadStartParams { |
| 26 void *(*start) (void* payload); |
| 27 void* param; |
| 28 }; |
| 29 |
| 30 void* ThreadMainProc(void* parameter) { |
| 31 ThreadStartParams* tsp = reinterpret_cast<ThreadStartParams*>(parameter); |
| 32 void *(*start) (void *) = tsp->start; |
| 33 void* param = tsp->param; |
| 34 |
| 35 delete tsp; |
| 36 |
| 37 void* result = NULL; |
| 38 __try { |
| 39 result = start(param); |
| 40 } __except(EXCEPTION_CONTINUE_SEARCH) { |
| 41 // Make sure only one thread complains and exits the process. Other |
| 42 // faulting threads simply return. |
| 43 if (0 == base::subtle::NoBarrier_CompareAndSwap( |
| 44 &g_process_terminating, 0, 1)) { |
| 45 // Service notification means we don't have a recursive event loop inside |
| 46 // this call, and so won't suffer recursive exceptions. |
| 47 ::MessageBox(NULL, |
| 48 PRODUCT_NAME_STRING |
| 49 L" has suffered a non-recoverable\n" |
| 50 L"exception, and must exit immediately", |
| 51 L"Nonrecoverable Exception", |
| 52 MB_OK | MB_APPLMODAL | MB_SERVICE_NOTIFICATION); |
| 53 |
| 54 ::ExitProcess(GetExceptionCode()); |
| 55 } |
| 56 } |
| 57 |
| 58 return result; |
| 59 } |
| 60 |
| 61 } // namespace |
| 62 |
| 63 #endif |
| 64 |
| 65 thread_handle CreatePThread(void *(*start) (void *), void* parameter) { |
| 66 #ifdef OS_WINDOWS |
| 67 scoped_ptr<ThreadStartParams> param(new ThreadStartParams); |
| 68 if (NULL == param.get()) |
| 69 return NULL; |
| 70 |
| 71 param->start = start; |
| 72 param->param = parameter; |
| 73 |
| 74 pthread_t pthread; |
| 75 if (0 != pthread_create(&pthread, NULL, ThreadMainProc, param.get())) |
| 76 return NULL; |
| 77 |
| 78 // ownership has passed to the new thread |
| 79 param.release(); |
| 80 |
| 81 const HANDLE thread_handle = pthread_getw32threadhandle_np(pthread); |
| 82 HANDLE thread_copy; |
| 83 // Have to duplicate the thread handle, because when we call |
| 84 // pthread_detach(), the handle will get closed as soon as the thread exits. |
| 85 // We want to keep the handle indefinitely. |
| 86 CHECK(DuplicateHandle(GetCurrentProcess(), thread_handle, |
| 87 GetCurrentProcess(), &thread_copy, 0, FALSE, |
| 88 DUPLICATE_SAME_ACCESS)) << |
| 89 "DuplicateHandle() failed with error " << GetLastError(); |
| 90 pthread_detach(pthread); |
| 91 return thread_copy; |
| 92 #else |
| 93 pthread_t handle; |
| 94 |
| 95 int result = pthread_create(&handle, NULL, start, parameter); |
| 96 if (result == 0) { |
| 97 return handle; |
| 98 } else { |
| 99 return 0; |
| 100 } |
| 101 #endif |
| 102 } |
| 103 |
| 104 struct timespec GetPThreadAbsoluteTime(uint32 ms) { |
| 105 #ifdef OS_WINDOWS |
| 106 FILETIME filenow; |
| 107 GetSystemTimeAsFileTime(&filenow); |
| 108 ULARGE_INTEGER n; |
| 109 n.LowPart = filenow.dwLowDateTime; |
| 110 n.HighPart = filenow.dwHighDateTime; |
| 111 // Filetime unit is 100-nanosecond intervals |
| 112 const int64 ms_ftime = 10000; |
| 113 n.QuadPart += ms_ftime * ms; |
| 114 |
| 115 // The number of 100 nanosecond intervals from Jan 1, 1601 'til Jan 1, 1970. |
| 116 const int64 kOffset = GG_LONGLONG(116444736000000000); |
| 117 timespec result; |
| 118 result.tv_sec = (n.QuadPart - kOffset) / 10000000; |
| 119 result.tv_nsec = (n.QuadPart - kOffset - |
| 120 (result.tv_sec * GG_LONGLONG(10000000))) * 100; |
| 121 return result; |
| 122 #else |
| 123 struct timeval now; |
| 124 struct timezone zone; |
| 125 gettimeofday(&now, &zone); |
| 126 struct timespec deadline = { now.tv_sec }; |
| 127 // microseconds to nanoseconds. |
| 128 // and add the ms delay. |
| 129 ms += now.tv_usec / 1000; |
| 130 deadline.tv_sec += ms / 1000; |
| 131 deadline.tv_nsec = (ms % 1000) * 1000000; |
| 132 return deadline; |
| 133 #endif |
| 134 } |
| 135 |
| 136 void NameCurrentThreadForDebugging(char* name) { |
| 137 #if defined(OS_WINDOWS) |
| 138 // This implementation is taken from Chromium's platform_thread framework. |
| 139 // The information on how to set the thread name comes from a MSDN article: |
| 140 // http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx |
| 141 const DWORD kVCThreadNameException = 0x406D1388; |
| 142 typedef struct tagTHREADNAME_INFO { |
| 143 DWORD dwType; // Must be 0x1000. |
| 144 LPCSTR szName; // Pointer to name (in user addr space). |
| 145 DWORD dwThreadID; // Thread ID (-1=caller thread). |
| 146 DWORD dwFlags; // Reserved for future use, must be zero. |
| 147 } THREADNAME_INFO; |
| 148 |
| 149 // The debugger needs to be around to catch the name in the exception. If |
| 150 // there isn't a debugger, we are just needlessly throwing an exception. |
| 151 if (!::IsDebuggerPresent()) |
| 152 return; |
| 153 |
| 154 THREADNAME_INFO info = { 0x1000, name, GetCurrentThreadId(), 0 }; |
| 155 |
| 156 __try { |
| 157 RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), |
| 158 reinterpret_cast<DWORD_PTR*>(&info)); |
| 159 } __except(EXCEPTION_CONTINUE_EXECUTION) { |
| 160 } |
| 161 #endif // defined(OS_WINDOWS) |
| 162 } |
OLD | NEW |