$B>pJs3XN`(B $B%*%Z%l!<%F%#%s%0%7%9%F%`#I#I(B 2007$BG/(B01$B7n(B23$BF|(B
$BC^GHBg3X%7%9%F%`>pJs9)3X8&5f2J(B
$B%3%s%T%e!<%?%5%$%(%s%9@l96(B, $BEE;R!&>pJs9)3X7O(B
$B?7>k(B $BLw(B
<yas@is.tsukuba.ac.jp>
$B$3$N%Z!<%8$O!"
http://www.coins.tsukuba.ac.jp/~yas/coins/os2-2006/2007-01-23
$B$"$k$$$O!"
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
$B9b669@OB(B, $B>.ED0oO:(B, $B;3H(0Y:45W(B: "Linux$B%+!<%M%k(B2.6$B2rFI<<(B",$B%U%H%P%s%/%/%j%(%$%F%#%V(B (2006/11/18). ISBN-13: 978-4797338263.
Marshall Kirk McKusick, George V. Neville$B!>(BNeil ($BCx(B), $B2NBe(B $BOB@5(B, $B:=86(B $B=( $B?^(B? $B%*%Z%l!<%F%#%s%0!&%7%9%F%`$NF/$-(B$B"#%*%Z%l!<%F%#%s%0!&%7%9%F%`(B
$B#2$D$N%$%s%?%U%'!<%9$r!"$&$^$/$D$J$0$b$N!#(B
$B%i%$%V%i%j$H%7%9%F%`!&%3!<%k$N0c$$$KCm0U(B
$B"#;~9o$H;~4V(B
$B"!I,MW$J5!G=(B
$B"!%+%l%s%@;~9o$NDs6!(B
struct timeval {
long tv_sec; /* seconds since Jan. 1, 1970 */
long tv_usec; /* and microseconds */
};
int gettimeofday(struct timeval *tp, struct timezone *tzp)
struct timeval tv;
gettimeofday(&tv, NULL);
$B&L(B($B%^%$%/%m(B)$BICC10L$N;~9o$rJV$9!#(BPOSIX 1003.1, 2003 $B$G$O!"%J%NICC10L!#(B
struct timespec {
time_t tv_sec; /* Seconds. */
long int tv_nsec; /* Nanoseconds. */
};
int clock_settime(clockid_t clock_id, const struct timespec *tp);
int clock_gettime(clockid_t clock_id, struct timespec *tp);
int clock_getres(clockid_t clock_id, struct timespec *res);
$B"!%$%s%?!<%P%k%?%$%^(B
$BDj4|E*$J;E;v$r$7$?$$;~$K;H$&(B
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
$BF1$8OC!#(B
$B"!;~4V@Z$l(B
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
struct timeval *timeout);
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
$B%M%C%H%o!<%/!&%W%m%0%i%`$G$h$/;H$&!#J#?t$NF~NO$r4F;k$9$k!#;XDj$5$l$?;~(B
$B4V!"F~NO$,$J$1$l$P!"%7%9%F%`!&%3!<%k$+$iI|5"$9$k!#(B
$B$J$K$b$7$J$$;~4V@Z$l!#(B
unsigned int sleep(unsigned int seconds); int usleep(useconds_t usec) int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
$B?^(B? $B%7%9%F%`%3!<%k$H%"%C%W%3!<%k(B
$B%"%C%W%3!<%k$O!"%7%9%F%`!&%3!<%k$N5U$K!"%*%Z%l!<%F%#%s%0!&%7%9%F%`$,%f!<(B $B%6!&%l%Y%k$N4X?t$r8F$S=P$9!#(B $B%&%$%s%I%&!&%7%9%F%`$N%W%m%0%i%`$G$O!"(Bcall-back $B4X?t$d(Blistener $B$H$7$FMx(B $BMQ$5$l$F$$$k!#(B$B?^(B? $B%?%$%^4XO"$N%O!<%I%&%'%"$N4pK\%b%G%k(B
2$B$D$N5!G=$,$"$k!#(B
$B$=$NB>$N3d9~$_(B
/* kernel/imer.c */
u64 jiffies_64;
void do_timer(unsigned long ticks)
{
jiffies_64 += ticks;
update_times(ticks);
}
/* include/asm-i386/mach-default/do_timer.h */
static inline void do_timer_interrupt_hook(void)
{
do_timer(1);
...
}
/* arch/i386/kernel/time.c */
irqreturn_t timer_interrupt(int irq, void *dev_id)
{
do_timer_interrupt_hook();
}
/* arch/i386/mach-default/setup.c */
static struct irqaction irq0 = { timer_interrupt, IRQF_DISABLED,
CPU_MASK_NONE, "timer", NULL, NULL};
void __init time_init_hook(void)
{
setup_irq(0, &irq0);
}
$B?^(B? callout $BBT$A9TNs(B(1)
f(x) $B$r$B?^(B? callout $BBT$A9TNs(B(2)
g(y), h(z) $B$r$B?^(B? callout $BBT$A9TNs(B(3)
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct tvec_t_base_s *base;
};
jiffies $B$,A}2C$7$F(B expires ($B@dBP;~9o(B)$B$KC#$9$l$P!"(B(*function)(data) $B$r8F$V!#(B
$B
timer->expires = jiffies + delay;
timer->data = (unsigned long)data;
timer->function = func;
add_timer(timer);
$B?^(B? Linux tv
/* timer.c: */
static void run_timer_softirq(struct softirq_action *h)
{
tvec_base_t *base = __get_cpu_var(tvec_bases);
hrtimer_run_queues();
if (time_after_eq(jiffies, base->timer_jiffies))
__run_timers(base);
}
static inline void __run_timers(tvec_base_t *base)
{
struct timer_list *timer;
...
while (time_after_eq(jiffies, base->timer_jiffies)) {
struct list_head work_list;
struct list_head *head = &work_list;
int index = base->timer_jiffies & TVR_MASK;
...
++base->timer_jiffies;
list_replace_init(base->tv1.vec + index, &work_list);
while (!list_empty(head)) {
void (*fn)(unsigned long);
unsigned long data;
..
timer = list_entry(head->next,struct timer_list,entry);
fn = timer->function;
data = timer->data;
...
fn(data);
}
}
}
/* itimer.c */
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
{
struct task_struct *tsk = current;
struct hrtimer *timer;
...
switch (which) {
case ITIMER_REAL:
...
timer = &tsk->signal->real_timer;
...
tsk->signal->it_real_incr =
timeval_to_ktime(value->it_interval);
expires = timeval_to_ktime(value->it_value);
if (expires.tv64 != 0)
hrtimer_start(timer, expires, HRTIMER_REL);
...
}
}
int
hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
...
base = lock_hrtimer_base(timer, &flags);
new_base = switch_hrtimer_base(timer, base);
timer->expires = tim;
enqueue_hrtimer(timer, new_base);
}
hrtimer $B$N4IM}$K$O!"LZ9=B$$,;H$o$l$F$$$k!#(BO(log n)$B!#(B
/* scheduler_tick() */
#define MIN_TIMESLICE max(5 * HZ / 1000, 1)
#define DEF_TIMESLICE (100 * HZ / 1000)
...
void scheduler_tick(void)
{
unsigned long long now = sched_clock();
struct task_struct *p = current;
int cpu = smp_processor_id();
struct rq *rq = cpu_rq(cpu);
update_cpu_clock(p, rq, now);
rq->timestamp_last_tick = now;
...
if (!--p->time_slice) {
dequeue_task(p, rq->active);
set_tsk_need_resched(p);
p->prio = effective_prio(p);
p->time_slice = task_timeslice(p);
p->first_time_slice = 0;
if (!rq->expired_timestamp)
rq->expired_timestamp = jiffies;
if (!TASK_INTERACTIVE(p) || expired_starving(rq)) {
enqueue_task(p, rq->expired);
if (p->static_prio < rq->best_expired_prio)
rq->best_expired_prio = p->static_prio;
} else
enqueue_task(p, rq->active);
} else {
...
}
...
}