mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-02 07:36:17 +01:00
Add two new functions, g_source_set_funcs and g_source_is_destroyed, that
2006-06-01 Matthias Clasen <mclasen@redhat.com> * glib/glib.symbols: * glib/gmain.h: * glib/gmain.c: Add two new functions, g_source_set_funcs and g_source_is_destroyed, that will be necessary to solve thread-safety issues with idles in GTK+. (#321886, Chris Wilson)
This commit is contained in:
parent
14538bb8d6
commit
bef319723b
@ -1,3 +1,12 @@
|
||||
2006-06-01 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* glib/glib.symbols:
|
||||
* glib/gmain.h:
|
||||
* glib/gmain.c: Add two new functions,
|
||||
g_source_set_funcs and g_source_is_destroyed,
|
||||
that will be necessary to solve thread-safety
|
||||
issues with idles in GTK+. (#321886, Chris Wilson)
|
||||
|
||||
2006-06-01 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* glib/giochannel.c (g_io_channel_write_chars): Avoid
|
||||
|
@ -1,3 +1,12 @@
|
||||
2006-06-01 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* glib/glib.symbols:
|
||||
* glib/gmain.h:
|
||||
* glib/gmain.c: Add two new functions,
|
||||
g_source_set_funcs and g_source_is_destroyed,
|
||||
that will be necessary to solve thread-safety
|
||||
issues with idles in GTK+. (#321886, Chris Wilson)
|
||||
|
||||
2006-06-01 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* glib/giochannel.c (g_io_channel_write_chars): Avoid
|
||||
|
@ -583,6 +583,7 @@ g_main_context_unref
|
||||
g_main_context_wait
|
||||
g_main_context_wakeup
|
||||
g_main_depth
|
||||
g_main_current_source
|
||||
g_main_loop_get_context
|
||||
g_main_loop_is_running
|
||||
g_main_loop_new
|
||||
@ -607,6 +608,8 @@ g_source_remove_poll
|
||||
g_source_set_callback
|
||||
g_source_set_callback_indirect
|
||||
g_source_set_can_recurse
|
||||
g_source_set_funcs
|
||||
g_source_is_destroyed
|
||||
g_source_set_priority
|
||||
g_source_unref
|
||||
g_idle_add
|
||||
|
144
glib/gmain.c
144
glib/gmain.c
@ -102,6 +102,14 @@ struct _GMainWaiter
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef struct _GMainDispatch GMainDispatch;
|
||||
|
||||
struct _GMainDispatch
|
||||
{
|
||||
gint depth;
|
||||
GSList *source;
|
||||
};
|
||||
|
||||
struct _GMainContext
|
||||
{
|
||||
#ifdef G_THREADS_ENABLED
|
||||
@ -1227,6 +1235,29 @@ g_source_set_callback (GSource *source,
|
||||
g_source_set_callback_indirect (source, new_callback, &g_source_callback_funcs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* g_source_set_funcs:
|
||||
* @source: a #GSource
|
||||
* @funcs: the new #GSourceFuncs
|
||||
*
|
||||
* Sets the source functions (can be used to override
|
||||
* default implementations) of an unattached source.
|
||||
*
|
||||
* Since: 2.12
|
||||
*/
|
||||
void
|
||||
g_source_set_funcs (GSource *source,
|
||||
GSourceFuncs *funcs)
|
||||
{
|
||||
g_return_if_fail (source != NULL);
|
||||
g_return_if_fail (source->context == NULL);
|
||||
g_return_if_fail (source->ref_count > 0);
|
||||
g_return_if_fail (funcs != NULL);
|
||||
|
||||
source->source_funcs = funcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_source_set_priority:
|
||||
* @source: a #GSource
|
||||
@ -1690,19 +1721,18 @@ g_get_current_time (GTimeVal *result)
|
||||
|
||||
/* Running the main loop */
|
||||
|
||||
static gint *
|
||||
get_depth_pointer (void)
|
||||
static GMainDispatch *
|
||||
get_dispatch (void)
|
||||
{
|
||||
static GStaticPrivate depth_private = G_STATIC_PRIVATE_INIT;
|
||||
gint *depth_pointer = g_static_private_get (&depth_private);
|
||||
if (!depth_pointer)
|
||||
GMainDispatch *dispatch = g_static_private_get (&depth_private);
|
||||
if (!dispatch)
|
||||
{
|
||||
depth_pointer = g_new (gint, 1);
|
||||
*depth_pointer = 0;
|
||||
g_static_private_set (&depth_private, depth_pointer, g_free);
|
||||
dispatch = g_slice_new0 (GMainDispatch);
|
||||
g_static_private_set (&depth_private, dispatch, NULL);
|
||||
}
|
||||
|
||||
return depth_pointer;
|
||||
return dispatch;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1824,10 +1854,96 @@ get_depth_pointer (void)
|
||||
int
|
||||
g_main_depth (void)
|
||||
{
|
||||
gint *depth = get_depth_pointer ();
|
||||
return *depth;
|
||||
GMainDispatch *dispatch = get_dispatch ();
|
||||
return dispatch->depth;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_main_current_source:
|
||||
*
|
||||
* Return value: The currently firing source for this thread or NULL.
|
||||
*/
|
||||
GSource *
|
||||
g_main_current_source (void)
|
||||
{
|
||||
GMainDispatch *dispatch = get_dispatch ();
|
||||
return dispatch->source ? dispatch->source->data : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_source_is_destroyed:
|
||||
* @source: a #GSource
|
||||
*
|
||||
* Returns whether @source has been destroyed.
|
||||
*
|
||||
* This is important when you operate upon your objects
|
||||
* from within idle handlers, but may have freed the object
|
||||
* before the dispatch of your idle handler.
|
||||
*
|
||||
* <informalexample><programlisting>
|
||||
* static gboolean
|
||||
* idle_callback (gpointer data)
|
||||
* {
|
||||
* SomeWidget *self = data;
|
||||
*
|
||||
* GDK_THREADS_ENTER ();
|
||||
* /<!-- -->* do stuff with self *<!-- -->/
|
||||
* self->idle_id = 0;
|
||||
* GDK_THREADS_LEAVE ();
|
||||
*
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* some_widget_do_stuff_later (SomeWidget *self)
|
||||
* {
|
||||
* self->idle_id = g_idle_add (idle_callback, self);
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* some_widget_finalize (GObject *object)
|
||||
* {
|
||||
* SomeWidget *self = SOME_WIDGET (object);
|
||||
*
|
||||
* if (self->idle_id)
|
||||
* g_source_remove (self->idle_id);
|
||||
*
|
||||
* G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
* }
|
||||
* </programlisting></informalexample>
|
||||
*
|
||||
* This will fail in a multi-threaded application if the
|
||||
* widget is destroyed before the idle handler fires due
|
||||
* to the use after free in the callback. A solution, to
|
||||
* this particular problem, is to check to if the source
|
||||
* has already been destroy within the callback.
|
||||
*
|
||||
* <informalexample><programlisting>
|
||||
* static gboolean
|
||||
* idle_callback (gpointer data)
|
||||
* {
|
||||
* SomeWidget *self = data;
|
||||
*
|
||||
* GDK_THREADS_ENTER ();
|
||||
* if (!g_source_is_destroyed (g_main_get_current_source ()))
|
||||
* {
|
||||
* /<!-- -->* do stuff with self *<!-- -->/
|
||||
* }
|
||||
* GDK_THREADS_LEAVE ();
|
||||
*
|
||||
* return FALSE;
|
||||
* }
|
||||
* </programlisting></informalexample>
|
||||
*
|
||||
* Return value: %TRUE if the source has been destroyed
|
||||
*/
|
||||
gboolean
|
||||
g_source_is_destroyed (GSource *source)
|
||||
{
|
||||
return SOURCE_DESTROYED (source);
|
||||
}
|
||||
|
||||
|
||||
/* Temporarily remove all this source's file descriptors from the
|
||||
* poll(), so that if data comes available for one of the file descriptors
|
||||
* we don't continually spin in the poll()
|
||||
@ -1869,7 +1985,7 @@ unblock_source (GSource *source)
|
||||
static void
|
||||
g_main_dispatch (GMainContext *context)
|
||||
{
|
||||
gint *depth = get_depth_pointer ();
|
||||
GMainDispatch *current = get_dispatch ();
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < context->pending_dispatches->len; i++)
|
||||
@ -1912,11 +2028,13 @@ g_main_dispatch (GMainContext *context)
|
||||
|
||||
UNLOCK_CONTEXT (context);
|
||||
|
||||
(*depth)++;
|
||||
current->depth++;
|
||||
current->source = g_slist_prepend (current->source, source);
|
||||
need_destroy = ! dispatch (source,
|
||||
callback,
|
||||
user_data);
|
||||
(*depth)--;
|
||||
current->source = g_slist_remove (current->source, source);
|
||||
current->depth--;
|
||||
|
||||
if (cb_funcs)
|
||||
cb_funcs->unref (cb_data);
|
||||
|
29
glib/gmain.h
29
glib/gmain.h
@ -177,19 +177,21 @@ gint g_main_context_check (GMainContext *context,
|
||||
gint n_fds);
|
||||
void g_main_context_dispatch (GMainContext *context);
|
||||
|
||||
void g_main_context_set_poll_func (GMainContext *context,
|
||||
GPollFunc func);
|
||||
void g_main_context_set_poll_func (GMainContext *context,
|
||||
GPollFunc func);
|
||||
GPollFunc g_main_context_get_poll_func (GMainContext *context);
|
||||
|
||||
/* Low level functions for use by source implementations
|
||||
*/
|
||||
void g_main_context_add_poll (GMainContext *context,
|
||||
GPollFD *fd,
|
||||
gint priority);
|
||||
void g_main_context_remove_poll (GMainContext *context,
|
||||
GPollFD *fd);
|
||||
void g_main_context_add_poll (GMainContext *context,
|
||||
GPollFD *fd,
|
||||
gint priority);
|
||||
void g_main_context_remove_poll (GMainContext *context,
|
||||
GPollFD *fd);
|
||||
|
||||
gint g_main_depth (void);
|
||||
GSource *g_main_current_source (void);
|
||||
|
||||
int g_main_depth (void);
|
||||
|
||||
/* GMainLoop: */
|
||||
|
||||
@ -223,11 +225,14 @@ guint g_source_get_id (GSource *source);
|
||||
|
||||
GMainContext *g_source_get_context (GSource *source);
|
||||
|
||||
void g_source_set_callback (GSource *source,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
void g_source_set_callback (GSource *source,
|
||||
GSourceFunc func,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
|
||||
void g_source_set_funcs (GSource *source,
|
||||
GSourceFuncs *funcs);
|
||||
gboolean g_source_is_destroyed (GSource *source);
|
||||
|
||||
/* Used to implement g_source_connect_closure and internally*/
|
||||
void g_source_set_callback_indirect (GSource *source,
|
||||
|
Loading…
Reference in New Issue
Block a user