<div dir="ltr">Just want to say, thanks for all the work figuring out the right shape for this. =] This looks really, really nice.</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, May 15, 2014 at 8:33 PM, Juergen Ributzka <span dir="ltr"><<a href="mailto:juergen@apple.com" target="_blank">juergen@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ributzka<br>
Date: Thu May 15 21:33:15 2014<br>
New Revision: 208945<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=208945&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=208945&view=rev</a><br>
Log:<br>
Add C API for thread yielding callback.<br>
<br>
Sometimes a LLVM compilation may take more time then a client would like to<br>
wait for. The problem is that it is not possible to safely suspend the LLVM<br>
thread from the outside. When the timing is bad it might be possible that the<br>
LLVM thread holds a global mutex and this would block any progress in any other<br>
thread.<br>
<br>
This commit adds a new yield callback function that can be registered with a<br>
context. LLVM will try to yield by calling this callback function, but there is<br>
no guaranteed frequency. LLVM will only do so if it can guarantee that<br>
suspending the thread won't block any forward progress in other LLVM contexts<br>
in the same process.<br>
<br>
Once the client receives the call back it can suspend the thread safely and<br>
resume it at another time.<br>
<br>
Related to <rdar://problem/16728690><br>
<br>
Modified:<br>
    llvm/trunk/include/llvm-c/Core.h<br>
    llvm/trunk/include/llvm/IR/LLVMContext.h<br>
    llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp<br>
    llvm/trunk/lib/Analysis/LoopPass.cpp<br>
    llvm/trunk/lib/IR/Core.cpp<br>
    llvm/trunk/lib/IR/LLVMContext.cpp<br>
    llvm/trunk/lib/IR/LLVMContextImpl.cpp<br>
    llvm/trunk/lib/IR/LLVMContextImpl.h<br>
    llvm/trunk/lib/IR/LegacyPassManager.cpp<br>
    llvm/trunk/lib/IR/PassManager.cpp<br>
    llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp<br>
<br>
Modified: llvm/trunk/include/llvm-c/Core.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Core.h?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm-c/Core.h?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/include/llvm-c/Core.h (original)<br>
+++ llvm/trunk/include/llvm-c/Core.h Thu May 15 21:33:15 2014<br>
@@ -467,6 +467,7 @@ void LLVMEnablePrettyStackTrace(void);<br>
  */<br>
<br>
 typedef void (*LLVMDiagnosticHandler)(LLVMDiagnosticInfoRef, void *);<br>
+typedef void (*LLVMYieldCallback)(LLVMContextRef, void *);<br>
<br>
 /**<br>
  * Create a new context.<br>
@@ -489,6 +490,14 @@ void LLVMContextSetDiagnosticHandler(LLV<br>
                                      void *DiagnosticContext);<br>
<br>
 /**<br>
+ * Set the yield callback function for this context.<br>
+ *<br>
+ * @see LLVMContext::setYieldCallback()<br>
+ */<br>
+void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,<br>
+                                 void *OpaqueHandle);<br>
+<br>
+/**<br>
  * Destroy a context instance.<br>
  *<br>
  * This should be called for every call to LLVMContextCreate() or memory<br>
<br>
Modified: llvm/trunk/include/llvm/IR/LLVMContext.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/LLVMContext.h?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/LLVMContext.h?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/include/llvm/IR/LLVMContext.h (original)<br>
+++ llvm/trunk/include/llvm/IR/LLVMContext.h Thu May 15 21:33:15 2014<br>
@@ -72,6 +72,10 @@ public:<br>
   /// \see LLVMContext::diagnose.<br>
   typedef void (*DiagnosticHandlerTy)(const DiagnosticInfo &DI, void *Context);<br>
<br>
+  /// Defines the type of a yield callback.<br>
+  /// \see LLVMContext::setYieldCallback.<br>
+  typedef void (*YieldCallbackTy)(LLVMContext *Context, void *OpaqueHandle);<br>
+<br>
   /// setInlineAsmDiagnosticHandler - This method sets a handler that is invoked<br>
   /// when problems with inline asm are detected by the backend.  The first<br>
   /// argument is a function pointer and the second is a context pointer that<br>
@@ -118,6 +122,32 @@ public:<br>
   /// for RS_Error, "warning: " for RS_Warning, and "note: " for RS_Note.<br>
   void diagnose(const DiagnosticInfo &DI);<br>
<br>
+  /// \brief Registers a yield callback with the given context.<br>
+  ///<br>
+  /// The yield callback function may be called by LLVM to transfer control back<br>
+  /// to the client that invoked the LLVM compilation. This can be used to yield<br>
+  /// control of the thread, or perform periodic work needed by the client.<br>
+  /// There is no guaranteed frequency at which callbacks must occur; in fact,<br>
+  /// the client is not guaranteed to ever receive this callback. It is at the<br>
+  /// sole discretion of LLVM to do so and only if it can guarantee that<br>
+  /// suspending the thread won't block any forward progress in other LLVM<br>
+  /// contexts in the same process.<br>
+  ///<br>
+  /// At a suspend point, the state of the current LLVM context is intentionally<br>
+  /// undefined. No assumptions about it can or should be made. Only LLVM<br>
+  /// context API calls that explicitly state that they can be used during a<br>
+  /// yield callback are allowed to be used. Any other API calls into the<br>
+  /// context are not supported until the yield callback function returns<br>
+  /// control to LLVM. Other LLVM contexts are unaffected by this restriction.<br>
+  void setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle);<br>
+<br>
+  /// \brief Calls the yield callback (if applicable).<br>
+  ///<br>
+  /// This transfers control of the current thread back to the client, which may<br>
+  /// suspend the current thread. Only call this method when LLVM doesn't hold<br>
+  /// any global mutex or cannot block the execution in another LLVM context.<br>
+  void yield();<br>
+<br>
   /// emitError - Emit an error message to the currently installed error handler<br>
   /// with optional location information.  This function returns, so code should<br>
   /// be prepared to drop the erroneous construct on the floor and "not crash".<br>
<br>
Modified: llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/IPA/CallGraphSCCPass.cpp Thu May 15 21:33:15 2014<br>
@@ -22,6 +22,7 @@<br>
 #include "llvm/IR/Function.h"<br>
 #include "llvm/IR/IntrinsicInst.h"<br>
 #include "llvm/IR/LegacyPassManagers.h"<br>
+#include "llvm/IR/LLVMContext.h"<br>
 #include "llvm/Support/CommandLine.h"<br>
 #include "llvm/Support/Debug.h"<br>
 #include "llvm/Support/Timer.h"<br>
@@ -145,8 +146,11 @@ bool CGPassManager::RunPassOnSCC(Pass *P<br>
        I != E; ++I) {<br>
     if (Function *F = (*I)->getFunction()) {<br>
       dumpPassInfo(P, EXECUTION_MSG, ON_FUNCTION_MSG, F->getName());<br>
-      TimeRegion PassTimer(getPassTimer(FPP));<br>
-      Changed |= FPP->runOnFunction(*F);<br>
+      {<br>
+        TimeRegion PassTimer(getPassTimer(FPP));<br>
+        Changed |= FPP->runOnFunction(*F);<br>
+      }<br>
+      F->getContext().yield();<br>
     }<br>
   }<br>
<br>
<br>
Modified: llvm/trunk/lib/Analysis/LoopPass.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopPass.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/LoopPass.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/Analysis/LoopPass.cpp (original)<br>
+++ llvm/trunk/lib/Analysis/LoopPass.cpp Thu May 15 21:33:15 2014<br>
@@ -15,6 +15,7 @@<br>
<br>
 #include "llvm/Analysis/LoopPass.h"<br>
 #include "llvm/IR/IRPrintingPasses.h"<br>
+#include "llvm/IR/LLVMContext.h"<br>
 #include "llvm/Support/Debug.h"<br>
 #include "llvm/Support/Timer.h"<br>
 using namespace llvm;<br>
@@ -253,6 +254,8 @@ bool LPPassManager::runOnFunction(Functi<br>
<br>
         // Then call the regular verifyAnalysis functions.<br>
         verifyPreservedAnalysis(P);<br>
+<br>
+        F.getContext().yield();<br>
       }<br>
<br>
       removeNotPreservedAnalysis(P);<br>
<br>
Modified: llvm/trunk/lib/IR/Core.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Core.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Core.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/IR/Core.cpp (original)<br>
+++ llvm/trunk/lib/IR/Core.cpp Thu May 15 21:33:15 2014<br>
@@ -89,6 +89,13 @@ void LLVMContextSetDiagnosticHandler(LLV<br>
       DiagnosticContext);<br>
 }<br>
<br>
+void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,<br>
+                                 void *OpaqueHandle) {<br>
+  auto YieldCallback =<br>
+    LLVM_EXTENSION reinterpret_cast<LLVMContext::YieldCallbackTy>(Callback);<br>
+  unwrap(C)->setYieldCallback(YieldCallback, OpaqueHandle);<br>
+}<br>
+<br>
 void LLVMContextDispose(LLVMContextRef C) {<br>
   delete unwrap(C);<br>
 }<br>
<br>
Modified: llvm/trunk/lib/IR/LLVMContext.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContext.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContext.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/IR/LLVMContext.cpp (original)<br>
+++ llvm/trunk/lib/IR/LLVMContext.cpp Thu May 15 21:33:15 2014<br>
@@ -115,6 +115,17 @@ void *LLVMContext::getDiagnosticContext(<br>
   return pImpl->DiagnosticContext;<br>
 }<br>
<br>
+void LLVMContext::setYieldCallback(YieldCallbackTy Callback, void *OpaqueHandle)<br>
+{<br>
+  pImpl->YieldCallback = Callback;<br>
+  pImpl->YieldOpaqueHandle = OpaqueHandle;<br>
+}<br>
+<br>
+void LLVMContext::yield() {<br>
+  if (pImpl->YieldCallback)<br>
+    pImpl->YieldCallback(this, pImpl->YieldOpaqueHandle);<br>
+}<br>
+<br>
 void LLVMContext::emitError(const Twine &ErrorStr) {<br>
   diagnose(DiagnosticInfoInlineAsm(ErrorStr));<br>
 }<br>
<br>
Modified: llvm/trunk/lib/IR/LLVMContextImpl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContextImpl.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContextImpl.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/IR/LLVMContextImpl.cpp (original)<br>
+++ llvm/trunk/lib/IR/LLVMContextImpl.cpp Thu May 15 21:33:15 2014<br>
@@ -41,6 +41,8 @@ LLVMContextImpl::LLVMContextImpl(LLVMCon<br>
   InlineAsmDiagContext = nullptr;<br>
   DiagnosticHandler = nullptr;<br>
   DiagnosticContext = nullptr;<br>
+  YieldCallback = nullptr;<br>
+  YieldOpaqueHandle = nullptr;<br>
   NamedStructTypesUniqueID = 0;<br>
 }<br>
<br>
<br>
Modified: llvm/trunk/lib/IR/LLVMContextImpl.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContextImpl.h?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LLVMContextImpl.h?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/IR/LLVMContextImpl.h (original)<br>
+++ llvm/trunk/lib/IR/LLVMContextImpl.h Thu May 15 21:33:15 2014<br>
@@ -242,6 +242,9 @@ public:<br>
   LLVMContext::DiagnosticHandlerTy DiagnosticHandler;<br>
   void *DiagnosticContext;<br>
<br>
+  LLVMContext::YieldCallbackTy YieldCallback;<br>
+  void *YieldOpaqueHandle;<br>
+<br>
   typedef DenseMap<DenseMapAPIntKeyInfo::KeyTy, ConstantInt *,<br>
                    DenseMapAPIntKeyInfo> IntMapTy;<br>
   IntMapTy IntConstants;<br>
<br>
Modified: llvm/trunk/lib/IR/LegacyPassManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LegacyPassManager.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/LegacyPassManager.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/IR/LegacyPassManager.cpp (original)<br>
+++ llvm/trunk/lib/IR/LegacyPassManager.cpp Thu May 15 21:33:15 2014<br>
@@ -12,6 +12,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
<br>
+#include "llvm/IR/LLVMContext.h"<br>
 #include "llvm/IR/IRPrintingPasses.h"<br>
 #include "llvm/IR/LegacyPassManager.h"<br>
 #include "llvm/IR/LegacyPassManagers.h"<br>
@@ -1489,8 +1490,10 @@ bool FunctionPassManagerImpl::run(Functi<br>
   TimingInfo::createTheTimeInfo();<br>
<br>
   initializeAllAnalysisInfo();<br>
-  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)<br>
+  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {<br>
     Changed |= getContainedManager(Index)->runOnFunction(F);<br>
+    F.getContext().yield();<br>
+  }<br>
<br>
   for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)<br>
     getContainedManager(Index)->cleanup();<br>
@@ -1723,8 +1726,10 @@ bool PassManagerImpl::run(Module &M) {<br>
   }<br>
<br>
   initializeAllAnalysisInfo();<br>
-  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index)<br>
+  for (unsigned Index = 0; Index < getNumContainedManagers(); ++Index) {<br>
     Changed |= getContainedManager(Index)->runOnModule(M);<br>
+    M.getContext().yield();<br>
+  }<br>
<br>
   for (SmallVectorImpl<ImmutablePass *>::const_iterator I = IPV.begin(),<br>
        E = IPV.end(); I != E; ++I) {<br>
<br>
Modified: llvm/trunk/lib/IR/PassManager.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/PassManager.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/lib/IR/PassManager.cpp (original)<br>
+++ llvm/trunk/lib/IR/PassManager.cpp Thu May 15 21:33:15 2014<br>
@@ -8,6 +8,7 @@<br>
 //===----------------------------------------------------------------------===//<br>
<br>
 #include "llvm/ADT/STLExtras.h"<br>
+#include "llvm/IR/LLVMContext.h"<br>
 #include "llvm/IR/PassManager.h"<br>
 #include "llvm/Support/CommandLine.h"<br>
 #include "llvm/Support/Debug.h"<br>
@@ -32,6 +33,8 @@ PreservedAnalyses ModulePassManager::run<br>
     if (AM)<br>
       AM->invalidate(M, PassPA);<br>
     PA.intersect(std::move(PassPA));<br>
+<br>
+    M->getContext().yield();<br>
   }<br>
<br>
   if (DebugPM)<br>
@@ -92,6 +95,8 @@ PreservedAnalyses FunctionPassManager::r<br>
     if (AM)<br>
       AM->invalidate(F, PassPA);<br>
     PA.intersect(std::move(PassPA));<br>
+<br>
+    F->getContext().yield();<br>
   }<br>
<br>
   if (DebugPM)<br>
<br>
Modified: llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp?rev=208945&r1=208944&r2=208945&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp?rev=208945&r1=208944&r2=208945&view=diff</a><br>

==============================================================================<br>
--- llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp (original)<br>
+++ llvm/trunk/unittests/ExecutionEngine/MCJIT/MCJITCAPITest.cpp Thu May 15 21:33:15 2014<br>
@@ -28,6 +28,7 @@ using namespace llvm;<br>
<br>
 static bool didCallAllocateCodeSection;<br>
 static bool didAllocateCompactUnwindSection;<br>
+static bool didCallYield;<br>
<br>
 static uint8_t *roundTripAllocateCodeSection(void *object, uintptr_t size,<br>
                                              unsigned alignment,<br>
@@ -64,6 +65,10 @@ static void roundTripDestroy(void *objec<br>
   delete static_cast<SectionMemoryManager*>(object);<br>
 }<br>
<br>
+static void yield(LLVMContextRef, void *) {<br>
+  didCallYield = true;<br>
+}<br>
+<br>
 namespace {<br>
<br>
 // memory manager to test reserve allocation space callback<br>
@@ -142,6 +147,7 @@ protected:<br>
   virtual void SetUp() {<br>
     didCallAllocateCodeSection = false;<br>
     didAllocateCompactUnwindSection = false;<br>
+    didCallYield = false;<br>
     Module = 0;<br>
     Function = 0;<br>
     Engine = 0;<br>
@@ -429,3 +435,24 @@ TEST_F(MCJITCAPITest, reserve_allocation<br>
   EXPECT_TRUE(MM->UsedCodeSize > 0);<br>
   EXPECT_TRUE(MM->UsedDataSizeRW > 0);<br>
 }<br>
+<br>
+TEST_F(MCJITCAPITest, yield) {<br>
+  SKIP_UNSUPPORTED_PLATFORM;<br>
+<br>
+  buildSimpleFunction();<br>
+  buildMCJITOptions();<br>
+  buildMCJITEngine();<br>
+  LLVMContextRef C = LLVMGetGlobalContext();<br>
+  LLVMContextSetYieldCallback(C, yield, NULL);<br>
+  buildAndRunPasses();<br>
+<br>
+  union {<br>
+    void *raw;<br>
+    int (*usable)();<br>
+  } functionPointer;<br>
+  functionPointer.raw = LLVMGetPointerToGlobal(Engine, Function);<br>
+<br>
+  EXPECT_EQ(42, functionPointer.usable());<br>
+  EXPECT_TRUE(didCallYield);<br>
+}<br>
+<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>