From b356ac8780a62c50e1d122aa8cabc612d1c7d678 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Mon, 10 Sep 2007 23:00:48 +0200 Subject: [PATCH] support automatic GIL grabbing inside a function by addign 'withGIL' to its signature --- Cython/Compiler/Code.py | 7 +++++++ Cython/Compiler/ExprNodes.py | 2 +- Cython/Compiler/Naming.py | 1 + Cython/Compiler/Nodes.py | 29 +++++++++++++++++++++++++++-- Cython/Compiler/Parsing.py | 30 ++++++++++++++++++++++++++++-- Cython/Compiler/PyrexTypes.py | 10 ++++++++-- Cython/Compiler/Scanning.py | 2 +- 7 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index f52f6962..434d35eb 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -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 diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 8e506cfd..31ad5379 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -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)) diff --git a/Cython/Compiler/Naming.py b/Cython/Compiler/Naming.py index 0878d962..e110d633 100644 --- a/Cython/Compiler/Naming.py +++ b/Cython/Compiler/Naming.py @@ -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" diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 0900676a..0aa2aa74 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -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" diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 9ff8c65b..08a40d94 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -1455,10 +1455,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 @@ -1477,6 +1477,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 == "-": diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index b4ac6ed9..a19033d3 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -493,16 +493,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) @@ -585,6 +587,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 @@ -592,8 +595,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) diff --git a/Cython/Compiler/Scanning.py b/Cython/Compiler/Scanning.py index a0de4bc3..d5713762 100644 --- a/Cython/Compiler/Scanning.py +++ b/Cython/Compiler/Scanning.py @@ -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: -- 2.26.2