Commit 4fc2fd38 authored by Stefan Behnel's avatar Stefan Behnel

Support "@cython.nogil" decorator in pure mode.

Closes #2557.
parent 70b3d15d
...@@ -23,6 +23,9 @@ Features added ...@@ -23,6 +23,9 @@ Features added
* Raising exceptions from nogil code will automatically acquire the GIL, instead * Raising exceptions from nogil code will automatically acquire the GIL, instead
of requiring an explicit ``with gil`` block. of requiring an explicit ``with gil`` block.
* ``@cython.nogil`` is supported as a C-function decorator in Python code.
(Github issue #2557)
* In CPython 3.6 and later, looking up globals in the module dict is almost * In CPython 3.6 and later, looking up globals in the module dict is almost
as fast as looking up C globals. as fast as looking up C globals.
(Github issue #2313) (Github issue #2313)
......
...@@ -2777,7 +2777,8 @@ class DefNode(FuncDefNode): ...@@ -2777,7 +2777,8 @@ class DefNode(FuncDefNode):
self.num_required_kw_args = rk self.num_required_kw_args = rk
self.num_required_args = r self.num_required_args = r
def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None, except_val=None, modifiers=None): def as_cfunction(self, cfunc=None, scope=None, overridable=True, returns=None, except_val=None, modifiers=None,
nogil=False, with_gil=False):
if self.star_arg: if self.star_arg:
error(self.star_arg.pos, "cdef function cannot have star argument") error(self.star_arg.pos, "cdef function cannot have star argument")
if self.starstar_arg: if self.starstar_arg:
...@@ -2798,8 +2799,8 @@ class DefNode(FuncDefNode): ...@@ -2798,8 +2799,8 @@ class DefNode(FuncDefNode):
has_varargs=False, has_varargs=False,
exception_value=None, exception_value=None,
exception_check=exception_check, exception_check=exception_check,
nogil=False, nogil=nogil,
with_gil=False, with_gil=with_gil,
is_overridable=overridable) is_overridable=overridable)
cfunc = CVarDefNode(self.pos, type=cfunc_type) cfunc = CVarDefNode(self.pos, type=cfunc_type)
else: else:
......
...@@ -184,6 +184,7 @@ _directive_defaults = { ...@@ -184,6 +184,7 @@ _directive_defaults = {
'ccomplex' : False, # use C99/C++ for complex types and arith 'ccomplex' : False, # use C99/C++ for complex types and arith
'callspec' : "", 'callspec' : "",
'final' : False, 'final' : False,
'nogil' : False,
'internal' : False, 'internal' : False,
'profile': False, 'profile': False,
'no_gc_clear': False, 'no_gc_clear': False,
...@@ -323,6 +324,7 @@ directive_scopes = { # defaults to available everywhere ...@@ -323,6 +324,7 @@ directive_scopes = { # defaults to available everywhere
# 'module', 'function', 'class', 'with statement' # 'module', 'function', 'class', 'with statement'
'auto_pickle': ('module', 'cclass'), 'auto_pickle': ('module', 'cclass'),
'final' : ('cclass', 'function'), 'final' : ('cclass', 'function'),
'nogil' : ('function',),
'inline' : ('function',), 'inline' : ('function',),
'returns' : ('function',), 'returns' : ('function',),
'exceptval' : ('function',), 'exceptval' : ('function',),
......
...@@ -2333,6 +2333,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): ...@@ -2333,6 +2333,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
@cython.cclass @cython.cclass
@cython.ccall @cython.ccall
@cython.inline @cython.inline
@cython.nogil
""" """
def visit_ModuleNode(self, node): def visit_ModuleNode(self, node):
...@@ -2352,6 +2353,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): ...@@ -2352,6 +2353,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
modifiers = [] modifiers = []
if 'inline' in self.directives: if 'inline' in self.directives:
modifiers.append('inline') modifiers.append('inline')
nogil = self.directives.get('nogil')
except_val = self.directives.get('exceptval') except_val = self.directives.get('exceptval')
return_type_node = self.directives.get('returns') return_type_node = self.directives.get('returns')
if return_type_node is None and self.directives['annotation_typing']: if return_type_node is None and self.directives['annotation_typing']:
...@@ -2364,7 +2366,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): ...@@ -2364,7 +2366,7 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
except_val = (None, False) except_val = (None, False)
if 'ccall' in self.directives: if 'ccall' in self.directives:
node = node.as_cfunction( node = node.as_cfunction(
overridable=True, modifiers=modifiers, overridable=True, modifiers=modifiers, nogil=nogil,
returns=return_type_node, except_val=except_val) returns=return_type_node, except_val=except_val)
return self.visit(node) return self.visit(node)
if 'cfunc' in self.directives: if 'cfunc' in self.directives:
...@@ -2372,11 +2374,14 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations): ...@@ -2372,11 +2374,14 @@ class AdjustDefByDirectives(CythonTransform, SkipDeclarations):
error(node.pos, "cfunc directive is not allowed here") error(node.pos, "cfunc directive is not allowed here")
else: else:
node = node.as_cfunction( node = node.as_cfunction(
overridable=False, modifiers=modifiers, overridable=False, modifiers=modifiers, nogil=nogil,
returns=return_type_node, except_val=except_val) returns=return_type_node, except_val=except_val)
return self.visit(node) return self.visit(node)
if 'inline' in modifiers: if 'inline' in modifiers:
error(node.pos, "Python functions cannot be declared 'inline'") error(node.pos, "Python functions cannot be declared 'inline'")
if nogil:
# TODO: turn this into a "with gil" declaration.
error(node.pos, "Python functions cannot be declared 'nogil'")
self.visitchildren(node) self.visitchildren(node)
return node return node
......
...@@ -123,6 +123,8 @@ overflowcheck.fold = optimization.use_switch = \ ...@@ -123,6 +123,8 @@ overflowcheck.fold = optimization.use_switch = \
final = internal = type_version_tag = no_gc_clear = no_gc = _empty_decorator final = internal = type_version_tag = no_gc_clear = no_gc = _empty_decorator
gil = nogil = _EmptyDecoratorAndManager()
_cython_inline = None _cython_inline = None
def inline(f, *args, **kwds): def inline(f, *args, **kwds):
...@@ -185,17 +187,6 @@ def declare(type=None, value=_Unspecified, **kwds): ...@@ -185,17 +187,6 @@ def declare(type=None, value=_Unspecified, **kwds):
else: else:
return value return value
class _nogil(object):
"""Support for 'with nogil' statement
"""
def __enter__(self):
pass
def __exit__(self, exc_class, exc, tb):
return exc_class is None
nogil = _nogil()
gil = _nogil()
del _nogil
# Emulated types # Emulated types
......
# mode: error
# tag: warnings
import cython
@cython.cfunc
@cython.locals(x=cython.int)
@cython.returns(cython.int)
def cdef_needs_gil(x):
return x + 1
@cython.cfunc
@cython.nogil
@cython.locals(x=cython.int)
@cython.returns(cython.int)
def cdef_nogil(x):
return x + 1
@cython.locals(x=cython.int)
def test_cdef_nogil(x):
cdef_nogil(x) # ok
with cython.nogil:
cdef_needs_gil(x) # not ok
@cython.nogil
def pyfunc(x):
return x + 1
_ERRORS = """
25:22: Calling gil-requiring function not allowed without gil
29:0: Python functions cannot be declared 'nogil'
"""
...@@ -267,6 +267,25 @@ def call_cdef_inline(x): ...@@ -267,6 +267,25 @@ def call_cdef_inline(x):
return ret, cython.typeof(ret) return ret, cython.typeof(ret)
@cython.cfunc
@cython.nogil
@cython.locals(x=cython.int)
@cython.returns(cython.int)
def cdef_nogil(x):
return x + 1
@cython.locals(x=cython.int)
def test_cdef_nogil(x):
"""
>>> test_cdef_nogil(5)
6
"""
with cython.nogil:
result = cdef_nogil(x)
return result
@cython.locals(counts=cython.int[10], digit=cython.int) @cython.locals(counts=cython.int[10], digit=cython.int)
def count_digits_in_carray(digits): def count_digits_in_carray(digits):
""" """
......
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