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