インターバルタイマを掘削してみるなど

kernel/itimer.c にて定義されている模様。タグが無い、と思い gtags -v を始めたら終わらない。ちなみに linux-next ツリーです。ちょっと失敗?
# しかもそのうちディレクトリごと消しちゃう件

とりあえず

do_getitimer 手続きから確認。詳細な事情は別途エントリを入れてみたいと思ってます。SYSCALL_DEFINE2 マクロとか。
とりあえず do_getitimer 手続きの ITIMER_REAL な分岐のみ確認してみます。

int do_getitimer(int which, struct itimerval *value)
{
    struct task_struct *tsk = current;

    switch (which) {
    case ITIMER_REAL:
        spin_lock_irq(&tsk->sighand->siglock);
        value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
        value->it_interval =
            ktime_to_timeval(tsk->signal->it_real_incr);
        spin_unlock_irq(&tsk->sighand->siglock);
        break;

核心は spin_lock の囲みの中、ということで task_struct 方面から確認。include/linux/sched.h で定義なのか。ええと signal 属性あたりが以下。

/* signal handlers */
    struct signal_struct *signal;

struct signal_struct 型は sched.h で定義されているようです。ええと real_timer とか it_real_incr という属性が定義されてるあたりを確認すりゃ良いのか。

    /* ITIMER_REAL timer for the process */
    struct hrtimer real_timer;
    struct pid *leader_pid;
    ktime_t it_real_incr;

struct hrtimer 型も見ておいた方が良いのかな。include/linux/hrtimer.h で定義されてますね。

struct hrtimer {
    struct timerqueue_node        node;
    ktime_t                _softexpires;
    enum hrtimer_restart        (*function)(struct hrtimer *);
    struct hrtimer_clock_base    *base;
    unsigned long            state;
#ifdef CONFIG_TIMER_STATS
    int                start_pid;
    void                *start_site;
    char                start_comm[16];
#endif
};

これを前提に itimer_get_remtime 手続きを確認してみます。itimer.c で定義されてますね。ちなみに手続き定義なコメントが以下です。

 * itimer_get_remtime - get remaining time for the timer

実際 getitmer でもこのあたりの数値を使っているらしいのでこっちに重きを置いて確認入れた方が良さげ。手続き定義は以下なカンジですね。

static struct timeval itimer_get_remtime(struct hrtimer *timer)
{
    ktime_t rem = hrtimer_get_remaining(timer);

    /*
     * Racy but safe: if the itimer expires after the above
     * hrtimer_get_remtime() call but before this condition
     * then we return 0 - which is correct.
     */
    if (hrtimer_active(timer)) {
        if (rem.tv64 <= 0)
            rem.tv64 = NSEC_PER_USEC;
    } else
        rem.tv64 = 0;

    return ktime_to_timeval(rem);
}

ktime_t 型は一応確認しておきます。

union ktime {
    s64    tv64;
#if BITS_PER_LONG != 64 && !defined(CONFIG_KTIME_SCALAR)
    struct {
# ifdef __BIG_ENDIAN
    s32    sec, nsec;
# else
    s32    nsec, sec;
# endif
    } tv;
#endif
};

typedef union ktime ktime_t;        /* Kill this */

うう、意味不明。64bit な long と見ておきます。で、hrtimer_get_remaining 手続きですが、核心部分のみ引用。

    rem = hrtimer_expires_remaining(timer);

これ、include/linux/hrtimer.h にて以下な定義です。

static inline ktime_t hrtimer_expires_remaining(const struct hrtimer *timer)
{
    return ktime_sub(timer->node.expires, timer->base->get_time());
}

ktime_sub は include/linux/ktime.h でマクロになってますね。

/* Subtract two ktime_t variables. rem = lhs -rhs: */
#define ktime_sub(lhs, rhs) \
        ({ (ktime_t){ .tv64 = (lhs).tv64 - (rhs).tv64 }; })

ええと、timer->node.expires は以下な定義から解決されるのかな。node 属性は struct timerqueue_node 型です。

struct timerqueue_node {
    struct rb_node node;
    ktime_t expires;
};

で、base 属性は struct hrtimer_clock_base 型です。

struct hrtimer_clock_base {
    struct hrtimer_cpu_base    *cpu_base;
    int            index;
    clockid_t        clockid;
    struct timerqueue_head    active;
    ktime_t            resolution;
    ktime_t            (*get_time)(void);
    ktime_t            softirq_time;
    ktime_t            offset;
};

ええと、ktime_t を戻す get_time というナニがありますね。コメントが以下。

 * @get_time:		function to retrieve the current time of the clock

何故に引いて戻して残り時間を、にしているのかが微妙に謎。

マズッた

これは setitimer 側から見ないと駄目だな。つうか、

    case ITIMER_VIRTUAL:
        get_cpu_itimer(tsk, CPUCLOCK_VIRT, value);
        break;
    case ITIMER_PROF:
        get_cpu_itimer(tsk, CPUCLOCK_PROF, value);
        break;

なあたりもスルーだしorz

ざっくり確認してみた

get_cpu_itimer 手続きの先頭らへん。

static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
			   struct itimerval *const value)
{
    cputime_t cval, cinterval;
    struct cpu_itimer *it = &tsk->signal->it[clock_id];

    spin_lock_irq(&tsk->sighand->siglock);

    cval = it->expires;
    cinterval = it->incr;

ええと struct signal_struct 型の it 属性な定義が以下。

    /*
     * ITIMER_PROF and ITIMER_VIRTUAL timers for the process, we use
     * CPUCLOCK_PROF and CPUCLOCK_VIRT for indexing array as these
     * values are defined to 0 and 1 respectively
     */
    struct cpu_itimer it[2];

ほほう、これは CPUCLOCK_{VIRT, PROF} で、ということなのか。

うーん

掘りかたが微妙な気がしてきました。そもそもシグナルが云々ってところまでも行きつけてないし。
とりあえずもう少し勝手きままに掘削の方向にて。