minor optimization.
[platform/upstream/glib.git] / gmain.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gmain.c: Main loop abstraction, timeouts, and idle functions
5  * Copyright 1998 Owen Taylor
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
25  * file for a list of people on the GLib Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 /* 
31  * MT safe
32  */
33
34 #include "config.h"
35
36 /* uncomment the next line to get poll() debugging info */
37 /* #define G_MAIN_POLL_DEBUG */
38
39
40
41 #include "glib.h"
42 #include <sys/types.h>
43 #include <time.h>
44 #ifdef HAVE_SYS_TIME_H
45 #include <sys/time.h>
46 #endif /* HAVE_SYS_TIME_H */
47 #ifdef GLIB_HAVE_SYS_POLL_H
48 #  include <sys/poll.h>
49 #  undef events  /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */
50 #  undef revents /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */
51 #endif /* GLIB_HAVE_SYS_POLL_H */
52 #ifdef HAVE_UNISTD_H
53 #include <unistd.h>
54 #endif /* HAVE_UNISTD_H */
55 #include <errno.h>
56
57 #ifdef G_OS_WIN32
58 #define STRICT
59 #include <windows.h>
60 #endif /* G_OS_WIN32 */
61
62 #ifdef G_OS_BEOS
63 #include <net/socket.h>
64 #endif /* G_OS_BEOS */
65
66 /* Types */
67
68 typedef struct _GTimeoutData GTimeoutData;
69 typedef struct _GSource GSource;
70 typedef struct _GPollRec GPollRec;
71
72 typedef enum
73 {
74   G_SOURCE_READY = 1 << G_HOOK_FLAG_USER_SHIFT,
75   G_SOURCE_CAN_RECURSE = 1 << (G_HOOK_FLAG_USER_SHIFT + 1)
76 } GSourceFlags;
77
78 struct _GSource
79 {
80   GHook hook;
81   gint priority;
82   gpointer source_data;
83 };
84
85 struct _GMainLoop
86 {
87   gboolean is_running;
88 };
89
90 struct _GTimeoutData
91 {
92   GTimeVal    expiration;
93   gint        interval;
94   GSourceFunc callback;
95 };
96
97 struct _GPollRec
98 {
99   gint priority;
100   GPollFD *fd;
101   GPollRec *next;
102 };
103
104 /* Forward declarations */
105
106 static gint     g_source_compare          (GHook      *a,
107                                            GHook      *b);
108 static void     g_source_destroy_func     (GHookList  *hook_list,
109                                            GHook      *hook);
110 static void     g_main_poll               (gint      timeout,
111                                            gboolean  use_priority, 
112                                            gint      priority);
113 static void     g_main_add_poll_unlocked  (gint      priority,
114                                            GPollFD  *fd);
115 static void     g_main_wakeup             (void);
116
117 static gboolean g_timeout_prepare      (gpointer  source_data, 
118                                         GTimeVal *current_time,
119                                         gint     *timeout,
120                                         gpointer  user_data);
121 static gboolean g_timeout_check        (gpointer  source_data,
122                                         GTimeVal *current_time,
123                                         gpointer  user_data);
124 static gboolean g_timeout_dispatch     (gpointer  source_data,
125                                         GTimeVal *dispatch_time,
126                                         gpointer  user_data);
127 static gboolean g_idle_prepare         (gpointer  source_data, 
128                                         GTimeVal *current_time,
129                                         gint     *timeout,
130                                         gpointer  user_data);
131 static gboolean g_idle_check           (gpointer  source_data,
132                                         GTimeVal *current_time,
133                                         gpointer  user_data);
134 static gboolean g_idle_dispatch        (gpointer  source_data,
135                                         GTimeVal *dispatch_time,
136                                         gpointer  user_data);
137
138 /* Data */
139
140 static GSList *pending_dispatches = NULL;
141 static GHookList source_list = { 0 };
142 static gint in_check_or_prepare = 0;
143
144 /* The following lock is used for both the list of sources
145  * and the list of poll records
146  */
147 G_LOCK_DEFINE_STATIC (main_loop);
148
149 static GSourceFuncs timeout_funcs =
150 {
151   g_timeout_prepare,
152   g_timeout_check,
153   g_timeout_dispatch,
154   g_free,
155 };
156
157 static GSourceFuncs idle_funcs =
158 {
159   g_idle_prepare,
160   g_idle_check,
161   g_idle_dispatch,
162   NULL,
163 };
164
165 static GPollRec *poll_records = NULL;
166 static GPollRec *poll_free_list = NULL;
167 static GMemChunk *poll_chunk;
168 static guint n_poll_records = 0;
169
170 #ifdef G_THREADS_ENABLED
171 #ifndef G_OS_WIN32
172 /* this pipe is used to wake up the main loop when a source is added.
173  */
174 static gint wake_up_pipe[2] = { -1, -1 };
175 #else /* G_OS_WIN32 */
176 static HANDLE wake_up_semaphore = NULL;
177 #endif /* G_OS_WIN32 */
178 static GPollFD wake_up_rec;
179 static gboolean poll_waiting = FALSE;
180
181 /* Flag indicating whether the set of fd's changed during a poll */
182 static gboolean poll_changed = FALSE;
183 #endif /* G_THREADS_ENABLED */
184
185 #ifdef HAVE_POLL
186 /* SunOS has poll, but doesn't provide a prototype. */
187 #  if defined (sun) && !defined (__SVR4)
188 extern gint poll (GPollFD *ufds, guint nfsd, gint timeout);
189 #  endif  /* !sun */
190 static GPollFunc poll_func = (GPollFunc) poll;
191 #else   /* !HAVE_POLL */
192 #ifdef G_OS_WIN32
193
194 static gint
195 g_poll (GPollFD *fds, guint nfds, gint timeout)
196 {
197   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
198   GPollFD *f;
199   DWORD ready;
200   MSG msg;
201   UINT timer;
202   LONG prevcnt;
203   gint poll_msgs = -1;
204   gint nhandles = 0;
205
206   for (f = fds; f < &fds[nfds]; ++f)
207     if (f->fd >= 0)
208       {
209         if (f->events & G_IO_IN)
210           if (f->fd == G_WIN32_MSG_HANDLE)
211             poll_msgs = f - fds;
212           else
213             {
214               /* g_print ("g_poll: waiting for handle %#x\n", f->fd); */
215               handles[nhandles++] = (HANDLE) f->fd;
216             }
217       }
218
219   if (timeout == -1)
220     timeout = INFINITE;
221
222   if (poll_msgs >= 0)
223     {
224       /* Waiting for messages, and maybe events */
225       if (nhandles == 0)
226         {
227           if (timeout == INFINITE)
228             {
229               /* Waiting just for messages, infinite timeout
230                * -> Use PeekMessage, then WaitMessage
231                */
232               /* g_print ("WaitMessage, PeekMessage\n"); */
233               if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
234                 ready = WAIT_OBJECT_0;
235               else if (!WaitMessage ())
236                 g_warning ("g_poll: WaitMessage failed");
237               ready = WAIT_OBJECT_0;
238             }
239           else if (timeout == 0)
240             {
241               /* Waiting just for messages, zero timeout
242                * -> Use PeekMessage
243                */
244               /* g_print ("PeekMessage\n"); */
245               if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
246                 ready = WAIT_OBJECT_0;
247               else
248                 ready = WAIT_TIMEOUT;
249             }
250           else
251             {
252               /* Waiting just for messages, some timeout
253                * -> First try PeekMessage, then set a timer, wait for message,
254                * kill timer, use PeekMessage
255                */
256               /* g_print ("PeekMessage\n"); */
257               if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
258                 ready = WAIT_OBJECT_0;
259               else if ((timer = SetTimer (NULL, 0, timeout, NULL)) == 0)
260                 g_warning ("g_poll: SetTimer failed");
261               else
262                 {
263                   /* g_print ("WaitMessage\n"); */
264                   WaitMessage ();
265                   KillTimer (NULL, timer);
266                   if (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
267                     ready = WAIT_OBJECT_0;
268                   else
269                     ready = WAIT_TIMEOUT;
270                 }
271             }
272         }
273       else
274         {
275           /* Wait for either message or event
276            * -> Use MsgWaitForMultipleObjects
277            */
278           /* g_print ("MsgWaitForMultipleObjects(%d, %d)\n", nhandles, timeout); */
279           ready = MsgWaitForMultipleObjects (nhandles, handles, FALSE,
280                                              timeout, QS_ALLINPUT);
281           /* g_print("=%d\n", ready); */
282           if (ready == WAIT_FAILED)
283             g_warning ("g_poll: MsgWaitForMultipleObjects failed");
284         }
285     }
286   else if (nhandles == 0)
287     {
288       /* Wait for nothing (huh?) */
289       return 0;
290     }
291   else
292     {
293       /* Wait for just events
294        * -> Use WaitForMultipleObjects
295        */
296       /* g_print ("WaitForMultipleObjects(%d, %d)\n", nhandles, timeout); */
297       ready = WaitForMultipleObjects (nhandles, handles, FALSE, timeout);
298       /* g_print("=%d\n", ready); */
299       if (ready == WAIT_FAILED)
300         g_warning ("g_poll: WaitForMultipleObjects failed");
301     }
302
303   for (f = fds; f < &fds[nfds]; ++f)
304     f->revents = 0;
305
306   if (ready == WAIT_FAILED)
307     return -1;
308   else if (poll_msgs >= 0 && ready == WAIT_OBJECT_0 + nhandles)
309     {
310       fds[poll_msgs].revents |= G_IO_IN;
311     }
312   else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
313     for (f = fds; f < &fds[nfds]; ++f)
314       {
315         if ((f->events & G_IO_IN)
316             && f->fd == (gint) handles[ready - WAIT_OBJECT_0])
317           {
318             f->revents |= G_IO_IN;
319             /* g_print ("event %#x\n", f->fd); */
320             ResetEvent ((HANDLE) f->fd);
321           }
322       }
323     
324   if (ready == WAIT_TIMEOUT)
325     return 0;
326   else
327     return 1;
328 }
329
330 #else  /* !G_OS_WIN32 */
331
332 /* The following implementation of poll() comes from the GNU C Library.
333  * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
334  */
335
336 #include <string.h> /* for bzero on BSD systems */
337
338 #ifdef HAVE_SYS_SELECT_H
339 #include <sys/select.h>
340 #endif /* HAVE_SYS_SELECT_H */
341
342 #ifdef G_OS_BEOS
343 #undef NO_FD_SET
344 #endif /* G_OS_BEOS */
345
346 #ifndef NO_FD_SET
347 #  define SELECT_MASK fd_set
348 #else /* !NO_FD_SET */
349 #  ifndef _AIX
350 typedef long fd_mask;
351 #  endif /* _AIX */
352 #  ifdef _IBMR2
353 #    define SELECT_MASK void
354 #  else /* !_IBMR2 */
355 #    define SELECT_MASK int
356 #  endif /* !_IBMR2 */
357 #endif /* !NO_FD_SET */
358
359 static gint 
360 g_poll (GPollFD *fds,
361         guint    nfds,
362         gint     timeout)
363 {
364   struct timeval tv;
365   SELECT_MASK rset, wset, xset;
366   GPollFD *f;
367   int ready;
368   int maxfd = 0;
369
370   FD_ZERO (&rset);
371   FD_ZERO (&wset);
372   FD_ZERO (&xset);
373
374   for (f = fds; f < &fds[nfds]; ++f)
375     if (f->fd >= 0)
376       {
377         if (f->events & G_IO_IN)
378           FD_SET (f->fd, &rset);
379         if (f->events & G_IO_OUT)
380           FD_SET (f->fd, &wset);
381         if (f->events & G_IO_PRI)
382           FD_SET (f->fd, &xset);
383         if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
384           maxfd = f->fd;
385       }
386
387   tv.tv_sec = timeout / 1000;
388   tv.tv_usec = (timeout % 1000) * 1000;
389
390   ready = select (maxfd + 1, &rset, &wset, &xset,
391                   timeout == -1 ? NULL : &tv);
392   if (ready > 0)
393     for (f = fds; f < &fds[nfds]; ++f)
394       {
395         f->revents = 0;
396         if (f->fd >= 0)
397           {
398             if (FD_ISSET (f->fd, &rset))
399               f->revents |= G_IO_IN;
400             if (FD_ISSET (f->fd, &wset))
401               f->revents |= G_IO_OUT;
402             if (FD_ISSET (f->fd, &xset))
403               f->revents |= G_IO_PRI;
404           }
405       }
406
407   return ready;
408 }
409
410 #endif /* !G_OS_WIN32 */
411
412 static GPollFunc poll_func = g_poll;
413 #endif  /* !HAVE_POLL */
414
415 /* Hooks for adding to the main loop */
416
417 /* Use knowledge of insert_sorted algorithm here to make
418  * sure we insert at the end of equal priority items
419  */
420 static gint
421 g_source_compare (GHook *a,
422                   GHook *b)
423 {
424   GSource *source_a = (GSource *)a;
425   GSource *source_b = (GSource *)b;
426
427   return (source_a->priority < source_b->priority) ? -1 : 1;
428 }
429
430 /* HOLDS: main_loop lock */
431 static void
432 g_source_destroy_func (GHookList *hook_list,
433                        GHook     *hook)
434 {
435   GSource *source = (GSource*) hook;
436   GDestroyNotify destroy;
437
438   G_UNLOCK (main_loop);
439
440   destroy = hook->destroy;
441   if (destroy)
442     destroy (hook->data);
443
444   destroy = ((GSourceFuncs*) hook->func)->destroy;
445   if (destroy)
446     destroy (source->source_data);
447
448   G_LOCK (main_loop);
449 }
450
451 guint 
452 g_source_add (gint           priority,
453               gboolean       can_recurse,
454               GSourceFuncs  *funcs,
455               gpointer       source_data, 
456               gpointer       user_data,
457               GDestroyNotify notify)
458 {
459   guint return_val;
460   GSource *source;
461
462   G_LOCK (main_loop);
463
464   if (!source_list.is_setup)
465     {
466       g_hook_list_init (&source_list, sizeof (GSource));
467
468       source_list.hook_destroy = G_HOOK_DEFERRED_DESTROY;
469       source_list.hook_free = g_source_destroy_func;
470     }
471
472   source = (GSource*) g_hook_alloc (&source_list);
473   source->priority = priority;
474   source->source_data = source_data;
475   source->hook.func = funcs;
476   source->hook.data = user_data;
477   source->hook.destroy = notify;
478   
479   g_hook_insert_sorted (&source_list, 
480                         (GHook *)source, 
481                         g_source_compare);
482
483   if (can_recurse)
484     source->hook.flags |= G_SOURCE_CAN_RECURSE;
485
486   return_val = source->hook.hook_id;
487
488 #ifdef G_THREADS_ENABLED
489   /* Now wake up the main loop if it is waiting in the poll() */
490   g_main_wakeup ();
491 #endif
492   
493   G_UNLOCK (main_loop);
494
495   return return_val;
496 }
497
498 gboolean
499 g_source_remove (guint tag)
500 {
501   GHook *hook;
502
503   g_return_val_if_fail (tag > 0, FALSE);
504
505   G_LOCK (main_loop);
506
507   hook = g_hook_get (&source_list, tag);
508   if (hook)
509     g_hook_destroy_link (&source_list, hook);
510
511   G_UNLOCK (main_loop);
512
513   return hook != NULL;
514 }
515
516 gboolean
517 g_source_remove_by_user_data (gpointer user_data)
518 {
519   GHook *hook;
520   
521   G_LOCK (main_loop);
522   
523   hook = g_hook_find_data (&source_list, TRUE, user_data);
524   if (hook)
525     g_hook_destroy_link (&source_list, hook);
526
527   G_UNLOCK (main_loop);
528
529   return hook != NULL;
530 }
531
532 static gboolean
533 g_source_find_source_data (GHook        *hook,
534                            gpointer      data)
535 {
536   GSource *source = (GSource *)hook;
537
538   return (source->source_data == data);
539 }
540
541 gboolean
542 g_source_remove_by_source_data (gpointer source_data)
543 {
544   GHook *hook;
545
546   G_LOCK (main_loop);
547
548   hook = g_hook_find (&source_list, TRUE, 
549                       g_source_find_source_data, source_data);
550   if (hook)
551     g_hook_destroy_link (&source_list, hook);
552
553   G_UNLOCK (main_loop);
554
555   return hook != NULL;
556 }
557
558 static gboolean
559 g_source_find_funcs_user_data (GHook   *hook,
560                                gpointer data)
561 {
562   gpointer *d = data;
563
564   return hook->func == d[0] && hook->data == d[1];
565 }
566
567 gboolean
568 g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
569                                     gpointer      user_data)
570 {
571   gpointer d[2];
572   GHook *hook;
573
574   g_return_val_if_fail (funcs != NULL, FALSE);
575
576   G_LOCK (main_loop);
577
578   d[0] = funcs;
579   d[1] = user_data;
580
581   hook = g_hook_find (&source_list, TRUE,
582                       g_source_find_funcs_user_data, d);
583   if (hook)
584     g_hook_destroy_link (&source_list, hook);
585
586   G_UNLOCK (main_loop);
587
588   return hook != NULL;
589 }
590
591 void
592 g_get_current_time (GTimeVal *result)
593 {
594 #ifndef G_OS_WIN32
595   struct timeval r;
596   g_return_if_fail (result != NULL);
597
598   /*this is required on alpha, there the timeval structs are int's
599     not longs and a cast only would fail horribly*/
600   gettimeofday (&r, NULL);
601   result->tv_sec = r.tv_sec;
602   result->tv_usec = r.tv_usec;
603 #else
604   /* Avoid calling time() except for the first time.
605    * GetTickCount() should be pretty fast and low-level?
606    * I could also use ftime() but it seems unnecessarily overheady.
607    */
608   static DWORD start_tick = 0;
609   static time_t start_time;
610   DWORD tick;
611   time_t t;
612
613   g_return_if_fail (result != NULL);
614  
615   if (start_tick == 0)
616     {
617       start_tick = GetTickCount ();
618       time (&start_time);
619     }
620
621   tick = GetTickCount ();
622
623   result->tv_sec = (tick - start_tick) / 1000 + start_time;
624   result->tv_usec = ((tick - start_tick) % 1000) * 1000;
625 #endif
626 }
627
628 /* Running the main loop */
629
630 /* HOLDS: main_loop_lock */
631 static void
632 g_main_dispatch (GTimeVal *dispatch_time)
633 {
634   while (pending_dispatches != NULL)
635     {
636       gboolean need_destroy;
637       GSource *source = pending_dispatches->data;
638       GSList *tmp_list;
639
640       tmp_list = pending_dispatches;
641       pending_dispatches = g_slist_remove_link (pending_dispatches, pending_dispatches);
642       g_slist_free_1 (tmp_list);
643
644       if (G_HOOK_IS_VALID (source))
645         {
646           gboolean was_in_call;
647           gpointer hook_data = source->hook.data;
648           gpointer source_data = source->source_data;
649           gboolean (*dispatch) (gpointer,
650                                 GTimeVal *,
651                                 gpointer);
652
653           dispatch = ((GSourceFuncs *) source->hook.func)->dispatch;
654           
655           was_in_call = G_HOOK_IN_CALL (source);
656           source->hook.flags |= G_HOOK_FLAG_IN_CALL;
657
658           G_UNLOCK (main_loop);
659           need_destroy = ! dispatch (source_data,
660                                      dispatch_time,
661                                      hook_data);
662           G_LOCK (main_loop);
663
664           if (!was_in_call)
665             source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
666           
667           if (need_destroy && G_HOOK_IS_VALID (source))
668             g_hook_destroy_link (&source_list, (GHook *) source);
669         }
670
671       g_hook_unref (&source_list, (GHook*) source);
672     }
673 }
674
675 /* g_main_iterate () runs a single iteration of the mainloop, or,
676  * if !dispatch checks to see if any sources need dispatching.
677  * basic algorithm for dispatch=TRUE:
678  *
679  * 1) while the list of currently pending sources is non-empty,
680  *    we call (*dispatch) on those that are !IN_CALL or can_recurse,
681  *    removing sources from the list after each returns.
682  *    the return value of (*dispatch) determines whether the source
683  *    itself is kept alive.
684  *
685  * 2) call (*prepare) for sources that are not yet SOURCE_READY and
686  *    are !IN_CALL or can_recurse. a return value of TRUE determines
687  *    that the source would like to be dispatched immediatedly, it
688  *    is then flagged as SOURCE_READY.
689  *
690  * 3) poll with the pollfds from all sources at the priority of the
691  *    first source flagged as SOURCE_READY. if there are any sources
692  *    flagged as SOURCE_READY, we use a timeout of 0 or the minimum
693  *    of all timouts otherwise.
694  *
695  * 4) for each source !IN_CALL or can_recurse, if SOURCE_READY or
696  *    (*check) returns true, add the source to the pending list.
697  *    once one source returns true, stop after checking all sources
698  *    at that priority.
699  *
700  * 5) while the list of currently pending sources is non-empty,
701  *    call (*dispatch) on each source, removing the source
702  *    after the call.
703  *
704  */
705 static gboolean
706 g_main_iterate (gboolean block,
707                 gboolean dispatch)
708 {
709   GHook *hook;
710   GTimeVal current_time  = { 0, 0 };
711   gint n_ready = 0;
712   gint current_priority = 0;
713   gint timeout;
714   gboolean retval = FALSE;
715
716   g_return_val_if_fail (!block || dispatch, FALSE);
717
718   g_get_current_time (&current_time);
719
720   G_LOCK (main_loop);
721
722 #ifdef G_THREADS_ENABLED
723   if (poll_waiting)
724     {
725       g_warning("g_main_iterate(): main loop already active in another thread");
726       G_UNLOCK (main_loop);
727       return FALSE;
728     }
729 #endif G_THREADS_ENABLED  
730   
731   /* If recursing, finish up current dispatch, before starting over */
732   if (pending_dispatches)
733     {
734       if (dispatch)
735         g_main_dispatch (&current_time);
736       
737       G_UNLOCK (main_loop);
738
739       return TRUE;
740     }
741
742   /* Prepare all sources */
743
744   timeout = block ? -1 : 0;
745   
746   hook = g_hook_first_valid (&source_list, TRUE);
747   while (hook)
748     {
749       GSource *source = (GSource*) hook;
750       gint source_timeout = -1;
751
752       if ((n_ready > 0) && (source->priority > current_priority))
753         {
754           g_hook_unref (&source_list, hook);
755           break;
756         }
757       if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
758         {
759           hook = g_hook_next_valid (&source_list, hook, TRUE);
760           continue;
761         }
762
763       if (!(hook->flags & G_SOURCE_READY))
764         {
765           gboolean (*prepare)  (gpointer  source_data, 
766                                 GTimeVal *current_time,
767                                 gint     *timeout,
768                                 gpointer  user_data);
769
770           prepare = ((GSourceFuncs *) hook->func)->prepare;
771           in_check_or_prepare++;
772           G_UNLOCK (main_loop);
773
774           if ((*prepare) (source->source_data, &current_time, &source_timeout, source->hook.data))
775             hook->flags |= G_SOURCE_READY;
776           
777           G_LOCK (main_loop);
778           in_check_or_prepare--;
779         }
780
781       if (hook->flags & G_SOURCE_READY)
782         {
783           if (!dispatch)
784             {
785               g_hook_unref (&source_list, hook);
786               G_UNLOCK (main_loop);
787
788               return TRUE;
789             }
790           else
791             {
792               n_ready++;
793               current_priority = source->priority;
794               timeout = 0;
795             }
796         }
797       
798       if (source_timeout >= 0)
799         {
800           if (timeout < 0)
801             timeout = source_timeout;
802           else
803             timeout = MIN (timeout, source_timeout);
804         }
805
806       hook = g_hook_next_valid (&source_list, hook, TRUE);
807     }
808
809   /* poll(), if necessary */
810
811   g_main_poll (timeout, n_ready > 0, current_priority);
812
813   if (timeout != 0)
814     g_get_current_time (&current_time);
815   
816   /* Check to see what sources need to be dispatched */
817
818   n_ready = 0;
819   
820   hook = g_hook_first_valid (&source_list, TRUE);
821   while (hook)
822     {
823       GSource *source = (GSource *)hook;
824
825       if ((n_ready > 0) && (source->priority > current_priority))
826         {
827           g_hook_unref (&source_list, hook);
828           break;
829         }
830       if (G_HOOK_IN_CALL (hook) && !(hook->flags & G_SOURCE_CAN_RECURSE))
831         {
832           hook = g_hook_next_valid (&source_list, hook, TRUE);
833           continue;
834         }
835
836       if (!(hook->flags & G_SOURCE_READY))
837         {
838           gboolean (*check) (gpointer  source_data,
839                              GTimeVal *current_time,
840                              gpointer  user_data);
841
842           check = ((GSourceFuncs *) hook->func)->check;
843           in_check_or_prepare++;
844           G_UNLOCK (main_loop);
845           
846           if ((*check) (source->source_data, &current_time, source->hook.data))
847             hook->flags |= G_SOURCE_READY;
848
849           G_LOCK (main_loop);
850           in_check_or_prepare--;
851         }
852
853       if (hook->flags & G_SOURCE_READY)
854         {
855           if (dispatch)
856             {
857               hook->flags &= ~G_SOURCE_READY;
858               g_hook_ref (&source_list, hook);
859               pending_dispatches = g_slist_prepend (pending_dispatches, source);
860               current_priority = source->priority;
861               n_ready++;
862             }
863           else
864             {
865               g_hook_unref (&source_list, hook);
866               G_UNLOCK (main_loop);
867
868               return TRUE;
869             }
870         }
871       
872       hook = g_hook_next_valid (&source_list, hook, TRUE);
873     }
874  
875   /* Now invoke the callbacks */
876
877   if (pending_dispatches)
878     {
879       pending_dispatches = g_slist_reverse (pending_dispatches);
880       g_main_dispatch (&current_time);
881       retval = TRUE;
882     }
883
884   G_UNLOCK (main_loop);
885
886   return retval;
887 }
888
889 /* See if any events are pending
890  */
891 gboolean 
892 g_main_pending (void)
893 {
894   return in_check_or_prepare ? FALSE : g_main_iterate (FALSE, FALSE);
895 }
896
897 /* Run a single iteration of the mainloop. If block is FALSE,
898  * will never block
899  */
900 gboolean
901 g_main_iteration (gboolean block)
902 {
903   if (in_check_or_prepare)
904     {
905       g_warning ("g_main_iteration(): called recursively from within a source's check() or "
906                  "prepare() member or from a second thread, iteration not possible");
907       return FALSE;
908     }
909   else
910     return g_main_iterate (block, TRUE);
911 }
912
913 GMainLoop*
914 g_main_new (gboolean is_running)
915 {
916   GMainLoop *loop;
917
918   loop = g_new0 (GMainLoop, 1);
919   loop->is_running = is_running != FALSE;
920
921   return loop;
922 }
923
924 void 
925 g_main_run (GMainLoop *loop)
926 {
927   g_return_if_fail (loop != NULL);
928
929   if (in_check_or_prepare)
930     {
931       g_warning ("g_main_run(): called recursively from within a source's check() or "
932                  "prepare() member or from a second thread, iteration not possible");
933       return;
934     }
935   
936   loop->is_running = TRUE;
937   while (loop->is_running)
938     g_main_iterate (TRUE, TRUE);
939 }
940
941 void 
942 g_main_quit (GMainLoop *loop)
943 {
944   g_return_if_fail (loop != NULL);
945
946   loop->is_running = FALSE;
947 }
948
949 void 
950 g_main_destroy (GMainLoop *loop)
951 {
952   g_return_if_fail (loop != NULL);
953
954   g_free (loop);
955 }
956
957 gboolean
958 g_main_is_running (GMainLoop *loop)
959 {
960   g_return_val_if_fail (loop != NULL, FALSE);
961
962   return loop->is_running;
963 }
964
965 /* HOLDS: main_loop_lock */
966 static void
967 g_main_poll (gint     timeout,
968              gboolean use_priority,
969              gint     priority)
970 {
971 #ifdef  G_MAIN_POLL_DEBUG
972   GTimer *poll_timer;
973 #endif
974   GPollFD *fd_array;
975   GPollRec *pollrec;
976   gint i;
977   gint npoll;
978
979 #ifdef G_THREADS_ENABLED
980 #ifndef G_OS_WIN32
981   if (wake_up_pipe[0] < 0)
982     {
983       if (pipe (wake_up_pipe) < 0)
984         g_error ("Cannot create pipe main loop wake-up: %s\n",
985                  g_strerror (errno));
986
987       wake_up_rec.fd = wake_up_pipe[0];
988       wake_up_rec.events = G_IO_IN;
989       g_main_add_poll_unlocked (0, &wake_up_rec);
990     }
991 #else
992   if (wake_up_semaphore == NULL)
993     {
994       if ((wake_up_semaphore = CreateSemaphore (NULL, 0, 100, NULL)) == NULL)
995         g_error ("Cannot create wake-up semaphore: %d", GetLastError ());
996       wake_up_rec.fd = (gint) wake_up_semaphore;
997       wake_up_rec.events = G_IO_IN;
998       g_main_add_poll_unlocked (0, &wake_up_rec);
999     }
1000 #endif
1001 #endif
1002   fd_array = g_new (GPollFD, n_poll_records);
1003  
1004   pollrec = poll_records;
1005   i = 0;
1006   while (pollrec && (!use_priority || priority >= pollrec->priority))
1007     {
1008       if (pollrec->fd->events)
1009         {
1010           fd_array[i].fd = pollrec->fd->fd;
1011           /* In direct contradiction to the Unix98 spec, IRIX runs into
1012            * difficulty if you pass in POLLERR, POLLHUP or POLLNVAL
1013            * flags in the events field of the pollfd while it should
1014            * just ignoring them. So we mask them out here.
1015            */
1016           fd_array[i].events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL);
1017           fd_array[i].revents = 0;
1018           i++;
1019         }
1020       
1021       pollrec = pollrec->next;
1022     }
1023 #ifdef G_THREADS_ENABLED
1024   poll_waiting = TRUE;
1025   poll_changed = FALSE;
1026 #endif
1027   
1028   npoll = i;
1029   if (npoll || timeout != 0)
1030     {
1031 #ifdef  G_MAIN_POLL_DEBUG
1032       g_print ("g_main_poll(%d) timeout: %d\r", npoll, timeout);
1033       poll_timer = g_timer_new ();
1034 #endif
1035       
1036       G_UNLOCK (main_loop);
1037       (*poll_func) (fd_array, npoll, timeout);
1038       G_LOCK (main_loop);
1039       
1040 #ifdef  G_MAIN_POLL_DEBUG
1041       g_print ("g_main_poll(%d) timeout: %d - elapsed %12.10f seconds",
1042                npoll,
1043                timeout,
1044                g_timer_elapsed (poll_timer, NULL));
1045       g_timer_destroy (poll_timer);
1046       pollrec = poll_records;
1047       i = 0;
1048       while (i < npoll)
1049         {
1050           if (pollrec->fd->events)
1051             {
1052               if (fd_array[i].revents)
1053                 {
1054                   g_print (" [%d:", fd_array[i].fd);
1055                   if (fd_array[i].revents & G_IO_IN)
1056                     g_print ("i");
1057                   if (fd_array[i].revents & G_IO_OUT)
1058                     g_print ("o");
1059                   if (fd_array[i].revents & G_IO_PRI)
1060                     g_print ("p");
1061                   if (fd_array[i].revents & G_IO_ERR)
1062                     g_print ("e");
1063                   if (fd_array[i].revents & G_IO_HUP)
1064                     g_print ("h");
1065                   if (fd_array[i].revents & G_IO_NVAL)
1066                     g_print ("n");
1067                   g_print ("]");
1068                 }
1069               i++;
1070             }
1071           pollrec = pollrec->next;
1072         }
1073       g_print ("\n");
1074 #endif
1075     } /* if (npoll || timeout != 0) */
1076   
1077 #ifdef G_THREADS_ENABLED
1078   if (!poll_waiting)
1079     {
1080 #ifndef G_OS_WIN32
1081       gchar c;
1082       read (wake_up_pipe[0], &c, 1);
1083 #endif
1084     }
1085   else
1086     poll_waiting = FALSE;
1087
1088   /* If the set of poll file descriptors changed, bail out
1089    * and let the main loop rerun
1090    */
1091   if (poll_changed)
1092     {
1093       g_free (fd_array);
1094       return;
1095     }
1096 #endif
1097
1098   pollrec = poll_records;
1099   i = 0;
1100   while (i < npoll)
1101     {
1102       if (pollrec->fd->events)
1103         {
1104           pollrec->fd->revents = fd_array[i].revents;
1105           i++;
1106         }
1107       pollrec = pollrec->next;
1108     }
1109
1110   g_free (fd_array);
1111 }
1112
1113 void 
1114 g_main_add_poll (GPollFD *fd,
1115                  gint     priority)
1116 {
1117   G_LOCK (main_loop);
1118   g_main_add_poll_unlocked (priority, fd);
1119   G_UNLOCK (main_loop);
1120 }
1121
1122 /* HOLDS: main_loop_lock */
1123 static void 
1124 g_main_add_poll_unlocked (gint     priority,
1125                           GPollFD *fd)
1126 {
1127   GPollRec *lastrec, *pollrec, *newrec;
1128
1129   if (!poll_chunk)
1130     poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
1131
1132   if (poll_free_list)
1133     {
1134       newrec = poll_free_list;
1135       poll_free_list = newrec->next;
1136     }
1137   else
1138     newrec = g_chunk_new (GPollRec, poll_chunk);
1139
1140   newrec->fd = fd;
1141   newrec->priority = priority;
1142
1143   lastrec = NULL;
1144   pollrec = poll_records;
1145   while (pollrec && priority >= pollrec->priority)
1146     {
1147       lastrec = pollrec;
1148       pollrec = pollrec->next;
1149     }
1150   
1151   if (lastrec)
1152     lastrec->next = newrec;
1153   else
1154     poll_records = newrec;
1155
1156   newrec->next = pollrec;
1157
1158   n_poll_records++;
1159
1160 #ifdef G_THREADS_ENABLED
1161   poll_changed = TRUE;
1162
1163   /* Now wake up the main loop if it is waiting in the poll() */
1164   g_main_wakeup ();
1165 #endif
1166 }
1167
1168 void 
1169 g_main_remove_poll (GPollFD *fd)
1170 {
1171   GPollRec *pollrec, *lastrec;
1172
1173   G_LOCK (main_loop);
1174   
1175   lastrec = NULL;
1176   pollrec = poll_records;
1177
1178   while (pollrec)
1179     {
1180       if (pollrec->fd == fd)
1181         {
1182           if (lastrec != NULL)
1183             lastrec->next = pollrec->next;
1184           else
1185             poll_records = pollrec->next;
1186
1187           pollrec->next = poll_free_list;
1188           poll_free_list = pollrec;
1189
1190           n_poll_records--;
1191           break;
1192         }
1193       lastrec = pollrec;
1194       pollrec = pollrec->next;
1195     }
1196
1197 #ifdef G_THREADS_ENABLED
1198   poll_changed = TRUE;
1199   
1200   /* Now wake up the main loop if it is waiting in the poll() */
1201   g_main_wakeup ();
1202 #endif
1203
1204   G_UNLOCK (main_loop);
1205 }
1206
1207 void 
1208 g_main_set_poll_func (GPollFunc func)
1209 {
1210   if (func)
1211     poll_func = func;
1212   else
1213 #ifdef HAVE_POLL
1214     poll_func = (GPollFunc) poll;
1215 #else
1216     poll_func = (GPollFunc) g_poll;
1217 #endif
1218 }
1219
1220 /* Wake the main loop up from a poll() */
1221 static void
1222 g_main_wakeup (void)
1223 {
1224 #ifdef G_THREADS_ENABLED
1225   if (poll_waiting)
1226     {
1227       poll_waiting = FALSE;
1228 #ifndef G_OS_WIN32
1229       write (wake_up_pipe[1], "A", 1);
1230 #else
1231       ReleaseSemaphore (wake_up_semaphore, 1, NULL);
1232 #endif
1233     }
1234 #endif
1235 }
1236
1237 /* Timeouts */
1238
1239 static void
1240 g_timeout_set_expiration (GTimeoutData *data,
1241                           GTimeVal     *current_time)
1242 {
1243   guint seconds = data->interval / 1000;
1244   guint msecs = data->interval - seconds * 1000;
1245
1246   data->expiration.tv_sec = current_time->tv_sec + seconds;
1247   data->expiration.tv_usec = current_time->tv_usec + msecs * 1000;
1248   if (data->expiration.tv_usec >= 1000000)
1249     {
1250       data->expiration.tv_usec -= 1000000;
1251       data->expiration.tv_sec++;
1252     }
1253 }
1254
1255 static gboolean
1256 g_timeout_prepare  (gpointer  source_data,
1257                     GTimeVal *current_time,
1258                     gint     *timeout,
1259                     gpointer  user_data)
1260 {
1261   glong msec;
1262   GTimeoutData *data = source_data;
1263   
1264   msec = ((data->expiration.tv_sec  - current_time->tv_sec) * 1000 +
1265           (data->expiration.tv_usec - current_time->tv_usec) / 1000);
1266   
1267   if (msec < 0)
1268     msec = 0;
1269   else if (msec > data->interval)
1270     {
1271       /* The system time has been set backwards, so we
1272        * reset the expiration time to now + data->interval;
1273        * this at least avoids hanging for long periods of time.
1274        */
1275       g_timeout_set_expiration (data, current_time);
1276       msec = data->interval;
1277     }
1278   
1279   *timeout = msec;
1280   
1281   return msec == 0;
1282 }
1283
1284 static gboolean 
1285 g_timeout_check (gpointer  source_data,
1286                  GTimeVal *current_time,
1287                  gpointer  user_data)
1288 {
1289   GTimeoutData *data = source_data;
1290   
1291   return ((data->expiration.tv_sec < current_time->tv_sec) ||
1292           ((data->expiration.tv_sec == current_time->tv_sec) &&
1293            (data->expiration.tv_usec <= current_time->tv_usec)));
1294 }
1295
1296 static gboolean
1297 g_timeout_dispatch (gpointer source_data,
1298                     GTimeVal *dispatch_time,
1299                     gpointer user_data)
1300 {
1301   GTimeoutData *data = source_data;
1302
1303   if (data->callback (user_data))
1304     {
1305       g_timeout_set_expiration (data, dispatch_time);
1306
1307       return TRUE;
1308     }
1309   else
1310     return FALSE;
1311 }
1312
1313 guint
1314 g_timeout_add_full (gint           priority,
1315                     guint          interval,
1316                     GSourceFunc    function,
1317                     gpointer       data,
1318                     GDestroyNotify notify)
1319 {
1320   GTimeoutData *timeout_data = g_new (GTimeoutData, 1);
1321   GTimeVal current_time;
1322
1323   timeout_data->interval = interval;
1324   timeout_data->callback = function;
1325   g_get_current_time (&current_time);
1326
1327   g_timeout_set_expiration (timeout_data, &current_time);
1328
1329   return g_source_add (priority, FALSE, &timeout_funcs, timeout_data, data, notify);
1330 }
1331
1332 guint 
1333 g_timeout_add (guint32        interval,
1334                GSourceFunc    function,
1335                gpointer       data)
1336 {
1337   return g_timeout_add_full (G_PRIORITY_DEFAULT, 
1338                              interval, function, data, NULL);
1339 }
1340
1341 /* Idle functions */
1342
1343 static gboolean 
1344 g_idle_prepare  (gpointer  source_data, 
1345                  GTimeVal *current_time,
1346                  gint     *timeout,
1347                  gpointer  user_data)
1348 {
1349   timeout = 0;
1350   return TRUE;
1351 }
1352
1353 static gboolean 
1354 g_idle_check    (gpointer  source_data,
1355                  GTimeVal *current_time,
1356                  gpointer  user_data)
1357 {
1358   return TRUE;
1359 }
1360
1361 static gboolean
1362 g_idle_dispatch (gpointer source_data, 
1363                  GTimeVal *dispatch_time,
1364                  gpointer user_data)
1365 {
1366   GSourceFunc func = source_data;
1367
1368   return func (user_data);
1369 }
1370
1371 guint 
1372 g_idle_add_full (gint           priority,
1373                  GSourceFunc    function,
1374                  gpointer       data,
1375                  GDestroyNotify notify)
1376 {
1377   g_return_val_if_fail (function != NULL, 0);
1378
1379   return g_source_add (priority, FALSE, &idle_funcs, function, data, notify);
1380 }
1381
1382 guint 
1383 g_idle_add (GSourceFunc    function,
1384             gpointer       data)
1385 {
1386   return g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, function, data, NULL);
1387 }
1388
1389 gboolean
1390 g_idle_remove_by_data (gpointer data)
1391 {
1392   return g_source_remove_by_funcs_user_data (&idle_funcs, data);
1393 }