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