{
GMainContext *context;
gboolean is_running;
+ guint ref_count;
#ifdef G_THREADS_ENABLED
GMutex *mutex;
GCond *sem_cond;
-#endif G_THREADS_ENABLED
+#endif /* G_THREADS_ENABLED */
};
struct _GTimeoutSource
g_mem_chunk_destroy (context->poll_chunk);
+#ifdef G_THREADS_ENABLED
if (g_thread_supported())
{
#ifndef G_OS_WIN32
CloseHandle (context->wake_up_semaphore);
#endif
}
+#endif
g_free (context);
}
source->context = context;
result = source->id = context->next_id++;
+ source->ref_count++;
g_source_list_add (source, context);
tmp_list = source->poll_fds;
if (!SOURCE_DESTROYED (source))
{
+ GSList *tmp_list;
gpointer old_cb_data;
GSourceCallbackFuncs *old_cb_funcs;
LOCK_CONTEXT (context);
}
+ tmp_list = source->poll_fds;
+ while (tmp_list)
+ {
+ g_main_context_remove_poll_unlocked (context, tmp_list->data);
+ tmp_list = tmp_list->next;
+ }
+
g_source_unref_internal (source, context, TRUE);
}
g_return_if_fail (source != NULL);
g_return_if_fail (fd != NULL);
-
+ g_return_if_fail (!SOURCE_DESTROYED (source));
+
context = source->context;
if (context)
GMainContext *context,
gboolean have_lock)
{
- gpointer cb_data = NULL;
- GSourceCallbackFuncs *cb_funcs = NULL;
- GSList *tmp_list;
+ gpointer old_cb_data = NULL;
+ GSourceCallbackFuncs *old_cb_funcs = NULL;
g_return_if_fail (source != NULL);
source->ref_count--;
if (source->ref_count == 0)
{
+ old_cb_data = source->callback_data;
+ old_cb_funcs = source->callback_funcs;
+
+ source->callback_data = NULL;
+ source->callback_funcs = NULL;
+
if (context && !SOURCE_DESTROYED (source))
{
g_warning (G_STRLOC ": ref_count == 0, but source is still attached to a context!");
source->ref_count++;
}
- else
- {
- g_source_list_remove (source, context);
-
- tmp_list = source->poll_fds;
- while (tmp_list)
- {
- g_main_context_remove_poll_unlocked (context, tmp_list->data);
- tmp_list = tmp_list->next;
- }
- }
+ else if (context)
+ g_source_list_remove (source, context);
+
+ if (source->source_funcs->destroy)
+ source->source_funcs->destroy (source);
+
+ g_slist_free (source->poll_fds);
+ source->poll_fds = NULL;
+ g_free (source);
}
if (!have_lock && context)
UNLOCK_CONTEXT (context);
- if (cb_data)
+ if (old_cb_funcs)
{
if (have_lock)
UNLOCK_CONTEXT (context);
- cb_funcs->unref (cb_data);
+ old_cb_funcs->unref (old_cb_data);
if (have_lock)
LOCK_CONTEXT (context);
}
context->poll_waiting = TRUE;
-#endif G_THREADS_ENABLED
+#endif /* G_THREADS_ENABLED */
#if 0
/* If recursing, finish up current dispatch, before starting over */
pollrec = pollrec->next;
}
+#ifdef G_THREADS_ENABLED
context->poll_changed = FALSE;
-
+#endif
+
if (timeout)
{
*timeout = context->timeout;
}
else
context->poll_waiting = FALSE;
-#endif /* G_THREADS_ENABLED */
/* If the set of poll file descriptors changed, bail out
* and let the main loop rerun
*/
if (context->poll_changed)
return 0;
-
+#endif /* G_THREADS_ENABLED */
+
pollrec = context->poll_records;
i = 0;
while (i < n_fds)
loop = g_new0 (GMainLoop, 1);
loop->context = context;
loop->is_running = is_running != FALSE;
-
+ loop->ref_count = 1;
+
#ifdef G_THREADS_ENABLED
if (g_thread_supported ())
loop->mutex = g_mutex_new ();
else
loop->mutex = NULL;
loop->sem_cond = NULL;
-#endif G_THREADS_ENABLED
+#endif /* G_THREADS_ENABLED */
return loop;
}
/**
+ * g_main_loop_ref:
+ * @loop: a #GMainLoop
+ *
+ * Increase the reference count on a #GMainLoop object by one.
+ *
+ * Return value: @loop
+ **/
+GMainLoop *
+g_main_loop_ref (GMainLoop *loop)
+{
+ g_return_val_if_fail (loop != NULL, NULL);
+
+ LOCK_LOOP (loop);
+ loop->ref_count++;
+ UNLOCK_LOOP (loop);
+
+ return loop;
+}
+
+static void
+main_loop_destroy (GMainLoop *loop)
+{
+#ifdef G_THREADS_ENABLED
+ g_mutex_free (loop->mutex);
+ if (loop->sem_cond)
+ g_cond_free (loop->sem_cond);
+#endif /* G_THREADS_ENABLED */
+
+ g_free (loop);
+}
+
+/**
+ * g_main_loop_unref:
+ * @loop: a #GMainLoop
+ *
+ * Decreases the reference count on a #GMainLoop object by one. If
+ * the result is zero, free the loop and free all associated memory.
+ **/
+void
+g_main_loop_unref (GMainLoop *loop)
+{
+ g_return_if_fail (loop != NULL);
+ g_return_if_fail (loop->ref_count > 0);
+
+ LOCK_LOOP (loop);
+
+ loop->ref_count--;
+ if (loop->ref_count == 0)
+ {
+ /* When the ref_count is 0, there can be nobody else using the
+ * loop, so it is safe to unlock before destroying.
+ */
+ UNLOCK_LOOP (loop);
+ main_loop_destroy (loop);
+ }
+ else
+ UNLOCK_LOOP (loop);
+}
+
+/**
* g_main_loop_run:
* @loop: a #GMainLoop
*
{
g_return_if_fail (loop != NULL);
+ /* The assumption here is that a reference is held to the loop
+ * until we recursively iterate
+ */
#ifdef G_THREADS_ENABLED
if (loop->context->thread != g_thread_self ())
{
LOCK_LOOP (loop);
+ loop->ref_count++;
+
if (!g_thread_supported ())
{
g_warning ("g_main_loop_run() was called from second thread but"
while (loop->is_running)
g_cond_wait (loop->sem_cond, loop->mutex);
}
-
- UNLOCK_LOOP (loop);
}
else
#endif /* G_THREADS_ENABLED */
LOCK_LOOP (loop);
+ loop->ref_count++;
loop->is_running = TRUE;
while (loop->is_running)
{
g_main_context_iterate (loop->context, TRUE, TRUE);
LOCK_LOOP (loop);
}
+ }
+
+ /* We inline this here rather than calling g_main_loop_unref() to
+ * avoid an extra unlock/lock.
+ */
+ loop->ref_count--;
+ if (loop->ref_count == 0)
+ {
UNLOCK_LOOP (loop);
+ main_loop_destroy (loop);
}
+ else
+ UNLOCK_LOOP (loop);
}
/**
LOCK_LOOP (loop);
loop->is_running = FALSE;
+#ifdef G_THREADS_ENABLED
if (loop->sem_cond)
g_cond_broadcast (loop->sem_cond);
+#endif
UNLOCK_LOOP (loop);
}
/**
- * g_main_loop_destroy:
- * @loop: a #GMainLoop
- *
- * Destroy a #GMainLoop object and free all associated memory.
- * The loop must not currently be running via g_main_run().
- **/
-void
-g_main_loop_destroy (GMainLoop *loop)
-{
- g_return_if_fail (loop != NULL);
- g_return_if_fail (!loop->is_running);
-
-#ifdef G_THREADS_ENABLED
- g_mutex_free (loop->mutex);
- if (loop->sem_cond)
- g_cond_free (loop->sem_cond);
-#endif /* G_THREADS_ENABLED */
-
- g_free (loop);
-}
-
-/**
* g_main_loop_is_running:
* @loop: a #GMainLoop.
*
UNLOCK_CONTEXT (context);
}
-#ifdef G_OS_WIN32
-
/**
* g_main_context_get_poll_func:
* @context: a #GMainContext
GPollFunc
g_main_context_get_poll_func (GMainContext *context)
{
- GPollFunc *result;
+ GPollFunc result;
if (!context)
context = g_main_context_default ();
LOCK_CONTEXT (context);
result = context->poll_func;
UNLOCK_CONTEXT (context);
-}
-#endif
+ return result;
+}
/* HOLDS: context's lock */
/* Wake the main loop up from a poll() */
#ifndef G_OS_WIN32
write (context->wake_up_pipe[1], "A", 1);
#else
- ReleaseSemaphore (context->context->wake_up_semaphore, 1, NULL);
+ ReleaseSemaphore (context->wake_up_semaphore, 1, NULL);
#endif
}
#endif
GDestroyNotify notify)
{
GSource *source;
+ guint id;
g_return_val_if_fail (function != NULL, 0);
g_source_set_priority (source, priority);
g_source_set_callback (source, function, data, notify);
- return g_source_attach (source, NULL);
+ id = g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ return id;
}
/**
GDestroyNotify notify)
{
GSource *source;
+ guint id;
g_return_val_if_fail (function != NULL, 0);
g_source_set_priority (source, priority);
g_source_set_callback (source, function, data, notify);
- return g_source_attach (source, NULL);
+ id = g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ return id;
}
/**