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