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()
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()
// 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 = ®istered_con_driver[i];
// con_driver: ®istered_con_driver[0]
// con_driver->con: (®istered_con_driver[0])->con: NULL
if (con_driver->con == NULL) {
// con_driver->con: (®istered_con_driver[0])->con, conswitchp: &dummy_con
con_driver->con = conswitchp;
// con_driver->con: (®istered_con_driver[0])->con: &dummy_con
// con_driver->desc: (®istered_con_driver[0])->desc, display_desc: &"dummy device"
con_driver->desc = display_desc;
// con_driver->desc: (®istered_con_driver[0])->desc: &"dummy device"
// con_driver->flag: (®istered_con_driver[0])->flag, CON_DRIVER_FLAG_INIT: 2
con_driver->flag = CON_DRIVER_FLAG_INIT;
// con_driver->flag: (®istered_con_driver[0])->flag: 2
// con_driver->first: (®istered_con_driver[0])->first
con_driver->first = 0;
// con_driver->first: (®istered_con_driver[0])->first: 0
// con_driver->last: (®istered_con_driver[0])->last, MAX_NR_CONSOLES: 63
con_driver->last = MAX_NR_CONSOLES - 1;
// con_driver->last: (®istered_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 */
};
#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) */
};
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 */
};
// 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()
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()
- 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()
- 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()
- 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()
- timer_pending()
- __mod_timer()
// 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()
- timer_pending()
- __mod_timer()
// 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()
- timer_pending()
- __mod_timer()
// 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()
// 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()
- timer_pending()
- __mod_timer()
- lock_timer_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_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)
{
// 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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_pending()
- debug_activate()
- smp_processor_id()
- get_sysctl_timer_migration()
- idel_cpu()
- get_nohz_timer_target()
- per_cpu()
- internal_add_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에 연결
// 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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_pending()
- debug_activate()
- smp_processor_id()
- get_sysctl_timer_migration()
- idel_cpu()
- get_nohz_timer_target()
- per_cpu()
- internal_add_timer()
- tbase_get_deferrable()
timer.c::tbase_get_deferrable()
- called: start_kernel()->console_init()->con_init()
- mod_timer()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_pending()
- debug_activate()
- smp_processor_id()
- get_sysctl_timer_migration()
- idel_cpu()
- get_nohz_timer_target()
- per_cpu()
- internal_add_timer()
- 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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_pending()
- debug_activate()
- smp_processor_id()
- get_sysctl_timer_migration()
- idel_cpu()
- get_nohz_timer_target()
- per_cpu()
- internal_add_timer()
- 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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_pending()
- debug_activate()
- smp_processor_id()
- get_sysctl_timer_migration()
- idel_cpu()
- get_nohz_timer_target()
- per_cpu()
- internal_add_timer()
- 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()
- timer_pending()
- __mod_timer()
- lock_timer_base()
- spin_lock_irqsave()
- return base: &boot_tvec_bases
- detach_if_pending()
- debug_activate()
- smp_processor_id()
- get_sysctl_timer_migration()
- idel_cpu()
- get_nohz_timer_target()
- per_cpu()
- internal_add_timer()
- 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
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(-)
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(+)
댓글 없음:
댓글 쓰기