Commit 1c1c8b9a authored by gsamain's avatar gsamain

first batch for locking on assignment

parent bc47d4b5
...@@ -848,7 +848,8 @@ class ExprNode(Node): ...@@ -848,7 +848,8 @@ class ExprNode(Node):
self.generate_subexpr_disposal_code(code) self.generate_subexpr_disposal_code(code)
def generate_assignment_code(self, rhs, code, overloaded_assignment=False, def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
exception_check=None, exception_value=None): exception_check=None, exception_value=None, needs_unlock=False,
needs_rlock=False, needs_wlock=False):
# Stub method for nodes which are not legal as # Stub method for nodes which are not legal as
# the LHS of an assignment. An error will have # the LHS of an assignment. An error will have
# been reported earlier. # been reported earlier.
...@@ -2301,7 +2302,8 @@ class NameNode(AtomicExprNode): ...@@ -2301,7 +2302,8 @@ class NameNode(AtomicExprNode):
code.put_error_if_unbound(self.pos, entry, self.in_nogil_context) code.put_error_if_unbound(self.pos, entry, self.in_nogil_context)
def generate_assignment_code(self, rhs, code, overloaded_assignment=False, def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
exception_check=None, exception_value=None): exception_check=None, exception_value=None, needs_unlock=False,
needs_rlock=False, needs_wlock=False):
#print "NameNode.generate_assignment_code:", self.name ### #print "NameNode.generate_assignment_code:", self.name ###
entry = self.entry entry = self.entry
if entry is None: if entry is None:
...@@ -2396,6 +2398,8 @@ class NameNode(AtomicExprNode): ...@@ -2396,6 +2398,8 @@ class NameNode(AtomicExprNode):
code.put_cyxdecref(self.result()) code.put_cyxdecref(self.result())
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
if not assigned: if not assigned:
if needs_unlock:
code.putln("Cy_UNLOCK(%s);" % self.result())
if overloaded_assignment: if overloaded_assignment:
result = rhs.result() result = rhs.result()
if exception_check == '+': if exception_check == '+':
...@@ -2413,6 +2417,10 @@ class NameNode(AtomicExprNode): ...@@ -2413,6 +2417,10 @@ class NameNode(AtomicExprNode):
code.putln('new (&%s) decltype(%s){%s};' % (self.result(), self.result(), result)) code.putln('new (&%s) decltype(%s){%s};' % (self.result(), self.result(), result))
elif result != self.result(): elif result != self.result():
code.putln('%s = %s;' % (self.result(), result)) code.putln('%s = %s;' % (self.result(), result))
if needs_wlock:
code.putln("Cy_WLOCK(%s);" % self.result())
elif needs_rlock:
code.putln("Cy_RLOCK(%s);" % self.result())
if debug_disposal_code: if debug_disposal_code:
print("NameNode.generate_assignment_code:") print("NameNode.generate_assignment_code:")
print("...generating post-assignment code for %s" % rhs) print("...generating post-assignment code for %s" % rhs)
...@@ -6045,6 +6053,9 @@ class SimpleCallNode(CallNode): ...@@ -6045,6 +6053,9 @@ class SimpleCallNode(CallNode):
exc_checks.append("__Pyx_ErrOccurredWithGIL()") exc_checks.append("__Pyx_ErrOccurredWithGIL()")
else: else:
exc_checks.append("PyErr_Occurred()") exc_checks.append("PyErr_Occurred()")
for arg in self.args:
if arg.type.is_cyp_class and arg.type.lock_mode == "autolock":
code.putln("Cy_WLOCK(%s);" % arg.result())
if self.is_temp or exc_checks: if self.is_temp or exc_checks:
rhs = self.c_call_code() rhs = self.c_call_code()
if self.result(): if self.result():
...@@ -6833,7 +6844,6 @@ class AttributeNode(ExprNode): ...@@ -6833,7 +6844,6 @@ class AttributeNode(ExprNode):
is_memslice_transpose = False is_memslice_transpose = False
is_special_lookup = False is_special_lookup = False
is_py_attr = 0 is_py_attr = 0
needs_autolock = False
def as_cython_attribute(self): def as_cython_attribute(self):
if (isinstance(self.obj, NameNode) and if (isinstance(self.obj, NameNode) and
...@@ -7201,9 +7211,9 @@ class AttributeNode(ExprNode): ...@@ -7201,9 +7211,9 @@ class AttributeNode(ExprNode):
if hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and (obj.entry.is_variable or obj.entry.is_cfunction)\ if hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and (obj.entry.is_variable or obj.entry.is_cfunction)\
and not (obj.entry.is_rlocked and (not self.entry.is_cfunction or self.entry.type.is_const_method) or obj.entry.is_wlocked): and not (obj.entry.is_rlocked and (not self.entry.is_cfunction or self.entry.type.is_const_method) or obj.entry.is_wlocked):
if obj.entry.type.lock_mode == "autolock": if obj.entry.type.lock_mode == "autolock":
print "We will autolock here" print "Request read lock autolock here"
self.needs_autolock = True self.obj.entry.is_rlocked = True
self.obj.entry.is_wlocked = True self.obj.entry.locking_node.needs_rlock = True
elif obj.entry.type.lock_mode == "checklock": elif obj.entry.type.lock_mode == "checklock":
return False return False
return True return True
...@@ -7212,12 +7222,10 @@ class AttributeNode(ExprNode): ...@@ -7212,12 +7222,10 @@ class AttributeNode(ExprNode):
obj = self.obj obj = self.obj
if self.is_lvalue() and hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and not obj.entry.is_wlocked: if self.is_lvalue() and hasattr(obj, 'entry') and obj.entry.type.is_cyp_class and not obj.entry.is_wlocked:
if obj.entry.type.lock_mode == "autolock": if obj.entry.type.lock_mode == "autolock":
print "We will autolock here" print "Request write lock autolock here"
self.needs_autolock = True self.needs_autolock = True
self.obj.entry.is_wlocked = True self.obj.entry.is_wlocked = True
# FIXME: this needs to be obj.result(), because maybe we have to lock self.obj.entry.locking_node.needs_wlock = True
# an intermediate object (obj.att.__autolocked_obj__.attribute)
env.autolocked_entries.append(self.obj.entry)
elif obj.entry.type.lock_mode == "checklock": elif obj.entry.type.lock_mode == "checklock":
return False return False
return True return True
...@@ -7329,9 +7337,6 @@ class AttributeNode(ExprNode): ...@@ -7329,9 +7337,6 @@ class AttributeNode(ExprNode):
elif self.entry and self.entry.is_cmethod: elif self.entry and self.entry.is_cmethod:
# C method implemented as function call with utility code # C method implemented as function call with utility code
code.globalstate.use_entry_utility_code(self.entry) code.globalstate.use_entry_utility_code(self.entry)
if self.needs_autolock:
obj_code = self.obj.result_as(self.obj.type)
code.putln("Cy_WLOCK(%s);" % obj_code)
def generate_disposal_code(self, code): def generate_disposal_code(self, code):
if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose: if self.is_temp and self.type.is_memoryviewslice and self.is_memslice_transpose:
...@@ -7344,7 +7349,8 @@ class AttributeNode(ExprNode): ...@@ -7344,7 +7349,8 @@ class AttributeNode(ExprNode):
ExprNode.generate_disposal_code(self, code) ExprNode.generate_disposal_code(self, code)
def generate_assignment_code(self, rhs, code, overloaded_assignment=False, def generate_assignment_code(self, rhs, code, overloaded_assignment=False,
exception_check=None, exception_value=None): exception_check=None, exception_value=None, needs_unlock=False,
needs_rlock=False, needs_wlock=False):
self.obj.generate_evaluation_code(code) self.obj.generate_evaluation_code(code)
if self.is_py_attr: if self.is_py_attr:
code.globalstate.use_utility_code( code.globalstate.use_utility_code(
...@@ -7378,15 +7384,19 @@ class AttributeNode(ExprNode): ...@@ -7378,15 +7384,19 @@ class AttributeNode(ExprNode):
code.put_cygotref(select_code) code.put_cygotref(select_code)
code.put_cyxdecref(select_code) code.put_cyxdecref(select_code)
if self.needs_autolock: if needs_unlock:
code.putln("Cy_WLOCK(%s);" % self.obj.result()) code.putln("Cy_UNLOCK(%s);" % select_code)
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
select_code, select_code,
rhs.result_as(self.ctype()))) rhs.result_as(self.ctype())))
#rhs.result())) #rhs.result()))
if needs_wlock:
code.putln("Cy_WLOCK(%s);" % select_code)
elif needs_rlock:
code.putln("Cy_RLOCK(%s);" % select_code)
rhs.generate_post_assignment_code(code) rhs.generate_post_assignment_code(code)
rhs.free_temps(code) rhs.free_temps(code)
self.obj.generate_disposal_code(code) self.obj.generate_disposal_code(code)
......
...@@ -2186,8 +2186,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -2186,8 +2186,8 @@ class FuncDefNode(StatNode, BlockNode):
# NULL as a valid cypclass (with a typecast) # NULL as a valid cypclass (with a typecast)
code.put_cyxdecref(entry.cname) code.put_cyxdecref(entry.cname)
for entry in lenv.autolocked_entries: for node in lenv.autolocked_nodes:
code.putln("Cy_UNLOCK(%s);" % entry.cname) code.putln("Cy_UNLOCK(%s);" % node.result())
# Decref any increfed args # Decref any increfed args
for entry in lenv.arg_entries: for entry in lenv.arg_entries:
...@@ -5448,6 +5448,9 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -5448,6 +5448,9 @@ class SingleAssignmentNode(AssignmentNode):
first = False first = False
is_overloaded_assignment = False is_overloaded_assignment = False
declaration_only = False declaration_only = False
needs_unlock = False
needs_rlock = False
needs_wlock = False
def analyse_declarations(self, env): def analyse_declarations(self, env):
from . import ExprNodes from . import ExprNodes
...@@ -5544,6 +5547,16 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -5544,6 +5547,16 @@ class SingleAssignmentNode(AssignmentNode):
self.lhs = self.lhs.analyse_target_types(env) self.lhs = self.lhs.analyse_target_types(env)
self.lhs.gil_assignment_check(env) self.lhs.gil_assignment_check(env)
if hasattr(self.lhs, 'entry'):
entry = self.lhs.entry
if entry.type.is_cyp_class and entry.type.lock_mode == "autolock":
if entry.locking_node is None:
env.declare_autolocked(self.lhs)
else:
self.needs_unlock = True
self.lhs.entry.locking_node = self
self.lhs.entry.is_wlocked = False
self.lhs.entry.is_rlocked = False
self.rhs.check_rhs_locked(env) self.rhs.check_rhs_locked(env)
self.lhs.check_lhs_locked(env) self.lhs.check_lhs_locked(env)
unrolled_assignment = self.unroll_lhs(env) unrolled_assignment = self.unroll_lhs(env)
...@@ -5726,9 +5739,17 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -5726,9 +5739,17 @@ class SingleAssignmentNode(AssignmentNode):
code, code,
overloaded_assignment=self.is_overloaded_assignment, overloaded_assignment=self.is_overloaded_assignment,
exception_check=self.exception_check, exception_check=self.exception_check,
exception_value=self.exception_value) exception_value=self.exception_value,
needs_unlock=self.needs_unlock,
needs_rlock=self.needs_rlock,
needs_wlock=self.needs_wlock)
else: else:
self.lhs.generate_assignment_code(self.rhs, code) self.lhs.generate_assignment_code(
self.rhs,
code,
needs_unlock=self.needs_unlock,
needs_rlock=self.needs_rlock,
needs_wlock=self.needs_wlock)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
self.rhs.generate_function_definitions(env, code) self.rhs.generate_function_definitions(env, code)
......
...@@ -137,6 +137,7 @@ class Entry(object): ...@@ -137,6 +137,7 @@ class Entry(object):
# is_cgetter boolean Is a c-level getter function # is_cgetter boolean Is a c-level getter function
# is_wlocked boolean Is locked with a write lock (used for cypclass) # is_wlocked boolean Is locked with a write lock (used for cypclass)
# is_rlocked boolean Is locked with a read lock (used for cypclass) # is_rlocked boolean Is locked with a read lock (used for cypclass)
# locking_node Node The assignment node doing the locking
# TODO: utility_code and utility_code_definition serves the same purpose... # TODO: utility_code and utility_code_definition serves the same purpose...
...@@ -209,6 +210,7 @@ class Entry(object): ...@@ -209,6 +210,7 @@ class Entry(object):
is_cgetter = False is_cgetter = False
is_wlocked = False is_wlocked = False
is_rlocked = False is_rlocked = False
locking_node = None
def __init__(self, name, cname, type, pos = None, init = None): def __init__(self, name, cname, type, pos = None, init = None):
self.name = name self.name = name
...@@ -292,7 +294,7 @@ class Scope(object): ...@@ -292,7 +294,7 @@ class Scope(object):
# pyfunc_entries [Entry] Python function entries # pyfunc_entries [Entry] Python function entries
# cfunc_entries [Entry] C function entries # cfunc_entries [Entry] C function entries
# c_class_entries [Entry] All extension type entries # c_class_entries [Entry] All extension type entries
# autolocked_entries[Entry] All autolocked entries that needs unlocking # autolocked_nodes [ExprNodes] All autolocked nodes that needs unlocking
# cname_to_entry {string : Entry} Temp cname to entry mapping # cname_to_entry {string : Entry} Temp cname to entry mapping
# return_type PyrexType or None Return type of function owning scope # return_type PyrexType or None Return type of function owning scope
# is_builtin_scope boolean Is the builtin scope of Python/Cython # is_builtin_scope boolean Is the builtin scope of Python/Cython
...@@ -352,7 +354,7 @@ class Scope(object): ...@@ -352,7 +354,7 @@ class Scope(object):
self.cfunc_entries = [] self.cfunc_entries = []
self.c_class_entries = [] self.c_class_entries = []
self.defined_c_classes = [] self.defined_c_classes = []
self.autolocked_entries = [] self.autolocked_nodes = []
self.imported_c_classes = {} self.imported_c_classes = {}
self.cname_to_entry = {} self.cname_to_entry = {}
self.identifier_to_entry = {} self.identifier_to_entry = {}
...@@ -1794,10 +1796,18 @@ class LocalScope(Scope): ...@@ -1794,10 +1796,18 @@ class LocalScope(Scope):
if type.is_pyobject: if type.is_pyobject:
entry.init = "0" entry.init = "0"
entry.is_arg = 1 entry.is_arg = 1
if type.is_cyp_class and type.lock_mode == "autolock":
entry.is_wlocked = True
#entry.borrowed = 1 # Not using borrowed arg refs for now #entry.borrowed = 1 # Not using borrowed arg refs for now
self.arg_entries.append(entry) self.arg_entries.append(entry)
return entry return entry
def declare_autolocked(self, node):
# Add an entry for autolocked cypclass
if not (node.type.is_cyp_class and node.type.lock_mode == "autolock"):
error(pos, "Trying to autolock a non cypclass object !")
self.autolocked_nodes.append(node)
def declare_var(self, name, type, pos, def declare_var(self, name, type, pos,
cname = None, visibility = 'private', cname = None, visibility = 'private',
api = 0, in_pxd = 0, is_cdef = 0): api = 0, in_pxd = 0, is_cdef = 0):
......
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