timer.c

Go to the documentation of this file.
00001 /*              $Id: $          */
00002 
00003 /*
00004  * Copyright (c) 2007 Mark Heily <devel@heily.com>
00005  *
00006  * Permission to use, copy, modify, and distribute this software for any
00007  * purpose with or without fee is hereby granted, provided that the above
00008  * copyright notice and this permission notice appear in all copies.
00009  *
00010  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
00011  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00012  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
00013  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00014  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00015  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00016  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00017  */
00018 
00024 #include "pnotify.h"
00025 #include "pnotify-internal.h"
00026 #include "queue.h"
00027 #include "thread.h"
00028 
00029 
00030 struct pn_timer {
00031 
00033         int remaining;
00034 
00036         struct pn_watch *watch;
00037 
00039         LIST_ENTRY(pn_timer) entries;
00040 };
00041 
00042 
00044 LIST_HEAD(, pn_timer) TIMER;
00045 
00047 size_t TIMER_INTERVAL = 1;
00048 
00050 pthread_mutex_t TIMER_MUTEX = PTHREAD_MUTEX_INITIALIZER;
00051 
00053 static void
00054 timer_enable()
00055 {
00056         struct itimerval itv;
00057 
00058         itv.it_value.tv_sec = TIMER_INTERVAL;
00059         itv.it_value.tv_usec = 0;
00060         itv.it_interval.tv_sec = TIMER_INTERVAL;
00061         itv.it_interval.tv_usec = 0;
00062 
00063         if (setitimer(ITIMER_REAL, &itv, NULL) != 0) 
00064                 err(1, "setitimer(2)");
00065 }
00066 
00067 
00069 static void
00070 timer_disable()
00071 {
00072         struct itimerval itv;
00073 
00074         memset(&itv, 0, sizeof(itv));
00075 
00076         if (setitimer(ITIMER_REAL, &itv, NULL) != 0) 
00077                 err(1, "setitimer(2)");
00078 }
00079 
00080 
00081 int
00082 pn_add_timer(struct pn_watch *watch)
00083 {
00084         struct pn_timer *timer;
00085 
00086         /* Allocate a new timer struct */
00087         if ((timer = calloc(1, sizeof(*timer))) == NULL) {
00088                 warn("malloc(3)");
00089                 return -1;
00090         }
00091         timer->remaining = watch->ident.interval;
00092         timer->watch = watch;
00093 
00094         pthread_mutex_lock(&TIMER_MUTEX);
00095 
00096         /* Enable the periodic timer if this is the first entry */
00097         if (LIST_EMPTY(&TIMER))
00098                 timer_enable();
00099 
00100         /* Add the timer to the list */
00101         LIST_INSERT_HEAD(&TIMER, timer, entries);
00102 
00103         pthread_mutex_unlock(&TIMER_MUTEX);
00104 
00105         return 0;
00106 }
00107 
00108 
00109 int
00110 pn_rm_timer(struct pn_watch *watch)
00111 {
00112         struct pn_timer *timer, *tmp;
00113 
00114         pthread_mutex_lock(&TIMER_MUTEX);
00115 
00116         /* Disable the periodic timer if there are no more timers */
00117         if (LIST_EMPTY(&TIMER)) 
00118                 timer_disable();
00119 
00120         /* Remove the timer struct */
00121         LIST_FOREACH_SAFE(timer, &TIMER, entries, tmp) {
00122                 if (timer->watch == watch) {
00123                         LIST_REMOVE(timer, entries);
00124                         break;
00125                 }
00126         }
00127 
00128         pthread_mutex_unlock(&TIMER_MUTEX);
00129 
00130         return 0;
00131 }
00132 
00133 
00134 void
00135 pn_timer_init(void)
00136 {
00137         LIST_INIT(&TIMER);
00138 }
00139 
00140 void *
00141 pn_timer_loop(void * unused)
00142 {
00143         struct pnotify_event *evt;
00144         struct pn_timer *timer;
00145         sigset_t signal_set;
00146         int signum;
00147 
00148         /* Avoid a compiler warning */
00149         evt = unused;
00150 
00151         /* Loop forever waiting for an alarm signal */
00152         for (;;) {
00153 
00154                 /* Wait for SIGALRM */
00155                 sigemptyset(&signal_set);
00156                 sigaddset(&signal_set, SIGALRM);
00157                 sigwait(&signal_set, &signum);
00158                 
00159                 /* Reduce the time remaining on all timers */
00160                 pthread_mutex_lock(&TIMER_MUTEX);
00161                 LIST_FOREACH(timer, &TIMER, entries) {
00162 
00163                         /* If the timer has expired, generate an event ... */
00164                         if (TIMER_INTERVAL > timer->remaining) {
00165 
00166                                 /* Create a new event structure */
00167                                 if ((evt = calloc(1, sizeof(*evt))) == NULL)
00168                                         err(1, "calloc(3)");
00169                                 evt->watch = timer->watch;
00170                                 evt->mask = PN_TIMEOUT;
00171 
00172                                 /* Add the event to an event queue */
00173                                 pn_event_add(timer->watch->ctx, evt);
00174 
00175                                 /* Reset the timer to it's initial value */
00176                                 timer->remaining = timer->watch->ident.interval;
00177                         }
00178 
00179                         /* Otherwise, decrease the timer value */
00180                         else {
00181                                 timer->remaining -= TIMER_INTERVAL;
00182                         }
00183                 }
00184                 pthread_mutex_unlock(&TIMER_MUTEX);
00185         }
00186 
00187         return NULL;
00188 }

Generated on Wed Aug 22 23:15:42 2007 for pnotify by  doxygen 1.5.1