mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-08 08:25:33 +00:00
make names only settable when unparented, so we can guarantee uniqueness inside a parent together with the _add checks
Original commit message from CVS: make names only settable when unparented, so we can guarantee uniqueness inside a parent together with the _add checks 2
This commit is contained in:
parent
91f1225038
commit
5d24ac1be7
7 changed files with 200 additions and 24 deletions
10
ChangeLog
10
ChangeLog
|
@ -1,3 +1,13 @@
|
||||||
|
2004-12-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
|
* docs/design/part-conventions.txt:
|
||||||
|
* docs/design/part-gstobject.txt:
|
||||||
|
* gst/gstobject.c:
|
||||||
|
* gst/gstobject.h:
|
||||||
|
* check/gst/gstobject.c:
|
||||||
|
make names only settable when unparented, so we can guarantee
|
||||||
|
uniqueness inside a parent together with the _add checks
|
||||||
|
|
||||||
2004-12-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
2004-12-13 Thomas Vander Stichele <thomas at apestaart dot org>
|
||||||
|
|
||||||
* check/Makefile.am:
|
* check/Makefile.am:
|
||||||
|
|
|
@ -187,21 +187,27 @@ G_STMT_START { \
|
||||||
#define MAIN_START_THREAD_FUNCTIONS(count, function, data) \
|
#define MAIN_START_THREAD_FUNCTIONS(count, function, data) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
int i; \
|
int i; \
|
||||||
GThread *thread = NULL; \
|
|
||||||
for (i = 0; i < count; ++i) { \
|
for (i = 0; i < count; ++i) { \
|
||||||
|
MAIN_START_THREAD_FUNCTION (i, function, data); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END;
|
||||||
|
|
||||||
|
#define MAIN_START_THREAD_FUNCTION(i, function, data) \
|
||||||
|
G_STMT_START { \
|
||||||
|
GThread *thread = NULL; \
|
||||||
g_message ("MAIN: creating thread %d\n", i); \
|
g_message ("MAIN: creating thread %d\n", i); \
|
||||||
g_mutex_lock (mutex); \
|
g_mutex_lock (mutex); \
|
||||||
thread = g_thread_create ((GThreadFunc) function, data, \
|
thread = g_thread_create ((GThreadFunc) function, data, \
|
||||||
TRUE, NULL); \
|
TRUE, NULL); \
|
||||||
thread_list = g_list_append (thread_list, thread); \
|
|
||||||
\
|
|
||||||
/* wait for thread to signal us that it's ready */ \
|
/* wait for thread to signal us that it's ready */ \
|
||||||
g_message ("MAIN: waiting for thread %d\n", i); \
|
g_message ("MAIN: waiting for thread %d\n", i); \
|
||||||
g_cond_wait (start_cond, mutex); \
|
g_cond_wait (start_cond, mutex); \
|
||||||
g_mutex_unlock (mutex); \
|
g_mutex_unlock (mutex); \
|
||||||
} \
|
\
|
||||||
|
thread_list = g_list_append (thread_list, thread); \
|
||||||
} G_STMT_END;
|
} G_STMT_END;
|
||||||
|
|
||||||
|
|
||||||
#define MAIN_SYNCHRONIZE() \
|
#define MAIN_SYNCHRONIZE() \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
g_message ("MAIN: synchronizing\n"); \
|
g_message ("MAIN: synchronizing\n"); \
|
||||||
|
@ -338,7 +344,74 @@ START_TEST (test_fake_object_name_threaded_right)
|
||||||
}
|
}
|
||||||
MAIN_STOP_THREADS ();
|
MAIN_STOP_THREADS ();
|
||||||
}
|
}
|
||||||
END_TEST Suite * gst_object_suite (void)
|
|
||||||
|
END_TEST
|
||||||
|
/*
|
||||||
|
* main thread creates lots of objects
|
||||||
|
* child threads sets default names on objects
|
||||||
|
* then main thread checks uniqueness of object names
|
||||||
|
*/
|
||||||
|
GList * object_list = NULL;
|
||||||
|
gint num_objects = 1000;
|
||||||
|
gint num_threads = 5;
|
||||||
|
|
||||||
|
/* thread function for threaded default name change test */
|
||||||
|
gpointer
|
||||||
|
thread_name_object_default (int *i)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
THREAD_START ();
|
||||||
|
|
||||||
|
for (j = *i; j < num_objects; j += num_threads) {
|
||||||
|
GstObject *o = GST_OBJECT (g_list_nth_data (object_list, j));
|
||||||
|
|
||||||
|
gst_object_set_name (o, NULL);
|
||||||
|
/* a minimal sleep invokes a thread switch */
|
||||||
|
g_usleep (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* thread is done, so let's return */
|
||||||
|
g_message ("THREAD %p: set name\n", g_thread_self ());
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_fake_object_name_threaded_unique)
|
||||||
|
{
|
||||||
|
GstObject *object;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_message ("\nTEST: uniqueness of default names\n");
|
||||||
|
|
||||||
|
for (i = 0; i < num_objects; ++i) {
|
||||||
|
object = g_object_new (gst_fake_object_get_type (), NULL);
|
||||||
|
object_list = g_list_append (object_list, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
MAIN_INIT ();
|
||||||
|
|
||||||
|
mark_point ();
|
||||||
|
for (i = 0; i < num_threads; ++i) {
|
||||||
|
MAIN_START_THREAD_FUNCTION (i, thread_name_object_default, &i);
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_point ();
|
||||||
|
MAIN_SYNCHRONIZE ();
|
||||||
|
mark_point ();
|
||||||
|
MAIN_STOP_THREADS ();
|
||||||
|
|
||||||
|
/* sort GList based on object name */
|
||||||
|
/* FIXME: sort and test */
|
||||||
|
|
||||||
|
/* free stuff */
|
||||||
|
g_list_foreach (object_list, (GFunc) g_object_unref, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
/* test: try renaming a parented object, make sure it fails */
|
||||||
|
Suite * gst_object_suite (void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create ("GstObject");
|
Suite *s = suite_create ("GstObject");
|
||||||
TCase *tc_chain = tcase_create ("general");
|
TCase *tc_chain = tcase_create ("general");
|
||||||
|
@ -349,6 +422,7 @@ END_TEST Suite * gst_object_suite (void)
|
||||||
tcase_add_test (tc_chain, test_fake_object_name);
|
tcase_add_test (tc_chain, test_fake_object_name);
|
||||||
tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
|
tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
|
||||||
tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
|
tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
|
||||||
|
tcase_add_test (tc_chain, test_fake_object_name_threaded_unique);
|
||||||
//tcase_add_checked_fixture (tc_chain, setup, teardown);
|
//tcase_add_checked_fixture (tc_chain, setup, teardown);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@ Function names
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
Within the context of a given object, functions defined in that object's header and/or source file will have their
|
Within the context of a given object, functions defined in that object's header and/or source file will have their
|
||||||
object-specific prefix stripped. For instance, gst_element_add_pad() would be referred to as simply _get_pad(). Note
|
object-specific prefix stripped. For instance, gst_element_add_pad() would be referred to as simply _add_pad(). Note
|
||||||
that the trailing parentheses should always be present, but sometimes may not be. A prefixing underscore (_) will
|
that the trailing parentheses should always be present, but sometimes may not be. A prefixing underscore (_) will
|
||||||
always tell you it's a function, however, regardless of the presence or absence of the trailing parentheses.
|
always tell you it's a function, however, regardless of the presence or absence of the trailing parentheses.
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,35 @@
|
||||||
GstObject
|
GstObject
|
||||||
=========
|
=========
|
||||||
|
|
||||||
The base class for the entire GStreamer hierarchy is the GstObject. It is currently a bit of a hack caused by the
|
The base class for the entire GStreamer hierarchy is the GstObject.
|
||||||
fact that GStreamer is built on top of GtkObject. GObject should help, if it's designed properly. Currently the
|
|
||||||
capabilities provided by GstObject are quite underutilized, this will be fixed with a refactoring of the
|
|
||||||
object system and a code cleanup at some point in the future. If nothing else, it serves as an easy check to see if a
|
|
||||||
given object belongs to GStreamer.
|
|
||||||
|
|
||||||
Parentage
|
Parentage
|
||||||
---------
|
---------
|
||||||
|
|
||||||
A pointer is available to store the current parent of the object. This one of the two fundamental requires for a
|
A pointer is available to store the current parent of the object.
|
||||||
|
This one of the two fundamental requires for a
|
||||||
hierarchical system such as GStreamer (for the other, read up on GstBin). Three functions are provided: _set_parent(),
|
hierarchical system such as GStreamer (for the other, read up on GstBin). Three functions are provided: _set_parent(),
|
||||||
_get_parent(), and _unparent(). The third is required because there is an explicit check in _set_parent(): an object
|
_get_parent(), and _unparent(). The third is required because there is an explicit check in _set_parent(): an object
|
||||||
must not already have a parent if you wish to set one. You must unparent the object first. This allows for new
|
must not already have a parent if you wish to set one. You must unparent the object first. This allows for new
|
||||||
additions later.
|
additions later.
|
||||||
|
|
||||||
|
- GstObject's that can be parented:
|
||||||
|
GstElement (inside a bin)
|
||||||
|
GstPad (inside an element)
|
||||||
|
|
||||||
Refcounting
|
Refcounting
|
||||||
-----------
|
-----------
|
||||||
|
- GObject refcount is not threadsafe.
|
||||||
|
GStreamer sets it to a constant value on each _ref/_unref()
|
||||||
|
and uses an atomic int "refcount" instead for threadsafe refcounting
|
||||||
|
This implies you should always use gst_object_ref() and gst_object_unref() !
|
||||||
|
|
||||||
A reference count is kept for the object. When this is fully utilized, it will enable generic destruction of objects
|
Naming
|
||||||
by simply reducing the reference count to zero. GObject should provide these capabilities, however.
|
------
|
||||||
|
- names of objects cannot be changed when they are parented
|
||||||
|
- names of objects should be unique across parent
|
||||||
|
- set_name() can fail because of this
|
||||||
|
- as can gst_element_add_pad()/gst_bin_add_element()
|
||||||
|
|
||||||
Locking
|
Locking
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -612,23 +612,32 @@ gst_object_set_name_default (GstObject * object)
|
||||||
* This function makes a copy of the provided name, so the caller
|
* This function makes a copy of the provided name, so the caller
|
||||||
* retains ownership of the name it sent.
|
* retains ownership of the name it sent.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* Returns: TRUE if the name could be set.
|
||||||
|
*
|
||||||
|
* MT safe. This function grabs and releases the object's LOCK.
|
||||||
*/
|
*/
|
||||||
void
|
gboolean
|
||||||
gst_object_set_name (GstObject * object, const gchar * name)
|
gst_object_set_name (GstObject * object, const gchar * name)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_IS_OBJECT (object));
|
g_return_val_if_fail (GST_IS_OBJECT (object), FALSE);
|
||||||
|
|
||||||
GST_LOCK (object);
|
GST_LOCK (object);
|
||||||
g_free (object->name);
|
|
||||||
|
/* parented objects cannot be renamed */
|
||||||
|
if (object->parent != NULL) {
|
||||||
|
GST_UNLOCK (object);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (name != NULL) {
|
if (name != NULL) {
|
||||||
|
g_free (object->name);
|
||||||
object->name = g_strdup (name);
|
object->name = g_strdup (name);
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
} else {
|
} else {
|
||||||
GST_UNLOCK (object);
|
GST_UNLOCK (object);
|
||||||
gst_object_set_name_default (object);
|
gst_object_set_name_default (object);
|
||||||
}
|
}
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -133,7 +133,7 @@ struct _GstObjectClass {
|
||||||
GType gst_object_get_type (void);
|
GType gst_object_get_type (void);
|
||||||
|
|
||||||
/* name routines */
|
/* name routines */
|
||||||
void gst_object_set_name (GstObject *object, const gchar *name);
|
gboolean gst_object_set_name (GstObject *object, const gchar *name);
|
||||||
gchar* gst_object_get_name (GstObject *object);
|
gchar* gst_object_get_name (GstObject *object);
|
||||||
|
|
||||||
/* parentage routines */
|
/* parentage routines */
|
||||||
|
|
|
@ -187,21 +187,27 @@ G_STMT_START { \
|
||||||
#define MAIN_START_THREAD_FUNCTIONS(count, function, data) \
|
#define MAIN_START_THREAD_FUNCTIONS(count, function, data) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
int i; \
|
int i; \
|
||||||
GThread *thread = NULL; \
|
|
||||||
for (i = 0; i < count; ++i) { \
|
for (i = 0; i < count; ++i) { \
|
||||||
|
MAIN_START_THREAD_FUNCTION (i, function, data); \
|
||||||
|
} \
|
||||||
|
} G_STMT_END;
|
||||||
|
|
||||||
|
#define MAIN_START_THREAD_FUNCTION(i, function, data) \
|
||||||
|
G_STMT_START { \
|
||||||
|
GThread *thread = NULL; \
|
||||||
g_message ("MAIN: creating thread %d\n", i); \
|
g_message ("MAIN: creating thread %d\n", i); \
|
||||||
g_mutex_lock (mutex); \
|
g_mutex_lock (mutex); \
|
||||||
thread = g_thread_create ((GThreadFunc) function, data, \
|
thread = g_thread_create ((GThreadFunc) function, data, \
|
||||||
TRUE, NULL); \
|
TRUE, NULL); \
|
||||||
thread_list = g_list_append (thread_list, thread); \
|
|
||||||
\
|
|
||||||
/* wait for thread to signal us that it's ready */ \
|
/* wait for thread to signal us that it's ready */ \
|
||||||
g_message ("MAIN: waiting for thread %d\n", i); \
|
g_message ("MAIN: waiting for thread %d\n", i); \
|
||||||
g_cond_wait (start_cond, mutex); \
|
g_cond_wait (start_cond, mutex); \
|
||||||
g_mutex_unlock (mutex); \
|
g_mutex_unlock (mutex); \
|
||||||
} \
|
\
|
||||||
|
thread_list = g_list_append (thread_list, thread); \
|
||||||
} G_STMT_END;
|
} G_STMT_END;
|
||||||
|
|
||||||
|
|
||||||
#define MAIN_SYNCHRONIZE() \
|
#define MAIN_SYNCHRONIZE() \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
g_message ("MAIN: synchronizing\n"); \
|
g_message ("MAIN: synchronizing\n"); \
|
||||||
|
@ -338,7 +344,74 @@ START_TEST (test_fake_object_name_threaded_right)
|
||||||
}
|
}
|
||||||
MAIN_STOP_THREADS ();
|
MAIN_STOP_THREADS ();
|
||||||
}
|
}
|
||||||
END_TEST Suite * gst_object_suite (void)
|
|
||||||
|
END_TEST
|
||||||
|
/*
|
||||||
|
* main thread creates lots of objects
|
||||||
|
* child threads sets default names on objects
|
||||||
|
* then main thread checks uniqueness of object names
|
||||||
|
*/
|
||||||
|
GList * object_list = NULL;
|
||||||
|
gint num_objects = 1000;
|
||||||
|
gint num_threads = 5;
|
||||||
|
|
||||||
|
/* thread function for threaded default name change test */
|
||||||
|
gpointer
|
||||||
|
thread_name_object_default (int *i)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
THREAD_START ();
|
||||||
|
|
||||||
|
for (j = *i; j < num_objects; j += num_threads) {
|
||||||
|
GstObject *o = GST_OBJECT (g_list_nth_data (object_list, j));
|
||||||
|
|
||||||
|
gst_object_set_name (o, NULL);
|
||||||
|
/* a minimal sleep invokes a thread switch */
|
||||||
|
g_usleep (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* thread is done, so let's return */
|
||||||
|
g_message ("THREAD %p: set name\n", g_thread_self ());
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
START_TEST (test_fake_object_name_threaded_unique)
|
||||||
|
{
|
||||||
|
GstObject *object;
|
||||||
|
gint i;
|
||||||
|
|
||||||
|
g_message ("\nTEST: uniqueness of default names\n");
|
||||||
|
|
||||||
|
for (i = 0; i < num_objects; ++i) {
|
||||||
|
object = g_object_new (gst_fake_object_get_type (), NULL);
|
||||||
|
object_list = g_list_append (object_list, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
MAIN_INIT ();
|
||||||
|
|
||||||
|
mark_point ();
|
||||||
|
for (i = 0; i < num_threads; ++i) {
|
||||||
|
MAIN_START_THREAD_FUNCTION (i, thread_name_object_default, &i);
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_point ();
|
||||||
|
MAIN_SYNCHRONIZE ();
|
||||||
|
mark_point ();
|
||||||
|
MAIN_STOP_THREADS ();
|
||||||
|
|
||||||
|
/* sort GList based on object name */
|
||||||
|
/* FIXME: sort and test */
|
||||||
|
|
||||||
|
/* free stuff */
|
||||||
|
g_list_foreach (object_list, (GFunc) g_object_unref, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
END_TEST
|
||||||
|
/* test: try renaming a parented object, make sure it fails */
|
||||||
|
Suite * gst_object_suite (void)
|
||||||
{
|
{
|
||||||
Suite *s = suite_create ("GstObject");
|
Suite *s = suite_create ("GstObject");
|
||||||
TCase *tc_chain = tcase_create ("general");
|
TCase *tc_chain = tcase_create ("general");
|
||||||
|
@ -349,6 +422,7 @@ END_TEST Suite * gst_object_suite (void)
|
||||||
tcase_add_test (tc_chain, test_fake_object_name);
|
tcase_add_test (tc_chain, test_fake_object_name);
|
||||||
tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
|
tcase_add_test (tc_chain, test_fake_object_name_threaded_wrong);
|
||||||
tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
|
tcase_add_test (tc_chain, test_fake_object_name_threaded_right);
|
||||||
|
tcase_add_test (tc_chain, test_fake_object_name_threaded_unique);
|
||||||
//tcase_add_checked_fixture (tc_chain, setup, teardown);
|
//tcase_add_checked_fixture (tc_chain, setup, teardown);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue