* Boston, MA 02111-1307, USA.
*/
+/*
+ * MT safe
+ */
+
#include "glib.h"
#include <sys/time.h>
#include <unistd.h>
+#include <errno.h>
#include "config.h"
/* Types */
/* Forward declarations */
-static void g_main_poll (gint timeout,
- gboolean use_priority,
- gint priority);
+static void g_main_poll (gint timeout,
+ gboolean use_priority,
+ gint priority);
+static void g_main_poll_add_unlocked (gint priority,
+ GPollFD *fd);
+
static gboolean g_timeout_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout);
static GSList *pending_dispatches = NULL;
static GHookList source_list = { 0 };
+/* The following lock is used for both the list of sources
+ * and the list of poll records
+ */
+G_LOCK_DECLARE_STATIC (main_loop);
+
static GSourceFuncs timeout_funcs = {
g_timeout_prepare,
g_timeout_check,
(GDestroyNotify)g_free
};
+static GPollRec *poll_records = NULL;
+static GPollRec *poll_free_list = NULL;
+static GMemChunk *poll_chunk;
+static guint n_poll_records = 0;
+
+/* this pipe is used to wake up the main loop when a source is added.
+ */
+static gint wake_up_pipe[2] = { -1, -1 };
+static GPollFD wake_up_rec;
+static gboolean poll_waiting = FALSE;
+
#ifdef HAVE_POLL
static GPollFunc poll_func = (GPollFunc)poll;
#else
gpointer user_data,
GDestroyNotify notify)
{
+ guint return_val;
GSource *source;
+ G_LOCK (main_loop);
+
if (!source_list.is_setup)
g_hook_list_init (&source_list, sizeof(GSource));
if (can_recurse)
source->hook.flags |= G_SOURCE_CAN_RECURSE;
- return source->hook.hook_id;
+ return_val = source->hook.hook_id;
+
+ /* Now wake up the main loop if it is waiting in the poll() */
+
+ if (poll_waiting)
+ {
+ poll_waiting = FALSE;
+ write (wake_up_pipe[1], "A", 1);
+ }
+
+ G_UNLOCK (main_loop);
+
+ return return_val;
}
void
g_source_remove (guint tag)
{
- GHook *hook = g_hook_get (&source_list, tag);
+ GHook *hook;
+
+ G_LOCK (main_loop);
+
+ hook = g_hook_get (&source_list, tag);
if (hook)
{
GSource *source = (GSource *)hook;
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ G_UNLOCK (main_loop);
}
void
g_source_remove_by_user_data (gpointer user_data)
{
- GHook *hook = g_hook_find_data (&source_list, TRUE, user_data);
+ GHook *hook;
+
+ G_LOCK (main_loop);
+
+ hook = g_hook_find_data (&source_list, TRUE, user_data);
if (hook)
{
GSource *source = (GSource *)hook;
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ G_UNLOCK (main_loop);
}
static gboolean
void
g_source_remove_by_source_data (gpointer source_data)
{
- GHook *hook = g_hook_find (&source_list, TRUE,
+ GHook *hook;
+
+ G_LOCK (main_loop);
+
+ hook = g_hook_find (&source_list, TRUE,
g_source_find_source_data, source_data);
if (hook)
{
((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, hook);
}
+
+ G_UNLOCK (main_loop);
}
void g_get_current_time (GTimeVal *result)
/* Running the main loop */
+/* HOLDS: main_loop_lock */
static void
g_main_dispatch (GTimeVal *current_time)
{
if (G_HOOK_IS_VALID (source))
{
+ gboolean (*dispatch) (gpointer, GTimeVal *, gpointer);
+ gpointer hook_data = source->hook.data;
+ gpointer source_data = source->source_data;
+
+ dispatch = ((GSourceFuncs *)source->hook.func)->dispatch;
+
source->hook.flags |= G_HOOK_FLAG_IN_CALL;
- need_destroy = !((GSourceFuncs *)source->hook.func)->dispatch (source->source_data,
- current_time,
- source->hook.data);
+
+ G_UNLOCK (main_loop);
+ need_destroy = ! dispatch(source_data,
+ current_time,
+ hook_data);
+ G_LOCK (main_loop);
+
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
if (need_destroy)
gint nready = 0;
gint current_priority = 0;
gint timeout;
+ gboolean retval = FALSE;
g_return_val_if_fail (!block || dispatch, FALSE);
g_get_current_time (¤t_time);
+
+ G_LOCK (main_loop);
/* If recursing, finish up current dispatch, before starting over */
if (pending_dispatches)
if (dispatch)
g_main_dispatch (¤t_time);
+ G_UNLOCK (main_loop);
return TRUE;
}
if (!dispatch)
{
g_hook_unref (&source_list, hook);
+ G_UNLOCK (main_loop);
return TRUE;
}
else
else
{
g_hook_unref (&source_list, hook);
+ G_UNLOCK (main_loop);
return TRUE;
}
}
{
pending_dispatches = g_slist_reverse (pending_dispatches);
g_main_dispatch (¤t_time);
- return TRUE;
+ retval = TRUE;
}
- else
- return FALSE;
+
+ G_UNLOCK (main_loop);
+
+ return retval;
}
/* See if any events are pending
g_free (loop);
}
-static GPollRec *poll_records = NULL;
-static GPollRec *poll_free_list = NULL;
-static GMemChunk *poll_chunk;
-static guint n_poll_records = 0;
-
+/* HOLDS: main_loop_lock */
static void
g_main_poll (gint timeout, gboolean use_priority, gint priority)
{
gint i;
gint npoll;
+ if (wake_up_pipe[0] < 0)
+ {
+ if (pipe (wake_up_pipe) < 0)
+ g_error ("Cannot create pipe main loop wake-up: %s\n",
+ g_strerror(errno));
+
+ wake_up_rec.fd = wake_up_pipe[0];
+ wake_up_rec.events = G_IO_IN;
+ g_main_poll_add_unlocked (0, &wake_up_rec);
+ }
+
pollrec = poll_records;
i = 0;
while (pollrec && (!use_priority || priority >= pollrec->priority))
i++;
}
+ poll_waiting = TRUE;
+
+ G_UNLOCK (main_loop);
npoll = i;
(*poll_func) (fd_array, npoll, timeout);
+ G_LOCK (main_loop);
+
+ if (!poll_waiting)
+ {
+ gchar c;
+ read (wake_up_pipe[0], &c, 1);
+ }
+ else
+ poll_waiting = FALSE;
pollrec = poll_records;
i = 0;
g_main_poll_add (gint priority,
GPollFD *fd)
{
+ G_LOCK (main_loop);
+ g_main_poll_add_unlocked (priority, fd);
+ G_UNLOCK (main_loop);
+}
+
+static void
+g_main_poll_add_unlocked (gint priority,
+ GPollFD *fd)
+{
GPollRec *lastrec, *pollrec, *newrec;
if (!poll_chunk)
poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
- newrec = g_chunk_new (GPollRec, poll_chunk);
+ if (poll_free_list)
+ {
+ newrec = poll_free_list;
+ poll_free_list = newrec->next;
+ }
+ else
+ newrec = g_chunk_new (GPollRec, poll_chunk);
+
newrec->fd = fd;
newrec->priority = priority;
newrec->next = pollrec;
n_poll_records++;
+
+ G_UNLOCK (main_loop);
}
void
{
GPollRec *pollrec, *lastrec;
+ G_LOCK (main_loop);
+
lastrec = NULL;
pollrec = poll_records;
pollrec->next = poll_free_list;
poll_free_list = pollrec;
+
+ n_poll_records--;
+ break;
}
lastrec = pollrec;
pollrec = pollrec->next;
}
- n_poll_records--;
+ G_UNLOCK (main_loop);
}
void