diff options
Diffstat (limited to 'chrome/browser/sync/util/pthread_helpers.cc')
-rw-r--r-- | chrome/browser/sync/util/pthread_helpers.cc | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/chrome/browser/sync/util/pthread_helpers.cc b/chrome/browser/sync/util/pthread_helpers.cc new file mode 100644 index 0000000..4dadc55 --- /dev/null +++ b/chrome/browser/sync/util/pthread_helpers.cc @@ -0,0 +1,162 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/util/pthread_helpers.h" + +#if (defined(OS_LINUX) || defined(OS_MACOSX)) +#include <sys/time.h> +#endif // (defined(OS_LINUX) || defined(OS_MACOSX)) + +#include "base/atomicops.h" +#include "base/logging.h" +#include "base/port.h" +#include "base/scoped_ptr.h" +#include "chrome/browser/sync/protocol/service_constants.h" + +#ifdef OS_WINDOWS + +namespace { + +// Ensure that we don't bug the user more than once about the process being +// terminated. +base::subtle::AtomicWord g_process_terminating = 0; + +struct ThreadStartParams { + void *(*start) (void* payload); + void* param; +}; + +void* ThreadMainProc(void* parameter) { + ThreadStartParams* tsp = reinterpret_cast<ThreadStartParams*>(parameter); + void *(*start) (void *) = tsp->start; + void* param = tsp->param; + + delete tsp; + + void* result = NULL; + __try { + result = start(param); + } __except(EXCEPTION_CONTINUE_SEARCH) { + // Make sure only one thread complains and exits the process. Other + // faulting threads simply return. + if (0 == base::subtle::NoBarrier_CompareAndSwap( + &g_process_terminating, 0, 1)) { + // Service notification means we don't have a recursive event loop inside + // this call, and so won't suffer recursive exceptions. + ::MessageBox(NULL, + PRODUCT_NAME_STRING + L" has suffered a non-recoverable\n" + L"exception, and must exit immediately", + L"Nonrecoverable Exception", + MB_OK | MB_APPLMODAL | MB_SERVICE_NOTIFICATION); + + ::ExitProcess(GetExceptionCode()); + } + } + + return result; +} + +} // namespace + +#endif + +thread_handle CreatePThread(void *(*start) (void *), void* parameter) { +#ifdef OS_WINDOWS + scoped_ptr<ThreadStartParams> param(new ThreadStartParams); + if (NULL == param.get()) + return NULL; + + param->start = start; + param->param = parameter; + + pthread_t pthread; + if (0 != pthread_create(&pthread, NULL, ThreadMainProc, param.get())) + return NULL; + + // ownership has passed to the new thread + param.release(); + + const HANDLE thread_handle = pthread_getw32threadhandle_np(pthread); + HANDLE thread_copy; + // Have to duplicate the thread handle, because when we call + // pthread_detach(), the handle will get closed as soon as the thread exits. + // We want to keep the handle indefinitely. + CHECK(DuplicateHandle(GetCurrentProcess(), thread_handle, + GetCurrentProcess(), &thread_copy, 0, FALSE, + DUPLICATE_SAME_ACCESS)) << + "DuplicateHandle() failed with error " << GetLastError(); + pthread_detach(pthread); + return thread_copy; +#else + pthread_t handle; + + int result = pthread_create(&handle, NULL, start, parameter); + if (result == 0) { + return handle; + } else { + return 0; + } +#endif +} + +struct timespec GetPThreadAbsoluteTime(uint32 ms) { +#ifdef OS_WINDOWS + FILETIME filenow; + GetSystemTimeAsFileTime(&filenow); + ULARGE_INTEGER n; + n.LowPart = filenow.dwLowDateTime; + n.HighPart = filenow.dwHighDateTime; + // Filetime unit is 100-nanosecond intervals + const int64 ms_ftime = 10000; + n.QuadPart += ms_ftime * ms; + + // The number of 100 nanosecond intervals from Jan 1, 1601 'til Jan 1, 1970. + const int64 kOffset = GG_LONGLONG(116444736000000000); + timespec result; + result.tv_sec = (n.QuadPart - kOffset) / 10000000; + result.tv_nsec = (n.QuadPart - kOffset - + (result.tv_sec * GG_LONGLONG(10000000))) * 100; + return result; +#else + struct timeval now; + struct timezone zone; + gettimeofday(&now, &zone); + struct timespec deadline = { now.tv_sec }; + // microseconds to nanoseconds. + // and add the ms delay. + ms += now.tv_usec / 1000; + deadline.tv_sec += ms / 1000; + deadline.tv_nsec = (ms % 1000) * 1000000; + return deadline; +#endif +} + +void NameCurrentThreadForDebugging(char* name) { +#if defined(OS_WINDOWS) + // This implementation is taken from Chromium's platform_thread framework. + // The information on how to set the thread name comes from a MSDN article: + // http://msdn2.microsoft.com/en-us/library/xcb2z8hs.aspx + const DWORD kVCThreadNameException = 0x406D1388; + typedef struct tagTHREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. + } THREADNAME_INFO; + + // The debugger needs to be around to catch the name in the exception. If + // there isn't a debugger, we are just needlessly throwing an exception. + if (!::IsDebuggerPresent()) + return; + + THREADNAME_INFO info = { 0x1000, name, GetCurrentThreadId(), 0 }; + + __try { + RaiseException(kVCThreadNameException, 0, sizeof(info)/sizeof(DWORD), + reinterpret_cast<DWORD_PTR*>(&info)); + } __except(EXCEPTION_CONTINUE_EXECUTION) { + } +#endif // defined(OS_WINDOWS) +} |