00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "klone_conf.h"
00012 #include <time.h>
00013 #include <unistd.h>
00014 #include <signal.h>
00015 #include <klone/timer.h>
00016 #include <klone/utils.h>
00017 #include <u/libu.h>
00018
00019 #ifdef OS_WIN
00020 #include <windows.h>
00021 #endif
00022
00023 TAILQ_HEAD(talarm_list_s, talarm_s);
00024 typedef struct talarm_list_s talarm_list_t;
00025
00026 typedef void (*timerm_cb_t)(int);
00027
00028 struct talarm_s
00029 {
00030 TAILQ_ENTRY(talarm_s) np;
00031 timerm_t *timer;
00032 time_t expire;
00033 talarm_cb_t cb;
00034 void *arg;
00035 };
00036
00037 struct timerm_s
00038 {
00039 talarm_list_t alist;
00040
00041 #ifdef OS_WIN
00042 CRITICAL_SECTION cs;
00043 time_t next;
00044 HANDLE hthread;
00045 DWORD tid;
00046 #endif
00047 };
00048
00049
00050 static timerm_t *timer = NULL;
00051
00052 static int timerm_set_alarm(int timeout)
00053 {
00054 #ifdef OS_UNIX
00055
00056 alarm(timeout);
00057 #else
00058 if(timeout > 0)
00059 timer->next = time(0) + timeout;
00060 else
00061 timer->next = NULL;
00062 #endif
00063
00064 return 0;
00065 }
00066
00067 static int timerm_set_next(void)
00068 {
00069 talarm_t *al = NULL;
00070 time_t now = time(0);
00071
00072 if((al = TAILQ_FIRST(&timer->alist)) == NULL)
00073 timerm_set_alarm(0);
00074 else
00075 timerm_set_alarm(MAX(1, al->expire - now));
00076
00077 return 0;
00078 }
00079
00080 void timerm_sigalrm(int sigalrm)
00081 {
00082 talarm_t *al = NULL, *next = NULL;
00083 int expire;
00084
00085 u_unused_args(sigalrm);
00086
00087 dbg_err_if(timer == NULL);
00088
00089 for(;;)
00090 {
00091
00092 al = TAILQ_FIRST(&timer->alist);
00093 nop_err_if(al == NULL);
00094
00095 expire = al->expire;
00096
00097 TAILQ_REMOVE(&timer->alist, al, np);
00098
00099
00100 al->cb(al, al->arg);
00101
00102
00103 next = TAILQ_FIRST(&timer->alist);
00104 if(next && next->expire == expire)
00105 continue;
00106
00107 break;
00108 }
00109
00110
00111 if(TAILQ_FIRST(&timer->alist))
00112 timerm_set_next();
00113
00114 err:
00115 return;
00116 }
00117
00118 static int timerm_block_alarms(void)
00119 {
00120 #ifdef OS_UNIX
00121 dbg_err_if(u_sig_block(SIGALRM));
00122 #endif
00123
00124 #ifdef OS_WIN
00125 EnterCriticalSection(&timer->cs);
00126 #endif
00127
00128 return 0;
00129 err:
00130 return ~0;
00131 }
00132
00133 static int timerm_unblock_alarms(void)
00134 {
00135 #ifdef OS_UNIX
00136 dbg_err_if(u_sig_unblock(SIGALRM));
00137 #endif
00138
00139 #ifdef OS_WIN
00140 LeaveCriticalSection(&timer->cs);
00141 #endif
00142
00143 return 0;
00144 err:
00145 return ~0;
00146 }
00147
00148 static int timerm_free(timerm_t *t)
00149 {
00150 talarm_t *a = NULL;
00151
00152 dbg_return_if (t == NULL, ~0);
00153
00154 if(t)
00155 {
00156 while((a = TAILQ_FIRST(&t->alist)) != NULL)
00157 dbg_if(timerm_del(a));
00158
00159 U_FREE(t);
00160 }
00161
00162 return 0;
00163 }
00164
00165 #ifdef OS_WIN
00166 static DWORD WINAPI thread_func(LPVOID param)
00167 {
00168 for(;;Sleep(250))
00169 {
00170 if(timer->next == NULL)
00171 continue;
00172
00173 if((timer->next - time(0)) <= 0)
00174 timerm_sigalrm(0);
00175 }
00176
00177 return 0;
00178 }
00179 #endif
00180
00181 static int timerm_create(timerm_t **pt)
00182 {
00183 timerm_t *t = NULL;
00184
00185 dbg_return_if (pt == NULL, ~0);
00186
00187 t = u_zalloc(sizeof(timerm_t));
00188 dbg_err_if(t == NULL);
00189
00190 TAILQ_INIT(&t->alist);
00191
00192 #ifdef OS_WIN
00193 InitializeCriticalSection(&t->cs);
00194
00195 dbg_err_if((t->hthread = CreateThread(NULL, 0, thread_func, NULL, 0,
00196 &t->tid)) == NULL);
00197 #endif
00198
00199 *pt = t;
00200
00201 return 0;
00202 err:
00203 if(t)
00204 timerm_free(t);
00205 return ~0;
00206 }
00207
00208 int timerm_add(int secs, talarm_cb_t cb, void *arg, talarm_t **pa)
00209 {
00210 talarm_t *al = NULL;
00211 talarm_t *item = NULL;
00212 time_t now = time(0);
00213
00214 dbg_return_if (cb == NULL, ~0);
00215 dbg_return_if (pa == NULL, ~0);
00216
00217 if(timer == NULL)
00218 {
00219 dbg_err_if(timerm_create(&timer));
00220 #ifdef OS_UNIX
00221 dbg_err_if(u_signal(SIGALRM, timerm_sigalrm));
00222 #endif
00223 }
00224
00225 al = (talarm_t*)u_zalloc(sizeof(talarm_t));
00226 dbg_err_if(al == NULL);
00227
00228 al->timer = timer;
00229 al->cb = cb;
00230 al->arg = arg;
00231 al->expire = now + secs;
00232
00233 dbg_err_if(timerm_block_alarms());
00234
00235
00236 TAILQ_FOREACH(item, &timer->alist, np)
00237 if(al->expire <= item->expire)
00238 break;
00239
00240 if(item)
00241 TAILQ_INSERT_BEFORE(item, al, np);
00242 else
00243 TAILQ_INSERT_TAIL(&timer->alist, al, np);
00244
00245
00246 timerm_set_next();
00247
00248 dbg_err_if(timerm_unblock_alarms());
00249
00250 *pa = al;
00251
00252 return 0;
00253 err:
00254 dbg("[%lu] timerm_add error", getpid());
00255 if(timer)
00256 {
00257 (void) timerm_free(timer);
00258 timer = NULL;
00259 }
00260 U_FREE(al);
00261
00262 dbg_err_if(timerm_unblock_alarms());
00263
00264 return ~0;
00265 }
00266
00267 static int timerm_alarm_pending(talarm_t *a)
00268 {
00269 talarm_t *t;
00270
00271 TAILQ_FOREACH(t, &timer->alist,np)
00272 {
00273 if(t == a)
00274 return 1;
00275 }
00276 return 0;
00277 }
00278
00279 int timerm_del(talarm_t *a)
00280 {
00281 dbg_return_if(a == NULL, ~0);
00282
00283 dbg_err_if(timerm_block_alarms());
00284
00285
00286 if(timerm_alarm_pending(a))
00287 TAILQ_REMOVE(&timer->alist, a, np);
00288
00289
00290 timerm_set_next();
00291
00292 dbg_err_if(timerm_unblock_alarms());
00293
00294 U_FREE(a);
00295
00296 return 0;
00297 err:
00298 dbg_err_if(timerm_unblock_alarms());
00299 return ~0;
00300 }