freezable_schedule 의 역할이 무엇인가요?

CVE 2015.02.23 08:31 조회 수 : 2825

freezable 또는 freezer 등의 단어가 많이 보이는데 이게 무엇을 의미하는지 모르겠네요...

 

좀 더 구체적인 질문은 이렇습니다.

 

futex_wait_requeue_pi 의 소스코드를 보고 있는데, 이 함수가 uaddr1 -> uaddr2 로 requeue

되기 전까지 계속 wait 상태에 들어가는데 그 코드가

 

static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
2546                                  u32 val, ktime_t *abs_time, u32 bitset,
2547                                  u32 __user *uaddr2)
2548 {
2549         struct hrtimer_sleeper timeout, *to = NULL;
2550         struct rt_mutex_waiter rt_waiter;
2551         struct rt_mutex *pi_mutex = NULL;
2552         struct futex_hash_bucket *hb;
2553         union futex_key key2 = FUTEX_KEY_INIT;
2554         struct futex_q q = futex_q_init;
2555         int res, ret;
2556
2557         if (uaddr == uaddr2)
2558                 return -EINVAL;
2559
2560         if (!bitset)
2561                 return -EINVAL;
2562
2563         if (abs_time) {
2564                 to = &timeout;
2565                 hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?
2566                                       CLOCK_REALTIME : CLOCK_MONOTONIC,
2567                                       HRTIMER_MODE_ABS);
2568                 hrtimer_init_sleeper(to, current);
2569                 hrtimer_set_expires_range_ns(&to->timer, *abs_time,
2570                                              current->timer_slack_ns);
2571         }
2572
2573         /*
2574 * The waiter is allocated on our stack, manipulated by the requeue
2575 * code while we sleep on uaddr.
2576 */
2577         debug_rt_mutex_init_waiter(&rt_waiter);
2578         RB_CLEAR_NODE(&rt_waiter.pi_tree_entry);
2579         RB_CLEAR_NODE(&rt_waiter.tree_entry);
2580         rt_waiter.task = NULL;
2581
2582         ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE);
2583         if (unlikely(ret != 0))
2584                 goto out;
2585
2586         q.bitset = bitset;
2587         q.rt_waiter = &rt_waiter;
2588         q.requeue_pi_key = &key2;
2589
2590         /*
2591 * Prepare to wait on uaddr. On success, increments q.key (key1) ref
2592 * count.
2593 */
2594         ret = futex_wait_setup(uaddr, val, flags, &q, &hb);
2595         if (ret)
2596                 goto out_key2;
2597
2598         /*
2599 * The check above which compares uaddrs is not sufficient for
2600 * shared futexes. We need to compare the keys:
2601 */
2602         if (match_futex(&q.key, &key2)) {
2603                 queue_unlock(hb);
2604                 ret = -EINVAL;
2605                 goto out_put_keys;
2606         }
2607
2608         /* Queue the futex_q, drop the hb lock, wait for wakeup. */
2609         futex_wait_queue_me(hb, &q, to);

 

저 위의 futex_wait_queue_me 에서 큐에 현재 uaddr1 / uaddr2 에 대한 정보를

넣고 대기로 빠지는 것으로 알고 있습니다.

 

그런데 futex_wait_queue_me 코드를 보면

 

 

2053 static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,
2054                                 struct hrtimer_sleeper *timeout)
2055 {
2056         /*
2057 * The task state is guaranteed to be set before another task can
2058 * wake it. set_current_state() is implemented using set_mb() and
2059 * queue_me() calls spin_unlock() upon completion, both serializing
2060 * access to the hash list and forcing another memory barrier.
2061 */
2062         set_current_state(TASK_INTERRUPTIBLE);
2063         queue_me(q, hb);
2064
2065         /* Arm the timer */
2066         if (timeout) {
2067                 hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);
2068                 if (!hrtimer_active(&timeout->timer))
2069                         timeout->task = NULL;
2070         }
2071
2072         /*
2073 * If we have been removed from the hash list, then another task
2074 * has tried to wake us, and we can skip the call to schedule().
2075 */
2076         if (likely(!plist_node_empty(&q->list))) {
2077                 /*
2078 * If the timer has already expired, current will already be
2079 * flagged for rescheduling. Only call schedule if there
2080 * is no timeout, or if it has yet to expire.
2081 */
2082                 if (!timeout || timeout->task)
2083                         freezable_schedule();
2084         }
2085         __set_current_state(TASK_RUNNING);
2086 }

특별히 루프나 그런 건 없고, 그냥 freezable_schedule() 함수를 호출하고 있습니다.

그럼 이 함수 호출 후에, 어떤 특정 신호를 받거나 할 때까지 이 태스크는 계속 대기한다는

의미인데 원래 schedule() 함수는 스케줄링을 한 다음 다른 태스크에서 다시 현재 태스크로

스케줄링할 수도 있으니 계속 대기가 아니라 다음 스케줄링까지만 대기(?) 를 하게 되는걸로 알고 있는데

저 freezable_schedule 함수는 한 번 호출하면 계속 대기를 하는 건가요?

 

아예 스케줄링 큐에서 빠지는 함수인지, 그러면 다시 다른 태스크에서 현재 태스크를 스케줄링 큐에

넣을때까지는 계속 대기하는 원리라서 futex_cmp_requeue_pi (futex_requeue) 에서 특정 uaddr1 / uaddr2 에 대해

대기하고 있는 waiter 가 있으면 그 waiter 의 태스크를 다시 스케줄링 큐에 넣어준다던지 하는 게 있는 건가요?

 

 

저 freezable_schedule 의 코드를 보면, 커널 컴파일시에 CONFIG_FREEZER 라는 옵션이 만약 n 이면

그냥 schedule() 로 치환이 되고(저런 옵션은 본 적이 없지만..) y 인 경우는 아래처럼

 

168 static inline void freezable_schedule(void)
169 {
170         freezer_do_not_count();
171         schedule();
172         freezer_count();
173 }

이렇게 되고, freezer_do_not_count 가 무엇인지 보니

 

106 static inline void freezer_do_not_count(void)
107 {
108         current->flags |= PF_FREEZER_SKIP;
109 }

그냥 현재 태스크(thread_info) 의 flags 에 PF_FREEZER_SKIP 이라는 플래그를

설정해주는데.. 이게 무슨 역할을 하는 플래그인지 모르겠네요..

스케줄러 소스코드에서 이 플래그를 가지고 뭔가 하는거라도 있어야되는데 찾아보니

그것도 없고 그냥 /kernel/hung_task.c 에서만 뭔가 하거나 freezer.h 에만 조금 뭐 있는거같고.. 

 

 

음.. 질문이 좀 말이 어수선하게 되었는데 그냥 freezable_schedule() 이 하는 일이 무엇인지가 궁금합니다..

freezing 이란 말의 의미로 봐서는 말 그대로 태스크를 프리징시킨다 = 스케줄링하지 않는다 정도인거 같긴 한데..

찾아보면 꼭 그런거같지도 않고... 답변 부탁드리겠습니다.

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 프로그래밍 관련 Q&A 게시판 입니다. woos 2016.04.09 23335
» freezable_schedule 의 역할이 무엇인가요? [2] CVE 2015.02.23 2825
438 raw device에 random write를 보내고 싶습니다. ysh 2015.01.29 6312
437 커널 이미지가 올라가는 물리 메모리의 시작주소는 어디일까요? shepherd44 2015.01.07 1977
436 메모리 페이지 테이블에 관란 질문입니다.(TTBR0, TTBR1) 김영민 2014.12.16 2465
435 리눅스 커널 내부구조 소스 키보드 LED예제중 에러문제 천하무적주석 2014.12.11 1880
434 TX timestamp 관련 질문 정재훈 2014.11.04 2257
433 ioremap 관련해서 질문드립니다. [1] ysh 2014.10.29 2593
432 안녕하세요. 쓰레드에 관련하여 질문이 있습니다. 송창인 2014.10.22 1643
431 리눅스에서 지원하는 priority inheritance futex 에 대해서 질문입니다. CVE 2014.10.13 2392
430 mmap하여 read,write에 관한 질문입니다. [1] ysh 2014.10.08 2254
429 NAND ERASE 할 때 BLOCK 단위로 지우지 않는 방법 있을까요 ? [1] 최고운 2014.10.02 1867
428 atomic_read, atomic_add 시 interrupt disable, restore 가 필요한지.. [4] YYS 2014.10.02 3932
427 32bit 운영체제 resistor가 double형 변수처리하는 방법 구자경 2014.09.25 1628
426 안드로이드 포팅 질문드려요. [1] shepherd44 2014.09.18 2045
425 compressed/head.s 에서 LC0: 코드 관련 [1] erasmooth 2014.09.17 1898
424 "코드로 알아보는 ARM 리눅스 커널" 책에서...(초판 2쇄) erasmooth 2014.09.17 2349
423 boot.bin 파일을 부팅하는 usb를 만들고 싶습니다. 마고 2014.09.16 1894
422 리눅스에서 local APIC 타이머 레지스터 사용 질문드립니다. it876 2014.09.15 2151
421 __mmap_switched 레이블 전후로 PIC 에서 절대주소로 전환되는 원리 [1] erasmooth 2014.09.12 1923
420 qemu에 커널을 올릴 때 에러가 발생합니다. [3] ysh 2014.09.10 2259
XE Login