Main Page | Modules | Class List | File List | Class Members | File Members | Related Pages

time.c

Go to the documentation of this file.
00001 /* $Id: time.c,v 1.19 2004/05/05 13:50:24 ch12 Exp $ */
00002 /*****************************************************************************/
00011 /* (c) 2003 Technische Universitaet Dresden
00012  * This file is part of DROPS, which is distributed under the terms of the
00013  * GNU General Public License 2. Please see the COPYING file for details.
00014  */
00015 
00030 /* L4 */
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 /* Linux */
00040 #include <linux/timer.h>
00041 #include <linux/sched.h>
00042 #include <linux/list.h>
00043 #include <asm/softirq.h>
00044 
00045 /* local */
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   /* do not notify myself about list update (it's checked later in timer
00077     loop) */
00078   if (l4_thread_equal(timer_l4id, l4_myself()))
00079     return;
00080 #endif
00081 
00082   /* send notification with timeout 0 so don't block here while holding
00083      timerlist_lock */
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    * must be cli-ed when calling this
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   /* do we need to restart the timer thread? */
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    * must be cli-ed when calling this
00142    */
00143 #if DEBUG_TIMER
00144   struct list_head *tmp;
00145 #endif
00146 
00147   if (!timer_pending(timer))
00148     {
00149 #if DEBUG_TIMER
00150 //      LOG("Oops, attempt to detach not pending timer.\n");
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 /* !CONFIG_SMP */
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 /* !CONFIG_SMP */
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   /* release lock */
00280   l4lock_unlock(&timerlist_lock);
00281 
00282   /* sleep */
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   /* reacquire lock */
00300   l4lock_lock(&timerlist_lock);
00301 
00302   /* done */
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   /* we are up */
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   /* acquire lock */
00341   l4lock_lock(&timerlist_lock);
00342 
00343   /* timer loop */
00344   while (1)
00345     {
00346       LOGd(DEBUG_TIMER, "begin of timer_loop");
00347       curr = head->next;
00348       curr_jiffies = jiffies;
00349 
00350       /* no timer set? */
00351       if (curr == head)
00352         {
00353           to = L4_IPC_NEVER;
00354 
00355           /* wait for __restart */
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       /* wait for next timer? */
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           /* wait for timeout or __restart */
00383           __timer_sleep(to);
00384           continue;
00385         }
00386 
00387       /* detach from timer list */
00388       __internal_detach_timer(tp);
00389       LOGd(DEBUG_TIMER, "timer_loop: run timer %p", tp);
00390 
00391       /* release lock */
00392       l4lock_unlock(&timerlist_lock);
00393 
00394       /* run timed function */
00395       tp->function(tp->data);
00396 
00397       /* reaquire lock */
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   /* that should never happen */
00406   Panic("left timer loop!");
00407   l4thread_exit();
00408 }
00409 
00417 int l4dde_time_init()
00418 {
00419   int err;
00420 
00421   /* create timer thread */
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 }

Linux DDE, written by Christian Helmuth  © 2003 Technische Universitaet Dresden