00001
00002
00011
00012
00013
00014
00015
00030
00031 #include <l4/sys/types.h>
00032 #include <l4/sys/ipc.h>
00033 #include <l4/thread/thread.h>
00034 #include <l4/lock/lock.h>
00035 #include <l4/util/util.h>
00036
00037 #include <l4/dde_linux/dde.h>
00038
00039
00040 #include <linux/timer.h>
00041 #include <linux/sched.h>
00042 #include <linux/list.h>
00043 #include <asm/softirq.h>
00044
00045
00046 #include "internal.h"
00047 #include "__config.h"
00048
00055 static struct list_head timer_list = LIST_HEAD_INIT(timer_list);
00056
00058 static l4lock_t timerlist_lock = L4LOCK_UNLOCKED;
00059
00061 static l4thread_t timer_tid = L4THREAD_INVALID_ID;
00062
00064 static int _initialized = 0;
00065
00067 static inline void __restart_timer_thread(void)
00068 {
00069 l4_threadid_t timer_l4id;
00070 l4_msgdope_t result;
00071 int err;
00072
00073 timer_l4id = l4thread_l4_id(timer_tid);
00074
00075 #if 0
00076
00077
00078 if (l4_thread_equal(timer_l4id, l4_myself()))
00079 return;
00080 #endif
00081
00082
00083
00084 do
00085 {
00086 err = l4_ipc_send(timer_l4id,
00087 L4_IPC_SHORT_MSG, 0, 0,
00088 L4_IPC_TIMEOUT(0,1,0,0,0,0), &result);
00089
00090 if (err == L4_IPC_SETIMEOUT)
00091 break;
00092
00093 if (err)
00094 LOGdL(DEBUG_ERRORS, "Error: IPC error 0x%02x in __restart()",
00095 L4_IPC_ERROR(result));
00096 }
00097 while (err);
00098 }
00099
00101 static inline void __internal_add_timer(struct timer_list *timer)
00102 {
00103
00104
00105
00106 struct list_head *tmp;
00107
00108 list_for_each(tmp, &timer_list)
00109 {
00110 struct timer_list *tp = list_entry(tmp, struct timer_list, list);
00111
00112 if (tp->expires > timer->expires)
00113 break;
00114 }
00115
00116 list_add_tail(&timer->list, tmp);
00117
00118 #if DEBUG_TIMER
00119 LOG("ADDED timer (current list follows)");
00120 list_for_each(tmp, &timer_list)
00121 {
00122 struct timer_list *tp = list_entry(tmp, struct timer_list, list);
00123 LOG(" [%p] expires %lu, data = %lu", tmp, tp->expires, tp->data);
00124 }
00125 #endif
00126
00127
00128 if (timer->list.prev == &timer_list)
00129 {
00130 LOGd(DEBUG_TIMER, " ... RESTART timer thread");
00131 __restart_timer_thread();
00132 }
00133
00134 LOGd(DEBUG_TIMER, "");
00135 }
00136
00138 static inline int __internal_detach_timer(struct timer_list *timer)
00139 {
00140
00141
00142
00143 #if DEBUG_TIMER
00144 struct list_head *tmp;
00145 #endif
00146
00147 if (!timer_pending(timer))
00148 {
00149 #if DEBUG_TIMER
00150
00151 #endif
00152 return 0;
00153 }
00154 list_del(&timer->list);
00155
00156 #if DEBUG_TIMER
00157 LOG("DETACHED timer (current list follows)");
00158 list_for_each(tmp, &timer_list)
00159 {
00160 struct timer_list *tp = list_entry(tmp, struct timer_list, list);
00161 LOG(" [%p] expires %lu, data = %lu",
00162 tmp, tp->expires, tp->data);
00163 }
00164 LOG("");
00165 #endif
00166 return 1;
00167 }
00168
00174 void add_timer(struct timer_list *timer)
00175 {
00176 l4lock_lock(&timerlist_lock);
00177 if (timer_pending(timer))
00178 goto bug;
00179 __internal_add_timer(timer);
00180 l4lock_unlock(&timerlist_lock);
00181 return;
00182 bug:
00183 l4lock_unlock(&timerlist_lock);
00184 LOG_Error("kernel timer added twice.");
00185 }
00186
00195 int mod_timer(struct timer_list *timer, unsigned long expires)
00196 {
00197 int ret;
00198
00199 l4lock_lock(&timerlist_lock);
00200 timer->expires = expires;
00201 ret = __internal_detach_timer(timer);
00202 __internal_add_timer(timer);
00203 l4lock_unlock(&timerlist_lock);
00204 return ret;
00205 }
00206
00214 int del_timer(struct timer_list *timer)
00215 {
00216 int ret;
00217
00218 l4lock_lock(&timerlist_lock);
00219 ret = __internal_detach_timer(timer);
00220 timer->list.next = timer->list.prev = NULL;
00221 l4lock_unlock(&timerlist_lock);
00222 return ret;
00223 }
00224
00234 #ifdef CONFIG_SMP
00235 int del_timer_sync(struct timer_list *timer)
00236 {
00237 int ret;
00238
00239 l4lock_lock(&timerlist_lock);
00240 ret = __internal_detach_timer(timer);
00241 timer->list.next = timer->list.prev = NULL;
00242 l4lock_unlock(&timerlist_lock);
00243 return ret;
00244 }
00245 #endif
00246
00252 #ifdef CONFIG_SMP
00253 void sync_timers(void)
00254 {
00255 #warning sync_timers() is not implemented
00256 LOG_Error("Not implemented");
00257 }
00258 #endif
00259
00269 static inline int __timer_sleep(l4_timeout_t to)
00270 {
00271 l4_threadid_t me;
00272 l4_threadid_t any;
00273 l4_umword_t dummy;
00274 l4_msgdope_t result;
00275 int err;
00276
00277 me = l4thread_l4_id(timer_tid);
00278
00279
00280 l4lock_unlock(&timerlist_lock);
00281
00282
00283 do
00284 {
00285 err = l4_ipc_wait(&any,
00286 L4_IPC_SHORT_MSG, &dummy, &dummy, to, &result);
00287
00288 if (err == L4_IPC_RETIMEOUT)
00289 break;
00290
00291 if (err)
00292 {
00293 LOG_Error("in IPC (0x%02x)", L4_IPC_ERROR(result));
00294 any = L4_INVALID_ID;
00295 }
00296 }
00297 while (!l4_task_equal(me, any));
00298
00299
00300 l4lock_lock(&timerlist_lock);
00301
00302
00303 return (err ? 1 : 0);
00304 }
00305
00314 static void dde_timer_thread(void)
00315 {
00316 l4_timeout_t to;
00317 int err, to_e, to_m;
00318
00319 struct list_head *head = &timer_list;
00320 struct list_head *curr;
00321 struct timer_list *tp;
00322
00323 unsigned long curr_jiffies;
00324 long diff;
00325 int to_us;
00326
00327 timer_tid = l4thread_myself();
00328 if (l4dde_process_add_worker())
00329 Panic("l4dde_process_add_worker() failed");
00330
00331 ++local_bh_count(smp_processor_id());
00332
00333
00334 if (l4thread_started(NULL))
00335 goto ret;
00336
00337 LOGd(DEBUG_MSG, "dde_timer_thread "l4util_idfmt" running.",
00338 l4util_idstr(l4thread_l4_id(l4thread_myself())));
00339
00340
00341 l4lock_lock(&timerlist_lock);
00342
00343
00344 while (1)
00345 {
00346 LOGd(DEBUG_TIMER, "begin of timer_loop");
00347 curr = head->next;
00348 curr_jiffies = jiffies;
00349
00350
00351 if (curr == head)
00352 {
00353 to = L4_IPC_NEVER;
00354
00355
00356 __timer_sleep(to);
00357 continue;
00358 }
00359
00360 tp = list_entry(curr, struct timer_list, list);
00361 diff = tp->expires - curr_jiffies;
00362
00363 LOGd(DEBUG_TIMER,
00364 "timer_loop: jiffies = %lu, tp->expires = %lu, diff = %ld",
00365 curr_jiffies, tp->expires, diff);
00366
00367
00368 if (diff > 0)
00369 {
00370 to_us = diff * (1000000 / HZ);
00371 if ((err = l4util_micros2l4to(to_us, &to_m, &to_e)))
00372 {
00373 Panic("error on timeout calculation (us = %d)", to_us);
00374 continue;
00375 }
00376 LOGd(DEBUG_TIMER,
00377 "timer_loop: to_us = %d, to_e = %d, to_m = %d",
00378 to_us, to_e, to_m);
00379
00380 to = L4_IPC_TIMEOUT(0, 0, to_m, to_e, 0, 0);
00381
00382
00383 __timer_sleep(to);
00384 continue;
00385 }
00386
00387
00388 __internal_detach_timer(tp);
00389 LOGd(DEBUG_TIMER, "timer_loop: run timer %p", tp);
00390
00391
00392 l4lock_unlock(&timerlist_lock);
00393
00394
00395 tp->function(tp->data);
00396
00397
00398 l4lock_lock(&timerlist_lock);
00399
00400 LOGd(DEBUG_TIMER, "timer_loop: jiffies = %lu, next = %p (head = %p)",
00401 curr_jiffies, head->next, head);
00402 }
00403
00404 ret:
00405
00406 Panic("left timer loop!");
00407 l4thread_exit();
00408 }
00409
00417 int l4dde_time_init()
00418 {
00419 int err;
00420
00421
00422 err = l4thread_create_long(L4THREAD_INVALID_ID,
00423 (l4thread_fn_t)dde_timer_thread,
00424 ".timer",
00425 L4THREAD_INVALID_SP,
00426 L4THREAD_DEFAULT_SIZE,
00427 L4THREAD_DEFAULT_PRIO,
00428 (void *) 0,
00429 L4THREAD_CREATE_SYNC);
00430
00431 if (err < 0)
00432 return err;
00433
00434 ++_initialized;
00435 return 0;
00436 }