mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-01-07 11:33:44 +00:00
Support: add llvm::unique_lock
Based on the STL class of the same name, it guards a mutex while also allowing it to be unlocked conditionally before destruction. This eliminates the last naked usages of mutexes in LLVM and clang. It also uncovered and fixed a bug in callExternalFunction() when compiled without USE_LIBFFI, where the mutex would never be unlocked if the end of the function was reached. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216338 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
d930a30833
commit
389f13012f
@ -29,6 +29,7 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/IR/ValueHandle.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/UniqueLock.h"
|
||||
#include "llvm/Support/type_traits.h"
|
||||
#include <iterator>
|
||||
|
||||
@ -216,12 +217,11 @@ public:
|
||||
// Make a copy that won't get changed even when *this is destroyed.
|
||||
ValueMapCallbackVH Copy(*this);
|
||||
typename Config::mutex_type *M = Config::getMutex(Copy.Map->Data);
|
||||
unique_lock<typename Config::mutex_type> Guard;
|
||||
if (M)
|
||||
M->lock();
|
||||
Guard = unique_lock<typename Config::mutex_type>(*M);
|
||||
Config::onDelete(Copy.Map->Data, Copy.Unwrap()); // May destroy *this.
|
||||
Copy.Map->Map.erase(Copy); // Definitely destroys *this.
|
||||
if (M)
|
||||
M->unlock();
|
||||
}
|
||||
void allUsesReplacedWith(Value *new_key) override {
|
||||
assert(isa<KeySansPointerT>(new_key) &&
|
||||
@ -229,8 +229,9 @@ public:
|
||||
// Make a copy that won't get changed even when *this is destroyed.
|
||||
ValueMapCallbackVH Copy(*this);
|
||||
typename Config::mutex_type *M = Config::getMutex(Copy.Map->Data);
|
||||
unique_lock<typename Config::mutex_type> Guard;
|
||||
if (M)
|
||||
M->lock();
|
||||
Guard = unique_lock<typename Config::mutex_type>(*M);
|
||||
|
||||
KeyT typed_new_key = cast<KeySansPointerT>(new_key);
|
||||
// Can destroy *this:
|
||||
@ -245,8 +246,6 @@ public:
|
||||
Copy.Map->insert(std::make_pair(typed_new_key, Target));
|
||||
}
|
||||
}
|
||||
if (M)
|
||||
M->unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
67
include/llvm/Support/UniqueLock.h
Normal file
67
include/llvm/Support/UniqueLock.h
Normal file
@ -0,0 +1,67 @@
|
||||
//===-- Support/UniqueLock.h - Acquire/Release Mutex In Scope ---*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines a guard for a block of code that ensures a Mutex is locked
|
||||
// upon construction and released upon destruction.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_UNIQUE_LOCK_H
|
||||
#define LLVM_SUPPORT_UNIQUE_LOCK_H
|
||||
|
||||
#include "llvm/Support/Mutex.h"
|
||||
|
||||
namespace llvm {
|
||||
/// A pared-down imitation of std::unique_lock from C++11. Contrary to the
|
||||
/// name, it's really more of a wrapper for a lock. It may or may not have
|
||||
/// an associated mutex, which is guaranteed to be locked upon creation
|
||||
/// and unlocked after destruction. unique_lock can also unlock the mutex
|
||||
/// and re-lock it freely during its lifetime.
|
||||
/// @brief Guard a section of code with a mutex.
|
||||
template<typename MutexT>
|
||||
class unique_lock {
|
||||
MutexT *M;
|
||||
bool locked;
|
||||
|
||||
unique_lock(const unique_lock &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const unique_lock &) LLVM_DELETED_FUNCTION;
|
||||
public:
|
||||
unique_lock() : M(nullptr), locked(false) {}
|
||||
explicit unique_lock(MutexT &m) : M(&m), locked(true) { M->lock(); }
|
||||
|
||||
void operator=(unique_lock &&o) {
|
||||
if (owns_lock())
|
||||
M->unlock();
|
||||
M = o.M;
|
||||
locked = o.locked;
|
||||
o.M = nullptr;
|
||||
o.locked = false;
|
||||
}
|
||||
|
||||
~unique_lock() { if (owns_lock()) M->unlock(); }
|
||||
|
||||
void lock() {
|
||||
assert(!locked && "mutex already locked!");
|
||||
assert(M && "no associated mutex!");
|
||||
M->lock();
|
||||
locked = true;
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
assert(locked && "unlocking a mutex that isn't locked!");
|
||||
assert(M && "no associated mutex!");
|
||||
M->unlock();
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool owns_lock() { return locked; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif // LLVM_SUPPORT_UNIQUE_LOCK_H
|
@ -28,6 +28,7 @@
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/UniqueLock.h"
|
||||
#include <cmath>
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
@ -248,14 +249,14 @@ GenericValue Interpreter::callExternalFunction(Function *F,
|
||||
const std::vector<GenericValue> &ArgVals) {
|
||||
TheInterpreter = this;
|
||||
|
||||
FunctionsLock->lock();
|
||||
unique_lock<sys::Mutex> Guard(*FunctionsLock);
|
||||
|
||||
// Do a lookup to see if the function is in our cache... this should just be a
|
||||
// deferred annotation!
|
||||
std::map<const Function *, ExFunc>::iterator FI = ExportedFunctions->find(F);
|
||||
if (ExFunc Fn = (FI == ExportedFunctions->end()) ? lookupFunction(F)
|
||||
: FI->second) {
|
||||
FunctionsLock->unlock();
|
||||
Guard.unlock();
|
||||
return Fn(F->getFunctionType(), ArgVals);
|
||||
}
|
||||
|
||||
@ -273,7 +274,7 @@ GenericValue Interpreter::callExternalFunction(Function *F,
|
||||
RawFn = RF->second;
|
||||
}
|
||||
|
||||
FunctionsLock->unlock();
|
||||
Guard.unlock();
|
||||
|
||||
GenericValue Result;
|
||||
if (RawFn != 0 && ffiInvoke(RawFn, F, ArgVals, getDataLayout(), Result))
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "Unix.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/Mutex.h"
|
||||
#include "llvm/Support/UniqueLock.h"
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@ -162,25 +163,25 @@ static RETSIGTYPE SignalHandler(int Sig) {
|
||||
sigfillset(&SigMask);
|
||||
sigprocmask(SIG_UNBLOCK, &SigMask, nullptr);
|
||||
|
||||
SignalsMutex.lock();
|
||||
RemoveFilesToRemove();
|
||||
{
|
||||
unique_lock<SmartMutex<true>> Guard(SignalsMutex);
|
||||
RemoveFilesToRemove();
|
||||
|
||||
if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
|
||||
if (InterruptFunction) {
|
||||
void (*IF)() = InterruptFunction;
|
||||
SignalsMutex.unlock();
|
||||
InterruptFunction = nullptr;
|
||||
IF(); // run the interrupt function.
|
||||
if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
|
||||
if (InterruptFunction) {
|
||||
void (*IF)() = InterruptFunction;
|
||||
Guard.unlock();
|
||||
InterruptFunction = nullptr;
|
||||
IF(); // run the interrupt function.
|
||||
return;
|
||||
}
|
||||
|
||||
Guard.unlock();
|
||||
raise(Sig); // Execute the default handler.
|
||||
return;
|
||||
}
|
||||
|
||||
SignalsMutex.unlock();
|
||||
raise(Sig); // Execute the default handler.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SignalsMutex.unlock();
|
||||
|
||||
// Otherwise if it is a fault (like SEGV) run any handler.
|
||||
for (unsigned i = 0, e = CallBacksToRun.size(); i != e; ++i)
|
||||
CallBacksToRun[i].first(CallBacksToRun[i].second);
|
||||
|
Loading…
Reference in New Issue
Block a user