# GIL methods
- def put_ensure_gil(self, declare_gilstate=True):
+ def put_ensure_gil(self, declare_gilstate=True, variable=None):
"""
Acquire the GIL. The generated code is safe even when no PyThreadState
has been allocated for this thread (for threads not initialized by
self.globalstate.use_utility_code(
UtilityCode.load_cached("ForceInitThreads", "ModuleSetupCode.c"))
self.putln("#ifdef WITH_THREAD")
- if declare_gilstate:
- self.put("PyGILState_STATE ")
- self.putln("__pyx_gilstate_save = PyGILState_Ensure();")
+ if not variable:
+ variable = '__pyx_gilstate_save'
+ if declare_gilstate:
+ self.put("PyGILState_STATE ")
+ self.putln("%s = PyGILState_Ensure();" % variable)
self.putln("#endif")
- def put_release_ensured_gil(self):
+ def put_release_ensured_gil(self, variable=None):
"""
Releases the GIL, corresponds to `put_ensure_gil`.
"""
+ if not variable:
+ variable = '__pyx_gilstate_save'
self.putln("#ifdef WITH_THREAD")
- self.putln("PyGILState_Release(__pyx_gilstate_save);")
+ self.putln("PyGILState_Release(%s);" % variable)
self.putln("#endif")
- def put_acquire_gil(self):
+ def put_acquire_gil(self, variable=None):
"""
Acquire the GIL. The thread's thread state must have been initialized
by a previous `put_release_gil`
"""
+ self.putln("#ifdef WITH_THREAD")
+ if variable:
+ self.putln('_save = %s;' % variable)
self.putln("Py_BLOCK_THREADS")
+ self.putln("#endif")
- def put_release_gil(self):
+ def put_release_gil(self, variable=None):
"Release the GIL, corresponds to `put_acquire_gil`."
self.putln("#ifdef WITH_THREAD")
self.putln("PyThreadState *_save = NULL;")
- self.putln("#endif")
self.putln("Py_UNBLOCK_THREADS")
+ if variable:
+ self.putln('%s = _save;' % variable)
+ self.putln("#endif")
def declare_gilstate(self):
self.putln("#ifdef WITH_THREAD")
def __init__(self, pos, state, body):
self.state = state
+ if state == 'gil':
+ temp_type = PyrexTypes.c_gilstate_type
+ else:
+ temp_type = PyrexTypes.c_threadstate_ptr_type
+ import ExprNodes
+ self.state_temp = ExprNodes.TempNode(pos, temp_type)
TryFinallyStatNode.__init__(self, pos,
- body = body,
- finally_clause = GILExitNode(pos, state = state))
+ body=body,
+ finally_clause=GILExitNode(
+ pos, state=state, state_temp=self.state_temp))
def analyse_declarations(self, env):
env._in_with_gil_block = (self.state == 'gil')
def generate_execution_code(self, code):
code.mark_pos(self.pos)
code.begin_block()
+ self.state_temp.allocate(code)
if self.state == 'gil':
- code.put_ensure_gil()
+ code.put_ensure_gil(variable=self.state_temp.result())
else:
- code.put_release_gil()
+ code.put_release_gil(variable=self.state_temp.result())
TryFinallyStatNode.generate_execution_code(self, code)
+
+ self.state_temp.release(code)
code.end_block()
"""
child_attrs = []
+ state_temp = None
def analyse_expressions(self, env):
return self
def generate_execution_code(self, code):
+ if self.state_temp:
+ variable = self.state_temp.result()
+ else:
+ variable = None
+
if self.state == 'gil':
- code.put_release_ensured_gil()
+ code.put_release_ensured_gil(variable)
else:
- code.put_acquire_gil()
+ code.put_acquire_gil(variable)
class EnsureGILNode(GILExitNode):
c_ssize_t_ptr_type = CPtrType(c_ssize_t_type)
c_size_t_ptr_type = CPtrType(c_size_t_type)
+# GIL state
+c_gilstate_type = CEnumType("PyGILState_STATE", "PyGILState_STATE", True)
+c_threadstate_type = CStructOrUnionType("PyThreadState", "struct", None, 1, "PyThreadState")
+c_threadstate_ptr_type = CPtrType(c_threadstate_type)
# the Py_buffer type is defined in Builtin.py
c_py_buffer_type = CStructOrUnionType("Py_buffer", "struct", None, 1, "Py_buffer")
"""
for i in range(n):
yield lambda : i
+
+
+def test_with_gil_section():
+ """
+ >>> list(test_with_gil_section())
+ [0, 1, 2]
+ """
+ cdef int i
+ with nogil:
+ for i in range(3):
+ with gil:
+ yield i
+
+
+def test_double_with_gil_section():
+ """
+ >>> list(test_double_with_gil_section())
+ [0, 1, 2, 3]
+ """
+ cdef int i,j
+ with nogil:
+ for i in range(2):
+ with gil:
+ with nogil:
+ for j in range(2):
+ with gil:
+ yield i*2+j