support automatic GIL grabbing inside a function by addign 'withGIL' to its signature
authorStefan Behnel <scoder@users.berlios.de>
Mon, 10 Sep 2007 21:00:48 +0000 (23:00 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Mon, 10 Sep 2007 21:00:48 +0000 (23:00 +0200)
Cython/Compiler/Code.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/Naming.py
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Scanning.py

index f52f6962775e87fbe2e7905f5a07400020c38873..434d35ebd36d6e33322ef4c812be93c257b29f82 100644 (file)
@@ -284,6 +284,13 @@ class CCodeWriter:
         #      code = "((PyObject*)%s)" % code
         self.put_init_to_py_none(code, entry.type)
 
+    def put_py_gil_state_ensure(self, cname):
+        self.putln("PyGILState_STATE %s;" % cname)
+        self.putln("%s = PyGILState_Ensure();" % cname)
+
+    def put_py_gil_state_release(self, cname):
+        self.putln("PyGILState_Release(%s);" % cname)
+
     def put_pymethoddef(self, entry, term):
         if entry.doc:
             doc_code = entry.doc_cname
index 80b0845ed409a4145a72ec356b624c2c5cad9879..f323635272064644d8820e2450d25963cfdaf984 100644 (file)
@@ -473,7 +473,7 @@ class ExprNode(Node):
         else: # neither src nor dst are py types
             # Added the string comparison, since for c types that
             # is enough, but SageX gets confused when the types are
-            # in different files. 
+            # in different files.
             if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
                 error(self.pos, "Cannot assign type '%s' to '%s'" %
                     (src.type, dst_type))
index 0878d9628d253c4032fb954336afc164d53434cf..e110d633cc3eab1d694fb074831c9a4b5cb355a4 100644 (file)
@@ -53,5 +53,6 @@ self_cname       = pyrex_prefix + "self"
 stringtab_cname  = pyrex_prefix + "string_tab"
 vtabslot_cname   = pyrex_prefix + "vtab"
 c_api_tab_cname  = pyrex_prefix + "c_api_tab"
+gilstate_cname   = pyrex_prefix + "state"
 
 extern_c_macro  = pyrex_prefix.upper() + "EXTERN_C"
index 11109d1cc97e101f2df13fb5a6561dd8857f0048..c8bf92e19c6411ab96a17c87530ed4b8f26469ce 100644 (file)
@@ -282,6 +282,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
     # has_varargs      boolean
     # exception_value  ConstNode
     # exception_check  boolean    True if PyErr_Occurred check needed
+    # with_gil         boolean    True if GIL should be grabbed/released
 
     def analyse(self, return_type, env):
         func_type_args = []
@@ -317,7 +318,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
             exc_check = self.exception_check
         func_type = PyrexTypes.CFuncType(
             return_type, func_type_args, self.has_varargs, 
-            exception_value = exc_val, exception_check = exc_check)
+            exception_value = exc_val, exception_check = exc_check,
+            with_gil = self.with_gil)
         return self.base.analyse(func_type, env)
 
 
@@ -572,6 +574,8 @@ class FuncDefNode(StatNode, BlockNode):
         self.generate_keyword_list(code)
         # ----- Extern library function declarations
         lenv.generate_library_function_declarations(code)
+        # ----- Grab GIL
+        self.generate_grab_gil(code)
         # ----- Fetch arguments
         self.generate_argument_parsing_code(code)
         self.generate_argument_increfs(lenv, code)
@@ -623,6 +627,9 @@ class FuncDefNode(StatNode, BlockNode):
         code.put_var_decrefs(lenv.var_entries, used_only = 1)
         code.put_var_decrefs(lenv.arg_entries)
         self.put_stararg_decrefs(code)
+        # ----- Release GIL
+        self.generate_release_gil(code)
+        # ----- Return
         if not self.return_type.is_void:
             retval_code = Naming.retval_cname
             #if self.return_type.is_extension_type:
@@ -653,6 +660,12 @@ class FuncDefNode(StatNode, BlockNode):
     def generate_execution_code(self, code):
         pass
 
+    def generate_grab_gil(self, code):
+        pass
+
+    def generate_release_gil(self, code):
+        pass
+
 
 class CFuncDefNode(FuncDefNode):
     #  C function definition.
@@ -756,7 +769,19 @@ class CFuncDefNode(FuncDefNode):
         else:
             error(arg.pos, "Cannot test type of extern C class "
                 "without type object name specification")
-    
+
+    def generate_grab_gil(self, code):
+        if self.entry.type.with_gil:
+            code.putln("")
+            code.put_py_gil_state_ensure(Naming.gilstate_cname)
+            code.putln("")
+
+    def generate_release_gil(self, code):
+        if self.entry.type.with_gil:
+            code.putln("")
+            code.put_py_gil_state_release(Naming.gilstate_cname)
+            code.putln("")
+
     def error_value(self):
         if self.return_type.is_pyobject:
             return "0"
index cbe3126c52e0ab45697c9d6ea569bcda7b94026c..760f2076344d3c8ab71b315f48b8356f814ebdd6 100644 (file)
@@ -1462,10 +1462,10 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0 , assignable = 0)
                 args = p_c_arg_list(s, in_pyfunc = 0, cmethod_flag = cmethod_flag)
                 ellipsis = p_optional_ellipsis(s)
                 s.expect(')')
-                exc_val, exc_check = p_exception_value_clause(s)
+                options = p_c_func_options(s)
                 result = Nodes.CFuncDeclaratorNode(pos, 
                     base = result, args = args, has_varargs = ellipsis,
-                    exception_value = exc_val, exception_check = exc_check)
+                    **options)
             cmethod_flag = 0
     return result
 
@@ -1484,6 +1484,32 @@ def p_exception_value_clause(s):
             exc_val = p_simple_expr(s) #p_exception_value(s)
     return exc_val, exc_check
 
+def p_c_with_gil(s):
+    if s.sy == 'withGIL':
+        s.next()
+        return True
+    return False
+
+def p_c_func_options(s):
+    exc_val = None
+    exc_check = 0
+    with_gil = False
+
+    if s.sy == 'except':
+        exc_val, exc_check = p_exception_value_clause(s)
+        with_gil = p_c_with_gil(s)
+    elif s.sy == 'withGIL':
+        with_gil = p_c_with_gil(s)
+        exc_val, exc_check = p_exception_value_clause(s)
+
+    ret = {
+        'exception_value': exc_val,
+        'exception_check': exc_check,
+        'with_gil': with_gil,
+        }
+
+    return ret
+
 #def p_exception_value(s):
 #      sign = ""
 #      if s.sy == "-":
index 238cc632901490eba3abac0266c82e5cd6f14b3d..bc5fcf488e30fa03a40caaa1e443d2ed33fc330b 100644 (file)
@@ -488,16 +488,18 @@ class CFuncType(CType):
     #  has_varargs      boolean
     #  exception_value  string
     #  exception_check  boolean  True if PyErr_Occurred check needed
+    #  with_gil         boolean  True if GIL should be grabbed/released
     
     is_cfunction = 1
     
     def __init__(self, return_type, args, has_varargs,
-            exception_value = None, exception_check = 0):
+            exception_value = None, exception_check = 0, with_gil = False):
         self.return_type = return_type
         self.args = args
         self.has_varargs = has_varargs
         self.exception_value = exception_value
         self.exception_check = exception_check
+        self.with_gil = with_gil
     
     def __repr__(self):
         arg_reprs = map(repr, self.args)
@@ -580,6 +582,7 @@ class CFuncType(CType):
         if not arg_decl_code and not pyrex:
             arg_decl_code = "void"
         exc_clause = ""
+        with_gil_clause = ""
         if pyrex or for_display:
             if self.exception_value and self.exception_check:
                 exc_clause = " except? %s" % self.exception_value
@@ -587,8 +590,11 @@ class CFuncType(CType):
                 exc_clause = " except %s" % self.exception_value
             elif self.exception_check:
                 exc_clause = " except *"
+            if self.with_gil:
+                with_gil_clause = " withGIL"
         return self.return_type.declaration_code(
-            "(%s(%s)%s)" % (entity_code, arg_decl_code, exc_clause),
+            "(%s(%s)%s%s)" % (entity_code, arg_decl_code,
+                              exc_clause, with_gil_clause),
             for_display, dll_linkage, pyrex)
 
 
index a0de4bc36b108e6a84a5159919a1de5a32e19920..d57137626964a57255f2908ec3df011ee924ea7e 100644 (file)
@@ -138,7 +138,7 @@ reserved_words = [
     "raise", "import", "exec", "try", "except", "finally",
     "while", "if", "elif", "else", "for", "in", "assert",
     "and", "or", "not", "is", "in", "lambda", "from",
-    "NULL", "cimport", "by"
+    "NULL", "cimport", "by", "withGIL"
 ]
 
 class Method: