Home | History | Annotate | Download | only in Support
      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 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 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 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 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                                             &param, 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