1 /*
2  * Copyright (C) 2008 2009 2010, Magnus Hjorth
3  *
4  * This file is part of mhWaveEdit.
5  *
6  * mhWaveEdit is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * mhWaveEdit is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with mhWaveEdit; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 
22 #include <config.h>
23 
24 
25 #include <poll.h>
26 #include <gtk/gtk.h>
27 #include "mainloop.h"
28 #include "sound.h"
29 #include "statusbar.h"
30 #include "document.h"
31 #include "mainwindow.h"
32 
33 gboolean idle_work_flag;
34 
35 struct constant_source {
36      constsource_cb cb;
37      gpointer user_data;
38      gboolean enabled;
39      gboolean lowprio;
40 };
41 
42 struct time_source {
43      timesource_cb cb;
44      gpointer user_data;
45      gboolean enabled;
46      GTimeVal call_time;
47 };
48 
49 struct io_source  {
50      GPollFD pfd;
51      iosource_cb cb;
52      gpointer user_data;
53      gboolean enabled;
54 };
55 
56 struct io_group {
57      int nfds;
58      GPollFD *pfds;
59      int *orig_events;
60      int wdtime_ms;
61      gpointer wd;
62      iogroup_cb cb;
63      gpointer user_data;
64      gboolean enabled;
65 };
66 
67 static GList *constsources = NULL, *timesources = NULL, *iosources = NULL;
68 static GList *iogroups = NULL;
69 static GList *dead_iosources = NULL;
70 
in_sources(gpointer src,gpointer * sources,int n_sources)71 static gboolean in_sources(gpointer src, gpointer *sources, int n_sources)
72 {
73      int i;
74      if (sources == NULL) return TRUE;
75      for (i=0; i<n_sources; i++)
76 	  if (src == sources[i]) return TRUE;
77      return FALSE;
78 }
79 
timesource_scan_main(GTimeVal * current_time,gboolean do_dispatch,gpointer * sources,int n_sources)80 static int timesource_scan_main(GTimeVal *current_time, gboolean do_dispatch,
81 				gpointer *sources, int n_sources)
82 {
83      GList *l,*nl;
84      struct time_source *src;
85      GTimeVal tv;
86      int i,j;
87      int timeout = -1;
88      for (l=timesources; l!=NULL; l=nl) {
89 	  nl = l->next;
90 	  src = (struct time_source *)l->data;
91 	  if (!src->enabled || !in_sources(src,sources,n_sources)) continue;
92 	  i = timeval_subtract(&tv, &src->call_time, current_time);
93 	  if (i || (tv.tv_sec==0 && tv.tv_usec==0)) {
94 	       timeout = 0;
95 
96 	       if (do_dispatch) {
97 		    src->enabled = FALSE;
98 		    j = src->cb(src, current_time, src->user_data);
99 		    if (j != 0) {
100 			 if (j > 0)
101 			      memcpy(&src->call_time,current_time,sizeof(GTimeVal));
102 			 else
103 			      j = -j;
104 			 src->call_time.tv_usec += j*1000;
105 			 while (src->call_time.tv_usec >= 1000000) {
106 			      src->call_time.tv_sec += 1;
107 			      src->call_time.tv_usec -= 1000000;
108 			 }
109 			 src->enabled = TRUE;
110 		    }
111 	       }
112 
113 	  } else {
114 	       j = tv.tv_usec / 1000 + tv.tv_sec * 1000;
115 	       if (j <= 0) j=1;
116 
117 	       if (timeout < 0 || j < timeout)
118 		    timeout = j;
119 	  }
120      }
121      return timeout;
122 }
123 
timesource_scan(GTimeVal * current_time,gboolean do_dispatch)124 static int timesource_scan(GTimeVal *current_time, gboolean do_dispatch)
125 {
126      return timesource_scan_main(current_time,do_dispatch,NULL,0);
127 }
128 
129 
iosource_check_main(void)130 static gboolean iosource_check_main(void)
131 {
132      GList *l;
133      struct io_source *src;
134      struct io_group *grp;
135      int i;
136 
137      for (l=iosources; l!=NULL; l=l->next) {
138 	  src = (struct io_source *)l->data;
139 	  if (src->enabled && src->pfd.revents != 0) return TRUE;
140      }
141      for (l=iogroups; l!=NULL; l=l->next) {
142 	  grp = (struct io_group *)l->data;
143 	  if (grp->enabled) {
144 	       for (i=0; i<grp->nfds; i++) {
145 		    if (grp->pfds[i].revents != 0) return TRUE;
146 	       }
147 	  }
148      }
149      return FALSE;
150 }
151 
iosource_dispatch_main(GTimeVal * current_time)152 static gboolean iosource_dispatch_main(GTimeVal *current_time)
153 {
154      GList *l;
155      struct io_source *src;
156      struct io_group *grp;
157      int i,j,k;
158      GTimeVal tv;
159 
160      for (l=iosources; l!=NULL; l=l->next) {
161 	  src = (struct io_source *)l->data;
162 	  if (src->enabled && src->pfd.revents != 0) {
163 	       src->cb(src,src->pfd.fd,src->pfd.revents,src->user_data);
164 	       src->pfd.revents = 0;
165 	  }
166      }
167      for (l=iogroups; l!=NULL; l=l->next) {
168 	  grp = (struct io_group *)l->data;
169 	  if (grp->enabled) {
170 	       j = 0;
171 	       for (i=0; i<grp->nfds; i++) {
172 		    if (j == 0 && grp->pfds[i].revents != 0) {
173 			 j++;
174 			 k = grp->cb(grp,grp->pfds[i].fd,grp->pfds[i].revents,
175 				     grp->user_data);
176 		    }
177 		    if (j != 0 && k == 0)
178 			 grp->pfds[i].events &= ~(grp->pfds[i].revents);
179 	       }
180 	       if (j != 0 && k != 0) {
181 		    mainloop_io_group_enable(grp,(k > 0));
182 	       }
183 	       /* Restart watchdog */
184 	       if (grp->wd != NULL) {
185 		    tv.tv_sec = current_time->tv_sec;
186 		    tv.tv_usec = current_time->tv_usec + grp->wdtime_ms*1000;
187 		    if (tv.tv_usec > 1000000) { tv.tv_sec++; tv.tv_usec-=1000000; }
188 		    mainloop_time_source_restart(grp->wd, &tv);
189 	       }
190 
191 	  }
192      }
193      return TRUE;
194 }
195 
196 
197 
198 
199 
200 #if GLIB_MAJOR_VERSION < 2
201 
timesource_prepare(gpointer source_data,GTimeVal * current_time,gint * timeout,gpointer user_data)202 static gboolean timesource_prepare(gpointer source_data,
203 				   GTimeVal *current_time, gint *timeout,
204 				   gpointer user_data)
205 {
206      int i;
207      i = timesource_scan(current_time,FALSE);
208      if (i < 0)
209 	  return FALSE;
210      else if (i == 0)
211 	  return TRUE;
212      else {
213 	  if (*timeout < 0 || i < *timeout)
214 	       *timeout = i;
215 	  return FALSE;
216      }
217 }
218 
timesource_check(gpointer source_data,GTimeVal * current_time,gpointer user_data)219 static gboolean timesource_check(gpointer source_data, GTimeVal *current_time,
220 				 gpointer user_data)
221 {
222      int i;
223      i = timesource_scan(current_time,FALSE);
224      return (i == 0);
225 }
226 
timesource_dispatch(gpointer source_data,GTimeVal * dispatch_time,gpointer user_data)227 static gboolean timesource_dispatch(gpointer source_data,
228 				    GTimeVal *dispatch_time, gpointer user_data)
229 {
230      timesource_scan(dispatch_time,TRUE);
231      return TRUE;
232 }
233 
234 static GSourceFuncs tsf = {
235      timesource_prepare, timesource_check, timesource_dispatch, NULL
236 };
237 
mainloop_time_source_added(struct time_source * src)238 static void mainloop_time_source_added(struct time_source *src)
239 {
240      static gboolean inited = FALSE;
241      if (!inited) {
242 	  g_source_add(G_PRIORITY_HIGH, FALSE, &tsf, NULL, NULL, NULL);
243 	  inited = TRUE;
244      }
245 }
246 
iosource_prepare(gpointer source_data,GTimeVal * current_time,gint * timeout,gpointer user_data)247 static gboolean iosource_prepare(gpointer source_data,
248 				 GTimeVal *current_time, gint *timeout,
249 				 gpointer user_data)
250 {
251      return FALSE;
252 }
253 
iosource_check(gpointer source_data,GTimeVal * current_time,gpointer user_data)254 static gboolean iosource_check(gpointer source_data, GTimeVal *current_time,
255 			       gpointer user_data)
256 {
257      return iosource_check_main();
258 }
259 
iosource_dispatch(gpointer source_data,GTimeVal * dispatch_time,gpointer user_data)260 static gboolean iosource_dispatch(gpointer source_data,
261 				    GTimeVal *dispatch_time, gpointer user_data)
262 {
263      iosource_dispatch_main(dispatch_time);
264      return TRUE;
265 }
266 
267 static GSourceFuncs isf = {
268      iosource_prepare, iosource_check, iosource_dispatch, NULL
269 };
270 
poll_add_main(GPollFD * pfd)271 static void poll_add_main(GPollFD *pfd)
272 {
273      static gboolean inited = FALSE;
274      if (!inited) {
275 	  g_source_add(G_PRIORITY_HIGH, FALSE, &isf, NULL, NULL, NULL);
276 	  inited = TRUE;
277      }
278      g_main_add_poll(pfd, G_PRIORITY_HIGH);
279 }
280 
poll_remove_main(GPollFD * pfd)281 static void poll_remove_main(GPollFD *pfd)
282 {
283      g_main_remove_poll(pfd);
284 }
285 
286 
287 
288 
289 
290 #else
291 
292 
293 
294 
295 
296 
timesource_prepare(GSource * source,gint * timeout)297 static gboolean timesource_prepare(GSource *source, gint *timeout)
298 {
299      GTimeVal tv;
300      int i;
301      g_source_get_current_time(source, &tv);
302      i = timesource_scan(&tv,FALSE);
303      if (i <= 0)
304 	  return (i == 0);
305      else {
306 	  if (*timeout < 0 || i < *timeout) *timeout = i;
307 	  return FALSE;
308      }
309 }
310 
timesource_check(GSource * source)311 static gboolean timesource_check(GSource *source)
312 {
313      GTimeVal tv;
314      int i;
315      g_source_get_current_time(source, &tv);
316      i = timesource_scan(&tv,FALSE);
317      return (i == 0);
318 }
319 
timesource_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)320 static gboolean timesource_dispatch(GSource *source, GSourceFunc callback,
321 				    gpointer user_data)
322 {
323      GTimeVal tv;
324      g_source_get_current_time(source,&tv);
325      timesource_scan(&tv,TRUE);
326      return TRUE;
327 }
328 
329 static GSourceFuncs tsf2 = {
330      timesource_prepare,
331      timesource_check,
332      timesource_dispatch,
333      NULL
334 };
335 
mainloop_time_source_added(struct time_source * src)336 static void mainloop_time_source_added(struct time_source *src)
337 {
338      static gboolean inited = FALSE;
339      GSource *s;
340      if (!inited) {
341 	  s = g_source_new(&tsf2, sizeof(*s));
342 	  g_source_attach(s,NULL);
343 	  inited = TRUE;
344      }
345 }
346 
347 
iosource_prepare(GSource * source,int * timeout)348 static gboolean iosource_prepare(GSource *source, int *timeout)
349 {
350      return FALSE;
351 }
352 
iosource_check(GSource * source)353 static gboolean iosource_check(GSource *source)
354 {
355      return iosource_check_main();
356 }
357 
358 
iosource_dispatch(GSource * source,GSourceFunc callback,gpointer user_data)359 static gboolean iosource_dispatch(GSource *source, GSourceFunc callback,
360 				  gpointer user_data)
361 {
362      GTimeVal tv;
363      g_source_get_current_time(source, &tv);
364      iosource_dispatch_main(&tv);
365      return TRUE;
366 }
367 
368 static GSource *iosource_handle = NULL;
369 
370 static GSourceFuncs isf2 = { iosource_prepare, iosource_check,
371 			     iosource_dispatch };
372 
poll_add_main(GPollFD * pfd)373 static void poll_add_main(GPollFD *pfd)
374 {
375      if (iosource_handle == NULL) {
376 	  iosource_handle = g_source_new(&isf2, sizeof(GSource));
377 	  g_source_attach(iosource_handle,NULL);
378      }
379      g_source_add_poll(iosource_handle, pfd);
380 }
381 
poll_remove_main(GPollFD * pfd)382 static void poll_remove_main(GPollFD *pfd)
383 {
384      g_source_remove_poll(iosource_handle, pfd);
385 }
386 
387 #endif
388 
389 
390 
391 /* ---------------------------------------- */
392 
393 /* Note: Does not yet support io groups */
sources_poll(gpointer * sources,int n_sources)394 static void sources_poll(gpointer *sources, int n_sources)
395 {
396      int timeout,nfds,i;
397      GTimeVal tv;
398      struct pollfd *pfds;
399      GList *l;
400      struct io_source *src;
401      struct io_source **srcp;
402 
403      /* puts("sources_poll"); */
404 
405      g_get_current_time(&tv);
406      timeout = timesource_scan_main(&tv,TRUE,sources,n_sources);
407      if (timeout == 0) return;
408 
409      pfds = g_malloc(n_sources * sizeof(struct pollfd));
410      srcp = g_malloc(n_sources * sizeof(struct io_source *));
411 
412      nfds = 0;
413      for (l=iosources; l!=NULL; l=l->next) {
414 	  src = (struct io_source *)l->data;
415 	  if (in_sources(src,sources,n_sources)) {
416 	       srcp[nfds] = src;
417 	       memcpy(&pfds[nfds],&src->pfd,sizeof(pfds[0]));
418 	       nfds++;
419 	  }
420      }
421 
422      if (nfds == 0 && timeout < 0) return;
423 
424      /* printf("Calling poll with nfds=%d, timeout=%d (n_sources=%d)\n",
425 	nfds,timeout,n_sources); */
426 
427 
428      i = poll(pfds,nfds,timeout);
429 
430      if (i < 0) {
431 	  perror("poll");
432 	  return;
433      }
434 
435      if (i > 0) {
436 	  for (i=0; i<nfds; i++) {
437 	       src = srcp[i];
438 	       src->pfd.revents = pfds[i].revents;
439 	       if (src->enabled && src->pfd.revents != 0) {
440 		    src->cb(src,src->pfd.fd,src->pfd.revents,src->user_data);
441 		    src->pfd.revents = 0;
442 	       }
443 	  }
444      }
445 
446      g_free(pfds);
447      g_free(srcp);
448 }
449 
mainloop_main(gpointer * sources,int n_sources)450 static void mainloop_main(gpointer *sources, int n_sources)
451 {
452      static guint const_highprio_idle_count=0;
453      struct constant_source *csrc;
454      gint i,j;
455      GList *l,*ln;
456 
457      if (dead_iosources != NULL) {
458 	  for (l=dead_iosources; l!=NULL; l=l->next) {
459 	       g_free(l->data);
460 	  }
461 	  g_list_free(dead_iosources);
462 	  dead_iosources = NULL;
463      }
464 
465      i = -1;
466      for (l=constsources; l!=NULL; l=ln) {
467 	  ln = l->next;
468 	  csrc = (struct constant_source *)l->data;
469 	  if (csrc->enabled && !csrc->lowprio &&
470 	      in_sources(csrc,sources,n_sources)) {
471 	       j = csrc->cb(csrc,csrc->user_data);
472 	       if (j > 0 || sources != NULL) return;
473 	       if (j > i) i = j;
474 	  }
475      }
476      if (i > 0) { const_highprio_idle_count=0; return; }
477      const_highprio_idle_count++;
478 
479      if (sources == NULL && gtk_events_pending()) {
480 	  gtk_main_iteration();
481 	  return;
482      } else if (sources != NULL) {
483 	  sources_poll(sources,n_sources);
484      }
485 
486      if (!idle_work_flag) {
487 	  idle_work_flag = TRUE;
488 	  return;
489      }
490 
491      for (l=constsources; l!=NULL; l=ln) {
492 	  ln = l->next;
493 	  csrc = (struct constant_source *)l->data;
494 	  if (csrc->enabled && csrc->lowprio &&
495 	      in_sources(csrc,sources,n_sources)) {
496 	       j = csrc->cb(csrc,csrc->user_data);
497 	       if (j > 0) return;
498 	       if (j > i) i = j;
499 	  }
500      }
501 
502      if (sources != NULL) return;
503 
504      if (i < 0) {
505 	  gtk_main_iteration();
506      } else if (i >= 0 && const_highprio_idle_count > 10)
507 	  do_yield(TRUE);
508 }
509 
mainloop(void)510 void mainloop(void)
511 {
512      mainloop_main(NULL,0);
513 }
514 
515 /* Note: Does not (yet) support IO groups */
mainloop_recurse_on(gpointer * sources,int n_sources)516 void mainloop_recurse_on(gpointer *sources, int n_sources)
517 {
518      mainloop_main(sources, n_sources);
519 }
520 
521 
mainloop_constant_source_add(constsource_cb cb,gpointer user_data,gboolean low_prio)522 gpointer mainloop_constant_source_add(constsource_cb cb, gpointer user_data,
523 				      gboolean low_prio)
524 {
525      struct constant_source *src;
526      src = g_malloc(sizeof(*src));
527      src->cb = cb;
528      src->user_data = user_data;
529      src->enabled = TRUE;
530      src->lowprio = low_prio;
531      constsources = g_list_prepend(constsources, src);
532 
533      return src;
534 }
535 
mainloop_constant_source_enable(gpointer constsource,gboolean enable)536 void mainloop_constant_source_enable(gpointer constsource, gboolean enable)
537 {
538      struct constant_source *src = (struct constant_source *)constsource;
539      src->enabled = enable;
540 }
541 
mainloop_constant_source_free(gpointer constsource)542 void mainloop_constant_source_free(gpointer constsource)
543 {
544      constsources = g_list_remove(constsources, constsource);
545      g_free(constsource);
546 }
547 
mainloop_time_source_add(GTimeVal * tv,timesource_cb cb,gpointer user_data)548 gpointer mainloop_time_source_add(GTimeVal *tv, timesource_cb cb,
549 				  gpointer user_data)
550 {
551      struct time_source *src;
552 
553      src = g_malloc(sizeof(*src));
554      src->cb = cb;
555      src->user_data = user_data;
556      if (tv != NULL) {
557 	  memcpy(&src->call_time,tv,sizeof(src->call_time));
558 	  src->enabled = TRUE;
559      } else {
560 	  src->enabled = FALSE;
561      }
562 
563      timesources = g_list_append(timesources, src);
564 
565      mainloop_time_source_added(src);
566 
567      return src;
568 }
569 
mainloop_time_source_restart(gpointer timesource,GTimeVal * new_tv)570 void mainloop_time_source_restart(gpointer timesource, GTimeVal *new_tv)
571 {
572      struct time_source *src = (struct time_source *)timesource;
573      memcpy(&(src->call_time),new_tv,sizeof(src->call_time));
574      src->enabled = TRUE;
575 }
576 
mainloop_time_source_free(gpointer timesource)577 void mainloop_time_source_free(gpointer timesource)
578 {
579      timesources = g_list_remove(timesources, timesource);
580      g_free(timesource);
581 }
582 
mainloop_time_source_enabled(gpointer ts)583 gboolean mainloop_time_source_enabled(gpointer ts)
584 {
585      struct time_source *src = (struct time_source *)ts;
586      return src->enabled;
587 }
588 
mainloop_io_source_add(int fd,gushort events,iosource_cb cb,gpointer user_data)589 gpointer mainloop_io_source_add(int fd, gushort events, iosource_cb cb,
590 				gpointer user_data)
591 {
592      struct io_source *src;
593      src = g_malloc(sizeof(*src));
594      src->pfd.fd = fd;
595      src->pfd.events = events;
596      src->pfd.revents = 0;
597      src->cb = cb;
598      src->user_data = user_data;
599      src->enabled = TRUE;
600      iosources = g_list_append(iosources, src);
601 
602      poll_add_main(&(src->pfd));
603 
604      return src;
605 }
606 
mainloop_io_source_enable(gpointer iosource,gboolean enable)607 void mainloop_io_source_enable(gpointer iosource, gboolean enable)
608 {
609      struct io_source *src = (struct io_source *)iosource;
610      if (XOR(src->enabled,enable)) {
611 	  src->enabled = enable;
612 	  if (enable)
613 	       poll_add_main(&(src->pfd));
614 	  else
615 	       poll_remove_main(&(src->pfd));
616      }
617 }
618 
mainloop_io_source_set_events(gpointer iosource,gushort new_events)619 void mainloop_io_source_set_events(gpointer iosource, gushort new_events)
620 {
621      struct io_source *src = (struct io_source *)iosource;
622      src->pfd.events = new_events;
623      if (new_events != 0 && !src->enabled) {
624 	  poll_add_main(&(src->pfd));
625 	  src->enabled = TRUE;
626      }
627 }
628 
mainloop_io_source_free(gpointer iosource)629 void mainloop_io_source_free(gpointer iosource)
630 {
631      mainloop_io_source_enable(iosource,FALSE);
632      iosources = g_list_remove(iosources, iosource);
633      /* We can not free the IO source here, because we might be
634       * removing it from inside a callback called from sources_poll */
635      dead_iosources = g_list_append(dead_iosources, iosource);
636 }
637 
mainloop_io_group_add(int nfds,GPollFD * pfds,int wdtime_ms,iogroup_cb cb,gpointer user_data)638 gpointer mainloop_io_group_add(int nfds, GPollFD *pfds, int wdtime_ms,
639 			       iogroup_cb cb, gpointer user_data)
640 {
641      struct io_group *grp;
642      int i;
643      grp = g_malloc(sizeof(*grp));
644      grp->nfds = nfds;
645      grp->pfds = NULL;
646      grp->orig_events = NULL;
647      if (nfds > 0) {
648 	  grp->pfds = g_malloc(nfds*sizeof(GPollFD));
649 	  memcpy(grp->pfds, pfds, nfds*sizeof(GPollFD));
650 	  grp->orig_events = g_malloc(nfds*sizeof(int));
651      }
652      for (i=0; i<nfds; i++) {
653 	  grp->orig_events[i] = pfds[i].events;
654 	  poll_add_main(&(grp->pfds[i]));
655      }
656      grp->wdtime_ms = wdtime_ms;
657      grp->wd = NULL;
658      grp->cb = cb;
659      grp->user_data = user_data;
660      grp->enabled = FALSE;
661 
662      iogroups = g_list_append(iogroups, grp);
663 
664      mainloop_io_group_enable(grp,TRUE);
665 
666      return grp;
667 }
668 
iogroup_watchdog_cb(gpointer timesource,GTimeVal * current_time,gpointer user_data)669 static gint iogroup_watchdog_cb(gpointer timesource, GTimeVal *current_time,
670 				gpointer user_data)
671 {
672      struct io_group *grp = (struct io_group *)user_data;
673      int i,j;
674      i = grp->cb(grp, -1, 0, grp->user_data);
675      if (i > 0) {
676 	  for (j=0; j<grp->nfds; j++)
677 	       grp->pfds[j].events = grp->orig_events[j];
678      }
679      if (i >= 0)
680 	  return -grp->wdtime_ms;
681      else
682 	  return 0;
683 }
684 
mainloop_io_group_enable(gpointer iogroup,gboolean enable)685 void mainloop_io_group_enable(gpointer iogroup, gboolean enable)
686 {
687      struct io_group *grp = (struct io_group *)iogroup;
688      int i;
689      GTimeVal tv;
690 
691      if (XOR(grp->enabled,enable)) {
692 	  if (enable) {
693 	       if (grp->wdtime_ms > 0)
694 		    grp->wd = mainloop_time_source_add(NULL,iogroup_watchdog_cb,grp);
695 	  } else {
696 	       mainloop_time_source_free(grp->wd);
697 	       grp->wd = NULL;
698 	  }
699      }
700 
701      if (enable && grp->wd != NULL) {
702 	  g_get_current_time(&tv);
703 	  tv.tv_sec += grp->wdtime_ms / 1000;
704 	  tv.tv_usec += 1000*(grp->wdtime_ms%1000);
705 	  if (tv.tv_usec >= 1000000) {
706 	       tv.tv_sec++;
707 	       tv.tv_usec -= 1000000;
708 	  }
709 	  mainloop_time_source_restart(grp->wd,&tv);
710      }
711 
712      for (i=0; i<grp->nfds; i++) {
713 	  grp->pfds[i].events = enable ? grp->orig_events[i] : 0;
714      }
715 
716      grp->enabled = enable;
717 
718 }
719 
mainloop_io_group_free(gpointer iogroup)720 void mainloop_io_group_free(gpointer iogroup)
721 {
722      struct io_group *grp = (struct io_group *)iogroup;
723      int i;
724 
725      iogroups = g_list_remove(iogroups, grp);
726 
727      mainloop_io_group_enable(iogroup,FALSE);
728      for (i=0; i<grp->nfds; i++) {
729 	  poll_remove_main(&(grp->pfds[i]));
730      }
731      g_free(grp->pfds);
732      g_free(grp->orig_events);
733      g_free(grp);
734 }
735 
736 
737 
738 struct defer {
739      gpointer src;
740      defer_once_cb cscb;
741      gpointer user_data;
742 };
743 
defer_once_cb1(gpointer csource,gpointer user_data)744 static int defer_once_cb1(gpointer csource, gpointer user_data)
745 {
746      struct defer *d = (struct defer *)user_data;
747      d->cscb(d->user_data);
748      mainloop_constant_source_free(csource);
749      g_free(d);
750      return -1;
751 }
752 
defer_once_cb2(gpointer tsource,GTimeVal * tm,gpointer user_data)753 static int defer_once_cb2(gpointer tsource, GTimeVal *tm, gpointer user_data)
754 {
755      struct defer *d = (struct defer *)user_data;
756      d->cscb(d->user_data);
757      mainloop_time_source_free(tsource);
758      g_free(d);
759      return 0;
760 }
761 
mainloop_defer_once(defer_once_cb cb,gint reltime,gpointer user_data)762 void mainloop_defer_once(defer_once_cb cb, gint reltime, gpointer user_data)
763 {
764      struct defer *d;
765      GTimeVal t;
766      d = g_malloc(sizeof(*d));
767      if (reltime <= 0)
768 	  d->src = mainloop_constant_source_add(defer_once_cb1, d, TRUE);
769      else {
770 	  g_get_current_time(&t);
771 	  t.tv_usec += reltime*1000;
772 	  while (t.tv_usec >= 1000000) {
773 	       t.tv_usec -= 1000000;
774 	       t.tv_sec += 1;
775 	  }
776 	  d->src = mainloop_time_source_add(&t,defer_once_cb2,d);
777      }
778 
779      d->cscb = cb;
780      d->user_data = user_data;
781 }
782 
783