fix a race condition in test_buffer.py

Original commit message from CVS:
fix a race condition in test_buffer.py


* gst/gst.override:
* gst/gstmodule.c: (init_gst):
add a pygst debug category for bindings themselves to use
* gst/gstbuffer.override:
add a repr method; add some assertions
* gst/pygstminiobject.c: (pygst_miniobject_init),
(pygstminiobject_register_wrapper), (pygstminiobject_new),
(pygstminiobject_new_noref), (pygstminiobject_dealloc),
(pygstminiobject_clear):
make the miniobjs hash private with an underscore
add debugging for inserting/removal in hash
fix pygstminiobject_clear - it also needs to remove
from the global hash.  Fixes a nasty race problem in
test_buffer
* testsuite/test_buffer.py:
expand on the subbuffer test
This commit is contained in:
Thomas Vander Stichele 2005-09-01 14:41:28 +00:00
parent 1bbb59401a
commit dc83edf73e
6 changed files with 172 additions and 79 deletions

View file

@ -1,3 +1,22 @@
2005-09-01 Thomas Vander Stichele <thomas at apestaart dot org>
* gst/gst.override:
* gst/gstmodule.c: (init_gst):
add a pygst debug category for bindings themselves to use
* gst/gstbuffer.override:
add a repr method; add some assertions
* gst/pygstminiobject.c: (pygst_miniobject_init),
(pygstminiobject_register_wrapper), (pygstminiobject_new),
(pygstminiobject_new_noref), (pygstminiobject_dealloc),
(pygstminiobject_clear):
make the miniobjs hash private with an underscore
add debugging for inserting/removal in hash
fix pygstminiobject_clear - it also needs to remove
from the global hash. Fixes a nasty race problem in
test_buffer
* testsuite/test_buffer.py:
expand on the subbuffer test
2005-09-01 Andy Wingo <wingo@pobox.com> 2005-09-01 Andy Wingo <wingo@pobox.com>
* examples/Makefile.am (examples_DATA): Dist fixer. * examples/Makefile.am (examples_DATA): Dist fixer.

View file

@ -53,8 +53,8 @@ headers
PyObject *PyGstExc_LinkError = NULL; PyObject *PyGstExc_LinkError = NULL;
GST_DEBUG_CATEGORY_EXTERN (gst_python); GST_DEBUG_CATEGORY_EXTERN (python_debug);
#define GST_CAT_DEFAULT gst_python #define GST_CAT_DEFAULT python_debug
GSList *mainloops = NULL; GSList *mainloops = NULL;
void void

View file

@ -131,16 +131,56 @@ _wrap_gst_buffer_set_data(PyObject *self, PyObject *args, PyObject *kwargs)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
%% %%
override-slot GstBuffer.tp_str override-slot GstBuffer.tp_str
static PyObject * static PyObject *
_wrap_gst_buffer_tp_str(PyGstMiniObject *self) _wrap_gst_buffer_tp_str (PyGstMiniObject *self)
{ {
GstBuffer *buf = pyg_boxed_get(self, GstBuffer); GstBuffer *buf;
g_assert (self);
buf = pyg_boxed_get (self, GstBuffer);
g_assert (buf);
return PyString_FromStringAndSize((const gchar*) GST_BUFFER_DATA(buf), return PyString_FromStringAndSize((const gchar*) GST_BUFFER_DATA(buf),
(gint) GST_BUFFER_SIZE(buf)); (gint) GST_BUFFER_SIZE(buf));
} }
%%
override-slot GstBuffer.tp_repr
static PyObject *
_wrap_gst_buffer_tp_repr (PyGstMiniObject *self)
{
GstBuffer *buf;
guchar *data;
gchar *repr;
gint size = 0;
PyObject *ret;
g_assert (self);
buf = pyg_boxed_get (self, GstBuffer);
g_assert (buf);
size = GST_BUFFER_SIZE (buf);
if (size == 0) {
repr = g_strdup_printf ("<gst.Buffer %p of size %d>", buf, size);
} else {
data = GST_BUFFER_DATA (buf);
repr = g_strdup_printf (
"<gst.Buffer %p of size %d and data 0x%02x%02x%02x%02x>", buf, size,
*data,
size > 0 ? *(data + 1) : 0,
size > 1 ? *(data + 2) : 0,
size > 2 ? *(data + 3) : 0
);
}
ret = PyString_FromStringAndSize(repr, strlen (repr));
g_free (repr);
return ret;
}
%% %%
override-slot GstBuffer.tp_as_buffer override-slot GstBuffer.tp_as_buffer
static PyBufferProcs _wrap_gst_buffer_tp_as_buffer = { static PyBufferProcs _wrap_gst_buffer_tp_as_buffer = {
@ -367,6 +407,7 @@ _wrap_gst_buffer_flag_unset(PyObject *self, PyObject *args)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
%% %%
override-attr GstBuffer.timestamp override-attr GstBuffer.timestamp
static PyObject * static PyObject *
@ -417,57 +458,73 @@ _wrap_gst_buffer__set_duration(PyGstMiniObject *self, PyObject *value, void *clo
GST_BUFFER(self->obj)->duration = val; GST_BUFFER(self->obj)->duration = val;
return 0; return 0;
} }
%% %%
override-attr GstBuffer.offset override-attr GstBuffer.offset
static PyObject * static PyObject *
_wrap_gst_buffer__get_offset(PyObject *self, void *closure) _wrap_gst_buffer__get_offset (PyObject *self, void *closure)
{ {
guint64 ret; guint64 ret;
GstMiniObject *miniobject;
g_assert (self);
ret = GST_BUFFER(pygstminiobject_get(self))->offset; miniobject = pygstminiobject_get (self);
return PyLong_FromUnsignedLongLong(ret); g_assert (miniobject);
ret = GST_BUFFER_OFFSET (GST_BUFFER (miniobject));
return PyLong_FromUnsignedLongLong (ret);
} }
static int static int
_wrap_gst_buffer__set_offset(PyGstMiniObject *self, PyObject *value, void *closure) _wrap_gst_buffer__set_offset (PyGstMiniObject *self, PyObject *value, void *closure)
{ {
guint64 val; guint64 val;
g_assert (self);
if (PyInt_CheckExact(value)) if (PyInt_CheckExact (value))
val = PyInt_AsUnsignedLongLongMask(value); val = PyInt_AsUnsignedLongLongMask (value);
else else
val = PyLong_AsUnsignedLongLong(value); val = PyLong_AsUnsignedLongLong (value);
if (PyErr_Occurred()) if (PyErr_Occurred())
return -1; return -1;
GST_BUFFER(self->obj)->offset = val; GST_BUFFER_OFFSET (GST_BUFFER (self->obj)) = val;
return 0; return 0;
} }
%% %%
override-attr GstBuffer.offset_end override-attr GstBuffer.offset_end
static PyObject * static PyObject *
_wrap_gst_buffer__get_offset_end(PyObject *self, void *closure) _wrap_gst_buffer__get_offset_end (PyObject *self, void *closure)
{ {
guint64 ret; guint64 ret;
GstMiniObject *miniobject;
g_assert (self);
miniobject = pygstminiobject_get (self);
g_assert (miniobject);
ret = GST_BUFFER(pygstminiobject_get(self))->offset_end; ret = GST_BUFFER_OFFSET_END (GST_BUFFER (miniobject));
return PyLong_FromUnsignedLongLong(ret); return PyLong_FromUnsignedLongLong (ret);
} }
static int static int
_wrap_gst_buffer__set_offset_end(PyGstMiniObject *self, PyObject *value, void *closure) _wrap_gst_buffer__set_offset_end (PyGstMiniObject *self, PyObject *value, void *closure)
{ {
guint64 val; guint64 val;
g_assert (self);
if (PyInt_CheckExact(value)) if (PyInt_CheckExact (value))
val = PyInt_AsUnsignedLongLongMask(value); val = PyInt_AsUnsignedLongLongMask (value);
else else
val = PyLong_AsUnsignedLongLong(value); val = PyLong_AsUnsignedLongLong (value);
if (PyErr_Occurred()) if (PyErr_Occurred ())
return -1; return -1;
GST_BUFFER(self->obj)->offset_end = val; GST_BUFFER_OFFSET_END (GST_BUFFER (self->obj)) = val;
return 0; return 0;
} }
%% %%
override gst_buffer_stamp kwargs override gst_buffer_stamp kwargs
static PyObject * static PyObject *

View file

@ -42,7 +42,8 @@ extern GSList *mainloops;
extern void _pygst_main_quit(void); extern void _pygst_main_quit(void);
extern PyObject *PyGstExc_LinkError; extern PyObject *PyGstExc_LinkError;
GST_DEBUG_CATEGORY (gst_python); GST_DEBUG_CATEGORY (pygst_debug); /* for bindings code */
GST_DEBUG_CATEGORY (python_debug); /* for python code */
/* This is a timeout that gets added to the mainloop to handle SIGINT (Ctrl-C) /* This is a timeout that gets added to the mainloop to handle SIGINT (Ctrl-C)
* Other signals get handled at some other point where transition from * Other signals get handled at some other point where transition from
@ -170,7 +171,8 @@ init_gst (void)
pygst_add_constants (m, "GST_"); pygst_add_constants (m, "GST_");
/* Initialize debugging category */ /* Initialize debugging category */
GST_DEBUG_CATEGORY_INIT (gst_python, "python", 0, "GStreamer python bindings"); GST_DEBUG_CATEGORY_INIT (pygst_debug, "pygst", 0, "GStreamer python bindings");
GST_DEBUG_CATEGORY_INIT (python_debug, "python", 0, "python code using gst-python");
g_timeout_add_full (0, 100, python_do_pending_calls, NULL, NULL); g_timeout_add_full (0, 100, python_do_pending_calls, NULL, NULL);

View file

@ -31,12 +31,15 @@ static void pygstminiobject_dealloc(PyGstMiniObject *self);
static int pygstminiobject_traverse(PyGstMiniObject *self, visitproc visit, void *arg); static int pygstminiobject_traverse(PyGstMiniObject *self, visitproc visit, void *arg);
static int pygstminiobject_clear(PyGstMiniObject *self); static int pygstminiobject_clear(PyGstMiniObject *self);
static GHashTable *miniobjs; GST_DEBUG_CATEGORY_EXTERN (pygst_debug);
#define GST_CAT_DEFAULT pygst_debug
static GHashTable *_miniobjs;
void void
pygst_miniobject_init() pygst_miniobject_init ()
{ {
miniobjs = g_hash_table_new (NULL, NULL); _miniobjs = g_hash_table_new (NULL, NULL);
} }
/** /**
@ -133,16 +136,17 @@ pygstminiobject_register_class(PyObject *dict, const gchar *type_name,
* floating references on the Gstminiobject. * floating references on the Gstminiobject.
*/ */
void void
pygstminiobject_register_wrapper(PyObject *self) pygstminiobject_register_wrapper (PyObject *self)
{ {
GstMiniObject *obj = ((PyGstMiniObject *)self)->obj; GstMiniObject *obj = ((PyGstMiniObject *) self)->obj;
PyGILState_STATE state; PyGILState_STATE state;
Py_INCREF(self); g_assert (obj);
state = pyg_gil_state_ensure(); Py_INCREF (self);
g_hash_table_insert (miniobjs, (gpointer) obj, (gpointer) self); GST_DEBUG ("inserting self %p in the table for object %p", self, obj);
state = pyg_gil_state_ensure ();
pyg_gil_state_release(state); g_hash_table_insert (_miniobjs, (gpointer) obj, (gpointer) self);
pyg_gil_state_release (state);
} }
@ -158,50 +162,56 @@ pygstminiobject_register_wrapper(PyObject *self)
* Returns: a reference to the wrapper for the GstMiniObject. * Returns: a reference to the wrapper for the GstMiniObject.
*/ */
PyObject * PyObject *
pygstminiobject_new(GstMiniObject *obj) pygstminiobject_new (GstMiniObject *obj)
{ {
PyGILState_STATE state; PyGILState_STATE state;
PyGstMiniObject *self; PyGstMiniObject *self = NULL;
if (obj == NULL) { if (obj == NULL) {
Py_INCREF(Py_None); Py_INCREF (Py_None);
return Py_None; return Py_None;
} }
/* we already have a wrapper for this object -- return it. */ /* see if we already have a wrapper for this object */
state = pyg_gil_state_ensure(); state = pyg_gil_state_ensure ();
self = (PyGstMiniObject *)g_hash_table_lookup (miniobjs, (gpointer) obj); self = (PyGstMiniObject *) g_hash_table_lookup (_miniobjs, (gpointer) obj);
pyg_gil_state_release(state); pyg_gil_state_release (state);
if (self != NULL) { if (self != NULL) {
Py_INCREF(self); GST_DEBUG ("had self %p in the table for object %p", self, obj);
/* make sure the lookup returned our object */
g_assert (self->obj);
g_assert (self->obj == obj);
Py_INCREF (self);
} else { } else {
/* create wrapper */ GST_DEBUG ("have to create wrapper for object %p", obj);
PyTypeObject *tp = pygstminiobject_lookup_class(G_OBJECT_TYPE(obj)); /* we don't, so create one */
PyTypeObject *tp = pygstminiobject_lookup_class (G_OBJECT_TYPE (obj));
if (!tp) if (!tp)
g_warning ("Couldn't get class for type object : %p", obj); g_warning ("Couldn't get class for type object : %p", obj);
/* need to bump type refcount if created with /* need to bump type refcount if created with
pygstminiobject_new_with_interfaces(). fixes bug #141042 */ pygstminiobject_new_with_interfaces(). fixes bug #141042 */
if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE)
Py_INCREF(tp); Py_INCREF (tp);
self = PyObject_GC_New(PyGstMiniObject, tp); self = PyObject_GC_New (PyGstMiniObject, tp);
if (self == NULL) if (self == NULL)
return NULL; return NULL;
self->obj = gst_mini_object_ref(obj); self->obj = gst_mini_object_ref (obj);
self->inst_dict = NULL; self->inst_dict = NULL;
self->weakreflist = NULL; self->weakreflist = NULL;
Py_INCREF(self); Py_INCREF (self);
state = pyg_gil_state_ensure();
/* save wrapper pointer so we can access it later */ /* save wrapper pointer so we can access it later */
g_hash_table_insert (miniobjs, (gpointer) obj, (gpointer) self); GST_DEBUG ("inserting self %p in the table for object %p", self, obj);
pyg_gil_state_release(state); state = pyg_gil_state_ensure ();
g_hash_table_insert (_miniobjs, (gpointer) obj, (gpointer) self);
PyObject_GC_Track((PyObject *)self); pyg_gil_state_release (state);
PyObject_GC_Track ((PyObject *)self);
} }
return (PyObject *)self; return (PyObject *) self;
} }
/** /**
@ -223,7 +233,7 @@ pygstminiobject_new_noref(GstMiniObject *obj)
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; return Py_None;
} }
/* create wrapper */ /* create wrapper */
PyTypeObject *tp = pygstminiobject_lookup_class(G_OBJECT_TYPE(obj)); PyTypeObject *tp = pygstminiobject_lookup_class(G_OBJECT_TYPE(obj));
if (!tp) if (!tp)
@ -238,31 +248,28 @@ pygstminiobject_new_noref(GstMiniObject *obj)
/* DO NOT REF !! */ /* DO NOT REF !! */
self->obj = obj; self->obj = obj;
/*self->obj = gst_mini_object_ref(obj);*/ /*self->obj = gst_mini_object_ref(obj);*/
self->inst_dict = NULL; self->inst_dict = NULL;
self->weakreflist = NULL; self->weakreflist = NULL;
/* save wrapper pointer so we can access it later */ /* save wrapper pointer so we can access it later */
Py_INCREF(self); Py_INCREF(self);
GST_DEBUG ("inserting self %p in the table for object %p", self, obj);
state = pyg_gil_state_ensure(); state = pyg_gil_state_ensure();
g_hash_table_insert (_miniobjs, (gpointer) obj, (gpointer) self);
g_hash_table_insert (miniobjs, (gpointer) obj, (gpointer) self);
pyg_gil_state_release(state); pyg_gil_state_release(state);
PyObject_GC_Track((PyObject *)self); PyObject_GC_Track((PyObject *)self);
return (PyObject *)self; return (PyObject *)self;
} }
static void static void
pygstminiobject_dealloc(PyGstMiniObject *self) pygstminiobject_dealloc(PyGstMiniObject *self)
{ {
GstMiniObject *obj = NULL;
g_return_if_fail (self != NULL); g_return_if_fail (self != NULL);
PyGILState_STATE state; PyGILState_STATE state;
state = pyg_gil_state_ensure(); state = pyg_gil_state_ensure();
PyObject_ClearWeakRefs((PyObject *)self); PyObject_ClearWeakRefs((PyObject *)self);
@ -270,9 +277,14 @@ pygstminiobject_dealloc(PyGstMiniObject *self)
PyObject_GC_UnTrack((PyObject *)self); PyObject_GC_UnTrack((PyObject *)self);
if (self->obj) { if (self->obj) {
gst_mini_object_unref(self->obj); /* the following causes problems with subclassed types */
obj = self->obj; /* self->ob_type->tp_free((PyObject *)self); */
GST_DEBUG ("removing self %p from the table for object %p", self,
self->obj);
g_assert (g_hash_table_remove (_miniobjs, (gpointer) self->obj));
gst_mini_object_unref(self->obj);
} }
GST_DEBUG ("setting self %p -> obj to NULL", self);
self->obj = NULL; self->obj = NULL;
if (self->inst_dict) { if (self->inst_dict) {
@ -280,10 +292,6 @@ pygstminiobject_dealloc(PyGstMiniObject *self)
} }
self->inst_dict = NULL; self->inst_dict = NULL;
/* the following causes problems with subclassed types */
/* self->ob_type->tp_free((PyObject *)self); */
g_hash_table_remove (miniobjs, (gpointer) obj);
PyObject_GC_Del(self); PyObject_GC_Del(self);
pyg_gil_state_release(state); pyg_gil_state_release(state);
} }
@ -333,15 +341,20 @@ pygstminiobject_traverse(PyGstMiniObject *self, visitproc visit, void *arg)
static int static int
pygstminiobject_clear(PyGstMiniObject *self) pygstminiobject_clear(PyGstMiniObject *self)
{ {
if (self->inst_dict) { if (self->inst_dict) {
Py_DECREF(self->inst_dict); Py_DECREF(self->inst_dict);
} }
self->inst_dict = NULL; self->inst_dict = NULL;
if (self->obj) { if (self->obj) {
gst_mini_object_unref(self->obj); /* the following causes problems with subclassed types */
/* self->ob_type->tp_free((PyObject *)self); */
GST_DEBUG ("removing self %p from the table for object %p", self,
self->obj);
g_assert (g_hash_table_remove (_miniobjs, (gpointer) self->obj));
gst_mini_object_unref (self->obj);
} }
GST_DEBUG ("setting self %p -> obj to NULL", self);
self->obj = NULL; self->obj = NULL;
return 0; return 0;

View file

@ -34,10 +34,10 @@ class BufferTest(unittest.TestCase):
assert str(buffer) == 'test' assert str(buffer) == 'test'
def testBufferAlloc(self): def testBufferAlloc(self):
bla = 'mooooooo' bla = 'mooooooo'
buffer = gst.Buffer(bla + '12345') buffer = gst.Buffer(bla + '12345')
gc.collect () gc.collect ()
assert str(buffer) == 'mooooooo12345' assert str(buffer) == 'mooooooo12345'
def testBufferBadConstructor(self): def testBufferBadConstructor(self):
self.assertRaises(TypeError, gst.Buffer, 'test', 0) self.assertRaises(TypeError, gst.Buffer, 'test', 0)
@ -60,10 +60,12 @@ class BufferTest(unittest.TestCase):
s += '%02d' % i s += '%02d' % i
buffer = gst.Buffer(s) buffer = gst.Buffer(s)
assert len(buffer) == 128 self.assertEquals(len(buffer), 128)
sub = buffer.create_sub(16, 16) sub = buffer.create_sub(16, 16)
assert sub.offset == gst.CLOCK_TIME_NONE, sub.offset self.assertEquals(sub.size, 16)
#self.assertEquals(sub.data, buffer.data[16:32])
self.assertEquals(sub.offset, gst.CLOCK_TIME_NONE)
def testBufferMerge(self): def testBufferMerge(self):
buffer1 = gst.Buffer('foo') buffer1 = gst.Buffer('foo')