2010年02月23日
情報科学類 オペレーティングシステム II
筑波大学 システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/literacy-2009/2010-02-23
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
試験について
struct timeval {
long tv_sec; /* seconds since Jan. 1, 1970 */
long tv_usec; /* and microseconds */
};
int gettimeofday(struct timeval *tp, struct timezone *tzp);
int settimeofday(const struct timeval *tp, const struct timezone *tzp);
使い方
struct timeval tv;
gettimeofday(&tv, NULL);
POSIX 1003.1, 2003 では、ナノ秒単位。
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);
カレンダ時刻は、変更できる。逆走させることも可能。
順方向のジャンプや逆走を避けて、カレンダ時刻を合わせるには、adjtime() を使う。
int adjtime(const struct timeval *delta, struct timeval *olddelta);
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);
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);
ネットワーク・プログラムでよく使う。複数の入力を監視する。指定された時
間、入力がなければ、システム・コールから復帰する。
なにもしない時間切れ。
unsigned int sleep(unsigned int seconds); int usleep(useconds_t usec) int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);

図? タイマ関連のハードウェアの基本モデル
kernel/timer.c
49: u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
...
1197: void do_timer(unsigned long ticks)
1198: {
1199: jiffies_64 += ticks;
1200: update_wall_time();
1201: calc_global_load();
1202: }
kernel/time/tick-common.c
60: static void tick_periodic(int cpu)
61: {
...
68: do_timer(1);
...
72: update_process_times(user_mode(get_irq_regs()));
...
74: }
..
79: void tick_handle_periodic(struct clock_event_device *dev)
80: {
81: int cpu = smp_processor_id();
...
84: tick_periodic(cpu);
...
109: }
kernel/time/tick-internal.h:125: dev->event_handler = tick_handle_periodic;
kernel/time/tick-broadcast.c:108: dev->event_handler = tick_handle_periodic;
kernel/time/tick-broadcast.c:288: dev->event_handler = tick_handle_periodic;
arch/x86/include/asm/i8253.h
11: extern struct clock_event_device *global_clock_event;
arch/x86/include/asm/do_timer.h:
13: static inline void do_timer_interrupt_hook(void)
14: {
15: global_clock_event->event_handler(global_clock_event);
16: }
arch/x86/kernel/time_32.c
75: irqreturn_t timer_interrupt(int irq, void *dev_id)
76: {
...
95: do_timer_interrupt_hook();
...
113: return IRQ_HANDLED;
114: }
arch/x86/kernel/setup.c
1069: static struct irqaction irq0 = {
1070: .handler = timer_interrupt,
1071: .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
1072: .name = "timer"
1073: };
1092: void __init x86_quirk_time_init(void)
1093: {
...
1104: irq0.mask = cpumask_of_cpu(0);
1105: setup_irq(0, &irq0);
1106: }
kernel/time.c
102: SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
103: struct timezone __user *, tz)
104: {
105: if (likely(tv != NULL)) {
106: struct timeval ktv;
107: do_gettimeofday(&ktv);
108: if (copy_to_user(tv, &ktv, sizeof(ktv)))
109: return -EFAULT;
110: }
111: if (unlikely(tz != NULL)) {
112: if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
113: return -EFAULT;
114: }
115: return 0;
116: }
kernel/time/timekeeping.c
134: void do_gettimeofday(struct timeval *tv)
135: {
136: struct timespec now;
137:
138: getnstimeofday(&now);
139: tv->tv_sec = now.tv_sec;
140: tv->tv_usec = now.tv_nsec/1000;
141: }
45: struct timespec xtime __attribute__ ((aligned (16)));
...
96: void getnstimeofday(struct timespec *ts)
97: {
...
107: *ts = xtime;
110: cycle_now = clocksource_read(clock);
113: cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;
116: nsecs = cyc2ns(clock, cycle_delta);
119: nsecs += arch_gettimeoffset();
...
123: timespec_add_ns(ts, nsecs);
124: }
493: void update_wall_time(void)
494: {
...
519: xtime.tv_sec++;
...
562: xtime.tv_nsec = ((s64)clock->xtime_nsec >> clock->) + 1;
...
571: }
ある時間が経過したら、関数を実行する。
include/linux/timer.h
12: struct timer_list {
13: struct list_head entry;
14: unsigned long expires;
15:
16: void (*function)(unsigned long);
17: unsigned long data;
18:
19: struct tvec_base *base;
...
28: };
29:
jiffies が増加して expires に達すれば、(*function)(data) を呼ぶ。
主に次の関数で操作する。
init_timer(&timer);
timer.expires = jiffies + delay;
timer.data = (unsigned long)data;
timer.function = func;
add_timer(&timer);
主に次の関数で操作する。
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer.function = timer_handler;
...
hrtimer_start(&timer, ktime_set(0, nano), HRTIMER_MODE_REL);
...
enum hrtimer_restart timer_handler(struct hrtimer *timer)
{
...
return HRTIMER_NORESTART;
}
ハンドラで HRTIMER_RESTART を return すると、タイマが再設定される。
hrtimer_init(&timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
timer.function = func;
...
hrtimer_start(&timer, ktime_add_ns(ktime_get(), period),
HRTIMER_MODE_ABS);
hrtimer の管理には、red-black tree が使われている。