Commit b80032da authored by Stefan Behnel's avatar Stefan Behnel

support automatic GIL grabbing inside a function by addign 'withGIL' to its signature

parent 7ad701d1
...@@ -284,6 +284,13 @@ class CCodeWriter: ...@@ -284,6 +284,13 @@ class CCodeWriter:
# code = "((PyObject*)%s)" % code # code = "((PyObject*)%s)" % code
self.put_init_to_py_none(code, entry.type) 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): def put_pymethoddef(self, entry, term):
if entry.doc: if entry.doc:
doc_code = entry.doc_cname doc_code = entry.doc_cname
......
...@@ -473,7 +473,7 @@ class ExprNode(Node): ...@@ -473,7 +473,7 @@ class ExprNode(Node):
else: # neither src nor dst are py types else: # neither src nor dst are py types
# Added the string comparison, since for c types that # Added the string comparison, since for c types that
# is enough, but SageX gets confused when the types are # 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)): if not (str(src.type) == str(dst_type) or dst_type.assignable_from(src_type)):
error(self.pos, "Cannot assign type '%s' to '%s'" % error(self.pos, "Cannot assign type '%s' to '%s'" %
(src.type, dst_type)) (src.type, dst_type))
......
...@@ -53,5 +53,6 @@ self_cname = pyrex_prefix + "self" ...@@ -53,5 +53,6 @@ self_cname = pyrex_prefix + "self"
stringtab_cname = pyrex_prefix + "string_tab" stringtab_cname = pyrex_prefix + "string_tab"
vtabslot_cname = pyrex_prefix + "vtab" vtabslot_cname = pyrex_prefix + "vtab"
c_api_tab_cname = pyrex_prefix + "c_api_tab" c_api_tab_cname = pyrex_prefix + "c_api_tab"
gilstate_cname = pyrex_prefix + "state"
extern_c_macro = pyrex_prefix.upper() + "EXTERN_C" extern_c_macro = pyrex_prefix.upper() + "EXTERN_C"
...@@ -282,6 +282,7 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -282,6 +282,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
# has_varargs boolean # has_varargs boolean
# exception_value ConstNode # exception_value ConstNode
# exception_check boolean True if PyErr_Occurred check needed # 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): def analyse(self, return_type, env):
func_type_args = [] func_type_args = []
...@@ -317,7 +318,8 @@ class CFuncDeclaratorNode(CDeclaratorNode): ...@@ -317,7 +318,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
exc_check = self.exception_check exc_check = self.exception_check
func_type = PyrexTypes.CFuncType( func_type = PyrexTypes.CFuncType(
return_type, func_type_args, self.has_varargs, 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) return self.base.analyse(func_type, env)
...@@ -572,6 +574,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -572,6 +574,8 @@ class FuncDefNode(StatNode, BlockNode):
self.generate_keyword_list(code) self.generate_keyword_list(code)
# ----- Extern library function declarations # ----- Extern library function declarations
lenv.generate_library_function_declarations(code) lenv.generate_library_function_declarations(code)
# ----- Grab GIL
self.generate_grab_gil(code)
# ----- Fetch arguments # ----- Fetch arguments
self.generate_argument_parsing_code(code) self.generate_argument_parsing_code(code)
self.generate_argument_increfs(lenv, code) self.generate_argument_increfs(lenv, code)
...@@ -623,6 +627,9 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -623,6 +627,9 @@ class FuncDefNode(StatNode, BlockNode):
code.put_var_decrefs(lenv.var_entries, used_only = 1) code.put_var_decrefs(lenv.var_entries, used_only = 1)
code.put_var_decrefs(lenv.arg_entries) code.put_var_decrefs(lenv.arg_entries)
self.put_stararg_decrefs(code) self.put_stararg_decrefs(code)
# ----- Release GIL
self.generate_release_gil(code)
# ----- Return
if not self.return_type.is_void: if not self.return_type.is_void:
retval_code = Naming.retval_cname retval_code = Naming.retval_cname
#if self.return_type.is_extension_type: #if self.return_type.is_extension_type:
...@@ -653,6 +660,12 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -653,6 +660,12 @@ class FuncDefNode(StatNode, BlockNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
pass pass
def generate_grab_gil(self, code):
pass
def generate_release_gil(self, code):
pass
class CFuncDefNode(FuncDefNode): class CFuncDefNode(FuncDefNode):
# C function definition. # C function definition.
...@@ -756,7 +769,19 @@ class CFuncDefNode(FuncDefNode): ...@@ -756,7 +769,19 @@ class CFuncDefNode(FuncDefNode):
else: else:
error(arg.pos, "Cannot test type of extern C class " error(arg.pos, "Cannot test type of extern C class "
"without type object name specification") "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): def error_value(self):
if self.return_type.is_pyobject: if self.return_type.is_pyobject:
return "0" return "0"
......
...@@ -1462,10 +1462,10 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0 , assignable = 0) ...@@ -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) args = p_c_arg_list(s, in_pyfunc = 0, cmethod_flag = cmethod_flag)
ellipsis = p_optional_ellipsis(s) ellipsis = p_optional_ellipsis(s)
s.expect(')') s.expect(')')
exc_val, exc_check = p_exception_value_clause(s) options = p_c_func_options(s)
result = Nodes.CFuncDeclaratorNode(pos, result = Nodes.CFuncDeclaratorNode(pos,
base = result, args = args, has_varargs = ellipsis, base = result, args = args, has_varargs = ellipsis,
exception_value = exc_val, exception_check = exc_check) **options)
cmethod_flag = 0 cmethod_flag = 0
return result return result
...@@ -1484,6 +1484,32 @@ def p_exception_value_clause(s): ...@@ -1484,6 +1484,32 @@ def p_exception_value_clause(s):
exc_val = p_simple_expr(s) #p_exception_value(s) exc_val = p_simple_expr(s) #p_exception_value(s)
return exc_val, exc_check 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): #def p_exception_value(s):
# sign = "" # sign = ""
# if s.sy == "-": # if s.sy == "-":
......
...@@ -488,16 +488,18 @@ class CFuncType(CType): ...@@ -488,16 +488,18 @@ class CFuncType(CType):
# has_varargs boolean # has_varargs boolean
# exception_value string # exception_value string
# exception_check boolean True if PyErr_Occurred check needed # exception_check boolean True if PyErr_Occurred check needed
# with_gil boolean True if GIL should be grabbed/released
is_cfunction = 1 is_cfunction = 1
def __init__(self, return_type, args, has_varargs, 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.return_type = return_type
self.args = args self.args = args
self.has_varargs = has_varargs self.has_varargs = has_varargs
self.exception_value = exception_value self.exception_value = exception_value
self.exception_check = exception_check self.exception_check = exception_check
self.with_gil = with_gil
def __repr__(self): def __repr__(self):
arg_reprs = map(repr, self.args) arg_reprs = map(repr, self.args)
...@@ -580,6 +582,7 @@ class CFuncType(CType): ...@@ -580,6 +582,7 @@ class CFuncType(CType):
if not arg_decl_code and not pyrex: if not arg_decl_code and not pyrex:
arg_decl_code = "void" arg_decl_code = "void"
exc_clause = "" exc_clause = ""
with_gil_clause = ""
if pyrex or for_display: if pyrex or for_display:
if self.exception_value and self.exception_check: if self.exception_value and self.exception_check:
exc_clause = " except? %s" % self.exception_value exc_clause = " except? %s" % self.exception_value
...@@ -587,8 +590,11 @@ class CFuncType(CType): ...@@ -587,8 +590,11 @@ class CFuncType(CType):
exc_clause = " except %s" % self.exception_value exc_clause = " except %s" % self.exception_value
elif self.exception_check: elif self.exception_check:
exc_clause = " except *" exc_clause = " except *"
if self.with_gil:
with_gil_clause = " withGIL"
return self.return_type.declaration_code( 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) for_display, dll_linkage, pyrex)
......
...@@ -138,7 +138,7 @@ reserved_words = [ ...@@ -138,7 +138,7 @@ reserved_words = [
"raise", "import", "exec", "try", "except", "finally", "raise", "import", "exec", "try", "except", "finally",
"while", "if", "elif", "else", "for", "in", "assert", "while", "if", "elif", "else", "for", "in", "assert",
"and", "or", "not", "is", "in", "lambda", "from", "and", "or", "not", "is", "in", "lambda", "from",
"NULL", "cimport", "by" "NULL", "cimport", "by", "withGIL"
] ]
class Method: class Method:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment