00001 #include <l4/dde/ddekit/timer.h>
00002 #include <l4/dde/ddekit/thread.h>
00003 #include <l4/dde/ddekit/printf.h>
00004 #include <l4/dde/ddekit/panic.h>
00005 #include <l4/dde/ddekit/assert.h>
00006 #include <l4/dde/ddekit/memory.h>
00007 #include <l4/dde/ddekit/semaphore.h>
00008
00009 #include <l4/thread/thread.h>
00010 #include <l4/lock/lock.h>
00011 #include <l4/env/errno.h>
00012 #include <l4/generic_io/libio.h>
00013 #include <l4/sys/ipc.h>
00014 #include <l4/util/rdtsc.h>
00015
00016 #define __DEBUG 0
00017
00018
00019
00020
00021
00022
00023
00024
00025 extern volatile unsigned long jiffies;
00026 extern unsigned long HZ;
00027
00028 typedef struct _timer
00029 {
00030 struct _timer *next;
00031 void (*fn)(void *);
00032 void *args;
00033 unsigned long expires;
00034 int id;
00035 } ddekit_timer_t;
00036
00037
00038 static ddekit_timer_t *timer_list = NULL;
00039 static l4lock_t timer_lock = L4LOCK_UNLOCKED;
00040 static l4_threadid_t timer_thread = L4_NIL_ID;
00041 static ddekit_thread_t *timer_thread_ddekit = NULL;
00042 static ddekit_sem_t *notify_semaphore = NULL;
00043
00044 static int timer_id_ctr = 0;
00045
00046 static void dump_list(char *msg)
00047 {
00048 #if __DEBUG
00049 ddekit_timer_t *l = timer_list;
00050
00051 ddekit_printf("-=-=-=-= %s =-=-=-\n", msg);
00052 while (l) {
00053 ddekit_printf("-> %d (%lld)\n", l->id, l->expires);
00054 l = l->next;
00055 }
00056 ddekit_printf("-> NULL\n");
00057 ddekit_printf("-=-=-=-=-=-=-=-\n");
00058 #endif
00059 }
00060
00061
00062
00063
00064
00065 static inline void __notify_timer_thread(void)
00066 {
00067 int err;
00068 l4_msgdope_t result;
00069
00070
00071
00072
00073
00074 if (l4_is_nil_id(timer_thread))
00075 return;
00076
00077 ddekit_sem_up(notify_semaphore);
00078 }
00079
00080
00081 int ddekit_add_timer(void (*fn)(void *), void *args, unsigned long timeout)
00082 {
00083 ddekit_timer_t *it;
00084 ddekit_timer_t *t = ddekit_simple_malloc(sizeof(ddekit_timer_t));
00085
00086 Assert(t);
00087
00088
00089 t->fn = fn;
00090 t->args = args;
00091 t->expires = timeout;
00092 t->next = NULL;
00093
00094 l4lock_lock(&timer_lock);
00095
00096 t->id = timer_id_ctr++;
00097
00098
00099 if (timer_list == NULL || timer_list->expires >= t->expires) {
00100 t->next = timer_list;
00101 timer_list = t;
00102 }
00103 else {
00104 it = timer_list;
00105 while (it->next && it->next->expires < t->expires)
00106 it = it->next;
00107
00108 if (it->next) {
00109 t->next = it->next;
00110 it->next = t;
00111 }
00112 else
00113 it->next = t;
00114 }
00115
00116
00117
00118
00119
00120 if (t == timer_list) {
00121 Assert(!l4_is_nil_id(timer_thread));
00122 __notify_timer_thread();
00123 }
00124
00125 l4lock_unlock(&timer_lock);
00126
00127 dump_list("after add");
00128
00129 return t->id;
00130 }
00131
00132
00133 int ddekit_del_timer(int timer)
00134 {
00135 ddekit_timer_t *it, *it_next;
00136 int ret = -1;
00137
00138 l4lock_lock(&timer_lock);
00139
00140
00141 if (!timer_list) {
00142 ret = -2;
00143 goto out;
00144 }
00145
00146
00147 if (timer_list->id == timer) {
00148 it = timer_list->next;
00149 ret = timer_list->id;
00150 ddekit_simple_free(timer_list);
00151 timer_list = it;
00152
00153
00154
00155
00156
00157
00158 goto out;
00159 }
00160
00161 it = timer_list;
00162 it_next = it->next;
00163
00164
00165
00166
00167 while (it_next) {
00168 if (it_next->id == timer) {
00169 it->next = it->next->next;
00170 ret = it_next->id;
00171 ddekit_simple_free(it_next);
00172 goto out;
00173 }
00174 it = it->next;
00175 it_next = it->next;
00176 }
00177
00178 out:
00179 l4lock_unlock(&timer_lock);
00180
00181 dump_list("after del");
00182
00183 return ret;
00184 }
00185
00186
00187
00188
00189
00190
00191
00192
00193 int ddekit_timer_pending(int timer)
00194 {
00195 ddekit_timer_t *t = NULL;
00196 int r = 0;
00197
00198 l4lock_lock(&timer_lock);
00199
00200 t = timer_list;
00201 while (t) {
00202 if (t->id == timer) {
00203 r = 1;
00204 break;
00205 }
00206 t = t->next;
00207 }
00208
00209 l4lock_unlock(&timer_lock);
00210
00211 return r;
00212 }
00213
00214
00215
00216
00217
00218
00219
00220 static ddekit_timer_t *get_next_timer(void)
00221 {
00222 ddekit_timer_t *t = NULL;
00223
00224
00225 Assert(l4_thread_equal(l4thread_l4_id(l4lock_owner(&timer_lock)),
00226 timer_thread));
00227
00228 if (timer_list &&
00229 (timer_list->expires <= jiffies)) {
00230 t = timer_list;
00231 timer_list = timer_list->next;
00232 }
00233
00234 return t;
00235 }
00236
00237 enum
00238 {
00239 DDEKIT_TIMEOUT_NEVER = 0xFFFFFFFF,
00240 };
00241
00242
00243
00244
00245
00246
00247
00248
00249 static inline int __timer_sleep(unsigned to)
00250 {
00251 l4_umword_t dummy;
00252 l4_msgdope_t res;
00253
00254 int err = 0;
00255
00256 l4lock_unlock(&timer_lock);
00257
00258 if (to == DDEKIT_TIMEOUT_NEVER) {
00259 ddekit_sem_down(notify_semaphore);
00260 }
00261 else {
00262 #if 0
00263 ddekit_printf("Going to sleep for %lu µs (%lu ms)\n", to * 1000, to);
00264 #endif
00265 err = ddekit_sem_down_timed(notify_semaphore, to);
00266 #if 0
00267 ddekit_printf("err: %x\n", err);
00268 #endif
00269 }
00270
00271 l4lock_lock(&timer_lock);
00272
00273 return (err ? 1 : 0);
00274 }
00275
00276
00277 static void ddekit_timer_thread(void *arg)
00278 {
00279 timer_thread_ddekit = ddekit_thread_setup_myself("ddekit_timer");
00280
00281 notify_semaphore = ddekit_sem_init(0);
00282 #if 0
00283 l4thread_set_prio(l4thread_myself(), 0x11);
00284 #endif
00285
00286 l4thread_started(0);
00287
00288 l4lock_lock(&timer_lock);
00289 while (1) {
00290 ddekit_timer_t *timer = NULL;
00291 unsigned long to = DDEKIT_TIMEOUT_NEVER;
00292
00293 if (timer_list) {
00294 #if 0
00295 int jdiff = timer_list->expires - jiffies;
00296 ddekit_printf("\033[31mscheduling new timeout.\033[0m\n");
00297 ddekit_printf("\033[31mjiffies diff = %ld (%d s)\033[0m\n", jdiff, jdiff/HZ);
00298 #endif
00299 to = (timer_list->expires - jiffies) * 1000000 / HZ;
00300 to /= 1000;
00301 }
00302
00303 __timer_sleep(to);
00304
00305 while ((timer = get_next_timer()) != NULL) {
00306 l4lock_unlock(&timer_lock);
00307
00308 timer->fn(timer->args);
00309 ddekit_simple_free(timer);
00310 l4lock_lock(&timer_lock);
00311 }
00312 }
00313 }
00314
00315 ddekit_thread_t *ddekit_get_timer_thread()
00316 {
00317 return timer_thread_ddekit;
00318 }
00319
00320
00321 void ddekit_init_timers(void)
00322 {
00323 l4_tsc_init(L4_TSC_INIT_AUTO);
00324
00325
00326 timer_thread = l4thread_l4_id( l4thread_create_named(ddekit_timer_thread,
00327 "ddekit_timer", 0,
00328 L4THREAD_CREATE_SYNC));
00329 }