gint ref_count;
+ GHashTable *sources; /* guint -> GSource */
+
GPtrArray *pending_dispatches;
gint timeout; /* Timeout for current iteration */
guint next_id;
- GHashTable *overflow_used_source_ids; /* set<guint> */
GList *source_lists;
gint in_check_or_prepare;
}
g_list_free (context->source_lists);
- if (context->overflow_used_source_ids)
- g_hash_table_destroy (context->overflow_used_source_ids);
+ g_hash_table_destroy (context->sources);
g_mutex_clear (&context->mutex);
g_mutex_init (&context->mutex);
g_cond_init (&context->cond);
+ context->sources = g_hash_table_new (NULL, NULL);
context->owner = NULL;
context->waiters = NULL;
context->source_lists = g_list_remove (context->source_lists, source_list);
g_slice_free (GSourceList, source_list);
}
-
- if (context->overflow_used_source_ids)
- g_hash_table_remove (context->overflow_used_source_ids,
- GUINT_TO_POINTER (source->source_id));
-
-}
-
-static void
-assign_source_id_unlocked (GMainContext *context,
- GSource *source)
-{
- guint id;
-
- /* Are we about to overflow back to 0?
- * See https://bugzilla.gnome.org/show_bug.cgi?id=687098
- */
- if (G_UNLIKELY (context->next_id == G_MAXUINT &&
- context->overflow_used_source_ids == NULL))
- {
- GSourceIter iter;
- GSource *source;
-
- context->overflow_used_source_ids = g_hash_table_new (NULL, NULL);
-
- g_source_iter_init (&iter, context, FALSE);
- while (g_source_iter_next (&iter, &source))
- {
- g_hash_table_add (context->overflow_used_source_ids,
- GUINT_TO_POINTER (source->source_id));
- }
- id = G_MAXUINT;
- g_hash_table_add (context->overflow_used_source_ids, GUINT_TO_POINTER (id));
- }
- else if (context->overflow_used_source_ids == NULL)
- {
- id = context->next_id++;
- }
- else
- {
- /*
- * If we overran G_MAXUINT, we fall back to randomly probing the
- * source ids for the current context. This will be slower the more
- * sources there are, but we're mainly concerned right now about
- * correctness and code size. There's time for a more clever solution
- * later.
- */
- do
- id = g_random_int ();
- while (id == 0 ||
- g_hash_table_contains (context->overflow_used_source_ids,
- GUINT_TO_POINTER (id)));
- g_hash_table_add (context->overflow_used_source_ids, GUINT_TO_POINTER (id));
- }
-
- source->source_id = id;
}
static guint
gboolean do_wakeup)
{
GSList *tmp_list;
+ guint id;
+
+ /* The counter may have wrapped, so we must ensure that we do not
+ * reuse the source id of an existing source.
+ */
+ do
+ id = context->next_id++;
+ while (id == 0 || g_hash_table_contains (context->sources, GUINT_TO_POINTER (id)));
source->context = context;
- assign_source_id_unlocked (context, source);
+ source->source_id = id;
source->ref_count++;
+
+ g_hash_table_insert (context->sources, GUINT_TO_POINTER (id), source);
+
source_add_to_context (source, context);
if (!SOURCE_BLOCKED (source))
* the @revents field in the #GPollFD struct and return %TRUE if events need
* to be processed.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* Using this API forces the linear scanning of event sources on each
* main loop iteration. Newly-written event sources should try to use
* g_source_add_unix_fd() instead of this API.
*
* Removes a file descriptor from the set of file descriptors polled for
* this source.
+ *
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
**/
void
g_source_remove_poll (GSource *source,
* @source will hold a reference on @child_source while @child_source
* is attached to it.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* Since: 2.28
**/
void
*
* Detaches @child_source from @source and destroys it.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* Since: 2.28
**/
void
* for both sources is reached during the same main context iteration
* then the order of dispatch is undefined.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* Since: 2.36
**/
void
if (!SOURCE_DESTROYED (source))
g_warning (G_STRLOC ": ref_count == 0, but source was still attached to a context!");
source_remove_from_context (source, context);
+
+ g_hash_table_remove (context->sources, GUINT_TO_POINTER (source->source_id));
}
if (source->source_funcs->finalize)
/**
* g_main_context_find_source_by_id:
* @context: (allow-none): a #GMainContext (if %NULL, the default context will be used)
- * @source_id: the source ID, as returned by g_source_get_id().
- *
+ * @source_id: the source ID, as returned by g_source_get_id().
+ *
* Finds a #GSource given a pair of context and ID.
- *
+ *
* Returns: (transfer none): the #GSource if found, otherwise, %NULL
**/
GSource *
g_main_context_find_source_by_id (GMainContext *context,
- guint source_id)
+ guint source_id)
{
- GSourceIter iter;
GSource *source;
-
+
g_return_val_if_fail (source_id > 0, NULL);
if (context == NULL)
context = g_main_context_default ();
-
- LOCK_CONTEXT (context);
-
- g_source_iter_init (&iter, context, FALSE);
- while (g_source_iter_next (&iter, &source))
- {
- if (!SOURCE_DESTROYED (source) &&
- source->source_id == source_id)
- break;
- }
- g_source_iter_clear (&iter);
+ LOCK_CONTEXT (context);
+ source = g_hash_table_lookup (context->sources, GUINT_TO_POINTER (source_id));
UNLOCK_CONTEXT (context);
+ if (source && SOURCE_DESTROYED (source))
+ source = NULL;
+
return source;
}
* It is not necessary to remove the fd before destroying the source; it
* will be cleaned up automatically.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* As the name suggests, this function is not available on Windows.
*
* Returns: an opaque tag
* If you want to remove a fd, don't set its event mask to zero.
* Instead, call g_source_remove_unix_fd().
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* As the name suggests, this function is not available on Windows.
*
* Since: 2.36
* watched while keeping the same source around. In the normal case you
* will just want to destroy the source.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* As the name suggests, this function is not available on Windows.
*
* Since: 2.36
* The return value of this function is only defined when the function
* is called from the check or dispatch functions for @source.
*
+ * This API is only intended to be used by implementations of #GSource.
+ * Do not call this API on a #GSource that you did not create.
+ *
* As the name suggests, this function is not available on Windows.
*
* Returns: the conditions reported on the fd
if (n_fds || timeout != 0)
{
#ifdef G_MAIN_POLL_DEBUG
+ poll_timer = NULL;
if (_g_main_poll_debug)
{
g_print ("polling context=%p n=%d timeout=%d\n",