Commit df5626e4 authored by Mark Florisson's avatar Mark Florisson

Acquisition count arguments, attributes + coerce memslice to objects

parent 83e7a363
...@@ -1362,6 +1362,7 @@ class NameNode(AtomicExprNode): ...@@ -1362,6 +1362,7 @@ class NameNode(AtomicExprNode):
node.entry = var_entry node.entry = var_entry
node.analyse_rvalue_entry(env) node.analyse_rvalue_entry(env)
return node return node
return super(NameNode, self).coerce_to(dst_type, env) return super(NameNode, self).coerce_to(dst_type, env)
def analyse_as_module(self, env): def analyse_as_module(self, env):
...@@ -1662,17 +1663,7 @@ class NameNode(AtomicExprNode): ...@@ -1662,17 +1663,7 @@ class NameNode(AtomicExprNode):
rhs.free_temps(code) rhs.free_temps(code)
else: else:
if self.type.is_memoryviewslice: if self.type.is_memoryviewslice:
import MemoryView self.generate_acquire_memoryviewslice(rhs, code)
MemoryView.put_acquire_memoryviewslice(rhs, self.type,
self.entry.is_cglobal, self.result(), self.pos, code)
if isinstance(rhs, CoerceToMemViewSliceNode):
# We had a new reference, the lhs now has another,
# dispose of ours.
# code.put_xdecref_memoryviewslice(rhs.result())
code.put_decref("%s.memview" % rhs.result(),
cython_memoryview_ptr_type,
nanny=False)
elif self.type.is_buffer: elif self.type.is_buffer:
# Generate code for doing the buffer release/acquisition. # Generate code for doing the buffer release/acquisition.
...@@ -1716,6 +1707,21 @@ class NameNode(AtomicExprNode): ...@@ -1716,6 +1707,21 @@ class NameNode(AtomicExprNode):
rhs.generate_post_assignment_code(code) rhs.generate_post_assignment_code(code)
rhs.free_temps(code) rhs.free_temps(code)
def generate_acquire_memoryviewslice(self, rhs, code):
"""
If the value was coerced to a memoryviewslice, its a new reference.
Otherwise we're simply using a borrowed reference from another slice
"""
import MemoryView
MemoryView.put_acquire_memoryviewslice(
lhs_cname=self.result(),
lhs_type=self.type,
lhs_pos=self.pos,
rhs=rhs,
code=code,
incref_rhs=not isinstance(rhs, CoerceToMemViewSliceNode))
def generate_acquire_buffer(self, rhs, code): def generate_acquire_buffer(self, rhs, code):
# rhstmp is only used in case the rhs is a complicated expression leading to # rhstmp is only used in case the rhs is a complicated expression leading to
# the object, to avoid repeating the same C expression for every reference # the object, to avoid repeating the same C expression for every reference
...@@ -4009,10 +4015,9 @@ class AttributeNode(ExprNode): ...@@ -4009,10 +4015,9 @@ class AttributeNode(ExprNode):
code.put_decref(select_code, self.ctype()) code.put_decref(select_code, self.ctype())
elif self.type.is_memoryviewslice: elif self.type.is_memoryviewslice:
import MemoryView import MemoryView
MemoryView.put_assign_to_memviewslice(select_code, rhs.result(), self.type, MemoryView.put_assign_to_memviewslice(
pos=self.pos, code=code) select_code, rhs.result(), self.type, code)
#if rhs.is_temp:
# code.put_xdecref_clear("%s.memview" % rhs.result(), cython_memoryview_ptr_type)
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
...@@ -7863,12 +7868,17 @@ class CoerceToPyTypeNode(CoercionNode): ...@@ -7863,12 +7868,17 @@ class CoerceToPyTypeNode(CoercionNode):
pass pass
def generate_result_code(self, code): def generate_result_code(self, code):
function = self.arg.type.to_py_function if self.arg.type.is_memoryviewslice:
code.putln('%s = %s(%s); %s' % ( funccall = self.arg.type.get_to_py_function(self.arg)
else:
funccall = "%s(%s)" % (self.arg.type.to_py_function,
self.arg.result())
code.putln('%s = %s; %s' % (
self.result(), self.result(),
function, funccall,
self.arg.result(),
code.error_goto_if_null(self.result(), self.pos))) code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
......
from Errors import CompileError from Errors import CompileError
import ExprNodes
from ExprNodes import IntNode, NoneNode, IntBinopNode, NameNode, AttributeNode from ExprNodes import IntNode, NoneNode, IntBinopNode, NameNode, AttributeNode
from Visitor import CythonTransform from Visitor import CythonTransform
import Options import Options
...@@ -74,8 +75,8 @@ def mangle_dtype_name(dtype): ...@@ -74,8 +75,8 @@ def mangle_dtype_name(dtype):
def axes_to_str(axes): def axes_to_str(axes):
return "".join([access[0].upper()+packing[0] for (access, packing) in axes]) return "".join([access[0].upper()+packing[0] for (access, packing) in axes])
def put_acquire_memoryviewslice(rhs, lhs_type, lhs_is_cglobal, lhs_result, lhs_pos, code): def put_acquire_memoryviewslice(lhs_cname, lhs_type, lhs_pos, rhs, code,
# import MemoryView incref_rhs=True, have_gil=False):
assert rhs.type.is_memoryviewslice assert rhs.type.is_memoryviewslice
pretty_rhs = isinstance(rhs, NameNode) or rhs.result_in_temp() pretty_rhs = isinstance(rhs, NameNode) or rhs.result_in_temp()
...@@ -86,14 +87,15 @@ def put_acquire_memoryviewslice(rhs, lhs_type, lhs_is_cglobal, lhs_result, lhs_p ...@@ -86,14 +87,15 @@ def put_acquire_memoryviewslice(rhs, lhs_type, lhs_is_cglobal, lhs_result, lhs_p
code.putln("%s = %s;" % (rhstmp, rhs.result_as(lhs_type))) code.putln("%s = %s;" % (rhstmp, rhs.result_as(lhs_type)))
code.putln(code.error_goto_if_null("%s.memview" % rhstmp, lhs_pos)) code.putln(code.error_goto_if_null("%s.memview" % rhstmp, lhs_pos))
put_assign_to_memviewslice(lhs_result, rhstmp, lhs_type, put_assign_to_memviewslice(lhs_cname, rhstmp, lhs_type, code, incref_rhs)
lhs_pos, code=code)
if not pretty_rhs: if not pretty_rhs:
code.funcstate.release_temp(rhstmp) code.funcstate.release_temp(rhstmp)
def put_assign_to_memviewslice(lhs_cname, rhs_cname, memviewslicetype, pos, code): def put_assign_to_memviewslice(lhs_cname, rhs_cname, memviewslicetype, code,
incref_rhs=True):
code.put_xdecref_memoryviewslice(lhs_cname) code.put_xdecref_memoryviewslice(lhs_cname)
if incref_rhs:
code.put_incref_memoryviewslice(rhs_cname) code.put_incref_memoryviewslice(rhs_cname)
code.putln("%s.memview = %s.memview;" % (lhs_cname, rhs_cname)) code.putln("%s.memview = %s.memview;" % (lhs_cname, rhs_cname))
...@@ -196,7 +198,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry): ...@@ -196,7 +198,7 @@ class MemoryViewSliceBufferEntry(Buffer.BufferEntry):
if access == 'full' and packing in ('strided', 'follow'): if access == 'full' and packing in ('strided', 'follow'):
code.globalstate.use_utility_code(memviewslice_index_helpers) code.globalstate.use_utility_code(memviewslice_index_helpers)
bufp = ('__pyx_memviewslice_index_full(%s, %s, %s)' % bufp = ('__pyx_memviewslice_index_full(%s, %s, %s, %s)' %
(bufp, index, stride, suboffset)) (bufp, index, stride, suboffset))
elif access == 'full' and packing == 'contig': elif access == 'full' and packing == 'contig':
...@@ -722,47 +724,6 @@ def _resolve_AttributeNode(env, node): ...@@ -722,47 +724,6 @@ def _resolve_AttributeNode(env, node):
scope = scope.lookup(modname).as_module scope = scope.lookup(modname).as_module
return scope.lookup(path[-1]) return scope.lookup(path[-1])
class MemoryViewSliceTransform(CythonTransform):
memviews_exist = False
def __call__(self, node):
return super(MemoryViewSliceTransform, self).__call__(node)
def inspect_scope(self, node, scope):
memviewvars = [entry for name, entry
in scope.entries.iteritems()
if entry.type.is_memoryviewslice]
if memviewvars:
self.memviews_exist = True
def visit_FuncDefNode(self, node):
# check for the existence of memview entries here.
self.inspect_scope(node, node.local_scope)
self.visitchildren(node)
return node
def visit_ModuleNode(self, node):
# check for memviews here.
self.inspect_scope(node, node.scope)
self.visitchildren(node)
return node
def visit_ClassDefNode(self, node):
# check for memviews in the class scope
if hasattr(node, 'scope'):
scope = node.scope
else:
scope = node.entry.type.scope
self.inspect_scope(node, scope)
self.visitchildren(node)
return node
def visit_SingleAssignmentNode(self, node):
return node
def load_memview_cy_utility(util_code_name, context=None, **kwargs): def load_memview_cy_utility(util_code_name, context=None, **kwargs):
return CythonUtilityCode.load(util_code_name, "MemoryView.pyx", return CythonUtilityCode.load(util_code_name, "MemoryView.pyx",
context=context, **kwargs) context=context, **kwargs)
......
...@@ -1251,8 +1251,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1251,8 +1251,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put_init_var_to_py_none(entry, "p->%s", nanny=False) code.put_init_var_to_py_none(entry, "p->%s", nanny=False)
for entry in memviewslice_attrs: for entry in memviewslice_attrs:
code.putln("p->%s.data = NULL;" % entry.cname) code.putln("p->%s.data = NULL;" % entry.cname)
code.put_init_to_py_none("p->%s.memview" % entry.cname, code.putln("p->%s.memview = NULL;" % entry.cname)
PyrexTypes.cython_memoryview_ptr_type, nanny=False)
entry = scope.lookup_here("__new__") entry = scope.lookup_here("__new__")
if entry and entry.is_special: if entry and entry.is_special:
if entry.trivial_signature: if entry.trivial_signature:
......
...@@ -1432,9 +1432,11 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1432,9 +1432,11 @@ class FuncDefNode(StatNode, BlockNode):
if entry.type.is_pyobject: if entry.type.is_pyobject:
if (acquire_gil or entry.assignments) and not entry.in_closure: if (acquire_gil or entry.assignments) and not entry.in_closure:
code.put_var_incref(entry) code.put_var_incref(entry)
if entry.type.is_memoryviewslice: # Note: all memoryviewslices are already newly acquired references
code.put_incref_memoryviewslice(entry.cname, # or increffed defaults!
have_gil=not lenv.nogil) #if entry.type.is_memoryviewslice:
# code.put_incref_memoryviewslice(entry.cname,
# have_gil=not lenv.nogil)
#code.put_incref("%s.memview" % entry.cname, cython_memoryview_ptr_type) #code.put_incref("%s.memview" % entry.cname, cython_memoryview_ptr_type)
# ----- Initialise local buffer auxiliary variables # ----- Initialise local buffer auxiliary variables
for entry in lenv.var_entries + lenv.arg_entries: for entry in lenv.var_entries + lenv.arg_entries:
...@@ -1482,6 +1484,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1482,6 +1484,8 @@ class FuncDefNode(StatNode, BlockNode):
# Clean up buffers -- this calls a Python function # Clean up buffers -- this calls a Python function
# so need to save and restore error state # so need to save and restore error state
buffers_present = len(lenv.buffer_entries) > 0 buffers_present = len(lenv.buffer_entries) > 0
memslice_entries = [e for e in lenv.entries.itervalues()
if e.type.is_memoryviewslice]
if buffers_present: if buffers_present:
code.globalstate.use_utility_code(restore_exception_utility_code) code.globalstate.use_utility_code(restore_exception_utility_code)
code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;") code.putln("{ PyObject *__pyx_type, *__pyx_value, *__pyx_tb;")
...@@ -1489,6 +1493,8 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1489,6 +1493,8 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.buffer_entries: for entry in lenv.buffer_entries:
Buffer.put_release_buffer_code(code, entry) Buffer.put_release_buffer_code(code, entry)
#code.putln("%s = 0;" % entry.cname) #code.putln("%s = 0;" % entry.cname)
#for entry in memslice_entries:
# code.put_xdecref_memoryviewslice(entry.cname)
code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}") code.putln("__Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}")
err_val = self.error_value() err_val = self.error_value()
...@@ -1548,10 +1554,12 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1548,10 +1554,12 @@ class FuncDefNode(StatNode, BlockNode):
for entry in lenv.var_entries: for entry in lenv.var_entries:
if not entry.used or entry.in_closure: if not entry.used or entry.in_closure:
continue continue
if entry.type.is_memoryviewslice: if entry.type.is_memoryviewslice:
#code.put_xdecref("%s.memview" % entry.cname, cython_memoryview_ptr_type) #code.put_xdecref("%s.memview" % entry.cname, cython_memoryview_ptr_type)
code.put_xdecref_memoryviewslice(entry.cname) code.put_xdecref_memoryviewslice(entry.cname)
if entry.type.is_pyobject:
elif entry.type.is_pyobject:
code.put_var_decref(entry) code.put_var_decref(entry)
# Decref any increfed args # Decref any increfed args
...@@ -1559,7 +1567,7 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1559,7 +1567,7 @@ class FuncDefNode(StatNode, BlockNode):
if entry.type.is_pyobject: if entry.type.is_pyobject:
if (acquire_gil or entry.assignments) and not entry.in_closure: if (acquire_gil or entry.assignments) and not entry.in_closure:
code.put_var_decref(entry) code.put_var_decref(entry)
if entry.type.is_memoryviewslice: if entry.type.is_memoryviewslice and isinstance(self, DefNode):
code.put_xdecref_memoryviewslice(entry.cname) code.put_xdecref_memoryviewslice(entry.cname)
#code.put_decref("%s.memview" % entry.cname, cython_memoryview_ptr_type) #code.put_decref("%s.memview" % entry.cname, cython_memoryview_ptr_type)
if self.needs_closure: if self.needs_closure:
...@@ -1574,9 +1582,6 @@ class FuncDefNode(StatNode, BlockNode): ...@@ -1574,9 +1582,6 @@ class FuncDefNode(StatNode, BlockNode):
err_val = default_retval err_val = default_retval
if self.return_type.is_pyobject: if self.return_type.is_pyobject:
code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname)) code.put_xgiveref(self.return_type.as_pyobject(Naming.retval_cname))
#elif self.return_type.is_memoryviewslice:
# code.put_xgiveref(code.as_pyobject("%s.memview" % Naming.retval_cname,cython_memoryview_ptr_type))
# code.put_xgiveref_memoryviewslice(Naming.retval_cname)
if self.entry.is_special and self.entry.name == "__hash__": if self.entry.is_special and self.entry.name == "__hash__":
# Returning -1 for __hash__ is supposed to signal an error # Returning -1 for __hash__ is supposed to signal an error
...@@ -2805,6 +2810,9 @@ class DefNode(FuncDefNode): ...@@ -2805,6 +2810,9 @@ class DefNode(FuncDefNode):
"%s = %s;" % ( "%s = %s;" % (
arg.entry.cname, arg.entry.cname,
arg.calculate_default_value_code(code))) arg.calculate_default_value_code(code)))
if arg.type.is_memoryviewslice:
code.put_incref_memoryviewslice(arg.entry.cname,
have_gil=True)
def generate_stararg_init_code(self, max_positional_args, code): def generate_stararg_init_code(self, max_positional_args, code):
if self.starstar_arg: if self.starstar_arg:
...@@ -2983,6 +2991,22 @@ class DefNode(FuncDefNode): ...@@ -2983,6 +2991,22 @@ class DefNode(FuncDefNode):
code.error_goto(self.pos))) code.error_goto(self.pos)))
code.putln('}') code.putln('}')
# convert arg values to their final type and assign them
for i, arg in enumerate(all_args):
if arg.default and not arg.type.is_pyobject:
code.putln("if (values[%d]) {" % i)
self.generate_arg_assignment(arg, "values[%d]" % i, code)
if arg.default and not arg.type.is_pyobject:
code.putln('} else {')
code.putln(
"%s = %s;" % (
arg.entry.cname,
arg.calculate_default_value_code(code)))
if arg.type.is_memoryviewslice:
code.put_incref_memoryviewslice(arg.entry.cname,
have_gil=True)
code.putln('}')
def generate_argument_conversion_code(self, code): def generate_argument_conversion_code(self, code):
# Generate code to convert arguments from signature type to # Generate code to convert arguments from signature type to
# declared type, if needed. Also copies signature arguments # declared type, if needed. Also copies signature arguments
...@@ -4291,8 +4315,12 @@ class ReturnStatNode(StatNode): ...@@ -4291,8 +4315,12 @@ class ReturnStatNode(StatNode):
self.value.generate_evaluation_code(code) self.value.generate_evaluation_code(code)
if self.return_type.is_memoryviewslice: if self.return_type.is_memoryviewslice:
import MemoryView import MemoryView
MemoryView.put_acquire_memoryviewslice(self.value, self.return_type, MemoryView.put_acquire_memoryviewslice(
False, Naming.retval_cname, None, code) lhs_cname=Naming.retval_cname,
lhs_type=self.return_type,
lhs_pos=self.value.pos,
rhs=self.value,
code=code)
else: else:
self.value.make_owned_reference(code) self.value.make_owned_reference(code)
code.putln( code.putln(
......
...@@ -376,12 +376,13 @@ class MemoryViewSliceType(PyrexType): ...@@ -376,12 +376,13 @@ class MemoryViewSliceType(PyrexType):
the *first* axis' packing spec and 'follow' for all other packing the *first* axis' packing spec and 'follow' for all other packing
specs. specs.
''' '''
import MemoryView
self.dtype = base_dtype self.dtype = base_dtype
self.axes = axes self.axes = axes
self.ndim = len(axes) self.ndim = len(axes)
self.flags = MemoryView.get_buf_flag(self.axes)
import MemoryView
self.is_c_contig, self.is_f_contig = MemoryView.is_cf_contig(self.axes) self.is_c_contig, self.is_f_contig = MemoryView.is_cf_contig(self.axes)
assert not (self.is_c_contig and self.is_f_contig) assert not (self.is_c_contig and self.is_f_contig)
...@@ -540,7 +541,7 @@ class MemoryViewSliceType(PyrexType): ...@@ -540,7 +541,7 @@ class MemoryViewSliceType(PyrexType):
context = dict( context = dict(
MemoryView.context, MemoryView.context,
buf_flag = MemoryView.get_buf_flag(self.axes), buf_flag = self.flags,
ndim = self.ndim, ndim = self.ndim,
axes_specs = ', '.join(self.axes_specs_to_code()), axes_specs = ', '.join(self.axes_specs_to_code()),
dtype_typedecl = self.dtype.declaration_code(""), dtype_typedecl = self.dtype.declaration_code(""),
...@@ -554,6 +555,13 @@ class MemoryViewSliceType(PyrexType): ...@@ -554,6 +555,13 @@ class MemoryViewSliceType(PyrexType):
return True return True
def create_to_py_utility_code(self, env):
return True
def get_to_py_function(self, obj):
return "__pyx_memoryview_fromslice(&%s, %s.memview->obj, %s, %s);" % (
obj.result(), obj.result(), self.flags, self.ndim)
def axes_specs_to_code(self): def axes_specs_to_code(self):
"Return a list of code constants for each axis" "Return a list of code constants for each axis"
import MemoryView import MemoryView
......
...@@ -166,7 +166,7 @@ cdef extern from "pythread.h": ...@@ -166,7 +166,7 @@ cdef extern from "pythread.h":
void PyThread_release_lock(PyThread_type_lock) nogil void PyThread_release_lock(PyThread_type_lock) nogil
cdef extern from *: cdef extern from *:
int __Pyx_GetBuffer(object, Py_buffer *, int) int __Pyx_GetBuffer(object, Py_buffer *, int) except -1
void __Pyx_ReleaseBuffer(Py_buffer *) void __Pyx_ReleaseBuffer(Py_buffer *)
ctypedef struct {{memviewslice_name}}: ctypedef struct {{memviewslice_name}}:
...@@ -175,6 +175,9 @@ cdef extern from *: ...@@ -175,6 +175,9 @@ cdef extern from *:
Py_ssize_t strides[{{max_dims}}] Py_ssize_t strides[{{max_dims}}]
Py_ssize_t suboffsets[{{max_dims}}] Py_ssize_t suboffsets[{{max_dims}}]
void puts(char *)
void printf(char *, ...)
@cname('__pyx_MemviewEnum') @cname('__pyx_MemviewEnum')
cdef class Enum(object): cdef class Enum(object):
...@@ -197,10 +200,9 @@ cdef indirect_contiguous = Enum("<contiguous and indirect>") ...@@ -197,10 +200,9 @@ cdef indirect_contiguous = Enum("<contiguous and indirect>")
cdef class memoryview(object): cdef class memoryview(object):
cdef object obj cdef object obj
cdef Py_buffer view
cdef PyThread_type_lock lock cdef PyThread_type_lock lock
cdef int acquisition_count cdef int acquisition_count
cdef Py_buffer view
def __cinit__(memoryview self, object obj, int flags): def __cinit__(memoryview self, object obj, int flags):
self.obj = obj self.obj = obj
...@@ -212,6 +214,7 @@ cdef class memoryview(object): ...@@ -212,6 +214,7 @@ cdef class memoryview(object):
def __dealloc__(memoryview self): def __dealloc__(memoryview self):
__Pyx_ReleaseBuffer(&self.view) __Pyx_ReleaseBuffer(&self.view)
if self.lock != NULL:
PyThread_free_lock(self.lock) PyThread_free_lock(self.lock)
@cname('__pyx_memoryview_getitem') @cname('__pyx_memoryview_getitem')
...@@ -255,6 +258,9 @@ cdef class memoryview(object): ...@@ -255,6 +258,9 @@ cdef class memoryview(object):
bytesitem = itemp[:self.view.itemsize] bytesitem = itemp[:self.view.itemsize]
return struct.unpack(fmt, bytesitem) return struct.unpack(fmt, bytesitem)
def __str__(self):
return "<MemoryView of %r at 0x%x>" % (self.obj, id(self))
@cname('__pyx_memoryviewslice') @cname('__pyx_memoryviewslice')
cdef class _memoryviewslice(memoryview): cdef class _memoryviewslice(memoryview):
...@@ -277,9 +283,9 @@ cdef memoryview_cwrapper(object o, int flags): ...@@ -277,9 +283,9 @@ cdef memoryview_cwrapper(object o, int flags):
return memoryview(o, flags) return memoryview(o, flags)
@cname('__pyx_memoryview_fromslice') @cname('__pyx_memoryview_fromslice')
cdef memoryview memoryview_from_memview_cwrapper(memoryview m, int flags, cdef memoryview memoryview_from_memview_cwrapper(
int new_ndim, {{memviewslice_name}} *memviewslice): {{memviewslice_name}} *memviewslice, object orig_obj, int flags, int new_ndim):
cdef _memoryviewslice result = _memoryviewslice(m.obj, flags) cdef _memoryviewslice result = _memoryviewslice(orig_obj, flags)
result.from_slice = memviewslice[0] result.from_slice = memviewslice[0]
......
...@@ -76,7 +76,6 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) { ...@@ -76,7 +76,6 @@ static CYTHON_INLINE {{memviewslice_name}} {{funcname}}(PyObject *obj) {
if (unlikely(retcode == -1)) if (unlikely(retcode == -1))
goto __pyx_fail; goto __pyx_fail;
memview->acquisition_count = 1;
return result; return result;
__pyx_fail: __pyx_fail:
Py_XDECREF(memview); Py_XDECREF(memview);
...@@ -165,7 +164,7 @@ static int __Pyx_ValidateAndInit_memviewslice( ...@@ -165,7 +164,7 @@ static int __Pyx_ValidateAndInit_memviewslice(
} }
} }
if (spec & (__Pyx_MEMVIEW_PTR | __Pyx_MEMVIEW_FULL)) { if (spec & __Pyx_MEMVIEW_PTR) {
if (!buf->suboffsets) { if (!buf->suboffsets) {
PyErr_SetString(PyExc_ValueError, PyErr_SetString(PyExc_ValueError,
"Buffer not able to be indirectly accessed."); "Buffer not able to be indirectly accessed.");
...@@ -252,6 +251,7 @@ static int __Pyx_init_memviewslice( ...@@ -252,6 +251,7 @@ static int __Pyx_init_memviewslice(
memviewslice->memview = memview; memviewslice->memview = memview;
memviewslice->data = (char *)buf->buf; memviewslice->data = (char *)buf->buf;
memview->acquisition_count++;
retval = 0; retval = 0;
goto no_fail; goto no_fail;
...@@ -265,23 +265,40 @@ no_fail: ...@@ -265,23 +265,40 @@ no_fail:
return retval; return retval;
} }
static CYTHON_INLINE void __pyx_fatalerror(char *fmt, ...) {
va_list vargs;
char msg[200];
va_start(vargs, fmt);
#ifdef HAVE_STDARG_PROTOTYPES
va_start(vargs, fmt);
#else
va_start(vargs);
#endif
vsnprintf(msg, 200, fmt, vargs);
Py_FatalError(msg);
va_end(vargs);
}
static CYTHON_INLINE void __Pyx_INC_MEMVIEW({{memviewslice_name}} *memslice, static CYTHON_INLINE void __Pyx_INC_MEMVIEW({{memviewslice_name}} *memslice,
int have_gil, int lineno) { int have_gil, int lineno) {
int first_time; int first_time;
struct {{memview_struct_name}} *memview = memslice->memview; struct {{memview_struct_name}} *memview = memslice->memview;
if (!memview) { if (!memview)
char msg[50]; __pyx_fatalerror("memoryslice is not initialized (line %d)", lineno);
snprintf(msg, 50, "memoryslice is not initialized (line %d)", lineno);
Py_FatalError(msg); if (memview->acquisition_count <= 0)
} __pyx_fatalerror("Acquisition count is %d (line %d)",
memview->acquisition_count, lineno);
PyThread_acquire_lock(memview->lock, 1); PyThread_acquire_lock(memview->lock, 1);
first_time = (memview->acquisition_count++ == 0); first_time = (memview->acquisition_count++ == 0);
PyThread_release_lock(memview->lock); PyThread_release_lock(memview->lock);
/* printf("INCREF %d: acquisition_count=%d, refcount=%d\n", lineno,
memview->acquisition_count, memview->ob_refcnt); */
if (first_time) { if (first_time) {
if (have_gil) { if (have_gil) {
Py_INCREF((PyObject *) memview); Py_INCREF((PyObject *) memview);
...@@ -298,26 +315,26 @@ static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *memslice, ...@@ -298,26 +315,26 @@ static CYTHON_INLINE void __Pyx_XDEC_MEMVIEW({{memviewslice_name}} *memslice,
int last_time; int last_time;
struct {{memview_struct_name}} *memview = memslice->memview; struct {{memview_struct_name}} *memview = memslice->memview;
if (!memview) { if (!memview)
return; return;
}
if (memview->acquisition_count <= 0)
__pyx_fatalerror("Acquisition count is %d (line %d)",
memview->acquisition_count, lineno);
PyThread_acquire_lock(memview->lock, 1); PyThread_acquire_lock(memview->lock, 1);
last_time = (memview->acquisition_count-- == 1); last_time = (memview->acquisition_count-- == 1);
PyThread_release_lock(memview->lock); PyThread_release_lock(memview->lock);
/* printf("DECREF %d: acquisition_count=%d, refcount=%d\n", lineno,
memview->acquisition_count, memview->ob_refcnt); */
if (last_time) { if (last_time) {
if (have_gil) { if (have_gil) {
Py_CLEAR(memview); Py_CLEAR(memslice->memview);
} else { } else {
PyGILState_STATE _gilstate = PyGILState_Ensure(); PyGILState_STATE _gilstate = PyGILState_Ensure();
Py_CLEAR(memview); Py_CLEAR(memslice->memview);
PyGILState_Release(_gilstate); PyGILState_Release(_gilstate);
} }
memslice->data = NULL; memslice->memview = NULL;
} }
} }
......
...@@ -48,13 +48,13 @@ def acquire_release(o1, o2): ...@@ -48,13 +48,13 @@ def acquire_release(o1, o2):
>>> B = IntMockBuffer("B", range(6)) >>> B = IntMockBuffer("B", range(6))
>>> acquire_release(A, B) >>> acquire_release(A, B)
acquired A acquired A
released A
acquired B acquired B
released A
released B released B
>>> acquire_release(None, None)
>>> acquire_release(None, B) >>> acquire_release(None, B)
acquired B Traceback (most recent call last):
released B ...
TypeError: 'NoneType' does not have the buffer interface
""" """
cdef int[:] buf cdef int[:] buf
buf = o1 buf = o1
...@@ -122,8 +122,6 @@ def acquire_failure3(): ...@@ -122,8 +122,6 @@ def acquire_failure3():
>>> acquire_failure3() >>> acquire_failure3()
acquired working acquired working
0 3 0 3
released working
acquired working
0 3 0 3
released working released working
""" """
...@@ -149,6 +147,10 @@ def acquire_nonbuffer1(first, second=None): ...@@ -149,6 +147,10 @@ def acquire_nonbuffer1(first, second=None):
... ...
TypeError: 'type' does not have the buffer interface TypeError: 'type' does not have the buffer interface
>>> acquire_nonbuffer1(None, 2) >>> acquire_nonbuffer1(None, 2)
Traceback (most recent call last):
...
TypeError: 'NoneType' does not have the buffer interface
>>> acquire_nonbuffer1(4, object())
Traceback (most recent call last): Traceback (most recent call last):
... ...
TypeError: 'int' does not have the buffer interface TypeError: 'int' does not have the buffer interface
...@@ -163,8 +165,6 @@ def acquire_nonbuffer2(): ...@@ -163,8 +165,6 @@ def acquire_nonbuffer2():
>>> acquire_nonbuffer2() >>> acquire_nonbuffer2()
acquired working acquired working
0 3 0 3
released working
acquired working
0 3 0 3
released working released working
""" """
...@@ -195,9 +195,7 @@ def as_argument(int[:] bufarg, int n): ...@@ -195,9 +195,7 @@ def as_argument(int[:] bufarg, int n):
def as_argument_defval(int[:] bufarg=IntMockBuffer('default', range(6)), int n=6): def as_argument_defval(int[:] bufarg=IntMockBuffer('default', range(6)), int n=6):
""" """
>>> as_argument_defval() >>> as_argument_defval()
acquired default
0 1 2 3 4 5 END 0 1 2 3 4 5 END
released default
>>> A = IntMockBuffer("A", range(6)) >>> A = IntMockBuffer("A", range(6))
>>> as_argument_defval(A, 6) >>> as_argument_defval(A, 6)
acquired A acquired A
...@@ -233,14 +231,14 @@ def forin_assignment(objs, int pick): ...@@ -233,14 +231,14 @@ def forin_assignment(objs, int pick):
>>> forin_assignment([A, B, A, A], 2) >>> forin_assignment([A, B, A, A], 2)
acquired A acquired A
2 2
released A
acquired B acquired B
released A
2 2
released B
acquired A acquired A
released B
2 2
released A
acquired A acquired A
released A
2 2
released A released A
""" """
...@@ -532,7 +530,7 @@ def c_contig_2d(int[:, ::1] buf): ...@@ -532,7 +530,7 @@ def c_contig_2d(int[:, ::1] buf):
@testcase @testcase
def f_contig(int[::1, :] buf): def f_contig(int[::1, :] buf):
""" """
>>> A = IntMockBuffer(None, range(4), shape=(2, 2)) >>> A = IntMockBuffer(None, range(4), shape=(2, 2), strides=(1, 2))
>>> f_contig(A) >>> f_contig(A)
2 2
>>> [str(x) for x in A.recieved_flags] >>> [str(x) for x in A.recieved_flags]
...@@ -688,7 +686,7 @@ def printbuf_int_2d(o, shape): ...@@ -688,7 +686,7 @@ def printbuf_int_2d(o, shape):
released A released A
""" """
# should make shape builtin # should make shape builtin
cdef int[:, :] buf cdef int[::view.generic, ::view.generic] buf
buf = o buf = o
cdef int i, j cdef int i, j
for i in range(shape[0]): for i in range(shape[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