OOF2: The Manual
Name
acquirePyLock — ensure thread-safe Python API calls
Synopsis
#include "common/threadstate.h"
| 
                     	      void
                     	      acquirePyLock
                     	    ( | ); | 
| 
                     	      void
                     	      releasePyLock
                     	    ( | ); | 
#include "common/ooferror.h"
| 
                     	      void
                     	      pythonErrorRelay
                     	    ( | ); | 
Description
The three functions described here are used whenever OOF2 C++ code calls Python API functions that might invoke the Python interpreter. It's often difficult to tell when the interpreter will be invoked, so it's a good idea to treat all Python API calls in this way. See http://docs.python.org/ext/thinIce.html for a relevant discussion (although in a different context).
         	  Because the Python interpreter is not thread safe, whenever
         	  a C++ function in OOF2 needs to call the Python API, it
         	  must first acquire the Python global interpreter lock by
         	  calling acquirePyLock().  When it's
         	  through with the Python API calls, it must release the lock
         	  by calling releasePyLock(). 
         	
      
         	  A function that neglects to call
         	  acquirePyLock() risks crashing the
         	  Python interpreter.  A function that neglects to call
         	  releasePyLock will probably deadlock
         	  the program when the C++ routine finishes.  If running
         	  OOF2 with the --unthreaded
         	  option solves a crashing or deadlocking problem, then check
         	  the code for missing calls to
         	  acquirePyLock and
         	  releasePyLock.
         	
      
         	  It is important to ensure that
         	  releasePyLock is called even if an
         	  exception is thrown during the Python API calls.  Python API
         	  calls should always occur within a try
            	  ... catch block, like this:
         	  
      
#include "common/threadstate.h"
   acquirePyLock();
   try {
      // Call Python API
   }
   catch (...) {
      releasePyLock();
      throw;
   }
   releasePyLock(); 
         	  It's possible that calls to the Python API will raise a
         	  Python exception but not throw a C++
         	  exception.  Generally, if a Python API function returns
         	  NULL, an exception has been raised.  The
         	  OOF2 function pythonErrorRelay
         	  ensures that Python exceptions are re-raised in Python when
         	  the C++ function exits.  It should be used like this:
         
         	  
      
#include "common/ooferror.h"
#include "common/threadstate.h"
   acquirePyLock();
   try {
      PyObject *func, *args; // assume these have been set
      PyObject *result = PyEval_Call_Object(func, args); // for example 
      if(result == NULL) 
         pythonErrorRelay();
      // do something with result
   }
   catch (...) {
      releasePyLock();
      throw;
   }
   releasePyLock(); 	  
         
         	  pythonErrorRelay raises a C++ exception
         	  that will be converted back into a Python exception when
         	  control returns to Python.  The mechanism even works if the
         	  Python exception was caused by a C++ exception that occurred
         	  during a second call back into C++, as long as the original
         	  C++ exception was derived from the OOF2 ErrError
         	  class.
         	
      
 
    


