fixes to #undef HAVE_POLL case
[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 #include "glib.h"
24 #include <sys/time.h>
25 #include <unistd.h>
26 #include "config.h"
27
28 /* Types */
29
30 typedef struct _GIdleData GIdleData;
31 typedef struct _GTimeoutData GTimeoutData;
32 typedef struct _GSource GSource;
33 typedef struct _GPollRec GPollRec;
34
35 typedef enum {
36   G_SOURCE_READY = 1 << G_HOOK_FLAG_USER_SHIFT,
37   G_SOURCE_CAN_RECURSE = 1 << (G_HOOK_FLAG_USER_SHIFT + 1)
38 } GSourceFlags;
39
40 struct _GSource {
41   GHook hook;
42   gint priority;
43   gpointer source_data;
44 };
45
46 struct _GMainLoop {
47   gboolean flag;
48 };
49
50 struct _GIdleData {
51   GSourceFunc callback;
52 };
53
54 struct _GTimeoutData {
55   GTimeVal    expiration;
56   gint        interval;
57   GSourceFunc callback;
58 };
59
60 struct _GPollRec {
61   gint priority;
62   GPollFD *fd;
63   GPollRec *next;
64 };
65
66 /* Forward declarations */
67
68 static void     g_main_poll            (gint      timeout,
69                                         gboolean  use_priority, 
70                                         gint      priority);
71 static gboolean g_timeout_prepare      (gpointer  source_data, 
72                                         GTimeVal *current_time,
73                                         gint     *timeout);
74 static gboolean g_timeout_check        (gpointer  source_data,
75                                         GTimeVal *current_time);
76 static gboolean g_timeout_dispatch     (gpointer  source_data,
77                                         GTimeVal *current_time,
78                                         gpointer  user_data);
79 static gboolean g_idle_prepare         (gpointer  source_data, 
80                                         GTimeVal *current_time,
81                                         gint     *timeout);
82 static gboolean g_idle_check           (gpointer  source_data,
83                                         GTimeVal *current_time);
84 static gboolean g_idle_dispatch        (gpointer  source_data,
85                                         GTimeVal *current_time,
86                                         gpointer  user_data);
87
88 /* Data */
89
90 static GSList *pending_dispatches = NULL;
91 static GHookList source_list = { 0 };
92
93 static GSourceFuncs timeout_funcs = {
94   g_timeout_prepare,
95   g_timeout_check,
96   g_timeout_dispatch,
97   (GDestroyNotify)g_free
98 };
99
100 static GSourceFuncs idle_funcs = {
101   g_idle_prepare,
102   g_idle_check,
103   g_idle_dispatch,
104   (GDestroyNotify)g_free
105 };
106
107 #ifdef HAVE_POLL
108 static GPollFunc poll_func = (GPollFunc)poll;
109 #else
110
111 /* The following implementation of poll() comes from the GNU C Library.
112  * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
113  */
114
115 #include <string.h> /* for bzero on BSD systems */
116
117 #ifdef HAVE_SYS_SELECT_H
118 #include <sys/select.h>
119 #endif /* HAVE_SYS_SELECT_H_ */
120
121 #ifndef NO_FD_SET
122 #  define SELECT_MASK fd_set
123 #else
124 #  ifndef _AIX
125 typedef long fd_mask;
126 #  endif
127 #  if defined(_IBMR2)
128 #    define SELECT_MASK void
129 #  else
130 #    define SELECT_MASK int
131 #  endif
132 #endif
133
134 static gint 
135 g_poll (GPollFD *fds, guint nfds, gint timeout)
136 {
137   struct timeval tv;
138   SELECT_MASK rset, wset, xset;
139   GPollFD *f;
140   int ready;
141   int maxfd = 0;
142
143   FD_ZERO (&rset);
144   FD_ZERO (&wset);
145   FD_ZERO (&xset);
146
147   for (f = fds; f < &fds[nfds]; ++f)
148     if (f->fd >= 0)
149       {
150         if (f->events & G_IO_IN)
151           FD_SET (f->fd, &rset);
152         if (f->events & G_IO_OUT)
153           FD_SET (f->fd, &wset);
154         if (f->events & G_IO_PRI)
155           FD_SET (f->fd, &xset);
156         if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
157           maxfd = f->fd;
158       }
159
160   tv.tv_sec = timeout / 1000;
161   tv.tv_usec = (timeout % 1000) * 1000;
162
163   ready = select (maxfd + 1, &rset, &wset, &xset,
164                   timeout == -1 ? NULL : &tv);
165   if (ready > 0)
166     for (f = fds; f < &fds[nfds]; ++f)
167       {
168         f->revents = 0;
169         if (f->fd >= 0)
170           {
171             if (FD_ISSET (f->fd, &rset))
172               f->revents |= G_IO_IN;
173             if (FD_ISSET (f->fd, &wset))
174               f->revents |= G_IO_OUT;
175             if (FD_ISSET (f->fd, &xset))
176               f->revents |= G_IO_PRI;
177           }
178       }
179
180   return ready;
181 }
182
183 static GPollFunc poll_func = g_poll;
184 #endif
185
186 /* Hooks for adding to the main loop */
187
188 /* Use knowledge of insert_sorted algorithm here to make
189  * sure we insert at the end of equal priority items
190  */
191 static gint
192 g_source_compare (GHook *a, GHook *b)
193 {
194   GSource *source_a = (GSource *)a;
195   GSource *source_b = (GSource *)b;
196
197   return (source_a->priority < source_b->priority) ? -1 : 1;
198 }
199
200 guint 
201 g_source_add (gint           priority,
202               gboolean       can_recurse,
203               GSourceFuncs  *funcs,
204               gpointer       source_data, 
205               gpointer       user_data,
206               GDestroyNotify notify)
207 {
208   GSource *source;
209
210   if (!source_list.is_setup)
211     g_hook_list_init (&source_list, sizeof(GSource));
212
213   source = (GSource *)g_hook_alloc (&source_list);
214   source->priority = priority;
215   source->source_data = source_data;
216   source->hook.func = funcs;
217   source->hook.data = user_data;
218   source->hook.destroy = notify;
219   
220   g_hook_insert_sorted (&source_list, 
221                         (GHook *)source, 
222                         g_source_compare);
223
224   if (can_recurse)
225     source->hook.flags |= G_SOURCE_CAN_RECURSE;
226
227   return source->hook.hook_id;
228 }
229
230 void 
231 g_source_remove (guint tag)
232 {
233   GHook *hook = g_hook_get (&source_list, tag);
234   if (hook)
235     {
236       GSource *source = (GSource *)hook;
237       ((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
238       g_hook_destroy_link (&source_list, hook);
239     }
240 }
241
242 void 
243 g_source_remove_by_user_data (gpointer user_data)
244 {
245   GHook *hook = g_hook_find_data (&source_list, TRUE, user_data);
246   if (hook)
247     {
248       GSource *source = (GSource *)hook;
249       ((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
250       g_hook_destroy_link (&source_list, hook);
251     }
252 }
253
254 static gboolean
255 g_source_find_source_data (GHook        *hook,
256                            gpointer      data)
257 {
258   GSource *source = (GSource *)hook;
259   return (source->source_data == data);
260 }
261
262 void 
263 g_source_remove_by_source_data (gpointer source_data)
264 {
265   GHook *hook = g_hook_find (&source_list, TRUE, 
266                              g_source_find_source_data, source_data);
267   if (hook)
268     {
269       GSource *source = (GSource *)hook;
270       ((GSourceFuncs *)source->hook.func)->destroy (source->source_data);
271       g_hook_destroy_link (&source_list, hook);
272     }
273 }
274
275 void g_get_current_time (GTimeVal *result)
276 {
277   gettimeofday ((struct timeval *)result, NULL);
278 }
279
280 /* Running the main loop */
281
282 static void
283 g_main_dispatch (GTimeVal *current_time)
284 {
285   while (pending_dispatches != NULL)
286     {
287       gboolean need_destroy;
288       GSource *source = pending_dispatches->data;
289       GSList *tmp_list;
290
291       tmp_list = pending_dispatches;
292       pending_dispatches = g_slist_remove_link (pending_dispatches, pending_dispatches);
293       g_slist_free_1 (tmp_list);
294
295       if (G_HOOK_IS_VALID (source))
296         {
297           source->hook.flags |= G_HOOK_FLAG_IN_CALL;
298           need_destroy = !((GSourceFuncs *)source->hook.func)->dispatch (source->source_data, 
299                                                    current_time,
300                                                    source->hook.data);
301           source->hook.flags &= ~G_HOOK_FLAG_IN_CALL;
302           
303           if (need_destroy)
304             g_hook_destroy_link (&source_list, (GHook *)source);
305         }
306
307       g_hook_unref (&source_list, (GHook *)source);
308     }
309 }
310
311 /* Run a single iteration of the mainloop, or, if !dispatch
312  * check to see if any events need dispatching, but don't
313  * run the loop.
314  */
315 static gboolean
316 g_main_iterate (gboolean block, gboolean dispatch)
317 {
318   GHook *hook;
319   GTimeVal current_time;
320   gint nready = 0;
321   gint current_priority = 0;
322   gint timeout;
323
324   g_return_val_if_fail (!block || dispatch, FALSE);
325
326   g_get_current_time (&current_time);
327   
328   /* If recursing, finish up current dispatch, before starting over */
329   if (pending_dispatches)
330     {
331       if (dispatch)
332         g_main_dispatch (&current_time);
333       
334       return TRUE;
335     }
336
337   /* Prepare all sources */
338
339   timeout = block ? -1 : 0;
340   
341   hook = g_hook_first_valid (&source_list, TRUE);
342   while (hook)
343     {
344       GSource *source = (GSource *)hook;
345       GHook *tmp;
346       gint source_timeout;
347
348       if ((nready > 0) && (source->priority > current_priority))
349         break;
350       if (!(hook->flags & G_SOURCE_CAN_RECURSE) && G_HOOK_IN_CALL (hook))
351         {
352           hook = g_hook_next_valid (hook, TRUE);
353           continue;
354         }
355
356       g_hook_ref (&source_list, hook);
357
358       if (((GSourceFuncs *)hook->func)->prepare (source->source_data,
359                                                  &current_time,
360                                                  &source_timeout))
361         {
362           if (!dispatch)
363             {
364               g_hook_unref (&source_list, hook);
365               return TRUE;
366             }
367           else
368             {
369               hook->flags |= G_SOURCE_READY;
370               nready++;
371               current_priority = source->priority;
372               timeout = 0;
373             }
374         }
375       
376       if (source_timeout >= 0)
377         {
378           if (timeout < 0)
379             timeout = source_timeout;
380           else
381             timeout = MIN (timeout, source_timeout);
382         }
383
384       tmp = g_hook_next_valid (hook, TRUE);
385       
386       g_hook_unref (&source_list, hook);
387       hook = tmp;
388     }
389
390   /* poll(), if necessary */
391
392   g_main_poll (timeout, nready > 0, current_priority);
393
394   /* Check to see what sources need to be dispatched */
395
396   nready = 0;
397   
398   hook = g_hook_first_valid (&source_list, TRUE);
399   while (hook)
400     {
401       GSource *source = (GSource *)hook;
402       GHook *tmp;
403
404       if ((nready > 0) && (source->priority > current_priority))
405         break;
406       if (!(hook->flags & G_SOURCE_CAN_RECURSE) && G_HOOK_IN_CALL (hook))
407         {
408           hook = g_hook_next_valid (hook, TRUE);
409           continue;
410         }
411
412       g_hook_ref (&source_list, hook);
413
414       if ((hook->flags & G_SOURCE_READY) ||
415           ((GSourceFuncs *)hook->func)->check (source->source_data,
416                                                &current_time))
417         {
418           if (dispatch)
419             {
420               hook->flags &= ~G_SOURCE_READY;
421               g_hook_ref (&source_list, hook);
422               pending_dispatches = g_slist_prepend (pending_dispatches, source);
423               current_priority = source->priority;
424               nready++;
425             }
426           else
427             {
428               g_hook_unref (&source_list, hook);
429               return TRUE;
430             }
431         }
432       
433       tmp = g_hook_next_valid (hook, TRUE);
434       
435       g_hook_unref (&source_list, hook);
436       hook = tmp;
437     }
438
439   /* Now invoke the callbacks */
440
441   if (pending_dispatches)
442     {
443       pending_dispatches = g_slist_reverse (pending_dispatches);
444       g_main_dispatch (&current_time);
445       return TRUE;
446     }
447   else
448     return FALSE;
449 }
450
451 /* See if any events are pending
452  */
453 gboolean 
454 g_main_pending ()
455 {
456   return g_main_iterate (FALSE, FALSE);
457 }
458
459 /* Run a single iteration of the mainloop. If block is FALSE,
460  * will never block
461  */
462 gboolean
463 g_main_iteration (gboolean block)
464 {
465   return g_main_iterate (block, TRUE);
466 }
467
468 GMainLoop *
469 g_main_new ()
470 {
471   GMainLoop *result = g_new (GMainLoop, 1);
472   result->flag = FALSE;
473
474   return result;
475 }
476
477 void 
478 g_main_run (GMainLoop *loop)
479 {
480   loop->flag = FALSE;
481   while (!loop->flag)
482     g_main_iterate (TRUE, TRUE);
483 }
484
485 void 
486 g_main_quit (GMainLoop *loop)
487 {
488   loop->flag = TRUE;
489 }
490
491 void 
492 g_main_destroy (GMainLoop *loop)
493 {
494   g_free (loop);
495 }
496
497 static GPollRec *poll_records = NULL;
498 static GPollRec *poll_free_list = NULL;
499 static GMemChunk *poll_chunk;
500 static guint n_poll_records = 0;
501
502 static void
503 g_main_poll (gint timeout, gboolean use_priority, gint priority)
504 {
505   GPollFD *fd_array = g_new (GPollFD, n_poll_records);
506   GPollRec *pollrec;
507
508   gint i;
509   gint npoll;
510
511   pollrec = poll_records;
512   i = 0;
513   while (pollrec && (!use_priority || priority >= pollrec->priority))
514     {
515       fd_array[i].fd = pollrec->fd->fd;
516       fd_array[i].events = pollrec->fd->events;
517       fd_array[i].revents = 0;
518         
519       pollrec = pollrec->next;
520       i++;
521     }
522
523   npoll = i;
524   (*poll_func) (fd_array, npoll, timeout);
525
526   pollrec = poll_records;
527   i = 0;
528   while (i < npoll)
529     {
530       pollrec->fd->revents = fd_array[i].revents;
531       pollrec = pollrec->next;
532       i++;
533     }
534
535   g_free (fd_array);
536 }
537
538 void 
539 g_main_poll_add (gint     priority,
540                  GPollFD *fd)
541 {
542   GPollRec *lastrec, *pollrec, *newrec;
543
544   if (!poll_chunk)
545     poll_chunk = g_mem_chunk_create (GPollRec, 32, G_ALLOC_ONLY);
546
547   newrec = g_chunk_new (GPollRec, poll_chunk);
548   newrec->fd = fd;
549   newrec->priority = priority;
550
551   lastrec = NULL;
552   pollrec = poll_records;
553   while (pollrec && priority >= pollrec->priority)
554     {
555       lastrec = pollrec;
556       pollrec = pollrec->next;
557     }
558   
559   if (lastrec)
560     lastrec->next = newrec;
561   else
562     poll_records = newrec;
563
564   newrec->next = pollrec;
565
566   n_poll_records++;
567 }
568
569 void 
570 g_main_poll_remove (GPollFD *fd)
571 {
572   GPollRec *pollrec, *lastrec;
573
574   lastrec = NULL;
575   pollrec = poll_records;
576
577   while (pollrec)
578     {
579       if (pollrec->fd == fd)
580         {
581           if (lastrec != NULL)
582             lastrec->next = pollrec->next;
583           else
584             poll_records = pollrec->next;
585
586           pollrec->next = poll_free_list;
587           poll_free_list = pollrec;
588         }
589       lastrec = pollrec;
590       pollrec = pollrec->next;
591     }
592
593   n_poll_records--;
594 }
595
596 void 
597 g_main_set_poll_func (GPollFunc func)
598 {
599   if (func)
600     poll_func = func;
601   else
602 #ifdef HAVE_POLL
603     poll_func = (GPollFunc)poll;
604 #else
605     poll_func = (GPollFunc)g_poll;
606 #endif
607 }
608
609 /* Timeouts */
610
611 static gboolean 
612 g_timeout_prepare  (gpointer source_data, 
613                     GTimeVal *current_time,
614                     gint    *timeout)
615 {
616   glong msec;
617   GTimeoutData *data = source_data;
618
619   msec = (data->expiration.tv_sec  - current_time->tv_sec) * 1000 +
620          (data->expiration.tv_usec - current_time->tv_usec) / 1000;
621
622   *timeout = (msec <= 0) ? 0 : msec;
623
624   return (msec <= 0);
625 }
626
627 static gboolean 
628 g_timeout_check    (gpointer source_data,
629                     GTimeVal *current_time)
630 {
631   GTimeoutData *data = source_data;
632
633   return (data->expiration.tv_sec < current_time->tv_sec) ||
634          ((data->expiration.tv_sec == current_time->tv_sec) &&
635           (data->expiration.tv_usec <= current_time->tv_usec));
636 }
637
638 static gboolean
639 g_timeout_dispatch (gpointer source_data, 
640                     GTimeVal *current_time,
641                     gpointer user_data)
642 {
643   GTimeoutData *data = source_data;
644
645   if (data->callback(user_data))
646     {
647       data->expiration.tv_sec = current_time->tv_sec;
648       data->expiration.tv_usec = current_time->tv_usec + data->interval * 1000;
649       if (data->expiration.tv_usec >= 1000000)
650         {
651           data->expiration.tv_usec -= 1000000;
652           data->expiration.tv_sec++;
653         }
654       return TRUE;
655     }
656   else
657     return FALSE;
658 }
659
660 guint 
661 g_timeout_add_full (gint           priority,
662                     guint          interval, 
663                     GSourceFunc    function,
664                     gpointer       data,
665                     GDestroyNotify notify)
666 {
667   GTimeoutData *timeout_data = g_new (GTimeoutData, 1);
668
669   timeout_data->interval = interval;
670   timeout_data->callback = function;
671   g_get_current_time (&timeout_data->expiration);
672
673   timeout_data->expiration.tv_usec += timeout_data->interval * 1000;
674   if (timeout_data->expiration.tv_usec >= 1000000)
675     {
676       timeout_data->expiration.tv_usec -= 1000000;
677       timeout_data->expiration.tv_sec++;
678     }
679
680   return g_source_add (priority, FALSE, &timeout_funcs, timeout_data, data, notify);
681 }
682
683 guint 
684 g_timeout_add (guint32        interval,
685                GSourceFunc    function,
686                gpointer       data)
687 {
688   return g_timeout_add_full (0, interval, function, data, NULL);
689 }
690
691 /* Idle functions */
692
693 static gboolean 
694 g_idle_prepare  (gpointer source_data, 
695                  GTimeVal *current_time,
696                  gint     *timeout)
697 {
698   timeout = 0;
699   return TRUE;
700 }
701
702 static gboolean 
703 g_idle_check    (gpointer  source_data,
704                  GTimeVal *current_time)
705 {
706   return TRUE;
707 }
708
709 static gboolean
710 g_idle_dispatch (gpointer source_data, 
711                  GTimeVal *current_time,
712                  gpointer user_data)
713 {
714   GIdleData *data = source_data;
715
716   return (*data->callback)(user_data);
717 }
718
719 guint 
720 g_idle_add_full (gint          priority,
721                  GSourceFunc    function,
722                  gpointer       data,
723                  GDestroyNotify notify)
724 {
725   GIdleData *idle_data = g_new (GIdleData, 1);
726
727   idle_data->callback = function;
728
729   return g_source_add (priority, FALSE, &idle_funcs, idle_data, data, notify);
730 }
731
732 guint 
733 g_idle_add (GSourceFunc    function,
734             gpointer       data)
735 {
736   return g_idle_add_full (0, function, data, NULL);
737 }