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