1 //===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file implements llvm_start_multithreaded() and friends. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/Support/Threading.h" 15 #include "llvm/Support/Atomic.h" 16 #include "llvm/Support/Mutex.h" 17 #include "llvm/Config/config.h" 18 #include <cassert> 19 20 using namespace llvm; 21 22 static bool multithreaded_mode = false; 23 24 static sys::Mutex* global_lock = 0; 25 26 bool llvm::llvm_start_multithreaded() { 27 #if LLVM_ENABLE_THREADS != 0 28 assert(!multithreaded_mode && "Already multithreaded!"); 29 multithreaded_mode = true; 30 global_lock = new sys::Mutex(true); 31 32 // We fence here to ensure that all initialization is complete BEFORE we 33 // return from llvm_start_multithreaded(). 34 sys::MemoryFence(); 35 return true; 36 #else 37 return false; 38 #endif 39 } 40 41 void llvm::llvm_stop_multithreaded() { 42 #if LLVM_ENABLE_THREADS != 0 43 assert(multithreaded_mode && "Not currently multithreaded!"); 44 45 // We fence here to insure that all threaded operations are complete BEFORE we 46 // return from llvm_stop_multithreaded(). 47 sys::MemoryFence(); 48 49 multithreaded_mode = false; 50 delete global_lock; 51 #endif 52 } 53 54 bool llvm::llvm_is_multithreaded() { 55 return multithreaded_mode; 56 } 57 58 void llvm::llvm_acquire_global_lock() { 59 if (multithreaded_mode) global_lock->acquire(); 60 } 61 62 void llvm::llvm_release_global_lock() { 63 if (multithreaded_mode) global_lock->release(); 64 } 65 66 #if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) 67 #include <pthread.h> 68 69 struct ThreadInfo { 70 void (*UserFn)(void *); 71 void *UserData; 72 }; 73 static void *ExecuteOnThread_Dispatch(void *Arg) { 74 ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); 75 TI->UserFn(TI->UserData); 76 return 0; 77 } 78 79 void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, 80 unsigned RequestedStackSize) { 81 ThreadInfo Info = { Fn, UserData }; 82 pthread_attr_t Attr; 83 pthread_t Thread; 84 85 // Construct the attributes object. 86 if (::pthread_attr_init(&Attr) != 0) 87 return; 88 89 // Set the requested stack size, if given. 90 if (RequestedStackSize != 0) { 91 if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) 92 goto error; 93 } 94 95 // Construct and execute the thread. 96 if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) 97 goto error; 98 99 // Wait for the thread and clean up. 100 ::pthread_join(Thread, 0); 101 102 error: 103 ::pthread_attr_destroy(&Attr); 104 } 105 #elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) 106 #include "Windows/Windows.h" 107 #include <process.h> 108 109 struct ThreadInfo { 110 void (*func)(void*); 111 void *param; 112 }; 113 114 static unsigned __stdcall ThreadCallback(void *param) { 115 struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); 116 info->func(info->param); 117 118 return 0; 119 } 120 121 void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, 122 unsigned RequestedStackSize) { 123 struct ThreadInfo param = { Fn, UserData }; 124 125 HANDLE hThread = (HANDLE)::_beginthreadex(NULL, 126 RequestedStackSize, ThreadCallback, 127 ¶m, 0, NULL); 128 129 if (hThread) { 130 // We actually don't care whether the wait succeeds or fails, in 131 // the same way we don't care whether the pthread_join call succeeds 132 // or fails. There's not much we could do if this were to fail. But 133 // on success, this call will wait until the thread finishes executing 134 // before returning. 135 (void)::WaitForSingleObject(hThread, INFINITE); 136 ::CloseHandle(hThread); 137 } 138 } 139 #else 140 // Support for non-Win32, non-pthread implementation. 141 void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, 142 unsigned RequestedStackSize) { 143 (void) RequestedStackSize; 144 Fn(UserData); 145 } 146 147 #endif 148