new function to check whether a main loop has been quitted. (g_main_new):

Fri Dec 18 00:03:17 1998  Tim Janik  <timj@gtk.org>

        * glib.h:
        * gmain.c:
        (g_main_is_running): new function to check whether a main loop has been
        quitted.
        (g_main_new): added a gboolean argument to determine whether the loop
        should be considered initially running or not. however, g_main_run ()
        will still reset the main loops running state to TRUE upon initial
        entrance.

        * gmain.c:
        (g_main_iterate): documented this function's purpose in 5 steps.
        for step 2), flag sources as G_SOURCE_READY even if !dispatch and
        check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
        on them multiple times.

Thu Dec 17 23:43:47 1998  Tim Janik  <timj@gtk.org>

        * gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
        first, <sigh> (sorry Snorfle, i should have let you know in the first
        place).
        (g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
        destructor when destroying a source.
This commit is contained in:
Tim Janik 1998-12-18 02:23:33 +00:00 committed by Tim Janik
parent c3c1b2edc0
commit 8be41eae4d
14 changed files with 390 additions and 78 deletions

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -1,3 +1,28 @@
Fri Dec 18 00:03:17 1998 Tim Janik <timj@gtk.org>
* glib.h:
* gmain.c:
(g_main_is_running): new function to check whether a main loop has been
quitted.
(g_main_new): added a gboolean argument to determine whether the loop
should be considered initially running or not. however, g_main_run ()
will still reset the main loops running state to TRUE upon initial
entrance.
* gmain.c:
(g_main_iterate): documented this function's purpose in 5 steps.
for step 2), flag sources as G_SOURCE_READY even if !dispatch and
check G_SOURCE_READY prior to (*prepare), so we don't call (*prepare)
on them multiple times.
Thu Dec 17 23:43:47 1998 Tim Janik <timj@gtk.org>
* gmain.c (g_main_add_poll): reordered arguments, so GPollFD* comes
first, <sigh> (sorry Snorfle, i should have let you know in the first
place).
(g_main_dispatch): stack G_HOOK_FLAG_IN_CALL flags. call source's
destructor when destroying a source.
1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de> 1998-12-17 Sebastian Wilhelmi <wilhelmi@ira.uka.de>
* garray.c (g_ptr_array_remove_index): Fixed size in g_memmove, * garray.c (g_ptr_array_remove_index): Fixed size in g_memmove,

View File

@ -276,7 +276,7 @@ g_io_unix_add_watch (GIOChannel *channel,
watch->pollfd.fd = unix_channel->fd; watch->pollfd.fd = unix_channel->fd;
watch->pollfd.events = condition; watch->pollfd.events = condition;
g_main_add_poll (priority, &watch->pollfd); g_main_add_poll (&watch->pollfd, priority);
return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify); return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
} }

7
glib.h
View File

@ -2427,10 +2427,11 @@ void g_source_remove_by_source_data (gpointer source_data);
void g_get_current_time (GTimeVal *result); void g_get_current_time (GTimeVal *result);
/* Running the main loop */ /* Running the main loop */
GMainLoop* g_main_new (void); GMainLoop* g_main_new (gboolean is_running);
void g_main_run (GMainLoop *loop); void g_main_run (GMainLoop *loop);
void g_main_quit (GMainLoop *loop); void g_main_quit (GMainLoop *loop);
void g_main_destroy (GMainLoop *loop); void g_main_destroy (GMainLoop *loop);
gboolean g_main_is_running (GMainLoop *loop);
/* Run a single iteration of the mainloop. If block is FALSE, /* Run a single iteration of the mainloop. If block is FALSE,
* will never block * will never block
@ -2472,8 +2473,8 @@ struct _GPollFD
gushort revents; gushort revents;
}; };
void g_main_add_poll (gint priority, void g_main_add_poll (GPollFD *fd,
GPollFD *fd); gint priority);
void g_main_remove_poll (GPollFD *fd); void g_main_remove_poll (GPollFD *fd);
void g_main_set_poll_func (GPollFunc func); void g_main_set_poll_func (GPollFunc func);

View File

@ -276,7 +276,7 @@ g_io_unix_add_watch (GIOChannel *channel,
watch->pollfd.fd = unix_channel->fd; watch->pollfd.fd = unix_channel->fd;
watch->pollfd.events = condition; watch->pollfd.events = condition;
g_main_add_poll (priority, &watch->pollfd); g_main_add_poll (&watch->pollfd, priority);
return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify); return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
} }

View File

@ -2427,10 +2427,11 @@ void g_source_remove_by_source_data (gpointer source_data);
void g_get_current_time (GTimeVal *result); void g_get_current_time (GTimeVal *result);
/* Running the main loop */ /* Running the main loop */
GMainLoop* g_main_new (void); GMainLoop* g_main_new (gboolean is_running);
void g_main_run (GMainLoop *loop); void g_main_run (GMainLoop *loop);
void g_main_quit (GMainLoop *loop); void g_main_quit (GMainLoop *loop);
void g_main_destroy (GMainLoop *loop); void g_main_destroy (GMainLoop *loop);
gboolean g_main_is_running (GMainLoop *loop);
/* Run a single iteration of the mainloop. If block is FALSE, /* Run a single iteration of the mainloop. If block is FALSE,
* will never block * will never block
@ -2472,8 +2473,8 @@ struct _GPollFD
gushort revents; gushort revents;
}; };
void g_main_add_poll (gint priority, void g_main_add_poll (GPollFD *fd,
GPollFD *fd); gint priority);
void g_main_remove_poll (GPollFD *fd); void g_main_remove_poll (GPollFD *fd);
void g_main_set_poll_func (GPollFunc func); void g_main_set_poll_func (GPollFunc func);

View File

@ -52,7 +52,7 @@ struct _GSource
struct _GMainLoop struct _GMainLoop
{ {
gboolean flag; gboolean is_running;
}; };
struct _GIdleData struct _GIdleData
@ -365,6 +365,7 @@ g_main_dispatch (GTimeVal *current_time)
if (G_HOOK_IS_VALID (source)) if (G_HOOK_IS_VALID (source))
{ {
gboolean was_in_call;
gpointer hook_data = source->hook.data; gpointer hook_data = source->hook.data;
gpointer source_data = source->source_data; gpointer source_data = source->source_data;
gboolean (*dispatch) (gpointer, gboolean (*dispatch) (gpointer,
@ -373,6 +374,7 @@ g_main_dispatch (GTimeVal *current_time)
dispatch = ((GSourceFuncs *) source->hook.func)->dispatch; dispatch = ((GSourceFuncs *) source->hook.func)->dispatch;
was_in_call = G_HOOK_IN_CALL (source);
source->hook.flags |= G_HOOK_FLAG_IN_CALL; source->hook.flags |= G_HOOK_FLAG_IN_CALL;
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
@ -381,19 +383,49 @@ g_main_dispatch (GTimeVal *current_time)
hook_data); hook_data);
G_LOCK (main_loop); G_LOCK (main_loop);
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL; if (!was_in_call)
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
if (need_destroy) if (need_destroy && G_HOOK_IS_VALID (source))
g_hook_destroy_link (&source_list, (GHook *) source); {
((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, (GHook *) source);
}
} }
g_hook_unref (&source_list, (GHook *)source); g_hook_unref (&source_list, (GHook *)source);
} }
} }
/* Run a single iteration of the mainloop, or, if !dispatch /* g_main_iterate () runs a single iteration of the mainloop, or,
* check to see if any events need dispatching, but don't * if !dispatch checks to see if any sources need dispatching.
* run the loop. * basic algorithm for dispatch=TRUE:
*
* 1) while the list of currently pending sources is non-empty,
* we call (*dispatch) on those that are !IN_CALL or can_recurse,
* removing sources from the list after each returns.
* the return value of (*dispatch) determines whether the source
* itself is kept alive.
*
* 2) call (*prepare) for sources that are not yet SOURCE_READY and
* are !IN_CALL or can_recurse. a return value of TRUE determines
* that the source would like to be dispatched immediatedly, it
* is then flagged as SOURCE_READY.
*
* 3) poll with the pollfds from all sources at the priority of the
* first source flagged as SOURCE_READY. if there are any sources
* flagged as SOURCE_READY, we use a timeout of 0 or the minimum
* of all timouts otherwise.
*
* 4) for each source !IN_CALL or can_recurse, if SOURCE_READY or
* (*check) returns true, add the source to the pending list.
* once one source returns true, stop after checking all sources
* at that priority.
*
* 5) while the list of currently pending sources is non-empty,
* call (*dispatch) on each source, removing the source
* after the call.
*
*/ */
static gboolean static gboolean
g_main_iterate (gboolean block, g_main_iterate (gboolean block,
@ -401,7 +433,7 @@ g_main_iterate (gboolean block,
{ {
GHook *hook; GHook *hook;
GTimeVal current_time; GTimeVal current_time;
gint nready = 0; gint n_ready = 0;
gint current_priority = 0; gint current_priority = 0;
gint timeout; gint timeout;
gboolean retval = FALSE; gboolean retval = FALSE;
@ -419,6 +451,7 @@ g_main_iterate (gboolean block,
g_main_dispatch (&current_time); g_main_dispatch (&current_time);
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
return TRUE; return TRUE;
} }
@ -433,30 +466,33 @@ g_main_iterate (gboolean block,
GHook *tmp; GHook *tmp;
gint source_timeout; gint source_timeout;
if ((nready > 0) && (source->priority > current_priority)) if ((n_ready > 0) && (source->priority > current_priority))
break; break;
if (!(hook->flags & G_SOURCE_CAN_RECURSE) && G_HOOK_IN_CALL (hook)) if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
{ {
hook = g_hook_next_valid (hook, TRUE); hook = g_hook_next_valid (hook, TRUE);
continue; continue;
} }
g_hook_ref (&source_list, hook); g_hook_ref (&source_list, hook);
if (((GSourceFuncs *)hook->func)->prepare (source->source_data, if (hook->flags & G_SOURCE_READY ||
&current_time, ((GSourceFuncs *) hook->func)->prepare (source->source_data,
&source_timeout)) &current_time,
&source_timeout))
{ {
if (!dispatch) if (!dispatch)
{ {
hook->flags |= G_SOURCE_READY;
g_hook_unref (&source_list, hook); g_hook_unref (&source_list, hook);
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
return TRUE; return TRUE;
} }
else else
{ {
hook->flags |= G_SOURCE_READY; hook->flags |= G_SOURCE_READY;
nready++; n_ready++;
current_priority = source->priority; current_priority = source->priority;
timeout = 0; timeout = 0;
} }
@ -478,11 +514,11 @@ g_main_iterate (gboolean block,
/* poll(), if necessary */ /* poll(), if necessary */
g_main_poll (timeout, nready > 0, current_priority); g_main_poll (timeout, n_ready > 0, current_priority);
/* Check to see what sources need to be dispatched */ /* Check to see what sources need to be dispatched */
nready = 0; n_ready = 0;
hook = g_hook_first_valid (&source_list, TRUE); hook = g_hook_first_valid (&source_list, TRUE);
while (hook) while (hook)
@ -490,9 +526,9 @@ g_main_iterate (gboolean block,
GSource *source = (GSource *)hook; GSource *source = (GSource *)hook;
GHook *tmp; GHook *tmp;
if ((nready > 0) && (source->priority > current_priority)) if ((n_ready > 0) && (source->priority > current_priority))
break; break;
if (!(hook->flags & G_SOURCE_CAN_RECURSE) && G_HOOK_IN_CALL (hook)) if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
{ {
hook = g_hook_next_valid (hook, TRUE); hook = g_hook_next_valid (hook, TRUE);
continue; continue;
@ -500,9 +536,9 @@ g_main_iterate (gboolean block,
g_hook_ref (&source_list, hook); g_hook_ref (&source_list, hook);
if ((hook->flags & G_SOURCE_READY) || if (hook->flags & G_SOURCE_READY ||
((GSourceFuncs *)hook->func)->check (source->source_data, ((GSourceFuncs *) hook->func)->check (source->source_data,
&current_time)) &current_time))
{ {
if (dispatch) if (dispatch)
{ {
@ -510,12 +546,13 @@ g_main_iterate (gboolean block,
g_hook_ref (&source_list, hook); g_hook_ref (&source_list, hook);
pending_dispatches = g_slist_prepend (pending_dispatches, source); pending_dispatches = g_slist_prepend (pending_dispatches, source);
current_priority = source->priority; current_priority = source->priority;
nready++; n_ready++;
} }
else else
{ {
g_hook_unref (&source_list, hook); g_hook_unref (&source_list, hook);
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
return TRUE; return TRUE;
} }
} }
@ -557,38 +594,56 @@ g_main_iteration (gboolean block)
return g_main_iterate (block, TRUE); return g_main_iterate (block, TRUE);
} }
GMainLoop * GMainLoop*
g_main_new () g_main_new (gboolean is_running)
{ {
GMainLoop *result = g_new (GMainLoop, 1); GMainLoop *loop;
result->flag = FALSE;
return result; loop = g_new0 (GMainLoop, 1);
loop->is_running = is_running != FALSE;
return loop;
} }
void void
g_main_run (GMainLoop *loop) g_main_run (GMainLoop *loop)
{ {
loop->flag = FALSE; g_return_if_fail (loop != NULL);
while (!loop->flag)
loop->is_running = TRUE;
while (loop->is_running)
g_main_iterate (TRUE, TRUE); g_main_iterate (TRUE, TRUE);
} }
void void
g_main_quit (GMainLoop *loop) g_main_quit (GMainLoop *loop)
{ {
loop->flag = TRUE; g_return_if_fail (loop != NULL);
loop->is_running = FALSE;
} }
void void
g_main_destroy (GMainLoop *loop) g_main_destroy (GMainLoop *loop)
{ {
g_return_if_fail (loop != NULL);
g_free (loop); g_free (loop);
} }
gboolean
g_main_is_running (GMainLoop *loop)
{
g_return_val_if_fail (loop != NULL, FALSE);
return loop->is_running;
}
/* HOLDS: main_loop_lock */ /* HOLDS: main_loop_lock */
static void static void
g_main_poll (gint timeout, gboolean use_priority, gint priority) g_main_poll (gint timeout,
gboolean use_priority,
gint priority)
{ {
GPollFD *fd_array = g_new (GPollFD, n_poll_records); GPollFD *fd_array = g_new (GPollFD, n_poll_records);
GPollRec *pollrec; GPollRec *pollrec;
@ -600,7 +655,7 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
{ {
if (pipe (wake_up_pipe) < 0) if (pipe (wake_up_pipe) < 0)
g_error ("Cannot create pipe main loop wake-up: %s\n", g_error ("Cannot create pipe main loop wake-up: %s\n",
g_strerror(errno)); g_strerror (errno));
wake_up_rec.fd = wake_up_pipe[0]; wake_up_rec.fd = wake_up_pipe[0];
wake_up_rec.events = G_IO_IN; wake_up_rec.events = G_IO_IN;
@ -647,8 +702,8 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
} }
void void
g_main_add_poll (gint priority, g_main_add_poll (GPollFD *fd,
GPollFD *fd) gint priority)
{ {
G_LOCK (main_loop); G_LOCK (main_loop);
g_main_add_unlocking_poll (priority, fd); g_main_add_unlocking_poll (priority, fd);

125
gmain.c
View File

@ -52,7 +52,7 @@ struct _GSource
struct _GMainLoop struct _GMainLoop
{ {
gboolean flag; gboolean is_running;
}; };
struct _GIdleData struct _GIdleData
@ -365,6 +365,7 @@ g_main_dispatch (GTimeVal *current_time)
if (G_HOOK_IS_VALID (source)) if (G_HOOK_IS_VALID (source))
{ {
gboolean was_in_call;
gpointer hook_data = source->hook.data; gpointer hook_data = source->hook.data;
gpointer source_data = source->source_data; gpointer source_data = source->source_data;
gboolean (*dispatch) (gpointer, gboolean (*dispatch) (gpointer,
@ -373,6 +374,7 @@ g_main_dispatch (GTimeVal *current_time)
dispatch = ((GSourceFuncs *) source->hook.func)->dispatch; dispatch = ((GSourceFuncs *) source->hook.func)->dispatch;
was_in_call = G_HOOK_IN_CALL (source);
source->hook.flags |= G_HOOK_FLAG_IN_CALL; source->hook.flags |= G_HOOK_FLAG_IN_CALL;
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
@ -381,19 +383,49 @@ g_main_dispatch (GTimeVal *current_time)
hook_data); hook_data);
G_LOCK (main_loop); G_LOCK (main_loop);
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL; if (!was_in_call)
source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
if (need_destroy) if (need_destroy && G_HOOK_IS_VALID (source))
g_hook_destroy_link (&source_list, (GHook *) source); {
((GSourceFuncs *) source->hook.func)->destroy (source->source_data);
g_hook_destroy_link (&source_list, (GHook *) source);
}
} }
g_hook_unref (&source_list, (GHook *)source); g_hook_unref (&source_list, (GHook *)source);
} }
} }
/* Run a single iteration of the mainloop, or, if !dispatch /* g_main_iterate () runs a single iteration of the mainloop, or,
* check to see if any events need dispatching, but don't * if !dispatch checks to see if any sources need dispatching.
* run the loop. * basic algorithm for dispatch=TRUE:
*
* 1) while the list of currently pending sources is non-empty,
* we call (*dispatch) on those that are !IN_CALL or can_recurse,
* removing sources from the list after each returns.
* the return value of (*dispatch) determines whether the source
* itself is kept alive.
*
* 2) call (*prepare) for sources that are not yet SOURCE_READY and
* are !IN_CALL or can_recurse. a return value of TRUE determines
* that the source would like to be dispatched immediatedly, it
* is then flagged as SOURCE_READY.
*
* 3) poll with the pollfds from all sources at the priority of the
* first source flagged as SOURCE_READY. if there are any sources
* flagged as SOURCE_READY, we use a timeout of 0 or the minimum
* of all timouts otherwise.
*
* 4) for each source !IN_CALL or can_recurse, if SOURCE_READY or
* (*check) returns true, add the source to the pending list.
* once one source returns true, stop after checking all sources
* at that priority.
*
* 5) while the list of currently pending sources is non-empty,
* call (*dispatch) on each source, removing the source
* after the call.
*
*/ */
static gboolean static gboolean
g_main_iterate (gboolean block, g_main_iterate (gboolean block,
@ -401,7 +433,7 @@ g_main_iterate (gboolean block,
{ {
GHook *hook; GHook *hook;
GTimeVal current_time; GTimeVal current_time;
gint nready = 0; gint n_ready = 0;
gint current_priority = 0; gint current_priority = 0;
gint timeout; gint timeout;
gboolean retval = FALSE; gboolean retval = FALSE;
@ -419,6 +451,7 @@ g_main_iterate (gboolean block,
g_main_dispatch (&current_time); g_main_dispatch (&current_time);
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
return TRUE; return TRUE;
} }
@ -433,30 +466,33 @@ g_main_iterate (gboolean block,
GHook *tmp; GHook *tmp;
gint source_timeout; gint source_timeout;
if ((nready > 0) && (source->priority > current_priority)) if ((n_ready > 0) && (source->priority > current_priority))
break; break;
if (!(hook->flags & G_SOURCE_CAN_RECURSE) && G_HOOK_IN_CALL (hook)) if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
{ {
hook = g_hook_next_valid (hook, TRUE); hook = g_hook_next_valid (hook, TRUE);
continue; continue;
} }
g_hook_ref (&source_list, hook); g_hook_ref (&source_list, hook);
if (((GSourceFuncs *)hook->func)->prepare (source->source_data, if (hook->flags & G_SOURCE_READY ||
&current_time, ((GSourceFuncs *) hook->func)->prepare (source->source_data,
&source_timeout)) &current_time,
&source_timeout))
{ {
if (!dispatch) if (!dispatch)
{ {
hook->flags |= G_SOURCE_READY;
g_hook_unref (&source_list, hook); g_hook_unref (&source_list, hook);
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
return TRUE; return TRUE;
} }
else else
{ {
hook->flags |= G_SOURCE_READY; hook->flags |= G_SOURCE_READY;
nready++; n_ready++;
current_priority = source->priority; current_priority = source->priority;
timeout = 0; timeout = 0;
} }
@ -478,11 +514,11 @@ g_main_iterate (gboolean block,
/* poll(), if necessary */ /* poll(), if necessary */
g_main_poll (timeout, nready > 0, current_priority); g_main_poll (timeout, n_ready > 0, current_priority);
/* Check to see what sources need to be dispatched */ /* Check to see what sources need to be dispatched */
nready = 0; n_ready = 0;
hook = g_hook_first_valid (&source_list, TRUE); hook = g_hook_first_valid (&source_list, TRUE);
while (hook) while (hook)
@ -490,9 +526,9 @@ g_main_iterate (gboolean block,
GSource *source = (GSource *)hook; GSource *source = (GSource *)hook;
GHook *tmp; GHook *tmp;
if ((nready > 0) && (source->priority > current_priority)) if ((n_ready > 0) && (source->priority > current_priority))
break; break;
if (!(hook->flags & G_SOURCE_CAN_RECURSE) && G_HOOK_IN_CALL (hook)) if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
{ {
hook = g_hook_next_valid (hook, TRUE); hook = g_hook_next_valid (hook, TRUE);
continue; continue;
@ -500,9 +536,9 @@ g_main_iterate (gboolean block,
g_hook_ref (&source_list, hook); g_hook_ref (&source_list, hook);
if ((hook->flags & G_SOURCE_READY) || if (hook->flags & G_SOURCE_READY ||
((GSourceFuncs *)hook->func)->check (source->source_data, ((GSourceFuncs *) hook->func)->check (source->source_data,
&current_time)) &current_time))
{ {
if (dispatch) if (dispatch)
{ {
@ -510,12 +546,13 @@ g_main_iterate (gboolean block,
g_hook_ref (&source_list, hook); g_hook_ref (&source_list, hook);
pending_dispatches = g_slist_prepend (pending_dispatches, source); pending_dispatches = g_slist_prepend (pending_dispatches, source);
current_priority = source->priority; current_priority = source->priority;
nready++; n_ready++;
} }
else else
{ {
g_hook_unref (&source_list, hook); g_hook_unref (&source_list, hook);
G_UNLOCK (main_loop); G_UNLOCK (main_loop);
return TRUE; return TRUE;
} }
} }
@ -557,38 +594,56 @@ g_main_iteration (gboolean block)
return g_main_iterate (block, TRUE); return g_main_iterate (block, TRUE);
} }
GMainLoop * GMainLoop*
g_main_new () g_main_new (gboolean is_running)
{ {
GMainLoop *result = g_new (GMainLoop, 1); GMainLoop *loop;
result->flag = FALSE;
return result; loop = g_new0 (GMainLoop, 1);
loop->is_running = is_running != FALSE;
return loop;
} }
void void
g_main_run (GMainLoop *loop) g_main_run (GMainLoop *loop)
{ {
loop->flag = FALSE; g_return_if_fail (loop != NULL);
while (!loop->flag)
loop->is_running = TRUE;
while (loop->is_running)
g_main_iterate (TRUE, TRUE); g_main_iterate (TRUE, TRUE);
} }
void void
g_main_quit (GMainLoop *loop) g_main_quit (GMainLoop *loop)
{ {
loop->flag = TRUE; g_return_if_fail (loop != NULL);
loop->is_running = FALSE;
} }
void void
g_main_destroy (GMainLoop *loop) g_main_destroy (GMainLoop *loop)
{ {
g_return_if_fail (loop != NULL);
g_free (loop); g_free (loop);
} }
gboolean
g_main_is_running (GMainLoop *loop)
{
g_return_val_if_fail (loop != NULL, FALSE);
return loop->is_running;
}
/* HOLDS: main_loop_lock */ /* HOLDS: main_loop_lock */
static void static void
g_main_poll (gint timeout, gboolean use_priority, gint priority) g_main_poll (gint timeout,
gboolean use_priority,
gint priority)
{ {
GPollFD *fd_array = g_new (GPollFD, n_poll_records); GPollFD *fd_array = g_new (GPollFD, n_poll_records);
GPollRec *pollrec; GPollRec *pollrec;
@ -600,7 +655,7 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
{ {
if (pipe (wake_up_pipe) < 0) if (pipe (wake_up_pipe) < 0)
g_error ("Cannot create pipe main loop wake-up: %s\n", g_error ("Cannot create pipe main loop wake-up: %s\n",
g_strerror(errno)); g_strerror (errno));
wake_up_rec.fd = wake_up_pipe[0]; wake_up_rec.fd = wake_up_pipe[0];
wake_up_rec.events = G_IO_IN; wake_up_rec.events = G_IO_IN;
@ -647,8 +702,8 @@ g_main_poll (gint timeout, gboolean use_priority, gint priority)
} }
void void
g_main_add_poll (gint priority, g_main_add_poll (GPollFD *fd,
GPollFD *fd) gint priority)
{ {
G_LOCK (main_loop); G_LOCK (main_loop);
g_main_add_unlocking_poll (priority, fd); g_main_add_unlocking_poll (priority, fd);