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                                            &param, 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