Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
PyPy
cffi
Commits
68008f1b02e3
Commit
b550eccc
authored
Jul 06, 2015
by
Armin Rigo
Browse files
Found a simpler and more efficient way to implement any ffi.gc().
parent
88b59dfa8176
Changes
5
Hide whitespace changes
Inline
Side-by-side
c/_cffi_backend.c
View file @
68008f1b
...
...
@@ -188,11 +188,13 @@ static PyTypeObject CField_Type;
static
PyTypeObject
CData_Type
;
static
PyTypeObject
CDataOwning_Type
;
static
PyTypeObject
CDataOwningGC_Type
;
static
PyTypeObject
CDataGCP_Type
;
#define CTypeDescr_Check(ob) (Py_TYPE(ob) == &CTypeDescr_Type)
#define CData_Check(ob) (Py_TYPE(ob) == &CData_Type || \
Py_TYPE(ob) == &CDataOwning_Type || \
Py_TYPE(ob) == &CDataOwningGC_Type)
Py_TYPE(ob) == &CDataOwningGC_Type || \
Py_TYPE(ob) == &CDataGCP_Type)
#define CDataOwn_Check(ob) (Py_TYPE(ob) == &CDataOwning_Type || \
Py_TYPE(ob) == &CDataOwningGC_Type)
...
...
@@ -234,6 +236,11 @@ typedef struct {
Py_buffer
*
bufferview
;
}
CDataObject_owngc_frombuf
;
typedef
struct
{
CDataObject
head
;
PyObject
*
origobj
,
*
destructor
;
}
CDataObject_gcp
;
typedef
struct
{
ffi_cif
cif
;
/* the following information is used when doing the call:
...
...
@@ -1625,6 +1632,35 @@ static int cdataowninggc_clear(CDataObject *cd)
return
0
;
}
/* forward */
static
void
_my_PyErr_WriteUnraisable
(
char
*
objdescr
,
PyObject
*
obj
,
char
*
extra_error_line
);
static
void
cdatagcp_dealloc
(
CDataObject_gcp
*
cd
)
{
PyObject
*
result
;
PyObject
*
destructor
=
cd
->
destructor
;
PyObject
*
origobj
=
cd
->
origobj
;
cdata_dealloc
((
CDataObject
*
)
cd
);
result
=
PyObject_CallFunctionObjArgs
(
destructor
,
origobj
,
NULL
);
if
(
result
!=
NULL
)
{
Py_DECREF
(
result
);
}
else
{
_my_PyErr_WriteUnraisable
(
"From callback for ffi.gc "
,
origobj
,
NULL
);
}
Py_DECREF
(
destructor
);
Py_DECREF
(
origobj
);
}
static
int
cdatagcp_traverse
(
CDataObject_gcp
*
cd
,
visitproc
visit
,
void
*
arg
)
{
Py_VISIT
(
cd
->
destructor
);
Py_VISIT
(
cd
->
origobj
);
return
0
;
}
static
PyObject
*
cdata_float
(
CDataObject
*
cd
);
/*forward*/
static
PyObject
*
convert_cdata_to_enum_string
(
CDataObject
*
cd
,
int
both
)
...
...
@@ -2729,6 +2765,41 @@ static PyTypeObject CDataOwningGC_Type = {
&
CDataOwning_Type
,
/* tp_base */
};
static
PyTypeObject
CDataGCP_Type
=
{
PyVarObject_HEAD_INIT
(
NULL
,
0
)
"_cffi_backend.CDataGCP"
,
sizeof
(
CDataObject_gcp
),
0
,
(
destructor
)
cdatagcp_dealloc
,
/* tp_dealloc */
0
,
/* tp_print */
0
,
/* tp_getattr */
0
,
/* tp_setattr */
0
,
/* tp_compare */
0
,
/* tp_repr */
0
,
/* tp_as_number */
0
,
/* tp_as_sequence */
0
,
/* tp_as_mapping */
0
,
/* tp_hash */
0
,
/* tp_call */
0
,
/* tp_str */
0
,
/* tp_getattro */
0
,
/* tp_setattro */
0
,
/* tp_as_buffer */
Py_TPFLAGS_DEFAULT
|
Py_TPFLAGS_CHECKTYPES
/* tp_flags */
|
Py_TPFLAGS_HAVE_GC
,
0
,
/* tp_doc */
(
traverseproc
)
cdatagcp_traverse
,
/* tp_traverse */
0
,
/* tp_clear */
0
,
/* tp_richcompare */
0
,
/* tp_weaklistoffset */
0
,
/* tp_iter */
0
,
/* tp_iternext */
0
,
/* tp_methods */
0
,
/* tp_members */
0
,
/* tp_getset */
&
CData_Type
,
/* tp_base */
};
/************************************************************/
typedef
struct
{
...
...
@@ -4709,7 +4780,8 @@ static int convert_from_object_fficallback(char *result,
return
convert_from_object
(
result
,
ctype
,
pyobj
);
}
static
void
_my_PyErr_WriteUnraisable
(
PyObject
*
obj
,
char
*
extra_error_line
)
static
void
_my_PyErr_WriteUnraisable
(
char
*
objdescr
,
PyObject
*
obj
,
char
*
extra_error_line
)
{
/* like PyErr_WriteUnraisable(), but write a full traceback */
PyObject
*
f
,
*
t
,
*
v
,
*
tb
;
...
...
@@ -4726,7 +4798,7 @@ static void _my_PyErr_WriteUnraisable(PyObject *obj, char *extra_error_line)
f
=
PySys_GetObject
(
"stderr"
);
if
(
f
!=
NULL
)
{
if
(
obj
!=
NULL
)
{
PyFile_WriteString
(
"From cffi callback "
,
f
);
PyFile_WriteString
(
objdescr
,
f
);
PyFile_WriteObject
(
obj
,
f
,
0
);
PyFile_WriteString
(
":
\n
"
,
f
);
}
...
...
@@ -4799,7 +4871,8 @@ static void invoke_callback(ffi_cif *cif, void *result, void **args,
}
onerror_cb
=
PyTuple_GET_ITEM
(
cb_args
,
3
);
if
(
onerror_cb
==
Py_None
)
{
_my_PyErr_WriteUnraisable
(
py_ob
,
extra_error_line
);
_my_PyErr_WriteUnraisable
(
"From cffi callback "
,
py_ob
,
extra_error_line
);
}
else
{
PyObject
*
exc1
,
*
val1
,
*
tb1
,
*
res1
,
*
exc2
,
*
val2
,
*
tb2
;
...
...
@@ -4824,11 +4897,12 @@ static void invoke_callback(ffi_cif *cif, void *result, void **args,
/* double exception! print a double-traceback... */
PyErr_Fetch
(
&
exc2
,
&
val2
,
&
tb2
);
PyErr_Restore
(
exc1
,
val1
,
tb1
);
_my_PyErr_WriteUnraisable
(
py_ob
,
extra_error_line
);
_my_PyErr_WriteUnraisable
(
"From cffi callback "
,
py_ob
,
extra_error_line
);
PyErr_Restore
(
exc2
,
val2
,
tb2
);
extra_error_line
=
(
"
\n
During the call to 'onerror', "
"another exception occurred:
\n\n
"
);
_my_PyErr_WriteUnraisable
(
NULL
,
extra_error_line
);
_my_PyErr_WriteUnraisable
(
NULL
,
NULL
,
extra_error_line
);
}
}
goto
done
;
...
...
@@ -5554,6 +5628,34 @@ static PyObject *b__get_types(PyObject *self, PyObject *noarg)
(
PyObject
*
)
&
CTypeDescr_Type
);
}
static
PyObject
*
b_gcp
(
PyObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
CDataObject_gcp
*
cd
;
CDataObject
*
origobj
;
PyObject
*
destructor
;
static
char
*
keywords
[]
=
{
"cdata"
,
"destructor"
,
NULL
};
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O!O:gc"
,
keywords
,
&
CData_Type
,
&
origobj
,
&
destructor
))
return
NULL
;
cd
=
PyObject_GC_New
(
CDataObject_gcp
,
&
CDataGCP_Type
);
if
(
cd
==
NULL
)
return
NULL
;
Py_INCREF
(
destructor
);
Py_INCREF
(
origobj
);
Py_INCREF
(
origobj
->
c_type
);
cd
->
head
.
c_data
=
origobj
->
c_data
;
cd
->
head
.
c_type
=
origobj
->
c_type
;
cd
->
head
.
c_weakreflist
=
NULL
;
cd
->
origobj
=
(
PyObject
*
)
origobj
;
cd
->
destructor
=
destructor
;
PyObject_GC_Track
(
cd
);
return
(
PyObject
*
)
cd
;
}
/************************************************************/
static
char
_testfunc0
(
char
a
,
char
b
)
...
...
@@ -5859,6 +5961,7 @@ static PyMethodDef FFIBackendMethods[] = {
{
"newp_handle"
,
b_newp_handle
,
METH_VARARGS
},
{
"from_handle"
,
b_from_handle
,
METH_O
},
{
"from_buffer"
,
b_from_buffer
,
METH_VARARGS
},
{
"gcp"
,
(
PyCFunction
)
b_gcp
,
METH_VARARGS
|
METH_KEYWORDS
},
#ifdef MS_WIN32
{
"getwinerror"
,
(
PyCFunction
)
b_getwinerror
,
METH_VARARGS
|
METH_KEYWORDS
},
#endif
...
...
@@ -6096,6 +6199,8 @@ init_cffi_backend(void)
INITERROR
;
if
(
PyType_Ready
(
&
CDataOwningGC_Type
)
<
0
)
INITERROR
;
if
(
PyType_Ready
(
&
CDataGCP_Type
)
<
0
)
INITERROR
;
if
(
PyType_Ready
(
&
CDataIter_Type
)
<
0
)
INITERROR
;
if
(
PyType_Ready
(
&
MiniBuffer_Type
)
<
0
)
...
...
c/cffi1_module.c
View file @
68008f1b
...
...
@@ -13,7 +13,6 @@ static PyTypeObject Lib_Type; /* forward */
#include "ffi_obj.c"
#include "cglob.c"
#include "cgc.c"
#include "lib_obj.c"
#include "cdlopen.c"
...
...
c/cgc.c
deleted
100644 → 0
View file @
88b59dfa
/* translated to C from cffi/gc_weakref.py */
static
PyObject
*
gc_wref_remove
(
PyObject
*
ffi_wref_tup
,
PyObject
*
key
)
{
FFIObject
*
ffi
;
PyObject
*
indexobj
,
*
destructor
,
*
cdata
,
*
freelist
,
*
result
;
Py_ssize_t
index
;
/* here, tup is a 4-tuple (ffi, destructor, cdata, index) */
if
(
!
PyTuple_Check
(
ffi_wref_tup
))
goto
oops
;
/* should never occur */
ffi
=
(
FFIObject
*
)
PyTuple_GET_ITEM
(
ffi_wref_tup
,
0
);
destructor
=
PyTuple_GET_ITEM
(
ffi_wref_tup
,
1
);
cdata
=
PyTuple_GET_ITEM
(
ffi_wref_tup
,
2
);
indexobj
=
PyTuple_GET_ITEM
(
ffi_wref_tup
,
3
);
index
=
PyInt_AsSsize_t
(
indexobj
);
if
(
index
<
0
)
goto
oops
;
/* should never occur */
/* assert gc_wrefs[index] is key */
if
(
PyList_GET_ITEM
(
ffi
->
gc_wrefs
,
index
)
!=
key
)
goto
oops
;
/* should never occur */
/* gc_wrefs[index] = freelist */
/* transfer ownership of 'freelist' to 'gc_wrefs[index]' */
freelist
=
ffi
->
gc_wrefs_freelist
;
PyList_SET_ITEM
(
ffi
->
gc_wrefs
,
index
,
freelist
);
/* freelist = index */
ffi
->
gc_wrefs_freelist
=
indexobj
;
Py_INCREF
(
indexobj
);
/* destructor(cdata) */
result
=
PyObject_CallFunctionObjArgs
(
destructor
,
cdata
,
NULL
);
Py_DECREF
(
key
);
/* free the reference that was in 'gc_wrefs[index]' */
return
result
;
oops:
PyErr_SetString
(
PyExc_SystemError
,
"cgc: internal inconsistency"
);
/* random leaks may follow */
return
NULL
;
}
static
PyMethodDef
remove_callback
=
{
"gc_wref_remove"
,
(
PyCFunction
)
gc_wref_remove
,
METH_O
};
static
PyObject
*
gc_weakrefs_build
(
FFIObject
*
ffi
,
CDataObject
*
cdata
,
PyObject
*
destructor
)
{
PyObject
*
new_cdata
,
*
ref
=
NULL
,
*
tup
=
NULL
,
*
remove_fn
=
NULL
;
Py_ssize_t
index
;
PyObject
*
datalist
;
if
(
ffi
->
gc_wrefs
==
NULL
)
{
/* initialize */
datalist
=
PyList_New
(
0
);
if
(
datalist
==
NULL
)
return
NULL
;
ffi
->
gc_wrefs
=
datalist
;
assert
(
ffi
->
gc_wrefs_freelist
==
NULL
);
ffi
->
gc_wrefs_freelist
=
Py_None
;
Py_INCREF
(
Py_None
);
}
/* new_cdata = self.ffi.cast(typeof(cdata), cdata) */
new_cdata
=
do_cast
(
cdata
->
c_type
,
(
PyObject
*
)
cdata
);
if
(
new_cdata
==
NULL
)
goto
error
;
/* if freelist is None: */
datalist
=
ffi
->
gc_wrefs
;
if
(
ffi
->
gc_wrefs_freelist
==
Py_None
)
{
/* index = len(gc_wrefs) */
index
=
PyList_GET_SIZE
(
datalist
);
/* gc_wrefs.append(None) */
if
(
PyList_Append
(
datalist
,
Py_None
)
<
0
)
goto
error
;
tup
=
Py_BuildValue
(
"OOOn"
,
ffi
,
destructor
,
cdata
,
index
);
}
else
{
/* index = freelist */
index
=
PyInt_AsSsize_t
(
ffi
->
gc_wrefs_freelist
);
if
(
index
<
0
)
goto
error
;
/* should not occur */
tup
=
PyTuple_Pack
(
4
,
ffi
,
destructor
,
cdata
,
ffi
->
gc_wrefs_freelist
);
}
if
(
tup
==
NULL
)
goto
error
;
remove_fn
=
PyCFunction_New
(
&
remove_callback
,
tup
);
if
(
remove_fn
==
NULL
)
goto
error
;
ref
=
PyWeakref_NewRef
(
new_cdata
,
remove_fn
);
if
(
ref
==
NULL
)
goto
error
;
/* freelist = gc_wrefs[index] (which is None if we just did append(None)) */
/* transfer ownership of 'datalist[index]' into gc_wrefs_freelist */
Py_DECREF
(
ffi
->
gc_wrefs_freelist
);
ffi
->
gc_wrefs_freelist
=
PyList_GET_ITEM
(
datalist
,
index
);
/* gc_wrefs[index] = ref */
/* transfer ownership of 'ref' into 'datalist[index]' */
PyList_SET_ITEM
(
datalist
,
index
,
ref
);
Py_DECREF
(
remove_fn
);
Py_DECREF
(
tup
);
return
new_cdata
;
error:
Py_XDECREF
(
new_cdata
);
Py_XDECREF
(
ref
);
Py_XDECREF
(
tup
);
Py_XDECREF
(
remove_fn
);
return
NULL
;
}
c/ffi_obj.c
View file @
68008f1b
...
...
@@ -664,21 +664,8 @@ PyDoc_STRVAR(ffi_gc_doc,
"Later, when this new cdata object is garbage-collected,
\n
"
"'destructor(old_cdata_object)' will be called."
);
static
PyObject
*
gc_weakrefs_build
(
FFIObject
*
ffi
,
CDataObject
*
cd
,
PyObject
*
destructor
);
/* forward */
static
PyObject
*
ffi_gc
(
FFIObject
*
self
,
PyObject
*
args
,
PyObject
*
kwds
)
{
CDataObject
*
cd
;
PyObject
*
destructor
;
static
char
*
keywords
[]
=
{
"cdata"
,
"destructor"
,
NULL
};
if
(
!
PyArg_ParseTupleAndKeywords
(
args
,
kwds
,
"O!O:gc"
,
keywords
,
&
CData_Type
,
&
cd
,
&
destructor
))
return
NULL
;
return
gc_weakrefs_build
(
self
,
cd
,
destructor
);
}
#define ffi_gc b_gcp
/* ffi_gc() => b_gcp()
from _cffi_backend.c */
PyDoc_STRVAR
(
ffi_callback_doc
,
"Return a callback object or a decorator making such a callback object.
\n
"
...
...
cffi/api.py
View file @
68008f1b
...
...
@@ -72,7 +72,6 @@ class FFI(object):
self
.
_cdefsources
=
[]
self
.
_included_ffis
=
[]
self
.
_windows_unicode
=
None
self
.
_gcp
=
None
if
hasattr
(
backend
,
'set_ffi'
):
backend
.
set_ffi
(
self
)
for
name
in
backend
.
__dict__
:
...
...
@@ -329,14 +328,13 @@ class FFI(object):
data. Later, when this new cdata object is garbage-collected,
'destructor(old_cdata_object)' will be called.
"""
if
self
.
_gcp
is
not
None
:
return
self
.
_
gcp
(
cdata
,
destructor
)
if
hasattr
(
self
.
_backend
,
'FFI'
)
:
compiled_ffi
=
self
.
_backend
.
FFI
()
self
.
_gcp
=
compiled_ffi
.
gc
return
self
.
_
gcp
(
cdata
,
destructor
)
try
:
gcp
=
self
.
_
backend
.
gcp
except
AttributeError
:
pass
else
:
return
gcp
(
cdata
,
destructor
)
#
# the rest is for the ctypes backend only
with
self
.
_lock
:
try
:
gc_weakrefs
=
self
.
gc_weakrefs
...
...
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