1218885Sdim//===-- llvm/Support/Threading.cpp- Control multithreading mode --*- C++ -*-==// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file implements llvm_start_multithreaded() and friends. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14218885Sdim#include "llvm/Support/Threading.h" 15249423Sdim#include "llvm/Config/config.h" 16218885Sdim#include "llvm/Support/Atomic.h" 17218885Sdim#include "llvm/Support/Mutex.h" 18218885Sdim#include <cassert> 19218885Sdim 20218885Sdimusing namespace llvm; 21218885Sdim 22218885Sdimstatic bool multithreaded_mode = false; 23218885Sdim 24218885Sdimstatic sys::Mutex* global_lock = 0; 25218885Sdim 26218885Sdimbool llvm::llvm_start_multithreaded() { 27234353Sdim#if LLVM_ENABLE_THREADS != 0 28218885Sdim assert(!multithreaded_mode && "Already multithreaded!"); 29218885Sdim multithreaded_mode = true; 30218885Sdim global_lock = new sys::Mutex(true); 31218885Sdim 32218885Sdim // We fence here to ensure that all initialization is complete BEFORE we 33218885Sdim // return from llvm_start_multithreaded(). 34218885Sdim sys::MemoryFence(); 35218885Sdim return true; 36218885Sdim#else 37218885Sdim return false; 38218885Sdim#endif 39218885Sdim} 40218885Sdim 41218885Sdimvoid llvm::llvm_stop_multithreaded() { 42234353Sdim#if LLVM_ENABLE_THREADS != 0 43218885Sdim assert(multithreaded_mode && "Not currently multithreaded!"); 44218885Sdim 45218885Sdim // We fence here to insure that all threaded operations are complete BEFORE we 46218885Sdim // return from llvm_stop_multithreaded(). 47218885Sdim sys::MemoryFence(); 48218885Sdim 49218885Sdim multithreaded_mode = false; 50218885Sdim delete global_lock; 51218885Sdim#endif 52218885Sdim} 53218885Sdim 54218885Sdimbool llvm::llvm_is_multithreaded() { 55218885Sdim return multithreaded_mode; 56218885Sdim} 57218885Sdim 58218885Sdimvoid llvm::llvm_acquire_global_lock() { 59218885Sdim if (multithreaded_mode) global_lock->acquire(); 60218885Sdim} 61218885Sdim 62218885Sdimvoid llvm::llvm_release_global_lock() { 63218885Sdim if (multithreaded_mode) global_lock->release(); 64218885Sdim} 65218885Sdim 66234353Sdim#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) 67218885Sdim#include <pthread.h> 68218885Sdim 69218885Sdimstruct ThreadInfo { 70218885Sdim void (*UserFn)(void *); 71218885Sdim void *UserData; 72218885Sdim}; 73218885Sdimstatic void *ExecuteOnThread_Dispatch(void *Arg) { 74218885Sdim ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); 75218885Sdim TI->UserFn(TI->UserData); 76218885Sdim return 0; 77218885Sdim} 78218885Sdim 79218885Sdimvoid llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, 80218885Sdim unsigned RequestedStackSize) { 81218885Sdim ThreadInfo Info = { Fn, UserData }; 82218885Sdim pthread_attr_t Attr; 83218885Sdim pthread_t Thread; 84218885Sdim 85218885Sdim // Construct the attributes object. 86218885Sdim if (::pthread_attr_init(&Attr) != 0) 87218885Sdim return; 88218885Sdim 89218885Sdim // Set the requested stack size, if given. 90218885Sdim if (RequestedStackSize != 0) { 91218885Sdim if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) 92218885Sdim goto error; 93218885Sdim } 94218885Sdim 95218885Sdim // Construct and execute the thread. 96218885Sdim if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) 97218885Sdim goto error; 98218885Sdim 99218885Sdim // Wait for the thread and clean up. 100218885Sdim ::pthread_join(Thread, 0); 101218885Sdim 102218885Sdim error: 103218885Sdim ::pthread_attr_destroy(&Attr); 104218885Sdim} 105234353Sdim#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) 106226633Sdim#include "Windows/Windows.h" 107226633Sdim#include <process.h> 108218885Sdim 109226633Sdimstruct ThreadInfo { 110226633Sdim void (*func)(void*); 111226633Sdim void *param; 112226633Sdim}; 113218885Sdim 114226633Sdimstatic unsigned __stdcall ThreadCallback(void *param) { 115226633Sdim struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param); 116226633Sdim info->func(info->param); 117218885Sdim 118226633Sdim return 0; 119226633Sdim} 120226633Sdim 121218885Sdimvoid llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, 122218885Sdim unsigned RequestedStackSize) { 123226633Sdim struct ThreadInfo param = { Fn, UserData }; 124226633Sdim 125226633Sdim HANDLE hThread = (HANDLE)::_beginthreadex(NULL, 126226633Sdim RequestedStackSize, ThreadCallback, 127226633Sdim ¶m, 0, NULL); 128226633Sdim 129226633Sdim if (hThread) { 130226633Sdim // We actually don't care whether the wait succeeds or fails, in 131226633Sdim // the same way we don't care whether the pthread_join call succeeds 132226633Sdim // or fails. There's not much we could do if this were to fail. But 133226633Sdim // on success, this call will wait until the thread finishes executing 134226633Sdim // before returning. 135226633Sdim (void)::WaitForSingleObject(hThread, INFINITE); 136226633Sdim ::CloseHandle(hThread); 137226633Sdim } 138226633Sdim} 139226633Sdim#else 140226633Sdim// Support for non-Win32, non-pthread implementation. 141226633Sdimvoid llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, 142226633Sdim unsigned RequestedStackSize) { 143218885Sdim (void) RequestedStackSize; 144218885Sdim Fn(UserData); 145218885Sdim} 146218885Sdim 147218885Sdim#endif 148