Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Gwenaël Samain
cython
Commits
86bb8a8f
Commit
86bb8a8f
authored
Mar 15, 2009
by
Stefan Behnel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactored GIL checking into separate transform (ticket #205)
parent
c93d8837
Changes
5
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
139 additions
and
76 deletions
+139
-76
Cython/Compiler/ExprNodes.py
Cython/Compiler/ExprNodes.py
+69
-47
Cython/Compiler/Main.py
Cython/Compiler/Main.py
+2
-0
Cython/Compiler/Nodes.py
Cython/Compiler/Nodes.py
+28
-24
Cython/Compiler/ParseTreeTransforms.py
Cython/Compiler/ParseTreeTransforms.py
+37
-1
tests/errors/nogil.pyx
tests/errors/nogil.pyx
+3
-4
No files found.
Cython/Compiler/ExprNodes.py
View file @
86bb8a8f
This diff is collapsed.
Click to expand it.
Cython/Compiler/Main.py
View file @
86bb8a8f
...
@@ -81,6 +81,7 @@ class Context(object):
...
@@ -81,6 +81,7 @@ class Context(object):
from
ParseTreeTransforms
import
CreateClosureClasses
,
MarkClosureVisitor
,
DecoratorTransform
from
ParseTreeTransforms
import
CreateClosureClasses
,
MarkClosureVisitor
,
DecoratorTransform
from
ParseTreeTransforms
import
InterpretCompilerDirectives
,
TransformBuiltinMethods
from
ParseTreeTransforms
import
InterpretCompilerDirectives
,
TransformBuiltinMethods
from
ParseTreeTransforms
import
ComprehensionTransform
,
AlignFunctionDefinitions
from
ParseTreeTransforms
import
ComprehensionTransform
,
AlignFunctionDefinitions
from
ParseTreeTransforms
import
GilCheck
from
AutoDocTransforms
import
EmbedSignature
from
AutoDocTransforms
import
EmbedSignature
from
Optimize
import
FlattenInListTransform
,
SwitchTransform
,
IterationTransform
from
Optimize
import
FlattenInListTransform
,
SwitchTransform
,
IterationTransform
from
Optimize
import
FlattenBuiltinTypeCreation
,
ConstantFolding
,
FinalOptimizePhase
from
Optimize
import
FlattenBuiltinTypeCreation
,
ConstantFolding
,
FinalOptimizePhase
...
@@ -129,6 +130,7 @@ class Context(object):
...
@@ -129,6 +130,7 @@ class Context(object):
IterationTransform
(),
IterationTransform
(),
SwitchTransform
(),
SwitchTransform
(),
FinalOptimizePhase
(
self
),
FinalOptimizePhase
(
self
),
GilCheck
(),
# ClearResultCodes(self),
# ClearResultCodes(self),
# SpecialFunctions(self),
# SpecialFunctions(self),
# CreateClosureClasses(context),
# CreateClosureClasses(context),
...
...
Cython/Compiler/Nodes.py
View file @
86bb8a8f
...
@@ -134,7 +134,8 @@ class Node(object):
...
@@ -134,7 +134,8 @@ class Node(object):
gil_message
=
"Operation"
gil_message
=
"Operation"
def
gil_check
(
self
,
env
):
gil_check
=
None
def
_gil_check
(
self
,
env
):
if
env
.
nogil
:
if
env
.
nogil
:
self
.
gil_error
()
self
.
gil_error
()
...
@@ -539,9 +540,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
...
@@ -539,9 +540,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
# Catch attempted C-style func(void) decl
# Catch attempted C-style func(void) decl
if
type
.
is_void
:
if
type
.
is_void
:
error
(
arg_node
.
pos
,
"Use spam() rather than spam(void) to declare a function with no arguments."
)
error
(
arg_node
.
pos
,
"Use spam() rather than spam(void) to declare a function with no arguments."
)
# if type.is_pyobject and self.nogil:
# error(self.pos,
# "Function with Python argument cannot be declared nogil")
func_type_args
.
append
(
func_type_args
.
append
(
PyrexTypes
.
CFuncTypeArg
(
name
,
type
,
arg_node
.
pos
))
PyrexTypes
.
CFuncTypeArg
(
name
,
type
,
arg_node
.
pos
))
if
arg_node
.
default
:
if
arg_node
.
default
:
...
@@ -1380,16 +1378,18 @@ class CFuncDefNode(FuncDefNode):
...
@@ -1380,16 +1378,18 @@ class CFuncDefNode(FuncDefNode):
self
.
declare_argument
(
env
,
arg
)
self
.
declare_argument
(
env
,
arg
)
def
need_gil_acquisition
(
self
,
lenv
):
def
need_gil_acquisition
(
self
,
lenv
):
return
self
.
type
.
with_gil
def
gil_check
(
self
,
env
):
type
=
self
.
type
type
=
self
.
type
with_gil
=
self
.
type
.
with_gil
with_gil
=
type
.
with_gil
if
type
.
nogil
and
not
with_gil
:
if
type
.
nogil
and
not
with_gil
:
if
type
.
return_type
.
is_pyobject
:
if
type
.
return_type
.
is_pyobject
:
error
(
self
.
pos
,
error
(
self
.
pos
,
"Function with Python return type cannot be declared nogil"
)
"Function with Python return type cannot be declared nogil"
)
for
entry
in
lenv
.
var_entries
+
l
env
.
temp_entries
:
for
entry
in
env
.
var_entries
+
env
.
temp_entries
:
if
entry
.
type
.
is_pyobject
:
if
entry
.
type
.
is_pyobject
:
error
(
self
.
pos
,
"Function declared nogil has Python locals or temporaries"
)
error
(
self
.
pos
,
"Function declared nogil has Python locals or temporaries"
)
return
with_gil
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
self
.
analyse_default_values
(
env
)
self
.
analyse_default_values
(
env
)
...
@@ -3227,8 +3227,8 @@ class PrintStatNode(StatNode):
...
@@ -3227,8 +3227,8 @@ class PrintStatNode(StatNode):
env
.
use_utility_code
(
printing_utility_code
)
env
.
use_utility_code
(
printing_utility_code
)
if
len
(
self
.
arg_tuple
.
args
)
==
1
and
self
.
append_newline
:
if
len
(
self
.
arg_tuple
.
args
)
==
1
and
self
.
append_newline
:
env
.
use_utility_code
(
printing_one_utility_code
)
env
.
use_utility_code
(
printing_one_utility_code
)
self
.
gil_check
(
env
)
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Python print statement"
gil_message
=
"Python print statement"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -3272,8 +3272,8 @@ class ExecStatNode(StatNode):
...
@@ -3272,8 +3272,8 @@ class ExecStatNode(StatNode):
self
.
temp_result
=
env
.
allocate_temp_pyobject
()
self
.
temp_result
=
env
.
allocate_temp_pyobject
()
env
.
release_temp
(
self
.
temp_result
)
env
.
release_temp
(
self
.
temp_result
)
env
.
use_utility_code
(
Builtin
.
pyexec_utility_code
)
env
.
use_utility_code
(
Builtin
.
pyexec_utility_code
)
self
.
gil_check
(
env
)
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Python exec statement"
gil_message
=
"Python exec statement"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -3311,12 +3311,15 @@ class DelStatNode(StatNode):
...
@@ -3311,12 +3311,15 @@ class DelStatNode(StatNode):
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
for
arg
in
self
.
args
:
for
arg
in
self
.
args
:
arg
.
analyse_target_expression
(
env
,
None
)
arg
.
analyse_target_expression
(
env
,
None
)
if
arg
.
type
.
is_pyobject
:
if
not
arg
.
type
.
is_pyobject
:
self
.
gil_check
(
env
)
else
:
error
(
arg
.
pos
,
"Deletion of non-Python object"
)
error
(
arg
.
pos
,
"Deletion of non-Python object"
)
#arg.release_target_temp(env)
#arg.release_target_temp(env)
def
gil_check
(
self
,
env
):
for
arg
in
self
.
args
:
if
arg
.
type
.
is_pyobject
:
self
.
_gil_check
(
env
)
gil_message
=
"Deleting Python object"
gil_message
=
"Deleting Python object"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -3402,8 +3405,10 @@ class ReturnStatNode(StatNode):
...
@@ -3402,8 +3405,10 @@ class ReturnStatNode(StatNode):
and
not
return_type
.
is_pyobject
and
not
return_type
.
is_pyobject
and
not
return_type
.
is_returncode
):
and
not
return_type
.
is_returncode
):
error
(
self
.
pos
,
"Return value required"
)
error
(
self
.
pos
,
"Return value required"
)
if
return_type
.
is_pyobject
:
self
.
gil_check
(
env
)
def
gil_check
(
self
,
env
):
if
self
.
return_type
.
is_pyobject
:
self
.
_gil_check
(
env
)
gil_message
=
"Returning Python object"
gil_message
=
"Returning Python object"
...
@@ -3478,8 +3483,8 @@ class RaiseStatNode(StatNode):
...
@@ -3478,8 +3483,8 @@ class RaiseStatNode(StatNode):
self
.
exc_tb
.
release_temp
(
env
)
self
.
exc_tb
.
release_temp
(
env
)
env
.
use_utility_code
(
raise_utility_code
)
env
.
use_utility_code
(
raise_utility_code
)
env
.
use_utility_code
(
restore_exception_utility_code
)
env
.
use_utility_code
(
restore_exception_utility_code
)
self
.
gil_check
(
env
)
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Raising exception"
gil_message
=
"Raising exception"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -3528,10 +3533,10 @@ class ReraiseStatNode(StatNode):
...
@@ -3528,10 +3533,10 @@ class ReraiseStatNode(StatNode):
child_attrs
=
[]
child_attrs
=
[]
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
self
.
gil_check
(
env
)
env
.
use_utility_code
(
raise_utility_code
)
env
.
use_utility_code
(
raise_utility_code
)
env
.
use_utility_code
(
restore_exception_utility_code
)
env
.
use_utility_code
(
restore_exception_utility_code
)
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Raising exception"
gil_message
=
"Raising exception"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -3560,9 +3565,9 @@ class AssertStatNode(StatNode):
...
@@ -3560,9 +3565,9 @@ class AssertStatNode(StatNode):
self
.
cond
.
release_temp
(
env
)
self
.
cond
.
release_temp
(
env
)
if
self
.
value
:
if
self
.
value
:
self
.
value
.
release_temp
(
env
)
self
.
value
.
release_temp
(
env
)
self
.
gil_check
(
env
)
#env.recycle_pending_temps() # TEMPORARY
#env.recycle_pending_temps() # TEMPORARY
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Raising exception"
gil_message
=
"Raising exception"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -4069,7 +4074,6 @@ class TryExceptStatNode(StatNode):
...
@@ -4069,7 +4074,6 @@ class TryExceptStatNode(StatNode):
except_clause
.
analyse_declarations
(
env
)
except_clause
.
analyse_declarations
(
env
)
if
self
.
else_clause
:
if
self
.
else_clause
:
self
.
else_clause
.
analyse_declarations
(
env
)
self
.
else_clause
.
analyse_declarations
(
env
)
self
.
gil_check
(
env
)
env
.
use_utility_code
(
reset_exception_utility_code
)
env
.
use_utility_code
(
reset_exception_utility_code
)
def
analyse_expressions
(
self
,
env
):
def
analyse_expressions
(
self
,
env
):
...
@@ -4085,8 +4089,8 @@ class TryExceptStatNode(StatNode):
...
@@ -4085,8 +4089,8 @@ class TryExceptStatNode(StatNode):
self
.
has_default_clause
=
default_clause_seen
self
.
has_default_clause
=
default_clause_seen
if
self
.
else_clause
:
if
self
.
else_clause
:
self
.
else_clause
.
analyse_expressions
(
env
)
self
.
else_clause
.
analyse_expressions
(
env
)
self
.
gil_check
(
env
)
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Try-except statement"
gil_message
=
"Try-except statement"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -4368,8 +4372,8 @@ class TryFinallyStatNode(StatNode):
...
@@ -4368,8 +4372,8 @@ class TryFinallyStatNode(StatNode):
self
.
body
.
analyse_expressions
(
env
)
self
.
body
.
analyse_expressions
(
env
)
self
.
cleanup_list
=
env
.
free_temp_entries
[:]
self
.
cleanup_list
=
env
.
free_temp_entries
[:]
self
.
finally_clause
.
analyse_expressions
(
env
)
self
.
finally_clause
.
analyse_expressions
(
env
)
self
.
gil_check
(
env
)
gil_check
=
StatNode
.
_gil_check
gil_message
=
"Try-finally statement"
gil_message
=
"Try-finally statement"
def
generate_execution_code
(
self
,
code
):
def
generate_execution_code
(
self
,
code
):
...
@@ -4517,7 +4521,7 @@ class GILStatNode(TryFinallyStatNode):
...
@@ -4517,7 +4521,7 @@ class GILStatNode(TryFinallyStatNode):
#
#
# state string 'gil' or 'nogil'
# state string 'gil' or 'nogil'
child_attrs
=
[]
#
child_attrs = []
preserve_exception
=
0
preserve_exception
=
0
...
...
Cython/Compiler/ParseTreeTransforms.py
View file @
86bb8a8f
...
@@ -847,6 +847,42 @@ class CreateClosureClasses(CythonTransform):
...
@@ -847,6 +847,42 @@ class CreateClosureClasses(CythonTransform):
return
node
return
node
class
GilCheck
(
VisitorTransform
):
"""
Call `node.gil_check(env)` on each node to make sure we hold the
GIL when we need it. Raise an error when on Python operations
inside a `nogil` environment.
"""
def
__call__
(
self
,
root
):
self
.
env_stack
=
[
root
.
scope
]
return
super
(
GilCheck
,
self
).
__call__
(
root
)
def
visit_FuncDefNode
(
self
,
node
):
self
.
env_stack
.
append
(
node
.
local_scope
)
if
node
.
gil_check
is
not
None
:
node
.
gil_check
(
self
.
env_stack
[
-
1
])
self
.
visitchildren
(
node
)
self
.
env_stack
.
pop
()
return
node
def
visit_GILStatNode
(
self
,
node
):
# FIXME: should we do some kind of GIL checking here, too?
# if node.gil_check is not None:
# node.gil_check(self.env_stack[-1])
env
=
self
.
env_stack
[
-
1
]
was_nogil
=
env
.
nogil
env
.
nogil
=
node
.
state
==
'nogil'
self
.
visitchildren
(
node
)
env
.
nogil
=
was_nogil
return
node
def
visit_Node
(
self
,
node
):
if
self
.
env_stack
and
node
.
gil_check
is
not
None
:
node
.
gil_check
(
self
.
env_stack
[
-
1
])
self
.
visitchildren
(
node
)
return
node
class
EnvTransform
(
CythonTransform
):
class
EnvTransform
(
CythonTransform
):
"""
"""
This transformation keeps a stack of the environments.
This transformation keeps a stack of the environments.
...
...
tests/errors/nogil.pyx
View file @
86bb8a8f
...
@@ -82,14 +82,14 @@ _ERRORS = u"""
...
@@ -82,14 +82,14 @@ _ERRORS = u"""
6: 6: Assignment of Python object not allowed without gil
6: 6: Assignment of Python object not allowed without gil
4: 5: Function declared nogil has Python locals or temporaries
4: 5: Function declared nogil has Python locals or temporaries
11: 5: Function with Python return type cannot be declared nogil
11: 5: Function with Python return type cannot be declared nogil
15: 5: Calling gil-requiring function without gil
15: 5: Calling gil-requiring function
not allowed
without gil
24: 9: Calling gil-requiring function without gil
24: 9: Calling gil-requiring function
not allowed
without gil
26:12: Assignment of Python object not allowed without gil
26:12: Assignment of Python object not allowed without gil
28: 8: Constructing complex number not allowed without gil
28: 8: Constructing complex number not allowed without gil
29:12: Accessing Python global or builtin not allowed without gil
29:12: Accessing Python global or builtin not allowed without gil
30: 8: Backquote expression not allowed without gil
30: 8: Backquote expression not allowed without gil
31:15: Python import not allowed without gil
31:15: Assignment of Python object not allowed without gil
31:15: Assignment of Python object not allowed without gil
31:15: Python import not allowed without gil
32:13: Python import not allowed without gil
32:13: Python import not allowed without gil
32:25: Constructing Python list not allowed without gil
32:25: Constructing Python list not allowed without gil
33:17: Iterating over Python object not allowed without gil
33:17: Iterating over Python object not allowed without gil
...
@@ -126,7 +126,6 @@ _ERRORS = u"""
...
@@ -126,7 +126,6 @@ _ERRORS = u"""
54: 8: Raising exception not allowed without gil
54: 8: Raising exception not allowed without gil
55:14: Truth-testing Python object not allowed without gil
55:14: Truth-testing Python object not allowed without gil
57:17: Truth-testing Python object not allowed without gil
57:17: Truth-testing Python object not allowed without gil
59: 8: Converting to Python object not allowed without gil
61: 8: Try-except statement not allowed without gil
61: 8: Try-except statement not allowed without gil
65: 8: Try-finally statement not allowed without gil
65: 8: Try-finally statement not allowed without gil
"""
"""
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment