Skip to content
This repository has been archived by the owner on Feb 5, 2019. It is now read-only.

Revert recent LLVM threading changes that break the mingw build #10

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions docs/ProgrammersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2170,25 +2170,67 @@ compiler, consider compiling LLVM and LLVM-GCC in single-threaded mode, and
using the resultant compiler to build a copy of LLVM with multithreading
support.

.. _startmultithreaded:

Entering and Exiting Multithreaded Mode
---------------------------------------

In order to properly protect its internal data structures while avoiding
excessive locking overhead in the single-threaded case, the LLVM must intialize
certain data structures necessary to provide guards around its internals. To do
so, the client program must invoke ``llvm_start_multithreaded()`` before making
any concurrent LLVM API calls. To subsequently tear down these structures, use
the ``llvm_stop_multithreaded()`` call. You can also use the
``llvm_is_multithreaded()`` call to check the status of multithreaded mode.

Note that both of these calls must be made *in isolation*. That is to say that
no other LLVM API calls may be executing at any time during the execution of
``llvm_start_multithreaded()`` or ``llvm_stop_multithreaded``. It is the
client's responsibility to enforce this isolation.

The return value of ``llvm_start_multithreaded()`` indicates the success or
failure of the initialization. Failure typically indicates that your copy of
LLVM was built without multithreading support, typically because GCC atomic
intrinsics were not found in your system compiler. In this case, the LLVM API
will not be safe for concurrent calls. However, it *will* be safe for hosting
threaded applications in the JIT, though :ref:`care must be taken
<jitthreading>` to ensure that side exits and the like do not accidentally
result in concurrent LLVM API calls.

.. _shutdown:

Ending Execution with ``llvm_shutdown()``
-----------------------------------------

When you are done using the LLVM APIs, you should call ``llvm_shutdown()`` to
deallocate memory used for internal structures.
deallocate memory used for internal structures. This will also invoke
``llvm_stop_multithreaded()`` if LLVM is operating in multithreaded mode. As
such, ``llvm_shutdown()`` requires the same isolation guarantees as
``llvm_stop_multithreaded()``.

Note that, if you use scope-based shutdown, you can use the
``llvm_shutdown_obj`` class, which calls ``llvm_shutdown()`` in its destructor.

.. _managedstatic:

Lazy Initialization with ``ManagedStatic``
------------------------------------------

``ManagedStatic`` is a utility class in LLVM used to implement static
initialization of static resources, such as the global type tables. In a
single-threaded environment, it implements a simple lazy initialization scheme.
When LLVM is compiled with support for multi-threading, however, it uses
initialization of static resources, such as the global type tables. Before the
invocation of ``llvm_shutdown()``, it implements a simple lazy initialization
scheme. Once ``llvm_start_multithreaded()`` returns, however, it uses
double-checked locking to implement thread-safe lazy initialization.

Note that, because no other threads are allowed to issue LLVM API calls before
``llvm_start_multithreaded()`` returns, it is possible to have
``ManagedStatic``\ s of ``llvm::sys::Mutex``\ s.

The ``llvm_acquire_global_lock()`` and ``llvm_release_global_lock`` APIs provide
access to the global lock used to implement the double-checked locking for lazy
initialization. These should only be used internally to LLVM, and only if you
know what you're doing!

.. _llvmcontext:

Achieving Isolation with ``LLVMContext``
Expand Down
13 changes: 8 additions & 5 deletions include/llvm-c/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -2848,13 +2848,16 @@ void LLVMDisposePassManager(LLVMPassManagerRef PM);
* @{
*/

/** Deprecated: Multi-threading can only be enabled/disabled with the compile
time define LLVM_ENABLE_THREADS. This function always returns
LLVMIsMultithreaded(). */
/** Allocate and initialize structures needed to make LLVM safe for
multithreading. The return value indicates whether multithreaded
initialization succeeded. Must be executed in isolation from all
other LLVM api calls.
@see llvm::llvm_start_multithreaded */
LLVMBool LLVMStartMultithreaded(void);

/** Deprecated: Multi-threading can only be enabled/disabled with the compile
time define LLVM_ENABLE_THREADS. */
/** Deallocate structures necessary to make LLVM safe for multithreading.
Must be executed in isolation from all other LLVM api calls.
@see llvm::llvm_stop_multithreaded */
void LLVMStopMultithreaded(void);

/** Check whether LLVM is executing in thread-safe mode or not.
Expand Down
7 changes: 4 additions & 3 deletions include/llvm/ExecutionEngine/ExecutionEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
#include "llvm/IR/ValueMap.h"
#include "llvm/MC/MCCodeGenInfo.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include <map>
#include <mutex>
#include <string>
#include <vector>

Expand All @@ -42,6 +42,7 @@ class JITEventListener;
class JITMemoryManager;
class MachineCodeInfo;
class Module;
class MutexGuard;
class ObjectCache;
class RTDyldMemoryManager;
class Triple;
Expand All @@ -58,7 +59,7 @@ class ExecutionEngineState {
public:
struct AddressMapConfig : public ValueMapConfig<const GlobalValue*> {
typedef ExecutionEngineState *ExtraData;
static std::recursive_mutex *getMutex(ExecutionEngineState *EES);
static sys::Mutex *getMutex(ExecutionEngineState *EES);
static void onDelete(ExecutionEngineState *EES, const GlobalValue *Old);
static void onRAUW(ExecutionEngineState *, const GlobalValue *,
const GlobalValue *);
Expand Down Expand Up @@ -163,7 +164,7 @@ class ExecutionEngine {
/// lock - This lock protects the ExecutionEngine, MCJIT, JIT, JITResolver and
/// JITEmitter classes. It must be held while changing the internal state of
/// any of those classes.
std::recursive_mutex lock;
sys::Mutex lock;

//===--------------------------------------------------------------------===//
// ExecutionEngine Startup
Expand Down
12 changes: 6 additions & 6 deletions include/llvm/IR/ValueMap.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@

#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Mutex.h"
#include "llvm/Support/type_traits.h"
#include <iterator>
#include <mutex>

namespace llvm {

Expand All @@ -45,7 +45,7 @@ class ValueMapConstIterator;
/// This class defines the default behavior for configurable aspects of
/// ValueMap<>. User Configs should inherit from this class to be as compatible
/// as possible with future versions of ValueMap.
template<typename KeyT, typename MutexT = std::recursive_mutex>
template<typename KeyT, typename MutexT = sys::Mutex>
struct ValueMapConfig {
typedef MutexT mutex_type;

Expand Down Expand Up @@ -216,11 +216,11 @@ class ValueMapCallbackVH : public CallbackVH {
ValueMapCallbackVH Copy(*this);
typename Config::mutex_type *M = Config::getMutex(Copy.Map->Data);
if (M)
M->lock();
M->acquire();
Config::onDelete(Copy.Map->Data, Copy.Unwrap()); // May destroy *this.
Copy.Map->Map.erase(Copy); // Definitely destroys *this.
if (M)
M->unlock();
M->release();
}
void allUsesReplacedWith(Value *new_key) override {
assert(isa<KeySansPointerT>(new_key) &&
Expand All @@ -229,7 +229,7 @@ class ValueMapCallbackVH : public CallbackVH {
ValueMapCallbackVH Copy(*this);
typename Config::mutex_type *M = Config::getMutex(Copy.Map->Data);
if (M)
M->lock();
M->acquire();

KeyT typed_new_key = cast<KeySansPointerT>(new_key);
// Can destroy *this:
Expand All @@ -245,7 +245,7 @@ class ValueMapCallbackVH : public CallbackVH {
}
}
if (M)
M->unlock();
M->release();
}
};

Expand Down
3 changes: 3 additions & 0 deletions include/llvm/Support/ManagedStatic.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ void llvm_shutdown();
/// llvm_shutdown() when it is destroyed.
struct llvm_shutdown_obj {
llvm_shutdown_obj() { }
explicit llvm_shutdown_obj(bool multithreaded) {
if (multithreaded) llvm_start_multithreaded();
}
~llvm_shutdown_obj() { llvm_shutdown(); }
};

Expand Down
29 changes: 25 additions & 4 deletions include/llvm/Support/Threading.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,40 @@
//
//===----------------------------------------------------------------------===//
//
// This file declares helper functions for running LLVM in a multi-threaded
// environment.
// TThis file defines llvm_start_multithreaded() and friends.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_THREADING_H
#define LLVM_SUPPORT_THREADING_H

namespace llvm {
/// Returns true if LLVM is compiled with support for multi-threading, and
/// false otherwise.
/// llvm_start_multithreaded - Allocate and initialize structures needed to
/// make LLVM safe for multithreading. The return value indicates whether
/// multithreaded initialization succeeded. LLVM will still be operational
/// on "failed" return, and will still be safe for hosting threading
/// applications in the JIT, but will not be safe for concurrent calls to the
/// LLVM APIs.
/// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS.
bool llvm_start_multithreaded();

/// llvm_stop_multithreaded - Deallocate structures necessary to make LLVM
/// safe for multithreading.
/// THIS MUST EXECUTE IN ISOLATION FROM ALL OTHER LLVM API CALLS.
void llvm_stop_multithreaded();

/// llvm_is_multithreaded - Check whether LLVM is executing in thread-safe
/// mode or not.
bool llvm_is_multithreaded();

/// acquire_global_lock - Acquire the global lock. This is a no-op if called
/// before llvm_start_multithreaded().
void llvm_acquire_global_lock();

/// release_global_lock - Release the global lock. This is a no-op if called
/// before llvm_start_multithreaded().
void llvm_release_global_lock();

/// llvm_execute_on_thread - Execute the given \p UserFn on a separate
/// thread, passing it the provided \p UserData.
///
Expand Down
16 changes: 8 additions & 8 deletions lib/ExecutionEngine/ExecutionEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void *ExecutionEngineState::RemoveMapping(const GlobalValue *ToUnmap) {
}

void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) {
std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);

DEBUG(dbgs() << "JIT: Map \'" << GV->getName()
<< "\' to [" << Addr << "]\n";);
Expand All @@ -184,14 +184,14 @@ void ExecutionEngine::addGlobalMapping(const GlobalValue *GV, void *Addr) {
}

void ExecutionEngine::clearAllGlobalMappings() {
std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);

EEState.getGlobalAddressMap().clear();
EEState.getGlobalAddressReverseMap().clear();
}

void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) {
std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);

for (Module::iterator FI = M->begin(), FE = M->end(); FI != FE; ++FI)
EEState.RemoveMapping(FI);
Expand All @@ -201,7 +201,7 @@ void ExecutionEngine::clearGlobalMappingsFromModule(Module *M) {
}

void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) {
std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);

ExecutionEngineState::GlobalAddressMapTy &Map =
EEState.getGlobalAddressMap();
Expand All @@ -228,15 +228,15 @@ void *ExecutionEngine::updateGlobalMapping(const GlobalValue *GV, void *Addr) {
}

void *ExecutionEngine::getPointerToGlobalIfAvailable(const GlobalValue *GV) {
std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);

ExecutionEngineState::GlobalAddressMapTy::iterator I =
EEState.getGlobalAddressMap().find(GV);
return I != EEState.getGlobalAddressMap().end() ? I->second : nullptr;
}

const GlobalValue *ExecutionEngine::getGlobalValueAtAddress(void *Addr) {
std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);

// If we haven't computed the reverse mapping yet, do so first.
if (EEState.getGlobalAddressReverseMap().empty()) {
Expand Down Expand Up @@ -555,7 +555,7 @@ void *ExecutionEngine::getPointerToGlobal(const GlobalValue *GV) {
if (Function *F = const_cast<Function*>(dyn_cast<Function>(GV)))
return getPointerToFunction(F);

std::lock_guard<std::recursive_mutex> locked(lock);
MutexGuard locked(lock);
if (void *P = EEState.getGlobalAddressMap()[GV])
return P;

Expand Down Expand Up @@ -1346,7 +1346,7 @@ ExecutionEngineState::ExecutionEngineState(ExecutionEngine &EE)
: EE(EE), GlobalAddressMap(this) {
}

std::recursive_mutex *
sys::Mutex *
ExecutionEngineState::AddressMapConfig::getMutex(ExecutionEngineState *EES) {
return &EES->EE.lock;
}
Expand Down
Loading