¶¨Ê±Æ÷ |
| ʱ¼ä£º2005-12-01 12:54:54 À´Ô´£º ×÷Õߣº |
£Ã¿¸ö½ø³Ìtask_struct½á¹¹Öж¼ÓÐÒ»¸ö³ÉÔ±times£¬ËüÊÇÒ»¸ötms ½á¹¹ÀàÐÍ£¨include/linux/times.h£©£º struct tms { clock_t tms_utime; £¯£ª ±¾½ø³ÌÔÚÓû§Ì¨ÏµÄÖ´ÐÐʱ¼ä×ÜºÍ £ª£¯ clock_t tms_stime; £¯£ª ±¾½ø³ÌÔÚºËÐÄ̬ϵÄÖ´ÐÐʱ¼ä×ÜºÍ £ª£¯ clock_t tms_cutime; £¯£ª ËùÓÐ×Ó½ø³ÌÔÚÓû§Ì¬ÏµÄÖ´ÐÐʱ¼ä×ÜºÍ £ª£¯ clock_t tms_cstime; £¯£ª ËùÓÐ×Ó½ø³ÌÔÚºËÐÄ̬ϵÄÖ´ÐÐʱ¼ä×ÜºÍ £ª£¯ }; ÉÏÊö½á¹¹µÄËùÓгÉÔ±¶¼ÒÔʱÖӵδð´ÎÊýΪµ¥Î»¡£ º¯Êýdo_process_times()µÄÔ´ÂëÈçÏ£¨kernel/timer.c£©£º static inline void do_process_times(struct task_struct *p, unsigned long user, unsigned long system) { unsigned long psecs;
psecs = (p->times.tms_utime += user); psecs += (p->times.tms_stime += system); if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_cur) { /* Send SIGXCPU every second.. */ if (!(psecs % HZ)) send_sig(SIGXCPU, p, 1); /* and SIGKILL when we go over max.. */ if (psecs / HZ > p->rlim[RLIMIT_CPU].rlim_max) send_sig(SIGKILL, p, 1); } } ×¢ÊÍÈçÏ£º £¨1£©¸ù¾Ý²ÎÊýuser¸üÐÂÖ¸¶¨½ø³Ìtask_struct½á¹¹ÖеÄtimes.tms_utimeÖµ¡£¸ù¾Ý²ÎÊýsystem¸üÐÂÖ¸¶¨½ø³Ìtask_struct½á¹¹ ÖеÄtimes.tms_stimeÖµ¡£ £¨2£©½«¸üкóµÄtimes.tms_utimeÖµÓëtimes.tms_stimeÖµµÄºÍ±£´æµ½¾Ö²¿±äÁ¿psecsÖУ¬Òò´Ëpsecs¾Í±íʾÁËÖ¸¶¨½ø³Ìpµ½Ä¿ ǰΪֹÒѾÔËÐеÄ×Üʱ¼ä³¤¶È£¨ÒÔʱÖӵδð´ÎÊý¼Æ£©¡£Èç¹ûÕâÒ»×ÜÔËÐÐʱ¼ä³¤³¬¹ý½ø³ÌPµÄ×ÊÔ´Ï޶ÄǾÍÿ¸ô1Ãë¸ø½ø³Ì·¢ËÍÒ»¸öÐÅ ºÅSIGXCPU£»Èç¹ûÔËÐÐʱ¼ä³¤¶È³¬¹ýÁ˽ø³Ì×ÊÔ´ÏÞ¶îµÄ×î´óÖµ£¬ÄǾͷ¢ËÍÒ»¸öSIGKILLÐźÅɱËÀ¸Ã½ø³Ì¡£
l do_it_virt()º¯Êý ÿ¸ö½ø³Ì¶¼ÓÐÒ»¸öÓû§Ì¬Ö´ÐÐʱ¼äµÄitimerÈí¼þ¶¨Ê±Æ÷¡£½ø³ÌÈÎÎñ½á¹¹task_structÖеÄit_virt_value³ÉÔ±ÊÇÕâ¸öÈí¼þ¶¨Ê±Æ÷ µÄʱ¼ä¼ÆÊýÆ÷¡£µ±½ø³ÌÔÚÓû§Ì¬ÏÂÖ´ÐÐʱ£¬Ã¿Ò»´ÎʱÖӵδð¶¼Ê¹¼ÆÊýÆ÷it_virt_value¼õ1£¬µ±¼õµ½0ʱÄÚºËÏò½ø³Ì·¢ËÍSIGVTALRM Ðźţ¬²¢ÖØÖóõÖµ¡£³õÖµ±£´æÔÚ½ø³ÌµÄtask_struct½á¹¹µÄit_virt_incr³ÉÔ±ÖС£ º¯Êýdo_it_virt()µÄÔ´ÂëÈçÏ£¨kernel/timer.c£©£º static inline void do_it_virt(struct task_struct * p, unsigned long ticks) { unsigned long it_virt = p->it_virt_value;
if (it_virt) { it_virt -= ticks; if (!it_virt) { it_virt = p->it_virt_incr; send_sig(SIGVTALRM, p, 1); } p->it_virt_value = it_virt; } }
l do_it_prof£¨£©º¯Êý ÀàËÆµØ£¬Ã¿¸ö½ø³ÌÒ²¶¼ÓÐÒ»¸öitimerÈí¼þ¶¨Ê±Æ÷ITIMER_PROF¡£½ø³Ìtask_structÖеÄit_prof_value³ÉÔ±¾ÍÊÇÕâ¸ö¶¨Ê±Æ÷µÄʱ ¼ä¼ÆÊýÆ÷¡£²»¹Ü½ø³ÌÊÇÔÚÓû§Ì¬Ï»¹ÊÇÔÚÄÚºË̬ÏÂÔËÐУ¬Ã¿¸öʱÖӵδð¶¼Ê¹it_prof_value¼õ1¡£µ±¼õµ½0ʱÄں˾ÍÏò½ø³Ì·¢ËÍ SIGPROFÐźţ¬²¢ÖØÖóõÖµ¡£³õÖµ±£´æÔÚ½ø³Ìtask_struct½á¹¹ÖеÄit_prof_incr³ÉÔ±ÖС£ º¯Êýdo_it_prof()¾ÍÊÇÓÃÀ´Íê³ÉÉÏÊö¹¦Äܵ쬯äÔ´ÂëÈçÏ£¨kernel/timer.c£©£º static inline void do_it_prof(struct task_struct *p) { unsigned long it_prof = p->it_prof_value;
if (it_prof) { if (--it_prof == 0) { it_prof = p->it_prof_incr; send_sig(SIGPROF, p, 1); } p->it_prof_value = it_prof; } } 7£®5 ʱÖÓÖжϵÄBottom Half ÓëʱÖÓÖжÏÏà¹ØµÄBottom HalfÏòÁ½Ö÷ÒªÓÐÁ½¸ö£ºTIMER_BHºÍTQUEUE_BH¡£ÓëTIMER_BHÏà¶ÔÓ¦µÄBHº¯ÊýÊÇtimer_bh()£¬Óë TQUEUE_BH¶ÔÓ¦µÄº¯ÊýÊÇtqueue_bh()¡£ËüÃǾùʵÏÖÔÚkernel/timer.cÎļþÖС£
7£®5£®1 TQUEUE_BHÏòÁ¿ TQUEUE_BHµÄ×÷ÓÃÊÇÓÃÀ´ÔËÐÐtq_timerÕâ¸öÈÎÎñ¶ÓÁÐÖеÄÈÎÎñ¡£Òò´Ëdo_timer()º¯Êý½ö½öÔÚtq_timerÈÎÎñ¶ÓÁв»Îª¿ÕµÄÇé¿ö²Å ¼¤»îTQUEUE_BHÏòÁ¿¡£º¯Êýtqueue_bh()µÄʵÏַdz£¼òµ¥£¬ËüÖ»ÊǼòµ¥µØµ÷ÓÃrun_task_queue()º¯ÊýÀ´ÔËÐÐÈÎÎñ¶ÓÁÐ tq_timer¡£ÈçÏÂËùʾ£º void tqueue_bh(void) { run_task_queue(&tq_timer); } ÈÎÎñ¶ÔÁÐtq_timerÒ²ÊǶ¨ÒåÔÚkernel/timer.cÎļþÖУ¬ÈçÏÂËùʾ£º DECLARE_TASK_QUEUE(tq_timer);
7£®5£®2 TIMER_BHÏòÁ¿ TIMER_BHÕâ¸öBottom HalfÏòÁ¿ÊÇLinuxÄÚºËʱÖÓÖжÏÇý¶¯µÄÒ»¸öÖØÒª¸¨Öú²¿·Ö¡£ÄÚºËÔÚÿһ´Î¶ÔʱÖÓÖжϵķþÎñ¿ìÒª½áÊøÊ±£¬¶¼ »áÎÞÌõ¼þµØ¼¤»îÒ»¸öTIMER_BHÏòÁ¿£¬ÒÔʹµÃÄÚºËÔÚÉÔºóÒ»¶ÎÑÓ³ÙºóÖ´ÐÐÏàÓ¦µÄBHº¯Êý¡ª¡ªtimer_bh()¡£¸ÃÈÎÎñµÄÔ´ÂëÈçÏ£º void timer_bh(void) { update_times(); run_timer_list(); } ´ÓÉÏÊöÔ´Âë¿ÉÒÔ¿´³ö£¬ÄÚºËÔÚʱÖÓÖжÏÇý¶¯µÄµ×°ë²¿·ÖÖ÷ÒªÓÐÁ½¸öÈÎÎñ£º£¨1£©µ÷ÓÃupdate_times()º¯ÊýÀ´¸üÐÂϵͳȫ¾Öʱ¼ä xtime£»£¨2£©µ÷ÓÃrun_timer_list()º¯ÊýÀ´Ö´Ðж¨Ê±Æ÷¡£¹ØÓÚ¶¨Ê±Æ÷ÎÒÃǽ«ÔÚÏÂÒ»½ÚÌÖÂÛ¡£±¾½ÚÎÒÃÇÖ÷ÒªÌÖÂÛTIMER_BHµÄµÚÒ» ¸öÈÎÎñ¡ª¡ª¶ÔÄÚºËʱ¼äxtimeµÄ¸üС£ ÎÒÃǶ¼ÖªµÀ£¬Äں˾ֲ¿Ê±¼äxtimeÊÇÓÃÀ´¹©Óû§³ÌÐòͨ¹ýʱ¼äsyscallÀ´¼ìË÷»òÉèÖõ±Ç°ÏµÍ³Ê±¼äµÄ£¬¶øÄں˴úÂëÔÚ´ó¶àÊýÇé¿ö϶¼ ÒýÓÃjiffies±äÁ¿£¬¶øºÜÉÙʹÓÃxtime£¨Å¼¶ûÒ²»áÓÐÒýÓÃxtimeµÄÇé¿ö£¬±ÈÈç¸üÐÂinodeµÄʱ¼ä±ê¼Ç£©¡£Òò´Ë£¬¶ÔÓÚʱÖÓÖжϷþÎñ³Ì Ðòtimer_interrupt£¨£©¶øÑÔ£¬jiffies±äÁ¿µÄ¸üÐÂÊÇ×î½ôÆÈµÄ£¬¶øxtimeµÄ¸üÐÂÔò¿ÉÒÔÑÓ³Ùµ½ÖжϷþÎñµÄµ×°ë²¿·ÖÀ´½øÐС£ ÓÉÓÚBottom Half»úÖÆÔÚÖ´ÐÐʱ¼ä¾ßÓÐijЩ²»È·¶¨ÐÔ£¬Òò´ËÔÚtimer_bh()º¯ÊýµÃµ½ÕæÕýÖ´ÐÐ֮ǰ£¬ÆÚ¼ä¿ÉÄÜÓÖ»áÓм¸´ÎʱÖÓÖжϷ¢ Éú¡£ÕâÑù¾Í»áÔì³ÉʱÖӵδðµÄ¶ªÊ§ÏÖÏó¡£ÎªÁË´¦ÀíÕâÖÖÇé¿ö£¬LinuxÄÚºËʹÓÃÁËÒ»¸ö¸¨ÖúÈ«¾Ö±äÁ¿wall_jiffies£¬À´±íʾÉÏÒ»´Î¸ü ÐÂxtimeʱµÄjiffiesÖµ¡£Æä¶¨ÒåÈçÏ£¨kernel/timer.c£©£º /* jiffies at the most recent update of wall time */ unsigned long wall_jiffies; ¶øtimer_bh()º¯ÊýÕæÕýÖ´ÐÐʱµÄjiffiesÖµÓëwall_jiffiesµÄ²î¾ÍÊÇÔÚtimer_bh()ÕæÕýÖ´ÐÐ֮ǰËù·¢ÉúµÄʱÖÓÖжϴÎÊý¡£ º¯Êýupdate_times()µÄÔ´ÂëÈçÏ£¨kernel/timer.c£©£º static inline void update_times(void) { unsigned long ticks;
/* * update_times() is run from the raw timer_bh handler so we * just know that the irqs are locally enabled and so we don't * need to save/restore the flags of the local CPU here. -arca */ write_lock_irq(&xtime_lock);
ticks = jiffies - wall_jiffies; if (ticks) { wall_jiffies += ticks; update_wall_time(ticks); } write_unlock_irq(&xtime_lock); calc_load(ticks); } £¨1£©Ê×ÏÈ£¬¸ù¾ÝjiffiesºÍwall_jiffiesµÄ²îÖµ¼ÆËãÔÚ´Ë֮ǰһ¹²·¢ÉúÁ˼¸´ÎʱÖӵδ𣬲¢½«Õâ¸öÖµ±£´æµ½¾Ö²¿±äÁ¿ticksÖС£ ²¢ÔÚticksÖµ´óÓÚ0µÄÇé¿öÏ£¨ticks´óÓÚµÈÓÚ1£¬Ò»°ãÇé¿öÏÂΪ1£©£º¢Ù¸üÐÂwall_jiffiesΪjiffies±äÁ¿µÄµ±Ç°Öµ £¨wall_jiffies£«£½ticksµÈ¼ÛÓÚwall_jiffies£½jiffies£©¡£¢ÚÒÔ²ÎÊýticksµ÷ÓÃupdate_wall_time()º¯ÊýÈ¥ÕæÕýµØ¸üÐÂÈ« ¾Öʱ¼äxtime¡£ £¨2£©µ÷ÓÃcalc_load()º¯ÊýÈ¥¼ÆËãϵͳ¸ºÔØÇé¿ö¡£ÕâÀïÎÒÃDz»È¥ÉËü¡£
º¯Êýupdate_wall_time()º¯Êý¸ù¾Ý²ÎÊýticksËùÖ¸¶¨µÄʱÖӵδð´ÎÊýÏàÓ¦µØ¸üÐÂÄÚºËÈ«¾Öʱ¼ä±äÁ¿xtime¡£ÆäÔ´ÂëÈçÏ £¨kernel/timer.c£©£º /* * Using a loop looks inefficient, but "ticks" is * usually just one (we shouldn't be losing ticks, * we're doing this this way mainly for interrupt * latency reasons, not because we think we'll * have lots of lost timer ticks */ static void update_wall_time(unsigned long ticks) { do { ticks--; update_wall_time_one_tick(); } while (ticks);
if (xtime.tv_usec >= 1000000) { xtime.tv_usec -= 1000000; xtime.tv_sec++; second_overflow(); } } ¶Ô¸Ãº¯ÊýµÄ×¢ÊÍÈçÏ£º £¨1£©Ê×ÏÈ£¬ÓÃÒ»¸ödo{}Ñ»·À´¸ù¾Ý²ÎÊýticksµÄÖµÒ»´ÎÒ»´Îµ÷ÓÃupdate_wall_time_one_tick()º¯ÊýÀ´ÎªÒ»´ÎʱÖӵδð¸üРxtimeÖеÄtv_usec³ÉÔ±¡£ £¨2£©¸ù¾ÝÐèÒªµ÷ÕûxtimeÖеÄÃëÊý³ÉÔ±tv_usecºÍ΢ÃëÊý³ÉÔ±tv_usec¡£Èç¹û΢ÃëÊý³ÉÔ±tv_usecµÄÖµ³¬¹ý106£¬Ôò˵Ã÷ÒѾ¹ýÁË Ò»ÃëÖÓ¡£Òò´Ë½«tv_usecµÄÖµ¼õÈ¥1000000£¬²¢½«ÃëÊý³ÉÔ±tv_secµÄÖµ¼Ó1£¬È»ºóµ÷ÓÃsecond_overflow£¨£©º¯ÊýÀ´´¦Àí΢ÃëÊý³É Ô±Òç³öµÄÇé¿ö¡£
º¯Êýupdate_wall_time_one_tick£¨£©ÓÃÀ´¸üÐÂÒ»´ÎʱÖӵδð¶Ôϵͳȫ¾Öʱ¼äxtimeµÄÓ°Ïì¡£ÓÉÓÚtickÈ«¾Ö±äÁ¿±íʾÁËÒ»´ÎʱÖÓ µÎ´ðµÄʱ¼ä¼ä¸ô³¤¶È£¨ÒÔusΪµ¥Î»£©£¬Òò´Ë¸Ãº¯ÊýµÄʵÏÖÖÐ×îºËÐĵĴúÂë¾ÍÊǽ«xtimeµÄtv_usec³ÉÔ±Ôö¼Ótick΢Ãë¡£ÕâÀïÎÒÃDz» È¥¹ØÐĺ¯ÊýʵÏÖÖÐÓëNTP£¨Network Time Protocol£©ºÍϵͳµ÷ÓÃadjtimex£¨£©µÄÏà¹Ø²¿·Ö¡£ÆäÔ´ÂëÈçÏ£¨kernel/ timer.c£©£º /* in the NTP reference this is called "hardclock()" */ static void update_wall_time_one_tick(void) { if ( (time_adjust_step = time_adjust) != 0 ) { /* We are doing an adjtime thing. * * Prepare time_adjust_step to be within bounds. * Note that a positive time_adjust means we want the clock * to run faster. * * Limit the amount of the step to be in the range * -tickadj .. +tickadj */ if (time_adjust > tickadj) time_adjust_step = tickadj; else if (time_adjust > SHIFT_SCALE; time_phase += ltemp = FINEUSEC) { long ltemp = time_phase >> SHIFT_SCALE; time_phase -= ltemp list.next = timer->list.prev = NULL; } ÓÉÓÚ¶¨Ê±Æ÷ͨ³£±»Á¬½ÓÔÚÒ»¸öË«ÏòÑ»·¶ÓÁÐÖеȴýÖ´ÐУ¨´ËʱÎÒÃÇ˵¶¨Ê±Æ÷´¦ÓÚpending״̬£©¡£Òò´Ëº¯Êýtime_pending()¾Í¿ÉÒÔ ÓÃlist³ÉÔ±ÊÇ·ñΪ¿ÕÀ´ÅжÏÒ»¸ö¶¨Ê±Æ÷ÊÇ·ñ´¦ÓÚpending״̬¡£ÈçÏÂËùʾ£¨include/linux/timer.h£©£º static inline int timer_pending (const struct timer_list * timer) { return timer->list.next != NULL; }
l ʱ¼ä±È½Ï²Ù×÷ ÔÚ¶¨Ê±Æ÷Ó¦ÓÃÖо³£ÐèÒª±È½ÏÁ½¸öʱ¼äÖµ£¬ÒÔÈ·¶¨timerÊÇ·ñ³¬Ê±£¬ËùÒÔLinuxÄÚºËÔÚtimer.hÍ·ÎļþÖж¨ÒåÁË4¸öʱ¼ä¹ØÏµ±È½Ï²Ù ×÷ºê¡£ÕâÀïÎÒÃÇ˵ʱ¿ÌaÔÚʱ¿ÌbÖ®ºó£¬¾ÍÒâζ×Åʱ¼äÖµa¡Ýb¡£LinuxÇ¿ÁÒÍÆ¼öÓû§Ê¹ÓÃËüËù¶¨ÒåµÄÏÂÁÐ4¸öʱ¼ä±È½Ï²Ù×÷ºê £¨include/linux/timer.h£©£º #define time_after(a,b) ((long)(b) - (long)(a) = 0) #define time_before_eq(a,b) time_after_eq(b,a)
7£®6£®2 ¶¯Ì¬Äں˶¨Ê±Æ÷»úÖÆµÄÔÀí LinuxÊÇÔõÑùΪÆäÄں˶¨Ê±Æ÷»úÖÆÌṩ¶¯Ì¬À©Õ¹ÄÜÁ¦µÄÄØ£¿Æä¹Ø¼ü¾ÍÔÚÓÚ¡°¶¨Ê±Æ÷ÏòÁ¿¡±µÄ¸ÅÄî¡£Ëùν¡°¶¨Ê±Æ÷ÏòÁ¿¡±¾ÍÊÇÖ¸ÕâÑùÒ»ÌõË« ÏòÑ»·¶¨Ê±Æ÷¶ÓÁУ¨¶ÔÁÐÖеÄÿһ¸öÔªËØ¶¼ÊÇÒ»¸ötimer_list½á¹¹£©£º¶ÔÁÐÖеÄËùÓж¨Ê±Æ÷¶¼ÔÚͬһ¸öʱ¿Ìµ½ÆÚ£¬Ò²¼´¶ÔÁÐÖеÄÿ Ò»¸ötimer_list½á¹¹¶¼¾ßÓÐÏàͬµÄexpiresÖµ¡£ÏÔÈ»£¬¿ÉÒÔÓÃÒ»¸ötimer_list½á¹¹ÀàÐ͵ÄÖ¸ÕëÀ´±íʾһ¸ö¶¨Ê±Æ÷ÏòÁ¿¡£ ÏÔÈ»£¬¶¨Ê±Æ÷expires³ÉÔ±µÄÖµÓëjiffies±äÁ¿µÄ²îÖµ¾ö¶¨ÁËÒ»¸ö¶¨Ê±Æ÷½«Ôڶ೤ʱ¼äºóµ½ÆÚ¡£ÔÚ32λϵͳÖУ¬Õâ¸öʱ¼ä²îÖµµÄ×î ´óÖµÓ¦¸ÃÊÇ0xffffffff¡£Òò´ËÈç¹ûÊÇ»ùÓÚ¡°¶¨Ê±Æ÷ÏòÁ¿¡±»ù±¾¶¨Ò壬Äں˽«ÖÁÉÙҪά»¤0xffffffff¸ötimer_list½á¹¹ÀàÐ͵ÄÖ¸ Õ룬ÕâÏÔÈ»ÊDz»ÏÖʵµÄ¡£ ÁíÒ»·½Ã棬´ÓÄں˱¾ÉíÕâ¸ö½Ç¶È¿´£¬ËüËù¹ØÐĵĶ¨Ê±Æ÷ÏÔÈ»²»ÊÇÄÇЩÒѾ¹ýÆÚ¶ø±»Ö´ÐйýµÄ¶¨Ê±Æ÷£¨ÕâЩ¶¨Ê±Æ÷ÍêÈ«¿ÉÒÔ±»¶ªÆú£©£¬ Ò²²»ÊÇÄÇЩҪ¾¹ýºÜ³¤Ê±¼ä²Å»áµ½ÆÚµÄ¶¨Ê±Æ÷£¬¶øÊÇÄÇЩµ±Ç°ÒѾµ½ÆÚ»òÕßÂíÉϾÍÒªµ½ÆÚµÄ¶¨Ê±Æ÷£¨×¢Ò⣡ʱ¼ä¼ä¸ôÊÇÒԵδð´ÎÊýΪ ¼ÆÊýµ¥Î»µÄ£©¡£ »ùÓÚÉÏÊö¿¼ÂÇ£¬²¢¼Ù¶¨Ò»¸ö¶¨Ê±Æ÷Òª¾¹ýinterval¸öʱÖӵδðºó²Åµ½ÆÚ£¨interval£½expires£jiffies£©£¬ÔòLinux²ÉÓÃÁËÏ ÁÐ˼ÏëÀ´ÊµÏÖÆä¶¯Ì¬Äں˶¨Ê±Æ÷»úÖÆ£º¶ÔÓÚÄÇЩ0¡Üinterval¡Ü255µÄ¶¨Ê±Æ÷£¬LinuxÑϸñ°´ÕÕ¶¨Ê±Æ÷ÏòÁ¿µÄ»ù±¾ÓïÒåÀ´×éÖ¯ÕâЩ¶¨Ê± Æ÷£¬Ò²¼´LinuxÄÚºË×î¹ØÐÄÄÇЩÔÚ½ÓÏÂÀ´µÄ255¸öʱÖÓ½ÚÅÄÄÚ¾ÍÒªµ½ÆÚµÄ¶¨Ê±Æ÷£¬Òò´Ë½«ËüÃǰ´ÕÕ¸÷×Ô²»Í¬µÄexpiresÖµ×éÖ¯³É256 ¸ö¶¨Ê±Æ÷ÏòÁ¿¡
|
|
|
|
|
|