📄 gmain.c
字号:
static inline GSource *next_valid_source (GMainContext *context, GSource *source){ GSource *new_source = source ? source->next : context->source_list; while (new_source) { if (!SOURCE_DESTROYED (new_source)) { new_source->ref_count++; break; } new_source = new_source->next; } if (source) SOURCE_UNREF (source, context); return new_source;}/** * g_main_context_acquire: * @context: a #GMainContext * * Tries to become the owner of the specified context. * If some other context is the owner of the context, * returns %FALSE immediately. Ownership is properly * recursive: the owner can require ownership again * and will release ownership when g_main_context_release() * is called as many times as g_main_context_acquire(). * * You must be the owner of a context before you * can call g_main_context_prepare(), g_main_context_query(), * g_main_context_check(), g_main_context_dispatch(). * * Return value: %TRUE if the operation succeeded, and * this thread is now the owner of @context. **/gboolean g_main_context_acquire (GMainContext *context){#ifdef G_THREADS_ENABLED gboolean result = FALSE; GThread *self = G_THREAD_SELF; if (context == NULL) context = g_main_context_default (); LOCK_CONTEXT (context); if (!context->owner) { context->owner = self; g_assert (context->owner_count == 0); } if (context->owner == self) { context->owner_count++; result = TRUE; } UNLOCK_CONTEXT (context); return result;#else /* !G_THREADS_ENABLED */ return TRUE;#endif /* G_THREADS_ENABLED */}/** * g_main_context_release: * @context: a #GMainContext * * Releases ownership of a context previously acquired by this thread * with g_main_context_acquire(). If the context was acquired multiple * times, the only release ownership when g_main_context_release() * is called as many times as it was acquired. **/voidg_main_context_release (GMainContext *context){#ifdef G_THREADS_ENABLED if (context == NULL) context = g_main_context_default (); LOCK_CONTEXT (context); context->owner_count--; if (context->owner_count == 0) { context->owner = NULL; if (context->waiters) { GMainWaiter *waiter = context->waiters->data; gboolean loop_internal_waiter = (waiter->mutex == g_static_mutex_get_mutex (&context->mutex)); context->waiters = g_slist_delete_link (context->waiters, context->waiters); if (!loop_internal_waiter) g_mutex_lock (waiter->mutex); g_cond_signal (waiter->cond); if (!loop_internal_waiter) g_mutex_unlock (waiter->mutex); } } UNLOCK_CONTEXT (context); #endif /* G_THREADS_ENABLED */}/** * g_main_context_wait: * @context: a #GMainContext * @cond: a condition variable * @mutex: a mutex, currently held * * Tries to become the owner of the specified context, * as with g_main_context_acquire(). But if another thread * is the owner, atomically drop @mutex and wait on @cond until * that owner releases ownership or until @cond is signaled, then * try again (once) to become the owner. * * Return value: %TRUE if the operation succeeded, and * this thread is now the owner of @context. **/gbooleang_main_context_wait (GMainContext *context, GCond *cond, GMutex *mutex){#ifdef G_THREADS_ENABLED gboolean result = FALSE; GThread *self = G_THREAD_SELF; gboolean loop_internal_waiter; if (context == NULL) context = g_main_context_default (); loop_internal_waiter = (mutex == g_static_mutex_get_mutex (&context->mutex)); if (!loop_internal_waiter) LOCK_CONTEXT (context); if (context->owner && context->owner != self) { GMainWaiter waiter; waiter.cond = cond; waiter.mutex = mutex; context->waiters = g_slist_append (context->waiters, &waiter); if (!loop_internal_waiter) UNLOCK_CONTEXT (context); g_cond_wait (cond, mutex); if (!loop_internal_waiter) LOCK_CONTEXT (context); context->waiters = g_slist_remove (context->waiters, &waiter); } if (!context->owner) { context->owner = self; g_assert (context->owner_count == 0); } if (context->owner == self) { context->owner_count++; result = TRUE; } if (!loop_internal_waiter) UNLOCK_CONTEXT (context); return result;#else /* !G_THREADS_ENABLED */ return TRUE;#endif /* G_THREADS_ENABLED */}/** * g_main_context_prepare: * @context: a #GMainContext * @priority: location to store priority of highest priority * source already ready. * * Prepares to poll sources within a main loop. The resulting information * for polling is determined by calling g_main_context_query (). * * Return value: %TRUE if some source is ready to be dispatched * prior to polling. **/gbooleang_main_context_prepare (GMainContext *context, gint *priority){ gint i; gint n_ready = 0; gint current_priority = G_MAXINT; GSource *source; if (context == NULL) context = g_main_context_default (); LOCK_CONTEXT (context); context->time_is_current = FALSE; if (context->in_check_or_prepare) { g_warning ("g_main_context_prepare() called recursively from within a source's check() or " "prepare() member."); UNLOCK_CONTEXT (context); return FALSE; }#ifdef G_THREADS_ENABLED if (context->poll_waiting) { g_warning("g_main_context_prepare(): main loop already active in another thread"); UNLOCK_CONTEXT (context); return FALSE; } context->poll_waiting = TRUE;#endif /* G_THREADS_ENABLED */#if 0 /* If recursing, finish up current dispatch, before starting over */ if (context->pending_dispatches) { if (dispatch) g_main_dispatch (context, ¤t_time); UNLOCK_CONTEXT (context); return TRUE; }#endif /* If recursing, clear list of pending dispatches */ for (i = 0; i < context->pending_dispatches->len; i++) { if (context->pending_dispatches->pdata[i]) SOURCE_UNREF ((GSource *)context->pending_dispatches->pdata[i], context); } g_ptr_array_set_size (context->pending_dispatches, 0); /* Prepare all sources */ context->timeout = -1; source = next_valid_source (context, NULL); while (source) { gint source_timeout = -1; if ((n_ready > 0) && (source->priority > current_priority)) { SOURCE_UNREF (source, context); break; } if ((source->flags & G_HOOK_FLAG_IN_CALL) && !(source->flags & G_SOURCE_CAN_RECURSE)) goto next; if (!(source->flags & G_SOURCE_READY)) { gboolean result; gboolean (*prepare) (GSource *source, gint *timeout); prepare = source->source_funcs->prepare; context->in_check_or_prepare++; UNLOCK_CONTEXT (context); result = (*prepare) (source, &source_timeout); LOCK_CONTEXT (context); context->in_check_or_prepare--; if (result) source->flags |= G_SOURCE_READY; } if (source->flags & G_SOURCE_READY) { n_ready++; current_priority = source->priority; context->timeout = 0; } if (source_timeout >= 0) { if (context->timeout < 0) context->timeout = source_timeout; else context->timeout = MIN (context->timeout, source_timeout); } next: source = next_valid_source (context, source); } UNLOCK_CONTEXT (context); if (priority) *priority = current_priority; return (n_ready > 0);}/** * g_main_context_query: * @context: a #GMainContext * @max_priority: maximum priority source to check * @timeout: location to store timeout to be used in polling * @fds: location to store #GPollFD records that need to be polled. * @n_fds: length of @fds. * * Determines information necessary to poll this main loop. * * Return value: the number of records actually stored in @fds, * or, if more than @n_fds records need to be stored, the number * of records that need to be stored. **/gintg_main_context_query (GMainContext *context, gint max_priority, gint *timeout, GPollFD *fds, gint n_fds){ gint n_poll; GPollRec *pollrec; LOCK_CONTEXT (context); pollrec = context->poll_records; n_poll = 0; while (pollrec && max_priority >= pollrec->priority) { if (pollrec->fd->events) { if (n_poll < n_fds) { fds[n_poll].fd = pollrec->fd->fd; /* In direct contradiction to the Unix98 spec, IRIX runs into * difficulty if you pass in POLLERR, POLLHUP or POLLNVAL * flags in the events field of the pollfd while it should * just ignoring them. So we mask them out here. */ fds[n_poll].events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL); fds[n_poll].revents = 0; } n_poll++; } pollrec = pollrec->next; }#ifdef G_THREADS_ENABLED context->poll_changed = FALSE;#endif if (timeout) { *timeout = context->timeout; if (timeout != 0) context->time_is_current = FALSE; } UNLOCK_CONTEXT (context); return n_poll;}/** * g_main_context_check: * @context: a #GMainContext * @max_priority: the maximum numerical priority of sources to check * @fds: array of #GPollFD's that was passed to the last call to * g_main_context_query() * @n_fds: return value of g_main_context_query() * * Passes the results of polling back to the main loop. * * Return value: %TRUE if some sources are ready to be dispatched. **/gbooleang_main_context_check (GMainContext *context, gint max_priority, GPollFD *fds, gint n_fds){ GSource *source; GPollRec *pollrec; gint n_ready = 0; gint i; LOCK_CONTEXT (context); if (context->in_check_or_prepare) { g_warning ("g_main_context_check() called recursively from within a source's check() or " "prepare() member."); UNLOCK_CONTEXT (context); return FALSE; } #ifdef G_THREADS_ENABLED if (!context->poll_waiting) {#ifndef G_OS_WIN32 gchar c; read (context->wake_up_pipe[0], &c, 1);#endif } else context->poll_waiting = FALSE; /* If the set of poll file descriptors changed, bail out * and let the main loop rerun */ if (context->poll_changed) { UNLOCK_CONTEXT (context); return 0; }#endif /* G_THREADS_ENABLED */ pollrec = context->poll_records; i = 0; while (i < n_fds) { if (pollrec->fd->events) { pollrec->fd->revents = fds[i].revents; i++; } pollrec = pollrec->next; } source = next_valid_source (context, NULL); while (source) { if ((n_ready > 0) && (source->priority > max_priority)) { SOURCE_UNREF (source, context); break; } if ((source->flags & G_HOOK_FLAG_IN_CALL) && !(source->flags & G_SOURCE_CAN_RECURSE)) goto next; if (!(source->flags & G_SOURCE_READY)) { gboolean result; gboolean (*check) (GSource *source); check = source->source_funcs->check; context->in_check_or_prepare++; UNLOCK_CONTEXT (context); result = (*check) (source); LOCK_CONTEXT (context); context->in_check_or_prepare--; if (result) source->flags |= G_SOURCE_READY; } if (source->flags & G_SOURCE_READY) { source->ref_count++; g_ptr_array_add (context->pending_dispatches, source); n_ready++; /* never dispatch sources with less priority than the first * one we choose to dispatch */ max_priority = source->priority; } next: source = next_valid_source (context, source); } UNLOCK_CONTEXT (context); return n_ready > 0;}/** * g_main_context_dispatch: * @context: a #GMainContext * * Dispatches all pending sources. **/voidg_main_context_dispatch (GMainContext *context){ LOCK_CONTEXT (context); if (context->pending_dispatches->len > 0) { g_main_dispatch (context); } UNLOCK_CONTEXT (context);}/* HOLDS context lock */static gbooleang_main_context_iterate (GMainContext *context, gboolean block, gboolean dispatch, GThread *self){ gint max_priority; gint timeout; gboolean some_ready; gint nfds, allocated_nfds; GPollFD *fds = NULL; UNLOCK_CONTEXT (context);#ifdef G_THREADS_ENABLED if (!g_main_context_acquire (context)) { gboolean got_ownership; g_return_val_if_fail (g_thread_supported (), FALSE); if (!block) return FALSE; LOCK_CONTEXT (context); if (!context->cond) context->cond = g_cond_new (); got_ownership = g_main_context_wait (context, context->cond, g_static_mutex_get_mutex (&context->mutex)); if (!got_ownership) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -