2015년 7월 11일 토요일

[Linux Kernel] 109주차(2015.07.11) console_init()->con_init()->mod_timer()

ARM10C : 109 주차
일시 : 2015.07.11 (109 주차 스터디 진행)
모임명 : NAVER개발자커뮤니티지원_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 3명

109 주차 진도

  • start_kernel 321 kernel/params.c
    • console_init 833 init/main.c
    • con_init 3512 drivers/tty/tty_io.c

main.c::main.c()

  • called: start_kernel()
asmlinkage void __init start_kernel(void)
{
...
    // irqs_disabled(): 1
    WARN(!irqs_disabled(), "Interrupts were enabled early\n");

    // early_boot_irqs_disabled: true
    early_boot_irqs_disabled = false;
    // early_boot_irqs_disabled: false

    local_irq_enable();
    // IRQ를 enable 함

    kmem_cache_init_late(); // null function

    /*
     * HACK ALERT! This is early. We're enabling the console before
     * we've done PCI setups etc, and console_init() must be aware of
     * this. But we do want output early, in case something goes wrong.
     */
    console_init();

tty_io.c::console_init()

  • called: start_kernel()->console_init()
// ARM10C 20150627
void __init console_init(void)
{
    initcall_t *call;

    /* Setup the default TTY line discipline. */
    tty_ldisc_begin();

    // tty_ldisc_begin에서 한일:
    // tty_ldiscs[0]: &tty_ldisc_N_TTY
    // (&tty_ldisc_N_TTY)->num: 0
    // (&tty_ldisc_N_TTY)->refcount: 0

    /*
     * set up the console device so that later boot sequences can
     * inform about problems etc..
     */
    call = __con_initcall_start;
    // call: &__con_initcall_start

// 2015/06/27 종료
// 2015/07/04 시작

    // call: &__con_initcall_start
    while (call < __con_initcall_end) {
        // call: __initcall_con_init: con_init
        // call: __initcall_s3c24xx_serial_console_init:
        // s3c24xx_serial_console_init
        (*call)();
        call++;
    }
  • call: start_kernel()->console_init()->con_init()
    • call: con_init()
    • next call: s3c24xx_serial_console_init()

vt.c::con_init()

  • called: start_kernel()->console_init()->con_init()
    • call: con_init()
// ARM10C 20150718
struct consw {
    struct module *owner;
    const char *(*con_startup)(void);
    void    (*con_init)(struct vc_data *, int);
    void    (*con_deinit)(struct vc_data *);
    void    (*con_clear)(struct vc_data *, int, int, int, int);
    void    (*con_putc)(struct vc_data *, int, int, int);
    void    (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int);
    void    (*con_cursor)(struct vc_data *, int);
    int (*con_scroll)(struct vc_data *, int, int, int, int);
    void    (*con_bmove)(struct vc_data *, int, int, int, int, int, int);
    int (*con_switch)(struct vc_data *);
    int (*con_blank)(struct vc_data *, int, int);
    int (*con_font_set)(struct vc_data *, struct console_font *, unsigned);
    int (*con_font_get)(struct vc_data *, struct console_font *);
    int (*con_font_default)(struct vc_data *, struct console_font *, char *);
    int (*con_font_copy)(struct vc_data *, int);
    int     (*con_resize)(struct vc_data *, unsigned int, unsigned int,
                   unsigned int);
    int (*con_set_palette)(struct vc_data *, unsigned char *);
    int (*con_scrolldelta)(struct vc_data *, int);
    int (*con_set_origin)(struct vc_data *);
    void    (*con_save_screen)(struct vc_data *);
    u8  (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8);
    void    (*con_invert_region)(struct vc_data *, u16 *, int);
    u16    *(*con_screen_pos)(struct vc_data *, int);
    unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *);
    /*
     * Prepare the console for the debugger.  This includes, but is not
     * limited to, unblanking the console, loading an appropriate
     * palette, and allowing debugger generated output.
     */
    int (*con_debug_enter)(struct vc_data *);
    /*
     * Restore the console to its pre-debug state as closely as possible.
     */
    int (*con_debug_leave)(struct vc_data *);
};
// ARM10C 20150704
static int __init con_init(void)
{
    const char *display_desc = NULL;
    // display_desc: NULL

    struct vc_data *vc;
    unsigned int currcons = 0, i;
    // currcons: 0

    console_lock();

    // console_lock에서 한일:
    // (&console_sem)->count: 0
    // console_locked: 1
    // console_may_schedule: 1

    // conswitchp: &dummy_con
    if (conswitchp)
        // conswitchp->con_startup: (&dummy_con)->con_startup: dummycon_startup
        // dummycon_startup(): &"dummy device"
        display_desc = conswitchp->con_startup();
        // display_desc: &"dummy device"

    // display_desc: &"dummy device"
    if (!display_desc) {
        fg_console = 0;
        console_unlock();
        return 0;
    }

    // MAX_NR_CON_DRIVER: 16
    for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
        // i: 0
        struct con_driver *con_driver = &registered_con_driver[i];
        // con_driver: &registered_con_driver[0]

        // con_driver->con: (&registered_con_driver[0])->con: NULL
        if (con_driver->con == NULL) {
            // con_driver->con: (&registered_con_driver[0])->con, conswitchp: &dummy_con
            con_driver->con = conswitchp;
            // con_driver->con: (&registered_con_driver[0])->con: &dummy_con

            // con_driver->desc: (&registered_con_driver[0])->desc, display_desc: &"dummy device"
            con_driver->desc = display_desc;
            // con_driver->desc: (&registered_con_driver[0])->desc: &"dummy device"

            // con_driver->flag: (&registered_con_driver[0])->flag, CON_DRIVER_FLAG_INIT: 2
            con_driver->flag = CON_DRIVER_FLAG_INIT;
            // con_driver->flag: (&registered_con_driver[0])->flag: 2

            // con_driver->first: (&registered_con_driver[0])->first
            con_driver->first = 0;
            // con_driver->first: (&registered_con_driver[0])->first: 0

            // con_driver->last: (&registered_con_driver[0])->last, MAX_NR_CONSOLES: 63
            con_driver->last = MAX_NR_CONSOLES - 1;
            // con_driver->last: (&registered_con_driver[0])->last: 62

            break;
            // break 수행
        }
    }

    // MAX_NR_CONSOLES: 63
    for (i = 0; i < MAX_NR_CONSOLES; i++)
        // i: 0, conswitchp: &dummy_con
        con_driver_map[i] = conswitchp;
        // con_driver_map[0]: &dummy_con

        // i: 1...62 loop 수행

    // blankinterval: 600
    if (blankinterval) {
        // blank_normal_wait: 1
        blank_state = blank_normal_wait;
        // blank_state: 1

        // NOTE:
        // jiffies은 interrupt enable이 되었기 때문에
        // 실시간으로 변하는 값이므로 현재 시간값을 알수 없음
        // jiffiex: xx_64 로 주석을 작성하도록 함

// 2015/07/04 종료
// 2015/07/11 시작

        // jiffies: xx_64, blankinterval: 600, HZ: 100
        // mod_timera(&console_timer, xx_64 + 60000): 0
        mod_timer(&console_timer, jiffies + (blankinterval * HZ));
  • sizeof(strunct vc_data): 653Byte
// ARM10C 20150704
struct vc_data {
    struct tty_port port;           /* Upper level data */

    unsigned short  vc_num;         /* Console number */
    unsigned int    vc_cols;        /* [#] Console size */
    unsigned int    vc_rows;
    unsigned int    vc_size_row;        /* Bytes per row */
    unsigned int    vc_scan_lines;      /* # of scan lines */
    unsigned long   vc_origin;      /* [!] Start of real screen */
    unsigned long   vc_scr_end;     /* [!] End of real screen */
    unsigned long   vc_visible_origin;  /* [!] Top of visible window */
    unsigned int    vc_top, vc_bottom;  /* Scrolling region */
    const struct consw *vc_sw;
    unsigned short  *vc_screenbuf;      /* In-memory character/attribute buffer */
    unsigned int    vc_screenbuf_size;
    unsigned char   vc_mode;        /* KD_TEXT, ... */
    /* attributes for all characters on screen */
    unsigned char   vc_attr;        /* Current attributes */
    unsigned char   vc_def_color;       /* Default colors */
    unsigned char   vc_color;       /* Foreground & background */
    unsigned char   vc_s_color;     /* Saved foreground & background */
    unsigned char   vc_ulcolor;     /* Color for underline mode */
    unsigned char   vc_itcolor;
    unsigned char   vc_halfcolor;       /* Color for half intensity mode */
    /* cursor */
    unsigned int    vc_cursor_type;
    unsigned short  vc_complement_mask; /* [#] Xor mask for mouse pointer */
    unsigned short  vc_s_complement_mask;   /* Saved mouse pointer mask */
    unsigned int    vc_x, vc_y;     /* Cursor position */
    unsigned int    vc_saved_x, vc_saved_y;
    unsigned long   vc_pos;         /* Cursor address */
    /* fonts */ 
    unsigned short  vc_hi_font_mask;    /* [#] Attribute set for upper 256 chars of font or 0 if not supported */
    struct console_font vc_font;        /* Current VC font set */
    unsigned short  vc_video_erase_char;    /* Background erase character */
    /* VT terminal data */
    unsigned int    vc_state;       /* Escape sequence parser state */
    unsigned int    vc_npar,vc_par[NPAR];   /* Parameters of current escape sequence */
    /* data for manual vt switching */
    struct vt_mode  vt_mode;
    struct pid  *vt_pid;
    int     vt_newvt;
    wait_queue_head_t paste_wait;
    /* mode flags */
    unsigned int    vc_charset  : 1;    /* Character set G0 / G1 */
    unsigned int    vc_s_charset    : 1;    /* Saved character set */
    unsigned int    vc_disp_ctrl    : 1;    /* Display chars < 32? */
    unsigned int    vc_toggle_meta  : 1;    /* Toggle high bit? */
    unsigned int    vc_decscnm  : 1;    /* Screen Mode */
    unsigned int    vc_decom    : 1;    /* Origin Mode */
    unsigned int    vc_decawm   : 1;    /* Autowrap Mode */
    unsigned int    vc_deccm    : 1;    /* Cursor Visible */
    unsigned int    vc_decim    : 1;    /* Insert Mode */
    unsigned int    vc_deccolm  : 1;    /* 80/132 Column Mode */
    /* attribute flags */
    unsigned int    vc_intensity    : 2;    /* 0=half-bright, 1=normal, 2=bold */
    unsigned int    vc_italic:1;
    unsigned int    vc_underline    : 1;
    unsigned int    vc_blink    : 1;
    unsigned int    vc_reverse  : 1;
    unsigned int    vc_s_intensity  : 2;    /* saved rendition */
    unsigned int    vc_s_italic:1;
    unsigned int    vc_s_underline  : 1;
    unsigned int    vc_s_blink  : 1;
    unsigned int    vc_s_reverse    : 1;
    /* misc */
    unsigned int    vc_ques     : 1;
    unsigned int    vc_need_wrap    : 1;
    unsigned int    vc_can_do_color : 1;
    unsigned int    vc_report_mouse : 2;
    unsigned char   vc_utf      : 1;    /* Unicode UTF-8 encoding */
    unsigned char   vc_utf_count;
         int    vc_utf_char;
    unsigned int    vc_tab_stop[8];     /* Tab stops. 256 columns. */
    unsigned char   vc_palette[16*3];       /* Colour palette for VGA+ */
    unsigned short * vc_translate;
    unsigned char   vc_G0_charset;
    unsigned char   vc_G1_charset;
    unsigned char   vc_saved_G0;
    unsigned char   vc_saved_G1;
    unsigned int    vc_resize_user;         /* resize request from user */
    unsigned int    vc_bell_pitch;      /* Console bell pitch */
    unsigned int    vc_bell_duration;   /* Console bell duration */
    struct vc_data **vc_display_fg;     /* [!] Ptr to var holding fg console for this display */
    unsigned long   vc_uni_pagedir;
    unsigned long   *vc_uni_pagedir_loc;  /* [!] Location of uni_pagedir variable for this console */
    bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */
    /* additional information is in vt_kern.h */
};
  • sizeof(struct tty_port) : 313 byte
struct tty_port {
    struct tty_bufhead  buf;        /* Locked internally */
    struct tty_struct   *tty;       /* Back pointer */
    struct tty_struct   *itty;      /* internal back ptr */
    const struct tty_port_operations *ops;  /* Port operations */
    spinlock_t      lock;       /* Lock protecting tty field */
    int         blocked_open;   /* Waiting to open */
    int         count;      /* Usage count */
    wait_queue_head_t   open_wait;  /* Open waiters */
    wait_queue_head_t   close_wait; /* Close waiters */
    wait_queue_head_t   delta_msr_wait; /* Modem status change */
    unsigned long       flags;      /* TTY flags ASY_*/
    unsigned char       console:1,  /* port is a console */
                low_latency:1;  /* optional: tune for latency */
    struct mutex        mutex;      /* Locking */
    struct mutex        buf_mutex;  /* Buffer alloc lock */
    unsigned char       *xmit_buf;  /* Optional buffer */
    unsigned int        close_delay;    /* Close port delay */
    unsigned int        closing_wait;   /* Delay for output */
    int         drain_delay;    /* Set to zero if no pure time
                           based drain is needed else
                           set to size of fifo */
    struct kref     kref;       /* Ref counter */
};
  • sizeof(struct consw *vc_sw): 4Byte
  • sizeof(struct console_font vc_font):
struct console_font {
    unsigned int width, height; /* font size */
    unsigned int charcount;
    unsigned char *data;    /* font data with height fixed to 32 */
};
  • NPAR
#define NPAR 16
  • sizeof(struct vt_mode): 16Byte
struct vt_mode {
    char mode;      /* vt mode */
    char waitv;     /* if set, hang on writes if not active */
    short relsig;       /* signal to raise on release req */
    short acqsig;       /* signal to raise on acquisition */
    short frsig;        /* unused (set to 0) */
};
  • sizeof(struct *vc)
struct keyboard_notifier_param {
    struct vc_data *vc; /* VC on which the keyboard press was done */
    int down;       /* Pressure of the key? */
    int shift;      /* Current shift mask */
    int ledstate;       /* Current led state */
    unsigned int value; /* keycode, unicode value or keysym */
};
  • INIT_WORK(_work, _func)
// ARM10C 20140809
// p->wq: (&vfree_deferred + __per_cpu_offset[0])->wq, free_work
#define INIT_WORK(_work, _func)                     \
    do {                                \
        __INIT_WORK((_work), (_func), 0);           \
    } while (0)
static inline void __init_work(struct work_struct *work, int onstack) { }
// ARM10C 20140809
// p->wq: (&vfree_deferred + __per_cpu_offset[0])->wq, free_work, 0
#define __INIT_WORK(_work, _func, _onstack)             \
    do {                                \
        __init_work((_work), _onstack);             \
        (_work)->data = (atomic_long_t) WORK_DATA_INIT();   \
        INIT_LIST_HEAD(&(_work)->entry);            \
        PREPARE_WORK((_work), (_func));             \
    } while (0)
#endif

timer.c::mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
  • apply_slack에서 한일: // timer의 expires 값을 효율적으로 보정하여 리턴
  • The first if, checking for timer->slack >= 0 fails,
  • so the else part is applied.
  • In that part the difference between expires and jiffies is slightly less than HZ
  • (you just did t.expires = jiffies + HZ.
  • Therefore, the delta in the function (with your data) is most likely about 4
  • and delta / 4 is non zero.
  • This in turn implies that mask (which is expires ^ expires_limit) is not zero.
  • The rest really depends on the value of expires, but for sure, it gets changed.
  • So there you have it, since slack is automatically set to -1,
  • the apply_slack function is changing your expires time to align with,
  • I guess, the timer ticks.
  • If you don't want this slack, you can set t.slack = 0;
  • when you are initializing the timer in timer_init.
  • 0.4% 이내의 expires를 적용하기 위해서 timer slack이라는 개념을 가져왔다.
// ARM10C 20150704
// &console_timer, jiffies: xx_64 + 60000
int mod_timer(struct timer_list *timer, unsigned long expires)
{
    // timer: &console_timer, expires: xx_64 + 60000
    // apply_slack(&console_timer, xx_64 + 60000): xx_64 + 60000
    expires = apply_slack(timer, expires);
    // expires: xx_64 + 60000


    /*
     * This is a common optimization triggered by the
     * networking code - if the timer is re-modified
     * to be the same thing then just return:
     */
    // timer: &console_timer, timer_pending(&console_timer): 0,
    // timer->expires: (&console_timer)->expires: 0, expires: xx_64 + 60000
    if (timer_pending(timer) && timer->expires == expires)
        return 1;

timer.h::timer_pending()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
// ARM10C 20150711
// timer: &console_timer
static inline int timer_pending(const struct timer_list * timer)
{
    // timer->entry.next: (&console_timer)->entry.next: NULL
    return timer->entry.next != NULL;
    // return 0
}

timer.c::mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    // timer: &console_timer, timer_pending(&console_timer): 0,
    // timer->expires: (&console_timer)->expires: 0, expires: xx_64 + 60000
    if (timer_pending(timer) && timer->expires == expires)
        return 1;

    // timer: &console_timer, expires: xx_64 + 60000, TIMER_NOT_PINNED: 0
    // __mod_timer(&console_timer, xx_64 + 60000, false, 0): 0
    return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);

timer.c::__mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
// ARM10C 20150711
// timer: &console_timer, expires: xx_64 + 60000, false, TIMER_NOT_PINNED: 0
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
                        bool pending_only, int pinned)
{
    struct tvec_base *base, *new_base;
    unsigned long flags;
    int ret = 0 , cpu;
    // ret: 0

    // timer: &console_timer
    timer_stats_timer_set_start_info(timer); // null function

    // timer->function: (&console_timer)->function: blank_screen_t
    BUG_ON(!timer->function);

    // timer: &console_timer
    // lock_timer_base(&console_timer, &flags): &boot_tvec_bases
    base = lock_timer_base(timer, &flags);

timer.c::lock_timer_base()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
// ARM10C 20150711
// timer: &console_timer, &flags
static struct tvec_base *lock_timer_base(struct timer_list *timer,
                    unsigned long *flags)
    __acquires(timer->base->lock)
{
    struct tvec_base *base;

    for (;;) {
        // timer->base: (&console_timer)->base: &boot_tvec_bases
        struct tvec_base *prelock_base = timer->base;
        // prelock_base: &boot_tvec_bases

        // prelock_base: &boot_tvec_bases
        // tbase_get_base(&boot_tvec_bases): &boot_tvec_bases
        base = tbase_get_base(prelock_base);
        // base: &boot_tvec_bases

timer.c::tbase_get_base()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
// ARM10C 20150711
// prelock_base: &boot_tvec_bases
static inline struct tvec_base *tbase_get_base(struct tvec_base *base)
{
    // base: &boot_tvec_bases, TIMER_FLAG_MASK: 0x3
    return ((struct tvec_base *)((unsigned long)base & ~TIMER_FLAG_MASK));
    // return &boot_tvec_bases
}

timer.c::lock_timer_base()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
// ARM10C 20150711
// timer: &console_timer, &flags
static struct tvec_base *lock_timer_base(struct timer_list *timer,
                    unsigned long *flags)
    __acquires(timer->base->lock)
{
    struct tvec_base *base;

    for (;;) {
        // timer->base: (&console_timer)->base: &boot_tvec_bases
        struct tvec_base *prelock_base = timer->base;
        // prelock_base: &boot_tvec_bases

        // prelock_base: &boot_tvec_bases
        // tbase_get_base(&boot_tvec_bases): &boot_tvec_bases
        base = tbase_get_base(prelock_base);
        // base: &boot_tvec_bases
        // base: &boot_tvec_bases
        if (likely(base != NULL)) {
            // &base->lock: &(&boot_tvec_bases)->lock, *flags: flags
            spin_lock_irqsave(&base->lock, *flags);

            // spin_lock_irqsave에서 한일:
            // &(&boot_tvec_bases)->lock을 사용하여 spinlock을 수행하고 cpsr을 flags을 저장

            // prelock_base: &boot_tvec_bases, timer->base: (&console_timer)->base: &boot_tvec_bases
            if (likely(prelock_base == timer->base))
                // base: &boot_tvec_bases
                return base;
                // return &boot_tvec_bases

            /* The timer has migrated to another CPU */
            spin_unlock_irqrestore(&base->lock, *flags);
        }
        cpu_relax();
    }
}

timer.c::__mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
  • lock_timer_base에서 한일:
    • &(&boot_tvec_bases)->lock을 사용하여 spinlock을 수행하고 cpsr을 flags을 저장
// ARM10C 20150711
// timer: &console_timer, expires: xx_64 + 60000, false, TIMER_NOT_PINNED: 0
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
                        bool pending_only, int pinned)
{
    struct tvec_base *base, *new_base;
    unsigned long flags;
    int ret = 0 , cpu;
    // ret: 0

    // timer: &console_timer
    timer_stats_timer_set_start_info(timer); // null function

    // timer->function: (&console_timer)->function: blank_screen_t
    BUG_ON(!timer->function);

    // timer: &console_timer
    // lock_timer_base(&console_timer, &flags): &boot_tvec_bases
    base = lock_timer_base(timer, &flags);
    // base: &boot_tvec_bases

    // lock_timer_base에서 한일:
    // &(&boot_tvec_bases)->lock을 사용하여 spinlock을 수행하고 cpsr을 flags을 저장

    // timer: &console_timer, base: &boot_tvec_bases
    // detach_if_pending(&console_timer, &boot_tvec_bases, false): 0
    ret = detach_if_pending(timer, base, false);

timer.c::detach_if_pending()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
// ARM10C 20150711
// timer: &console_timer, base: &boot_tvec_bases, false
static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
                 bool clear_pending)
{
    // timer: &console_timer, timer_pending(&console_timer): 0
    if (!timer_pending(timer))
        return 0;
  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
// ARM10C 20150711
// timer: &console_timer
static inline int timer_pending(const struct timer_list * timer)
{
    // timer->entry.next: (&console_timer)->entry.next: NULL
    return timer->entry.next != NULL;
    // return 0
}
// ARM10C 20150711
// timer: &console_timer, base: &boot_tvec_bases, false
static int detach_if_pending(struct timer_list *timer, struct tvec_base *base,
                 bool clear_pending)
{
    // timer: &console_timer, timer_pending(&console_timer): 0
    if (!timer_pending(timer))
        return 0;
        // return 0

timer.c::__mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
// ARM10C 20150711
// timer: &console_timer, expires: xx_64 + 60000, false, TIMER_NOT_PINNED: 0
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
                        bool pending_only, int pinned)
{
...
    // timer: &console_timer, base: &boot_tvec_bases
    // detach_if_pending(&console_timer, &boot_tvec_bases, false): 0
    ret = detach_if_pending(timer, base, false);
    // ret: 0

    // ret: 0, pending_only: false
    if (!ret && pending_only)
        goto out_unlock;

    // timer: &console_timer, expires: xx_64 + 60000
    debug_activate(timer, expires); // null function

    // smp_processor_id(): 0
    cpu = smp_processor_id();
    // cpu: 0

#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) // CONFIG_NO_HZ_COMMON=y, CONFIG_SMP=y
    // pinned: 0, get_sysctl_timer_migration(): 1, cpu: 0, idle_cpu(0): 1
    if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
        // get_nohz_timer_target(): 0
        cpu = get_nohz_timer_target();
        // cpu: 0
  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
// ARM10C 20150711
static inline unsigned int get_sysctl_timer_migration(void)
{
    // sysctl_timer_migration: 1
    return sysctl_timer_migration;
    // return 1
}
// ARM10C 20150711
// cpu: 0
int idle_cpu(int cpu)
{
    // cpu: 0, cpu_rq(0): [pcp0] &runqueues
    struct rq *rq = cpu_rq(cpu);
    // rq: [pcp0] &runqueues

    // rq->curr: [pcp0] (&runqueues)->curr: &init_task,
    // rq->idle: [pcp0] (&runqueues)->idle: &init_task
    if (rq->curr != rq->idle)
        return 0;

    // rq->nr_running: [pcp0] (&runqueues)->nr_running: 0
    if (rq->nr_running)
        return 0;

#ifdef CONFIG_SMP // CONFIG_SMP=y
    // &rq->wake_list: [pcp0] &(&runqueues)->wake_list,
    // llist_empty([pcp0] &(&runqueues)->wake_list): 1
    if (!llist_empty(&rq->wake_list))
        return 0;
#endif

    return 1;
    // return 1
}

timer.c::__mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
// ARM10C 20150711
// timer: &console_timer, expires: xx_64 + 60000, false, TIMER_NOT_PINNED: 0
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
                        bool pending_only, int pinned)
{
...
#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) // CONFIG_NO_HZ_COMMON=y, CONFIG_SMP=y
    // pinned: 0, get_sysctl_timer_migration(): 1, cpu: 0, idle_cpu(0): 1
    if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
        // get_nohz_timer_target(): 0
        cpu = get_nohz_timer_target();

core.c::get_nohz_timer_target()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
// ARM10C 20150711
int get_nohz_timer_target(void)
{
    // smp_processor_id(): 0
    int cpu = smp_processor_id();
    // cpu: 0

    int i;
    struct sched_domain *sd;

    rcu_read_lock();

core.c::get_nohz_timer_target(

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
// ARM10C 20150711
int get_nohz_timer_target(void)
{
...
    rcu_read_lock();
    // rcu_read_lock에서 한일:
    // (&init_task)->rcu_read_lock_nesting: 1

    // cpu_rq(0)->sd: ([pcp0] &runqueues)->sd: NULL,
    // rcu_dereference_check_sched_domain(([pcp0] &runqueues)->sd): ([pcp0] &runqueues)->sd,
    // sd: ([pcp0] &runqueues)->sd: NULL
    for_each_domain(cpu, sd) {
    // for (sd = rcu_dereference_check_sched_domain(cpu_rq(0)->sd); sd; sd = sd->parent)

        for_each_cpu(i, sched_domain_span(sd)) {
            if (!idle_cpu(i)) {
                cpu = i;
                goto unlock;
            }
        }
    }
unlock:
    rcu_read_unlock();

    // rcu_read_unlock에서 한일:
    // (&init_task)->rcu_read_lock_nesting: 0

    // cpu: 0
    return cpu;
    // return 0
}

timer.c::__mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
// ARM10C 20150711
// timer: &console_timer, expires: xx_64 + 60000, false, TIMER_NOT_PINNED: 0
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
                        bool pending_only, int pinned)
{
...
#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) // CONFIG_NO_HZ_COMMON=y, CONFIG_SMP=y
    // pinned: 0, get_sysctl_timer_migration(): 1, cpu: 0, idle_cpu(0): 1
    if (!pinned && get_sysctl_timer_migration() && idle_cpu(cpu))
        // get_nohz_timer_target(): 0
        cpu = get_nohz_timer_target();
        // cpu: 0
#endif
    // cpu: 0, per_cpu(tvec_bases, 0): [pcp0] tvec_bases: &boot_tvec_bases
    new_base = per_cpu(tvec_bases, cpu);
    // new_base: &boot_tvec_bases

    // base: &boot_tvec_bases, new_base: &boot_tvec_bases
    if (base != new_base) {
        /*
         * We are trying to schedule the timer on the local CPU.
         * However we can't change timer's base while it is running,
         * otherwise del_timer_sync() can't detect that the timer's
         * handler yet has not finished. This also guarantees that
         * the timer is serialized wrt itself.
         */
        if (likely(base->running_timer != timer)) {
            /* See the comment in lock_timer_base() */
            timer_set_base(timer, NULL);
            spin_unlock(&base->lock);
            base = new_base;
            spin_lock(&base->lock);
            timer_set_base(timer, base);
        }
    }

    // timer->expires: (&console_timer)->expires: 0, expires: xx_64 + 60000
    timer->expires = expires;
    // timer->expires: (&console_timer)->expires: xx_64 + 60000

    // base: &boot_tvec_bases, timer: &console_timer
    internal_add_timer(base, timer);

timer.c::internal_add_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
// ARM10C 20150711
// base: &boot_tvec_bases, timer: &console_timer
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
    // base: &boot_tvec_bases, timer: &console_timer
    __internal_add_timer(base, timer);

timer.c::internal_add_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
// ARM10C 20150711
// base: &boot_tvec_bases, timer: &console_timer
static void
__internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
    // timer->expires: (&console_timer)->expires: xx_64 + 60000
    unsigned long expires = timer->expires;
    // expires: xx_64 + 60000

    // expires: xx_64 + 60000, base->timer_jiffies: -30000 (0xFFFFFFFFFFFF8AD0)
    unsigned long idx = expires - base->timer_jiffies;
    // idx: xx_64 + 90000

    struct list_head *vec;

    // NOTE:
    // idx의 값을 가정하고 분석, xx_64은 0이라 보고
    // idx값이 90000의 값을 가진것으로 분석 진행

    // FIXME:
    // TVR_SIZE: 256 값이 왜 256 인지??

    // idx: 90000, TVR_SIZE: 256, TVR_BITS: 8, TVN_BITS: 6
    if (idx < TVR_SIZE) {
        int i = expires & TVR_MASK;
        vec = base->tv1.vec + i;
    } else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
        int i = (expires >> TVR_BITS) & TVN_MASK;
        vec = base->tv2.vec + i;
    } else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
        // NOTE:
        // xx_64은 0이라 가정하고
        // expires값이 60000의 값을 가진것으로 분석 진행

        // expires: 60000, TVR_BITS: 8, TVN_BITS: 6, TVN_MASK: 0x3f
        int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
        // i: 3

        // base->tv3.vec: (&boot_tvec_bases)->tv3.vec, i: 3
        vec = base->tv3.vec + i;
        // vec: &(&boot_tvec_bases)->tv3.vec[3]
    } else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
        int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
        vec = base->tv4.vec + i;
    } else if ((signed long) idx < 0) {
        /*
         * Can happen if you add a timer with expires == jiffies,
         * or you set a timer to go off in the past
         */
        vec = base->tv1.vec + (base->timer_jiffies & TVR_MASK);
    } else {
        int i;
        /* If the timeout is larger than MAX_TVAL (on 64-bit
         * architectures or with CONFIG_BASE_SMALL=1) then we
         * use the maximum timeout.
         */
        if (idx > MAX_TVAL) {
            idx = MAX_TVAL;
            expires = idx + base->timer_jiffies;
        }
        i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
        vec = base->tv5.vec + i;
    }
    /*
     * Timers are FIFO:
     */
    // &timer->entry: &(&console_timer)->entry, vec: &(&boot_tvec_bases)->tv3.vec[3]
    list_add_tail(&timer->entry, vec);

    // list_add_tail에서 한일:
    // &(&boot_tvec_bases)->tv3.vec[3]에 &(&console_timer)->entry을 tail에 연결
}

timer.c::internal_add_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
  • __internal_add_timer에서 한일: // NOTE: // idx의 값을 가정하고 분석, xx_64은 0이라 보고 // idx값이 90000의 값을 가진것으로 분석 진행 // FIXME: // TVR_SIZE: 256 값이 왜 256 인지?? // // &(&boot_tvec_bases)->tv3.vec[3]에 &(&console_timer)->entry을 tail에 연결
// ARM10C 20150711
// base: &boot_tvec_bases, timer: &console_timer
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
    // base: &boot_tvec_bases, timer: &console_timer
    __internal_add_timer(base, timer);

    // __internal_add_timer에서 한일:
    // NOTE:
    // idx의 값을 가정하고 분석, xx_64은 0이라 보고
    // idx값이 90000의 값을 가진것으로 분석 진행
    // FIXME:
    // TVR_SIZE: 256 값이 왜 256 인지??
    //
    // &(&boot_tvec_bases)->tv3.vec[3]에 &(&console_timer)->entry을 tail에 연결

    /*
     * Update base->active_timers and base->next_timer
     */
    // timer->base: (&console_timer)->base: &boot_tvec_bases
    // tbase_get_deferrable(&boot_tvec_bases): 0
    if (!tbase_get_deferrable(timer->base)) {
  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()

timer.c::tbase_get_deferrable()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
// ARM10C 20150711
// timer->base: (&console_timer)->base: &boot_tvec_bases
static inline unsigned int tbase_get_deferrable(struct tvec_base *base)
{
    // base: &boot_tvec_bases, TIMER_DEFERRABLE: 0x1
    return ((unsigned int)(unsigned long)base & TIMER_DEFERRABLE);
    // return 0
}

timer.c::internal_add_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
// ARM10C 20150711
// base: &boot_tvec_bases, timer: &console_timer
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
    // base: &boot_tvec_bases, timer: &console_timer
    __internal_add_timer(base, timer);

    /*
     * Update base->active_timers and base->next_timer
     */
    // timer->base: (&console_timer)->base: &boot_tvec_bases
    // tbase_get_deferrable(&boot_tvec_bases): 0
    if (!tbase_get_deferrable(timer->base)) {
        // NOTE:
        // 계산값 xx_64 + 90000 0 보다 크다고 가정하고 분석 진행

        // timer->expires: (&console_timer)->expires: xx_64 + 60000,
        // base->next_timer: (&boot_tvec_bases)->next_timer: -30000 (0xFFFFFFFFFFFF8AD0)
        // time_before(xx_64 + 60000, -30000): 0
        if (time_before(timer->expires, base->next_timer))
            base->next_timer = timer->expires;
// ARM10C 20150711
// timer->expires: (&console_timer)->expires: xx_64 + 60000,
// base->next_timer: (&boot_tvec_bases)->next_timer: -30000 (0xFFFFFFFFFFFF8AD0)
#define time_before(a,b)    time_after(b,a)
// ARM10C 20150711
// base: &boot_tvec_bases, timer: &console_timer
static void internal_add_timer(struct tvec_base *base, struct timer_list *timer)
{
    // base: &boot_tvec_bases, timer: &console_timer
    __internal_add_timer(base, timer);

    /*
     * Update base->active_timers and base->next_timer
     */
    // timer->base: (&console_timer)->base: &boot_tvec_bases
    // tbase_get_deferrable(&boot_tvec_bases): 0
    if (!tbase_get_deferrable(timer->base)) {
        // NOTE:
        // 계산값 xx_64 + 90000 0 보다 크다고 가정하고 분석 진행

        // timer->expires: (&console_timer)->expires: xx_64 + 60000,
        // base->next_timer: (&boot_tvec_bases)->next_timer: -30000 (0xFFFFFFFFFFFF8AD0)
        // time_before(xx_64 + 60000, -30000): 0
        if (time_before(timer->expires, base->next_timer))
            base->next_timer = timer->expires;

        // base->active_timers: (&boot_tvec_bases)->active_timers: 0
        base->active_timers++;
        // base->active_timers: (&boot_tvec_bases)->active_timers: 1
    }
}
  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
      • time_before()
  • internal_add_timer에서 한일: // NOTE: // idx의 값을 가정하고 분석, xx_64은 0이라 보고 // idx값이 90000의 값을 가진것으로 분석 진행 // 계산값 xx_64 + 90000 0 보다 크다고 가정하고 분석 진행 // FIXME: // TVR_SIZE: 256 값이 왜 256 인지?? // // &(&boot_tvec_bases)->tv3.vec[3]에 &(&console_timer)->entry을 tail에 연결 // (&boot_tvec_bases)->active_timers: 1
// ARM10C 20150711
// timer: &console_timer, expires: xx_64 + 60000, false, TIMER_NOT_PINNED: 0
static inline int
__mod_timer(struct timer_list *timer, unsigned long expires,
                        bool pending_only, int pinned)
{
...
    // base: &boot_tvec_bases, timer: &console_timer
    internal_add_timer(base, timer);


out_unlock:
    spin_unlock_irqrestore(&base->lock, flags);

    // spin_unlock_irqrestore에서 한일:
    // &(&boot_tvec_bases)->lock을 사용하여 spin unlock을 수행하고 flags에 저장된 cpsr을 복원

    // ret: 0
    return ret;
    // return 0
}

timer.c::mod_timer()

  • called: start_kernel()->console_init()->con_init()
    • mod_timer()
      • apply_slack()
    • timer_pending()
    • __mod_timer()
      • lock_timer_base()
        • tbase_get_base()
      • spin_lock_irqsave()
      • return base: &boot_tvec_bases
      • detach_if_pending()
        • timer_pending()
      • debug_activate()
      • smp_processor_id()
      • get_sysctl_timer_migration()
      • idel_cpu()
      • get_nohz_timer_target()
      • per_cpu()
      • internal_add_timer()
        • __internal_add_timer()
          • list_add_tail()
      • tbase_get_deferrable()
      • time_before()
  • __mod_timer에서 한일: // (&console_timer)->expires: xx_64 + 60000 // // NOTE: // idx의 값을 가정하고 분석, xx_64은 0이라 보고 // idx값이 90000의 값을 가진것으로 분석 진행 // 계산값 xx_64 + 90000 0 보다 크다고 가정하고 분석 진행 // FIXME: // TVR_SIZE: 256 값이 왜 256 인지?? // // &(&boot_tvec_bases)->tv3.vec[3]에 &(&console_timer)->entry을 tail에 연결 // (&boot_tvec_bases)->active_timers: 1
// ARM10C 20150704
// &console_timer, jiffies: xx_64 + 60000
int mod_timer(struct timer_list *timer, unsigned long expires)
{
    // timer: &console_timer, expires: xx_64 + 60000
    // apply_slack(&console_timer, xx_64 + 60000): xx_64 + 60000
    expires = apply_slack(timer, expires);
    // expires: xx_64 + 60000

    // apply_slack에서 한일:
    // timer의 expires 값을 효율적으로 보정하여 리턴

    /*
     * This is a common optimization triggered by the
     * networking code - if the timer is re-modified
     * to be the same thing then just return:
     */
    // timer: &console_timer, timer_pending(&console_timer): 0,
    // timer->expires: (&console_timer)->expires: 0, expires: xx_64 + 60000
    if (timer_pending(timer) && timer->expires == expires)
        return 1;
    // timer: &console_timer, expires: xx_64 + 60000, TIMER_NOT_PINNED: 0
    // __mod_timer(&console_timer, xx_64 + 60000, false, 0): 0
    return __mod_timer(timer, expires, false, TIMER_NOT_PINNED);

}
EXPORT_SYMBOL(mod_timer);

log

  • 1st log 
51a9b85..e4675c6  master     -> origin/master
Updating 51a9b85..e4675c6
Fast-forward
arch/arm/include/asm/bug.h            |  5 ++++-
arch/arm/include/asm/spinlock_types.h |  4 ++--
drivers/tty/vt/vt.c                   |  1 +
include/asm-generic/bug.h             |  1 +
include/linux/compiler.h              |  1 +
include/linux/sched/sysctl.h          |  1 +
include/linux/smp.h                   |  1 +
include/linux/spinlock.h              |  2 ++
include/linux/spinlock_types.h        |  2 +-
include/linux/timer.h                 |  9 +++++++++
kernel/hrtimer.c                      |  2 ++
kernel/sched/core.c                   |  4 ++++
kernel/timer.c                        | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
13 files changed, 97 insertions(+), 12 deletions(-)
  • 2nd log
e4675c6..b20cad6  master     -> origin/master
Updating e4675c6..b20cad6
Fast-forward
drivers/tty/vt/vt.c         |  16 +++++++
include/linux/jiffies.h     |   6 +++
include/linux/list.h        |   2 +
include/linux/percpu-defs.h |   4 ++
include/linux/timer.h       |   2 +
include/linux/types.h       |   1 +
kernel/timer.c              | 107 ++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 138 insertions(+)

댓글 없음:

댓글 쓰기