[BACK]Return to timer.c CVS log [TXT][DIR] Up to [local] / prex-old / sys / kern

Diff for /prex-old/sys/kern/timer.c between version 1.1.1.1 and 1.1.1.1.2.1

version 1.1.1.1, 2008/06/03 10:38:46 version 1.1.1.1.2.1, 2008/08/13 17:12:32
Line 41 
Line 41 
 #include <kmem.h>  #include <kmem.h>
 #include <exception.h>  #include <exception.h>
   
 static volatile u_long lbolt;           /* ticks elapsed since bootup */  static volatile u_long  lbolt;          /* ticks elapsed since bootup */
 static struct event timer_event;        /* event to wakeup timer thread */  
 static struct event delay_event;        /* event for the delay thread */  
 static struct list timer_list;          /* list of active timers */  
 static struct list expire_list;         /* list of expired timers */  
 static void (*tick_hook)(int);          /* hook routine for timer tick */  
   
   static struct event     timer_event;    /* event to wakeup a timer thread */
   static struct event     delay_event;    /* event for the thread delay */
   static struct list      timer_list;     /* list of active timers */
   static struct list      expire_list;    /* list of expired timers */
   
   static void (*volatile tick_hook)(int); /* hook routine for timer tick */
   
 /*  /*
  * Macro to get a timer element for the next timer expiration.   * Macro to get a timer element for the next expiration.
  */   */
 #define timer_next() \  #define timer_next() \
         (list_entry(list_first(&timer_list), struct timer, link))          (list_entry(list_first(&timer_list), struct timer, link))
   
 /*  /*
  * Helper routine to get remaining ticks for the expiration time.   * Get remaining ticks to the expiration time.
  * Return 0 if time already passed.   * Return 0 if time already passed.
  */   */
 static u_long  static u_long
Line 68 
Line 70 
 }  }
   
 /*  /*
  * Add a timer element to the timer list, in the proper place.   * Add a timer element to the timer list in the proper place.
  * Requires interrupts to be disabled by the caller.   * Requires interrupts to be disabled by the caller.
  */   */
 static void  static void
Line 80 
Line 82 
         tmr->expire = lbolt + ticks;          tmr->expire = lbolt + ticks;
   
         /*          /*
          * We sort the timer list by time. So, we can quickly           * We sort the timer list by time. So, we can
          * get the next expiration time from the head element           * quickly get the next expiration time from
          * of the timer list.           * the head element of the timer list.
          */           */
         head = &timer_list;          head = &timer_list;
         for (n = list_first(head); n != head; n = list_next(n)) {          for (n = list_first(head); n != head; n = list_next(n)) {
Line 94 
Line 96 
 }  }
   
 /*  /*
  * Execute a function after a specified length of time.   * Schedule a callout function to run after a specified
  * A device driver can call timer_callout() or timer_stop()   * length of time.  A device driver can call
  * from ISR at interrupt level.   * timer_callout()/timer_stop() from ISR at interrupt level.
  */   */
 void  void
 timer_callout(struct timer *tmr, void (*func)(void *),  timer_callout(struct timer *tmr, u_long msec,
               void *arg, u_long msec)                void (*func)(void *), void *arg)
 {  {
         u_long ticks;          u_long ticks;
   
Line 111 
Line 113 
                 ticks = 1;                  ticks = 1;
   
         irq_lock();          irq_lock();
   
         /*  
          * Stop timer if running  
          */  
         if (tmr->active)          if (tmr->active)
                 list_remove(&tmr->link);                  list_remove(&tmr->link);
         /*  
          * Program timer  
          */  
         tmr->func = func;          tmr->func = func;
         tmr->arg = arg;          tmr->arg = arg;
         tmr->active = 1;          tmr->active = 1;
         tmr->interval = 0;          tmr->interval = 0;
         timer_add(tmr, ticks);          timer_add(tmr, ticks);
   
         irq_unlock();          irq_unlock();
 }  }
   
Line 144 
Line 138 
   
 /*  /*
  * timer_delay - delay thread execution.   * timer_delay - delay thread execution.
    *
  * The caller thread is blocked for the specified time.   * The caller thread is blocked for the specified time.
  * Returns 0 on success, or the remaining time (msec) on failure.   * Returns 0 on success, or the remaining time (msec) on failure.
  * This service is not available at interrupt level.   * This service is not available at interrupt level.
Line 167 
Line 162 
   
 /*  /*
  * timer_sleep - sleep system call.   * timer_sleep - sleep system call.
  * @delay:  delay time in milli-second  
  * @remain: remaining time returned if the sleep is interrupted.  
  *   *
  * Stop execution of current thread for the indicated amount of time.   * Stop execution of the current thread for the indicated amount
  * Returns EINTR if sleep is canceled by some reasons.   * of time.  If the sleep is interrupted, the remaining time
    * is set in "remain".  Returns EINTR if sleep is canceled by
    * some reasons.
  */   */
 int  int
 timer_sleep(u_long delay, u_long *remain)  timer_sleep(u_long msec, u_long *remain)
 {  {
         u_long msec;          u_long left;
         int err = 0;          int err = 0;
   
         msec = timer_delay(delay);          left = timer_delay(msec);
   
         if (remain != NULL)          if (remain != NULL)
                 err = umem_copyout(&msec, remain, sizeof(u_long));                  err = umem_copyout(&left, remain, sizeof(left));
         if (err == 0 && msec > 0)          if (err == 0 && left > 0)
                 err = EINTR;                  err = EINTR;
         return err;          return err;
 }  }
Line 193 
Line 188 
  * Send an alarm exception to the target task.   * Send an alarm exception to the target task.
  */   */
 static void  static void
 alarm_expire(void *task)  alarm_expire(void *arg)
 {  {
   
         exception_post((task_t)task, SIGALRM);          exception_post((task_t)arg, SIGALRM);
 }  }
   
 /*  /*
  * timer_alarm - schedule an alarm exception.   * timer_alarm - alarm system call.
  * @delay:  delay time in milli-second. If delay is 0, stop timer.  
  * @remain: remaining time of the previous alarm request.  
  *   *
  * SIGALRM is sent to the caller task when specified delay time   * SIGALRM exception is sent to the caller task when specified
  * is passed.   * delay time is passed. If passed time is 0, stop the current
    * running timer.
  */   */
 int  int
 timer_alarm(u_long delay, u_long *remain)  timer_alarm(u_long msec, u_long *remain)
 {  {
         struct timer *tmr;          struct timer *tmr;
         u_long msec = 0;          task_t self = cur_task();
           u_long left = 0;
         int err = 0;          int err = 0;
   
         irq_lock();          irq_lock();
         tmr = &cur_task()->alarm;          tmr = &self->alarm;
         if (tmr->active) {          if (tmr->active) {
                 /*                  /*
                  * Save the remaining time before we update                   * Save the remaining time to return
                  * the timer value.                   * before we update the timer value.
                  */                   */
                 msec = tick_to_msec(time_remain(tmr->expire));                  left = tick_to_msec(time_remain(tmr->expire));
         }          }
         if (delay == 0) {          if (msec == 0) {
                 timer_stop(tmr);                  timer_stop(tmr);
         } else {          } else {
                 timer_callout(tmr, alarm_expire, cur_task(), delay);                  timer_callout(tmr, msec, &alarm_expire, self);
         }          }
         irq_unlock();          irq_unlock();
   
         if (remain != NULL)          if (remain != NULL)
                 err = umem_copyout(&msec, remain, sizeof(u_long));                  err = umem_copyout(&left, remain, sizeof(left));
         return err;          return err;
 }  }
   
 /*  /*
  * timer_periodic - set periodic timer for the specified thread.   * timer_periodic - set periodic timer for the specified thread.
  * @th:     thread to set timer.  
  * @start:  first time to wakeup. set 0 to stop timer.  
  * @period: time interval to wakeup. This must be non-zero.  
  *          (The unit of start/period is milli-seconds.)  
  *   *
  * The periodic thread will wait the timer period by calling   * The periodic thread will wait the timer period by calling
  * timer_waitperiod().   * timer_waitperiod(). The unit of start/period is milli-seconds.
  */   */
 int  int
 timer_periodic(thread_t th, u_long start, u_long period)  timer_periodic(thread_t th, u_long start, u_long period)
Line 274 
Line 265 
         } else {          } else {
                 if (tmr == NULL) {                  if (tmr == NULL) {
                         /*                          /*
                          * Allocate a timer element at first call. We                           * Allocate a timer element at first call.
                          * don't put this data in the thread structure                           * We don't put this data in the thread
                          * because only a few threads will use the                           * structure because only a few threads
                          * periodic timer function.                           * will use the periodic timer function.
                          */                           */
                         tmr = kmem_alloc(sizeof(struct timer));                          tmr = kmem_alloc(sizeof(tmr));
                         if (tmr == NULL) {                          if (tmr == NULL) {
                                 sched_unlock();                                  sched_unlock();
                                 return ENOMEM;                                  return ENOMEM;
Line 306 
Line 297 
 /*  /*
  * timer_waitperiod - wait next period of the periodic timer.   * timer_waitperiod - wait next period of the periodic timer.
  *   *
  * Since this routine can exit by any exceptions, the control may   * Since this routine can exit by any exceptions, the control
  * return at non-period time. So, the caller must retry immediately   * may return at non-period time. So, the caller must retry
  * if the error status is EINTR. This will be automatically done   * immediately if the error status is EINTR. This will be
  * by the library stub routine.   * automatically done by the library stub routine.
  */   */
 int  int
 timer_waitperiod(void)  timer_waitperiod(void)
Line 324 
Line 315 
   
         if (time_before(lbolt, tmr->expire)) {          if (time_before(lbolt, tmr->expire)) {
                 /*                  /*
                  * Sleep until timer_tick() routine wakes us up.                   * Sleep until timer_tick() routine
                    * wakes us up.
                  */                   */
                 rc = sched_sleep(&tmr->event);                  rc = sched_sleep(&tmr->event);
                 if (rc != SLP_SUCCESS)                  if (rc != SLP_SUCCESS)
Line 339 
Line 331 
 void  void
 timer_cleanup(thread_t th)  timer_cleanup(thread_t th)
 {  {
   
         if (th->periodic != NULL) {          if (th->periodic != NULL) {
                 timer_stop(th->periodic);                  timer_stop(th->periodic);
                 kmem_free(th->periodic);                  kmem_free(th->periodic);
         }          }
 }  }
   
   /*
    * Install a timer hook routine.
    * We allow only one hook routine in system.
    */
 int  int
 timer_hook(void (*func)(int))  timer_hook(void (*func)(int))
 {  {
Line 360 
Line 357 
 /*  /*
  * Timer thread.   * Timer thread.
  *   *
  * Handle all expired timers. Each callout routine is called   * Handle all expired timers. Each callout routine is
  * with scheduler locked and interrupts enabled.   * called with scheduler locked and interrupts enabled.
  */   */
 static void  static void
 timer_thread(u_long unused)  timer_thread(void *arg)
 {  {
         struct timer *tmr;          struct timer *tmr;
   
         for (;;) {          for (;;) {
   
                 /* Wait until next timer expiration. */                  /* Wait until next timer expiration. */
                 sched_sleep(&timer_event);                  sched_sleep(&timer_event);
   
Line 399 
Line 395 
 /*  /*
  * Timer tick handler   * Timer tick handler
  *   *
  * timer_tick() is called straight from the real time clock interrupt.   * timer_tick() is called straight from the real time
  * All interrupts are still disabled at the entry of this routine.   * clock interrupt.  All interrupts are still disabled
    * at the entry of this routine.
  */   */
 void  void
 timer_tick(void)  timer_tick(void)
Line 409 
Line 406 
         u_long ticks;          u_long ticks;
         int idle, wakeup = 0;          int idle, wakeup = 0;
   
         /* Bump time in ticks. */          /*
            * Bump time in ticks.
            * Note that it is allowed to wrap.
            */
         lbolt++;          lbolt++;
   
         /*          /*
          * Handle all of the timer elements that have expired.           * Handle all of the timer elements that have expired.
          */           */
         while (!list_empty(&timer_list) &&          while (!list_empty(&timer_list)) {
                time_after_eq(lbolt, timer_next()->expire)) {  
                 /*                  /*
                    * Check timer expiration.
                    */
                   tmr = timer_next();
                   if (time_before(lbolt, tmr->expire))
                           break;
                   /*
                  * Remove an expired timer from the list and wakup                   * Remove an expired timer from the list and wakup
                  * the appropriate thread. If it is periodic timer,                   * the appropriate thread. If it is periodic timer,
                  * reprogram the next expiration time. Otherwize,                   * reprogram the next expiration time. Otherwise,
                  * it is moved to the expired list.                   * it is moved to the expired list.
                  */                   */
                 tmr = timer_next();  
                 list_remove(&tmr->link);                  list_remove(&tmr->link);
                 if (tmr->interval != 0) {                  if (tmr->interval != 0) {
                         /*                          /*
Line 448 
Line 452 
         sched_tick();          sched_tick();
   
         /*          /*
          * Call a hook routine for power management or profiling work.           * Call a hook routine for power management
            * or profiling work.
          */           */
         if (tick_hook != NULL) {          if (tick_hook != NULL) {
                 idle = (cur_thread->prio == PRIO_IDLE) ? 1 : 0;                  idle = (cur_thread->prio == PRIO_IDLE) ? 1 : 0;
                 tick_hook(idle);                  (*tick_hook)(idle);
         }          }
 }  }
   
Line 470 
Line 475 
         info->hz = HZ;          info->hz = HZ;
 }  }
   
 #if defined(DEBUG) && defined(CONFIG_KDUMP)  
 void  
 timer_dump(void)  
 {  
         struct timer *tmr;  
         list_t head, n;  
   
         printk("Timer dump:\n");  
         printk("lbolt=%d\n", lbolt);  
   
         head = &timer_list;  
         for (n = list_first(head); n != head; n = list_next(n)) {  
                 tmr = list_entry(n, struct timer, link);  
                 printk("timer=%x func=%x arg=%x expire=%d\n", (int)tmr,  
                        (int)tmr->func, (int)tmr->arg, (int)tmr->expire);  
         }  
 }  
 #endif  
   
 /*  /*
  * Initialize the timer facility, called at system startup time.   * Initialize the timer facility, called at system startup time.
  */   */
 void  void
 timer_init(void)  timer_init(void)
 {  {
           thread_t th;
   
         list_init(&timer_list);          list_init(&timer_list);
         list_init(&expire_list);          list_init(&expire_list);
         event_init(&timer_event, "timer");          event_init(&timer_event, "timer");
         event_init(&delay_event, "delay");          event_init(&delay_event, "delay");
   
         /*          /* Start timer thread */
          * Start timer thread          th = kthread_create(&timer_thread, NULL, PRIO_TIMER);
          */          if (th == NULL)
         if (kernel_thread(PRIO_TIMER, timer_thread, 0) == NULL)  
                 panic("timer_init");                  panic("timer_init");
 }  }

Legend:
Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.1.2.1

CVSweb