1
vim:ft=cpp
2
3 @ 개요 4 wait_queue 설명 5 6 @ wait_queue 7 어떤 일이 발생할때 깨어날 task(process)를 저장하는 queue. 8 9 동일한 커널함수(코드)가 여러 task에 의해 실행될수 있어 어떤 조건을 10 만족할때까지 여러개의 task를 보류했다가 조건 발생시 task를 실행하기 위해 사용. 11 12 A constext에서 schdule()를 호출하게 되면 context는 다른 task로 넘어가게 되는데 13 A를 어떤일이 발생하면 다시 실행(TASK_RUNNING)으로 만들기 위해 wait queue를 사용한다. 14 15 A context에서 schedule()를 호출하기전 자신을 깨어날 조건 (TASK_INTERRUPTIBLEE등) 16 으로 변경한후 wait_queue 에 추가한다. 그리고 schedule()를 호출하여 context를 17 다른 task로 넘긴다. 다른 task실행중 A task가 깨어날 조건 (interrupt등)이 발생되면 18 관련함수(코드)가 실행되고 이곳에서 wake_up_xxx()함수를 호출하여 wait_queue의 19 task를 깨운다(TASK_RUNNING으로 변경). 20 그러면 A task의 schedule()아래 코드부터 다시 실행된다. 21 이때 주의할것이 22 - A task의 schedule()아래에서 remove_wait_queue()를 호출하여 23 wait_queue에서 자신을 (A task)를 제거해야 한다. 24 25 - add_wait_queue(), remove_wait_queue(), wake_up_xxx()에 인자로 넘어가는 26 wait_queue는 동일한 instance이다. 27 28 @ 용법 29 30 - wait 시작하는 함수 31 DECLARE_WAITQUEUE(wait, current); 32 add_wait_queue(&gQName, &wait); 33 set_current_state(TASK_INTERRUPTIBLEE); 34 schedule_timeout(timeout); 35 current->state = TASK_RUNNING; 36 remove_wait_queue(&gQName, &wait); 37 38 void tty_wait_until_sent(struct tty_struct * tty, long timeout) 39 { 40 DECLARE_WAITQUEUE(wait, current); 41 42 ... 43 add_wait_queue(&tty->write_wait, &wait); 44 if (!timeout) 45 timeout = MAX_SCHEDULE_TIMEOUT; 46 do { 47 ... 48 set_current_state(TASK_INTERRUPTIBLE); 49 ... 50 timeout = schedule_timeout(timeout); 51 } while (timeout); 52 if (tty->driver.wait_until_sent) 53 tty->driver.wait_until_sent(tty, timeout); // <- wait에서 깨어나서 해야할 일 54 stop_waiting: 55 current->state = TASK_RUNNING; 56 remove_wait_queue(&tty->write_wait, &wait); 57 } 58 59 - wait를 깨우는 함수 60 wake_up_interruptible(&gQName); 61 62 /* 63 * This can be called through the "tq_scheduler" 64 * task-list. That is process synchronous, but 65 * doesn't hold any locks, so we need to make 66 * sure we have the appropriate locks for what 67 * we're doing.. 68 */ 69 void do_tty_hangup(void *data) 70 { 71 ... 72 wake_up_interruptible(&tty->write_wait); 73 wake_up_interruptible(&tty->read_wait); 74 ... 75 } 76 77 @ wake_up_interruptible() 78 wait_queue list에서 TASK_INTERRUPTIBLEE로 설정된 79 task를 TASK_RUNNING로 변경 하고 add_to_runqueue()호출 80 81 #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) 82 #define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE) 83 #define wake_up_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) 84 #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) 85 #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE) 86 #define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE | TASK_EXCLUSIVE) 87 88 void __wake_up(wait_queue_head_t *q, unsigned int mode) 89 { 90 __wake_up_common(q, mode, 0); 91 } 92 93 static inline void __wake_up_common(wait_queue_head_t *q, unsigned int mode, const int sync) 94 { 95 struct list_head *tmp, *head; 96 struct task_struct *p; 97 unsigned long flags; 98 ... 99 list_for_each(tmp, head) { 100 unsigned int state; 101 wait_queue_t *curr = list_entry(tmp, wait_queue_t, task_list); 102 103 #if WAITQUEUE_DEBUG 104 CHECK_MAGIC(curr->__magic); 105 #endif 106 p = curr->task; 107 state = p->state; 108 if (state & (mode & ~TASK_EXCLUSIVE)) { 109 #if WAITQUEUE_DEBUG 110 curr->__waker = (long)__builtin_return_address(0); 111 #endif 112 if (sync) 113 wake_up_process_synchronous(p); 114 else 115 wake_up_process(p); 116 if (state & mode & TASK_EXCLUSIVE) 117 break; 118 } 119 } 120 wq_write_unlock_irqrestore(&q->lock, flags); 121 out: 122 return; 123 } 124 125 /* 126 * Wake up a process. Put it on the run-queue if it's not 127 * already there. The "current" process is always on the 128 * run-queue (except when the actual re-schedule is in 129 * progress), and as such you're allowed to do the simpler 130 * "current->state = TASK_RUNNING" to mark yourself runnable 131 * without the overhead of this. 132 */ 133 inline void wake_up_process(struct task_struct * p) 134 { 135 unsigned long flags; 136 137 /* 138 * We want the common case fall through straight, thus the goto. 139 */ 140 spin_lock_irqsave(&runqueue_lock, flags); 141 p->state = TASK_RUNNING; 142 if (task_on_runqueue(p)) 143 goto out; 144 add_to_runqueue(p); 145 reschedule_idle(p, flags); // spin_unlocks runqueue 146 147 return; 148 out: 149 spin_unlock_irqrestore(&runqueue_lock, flags); 150 } 151 152 /* 153 * Careful! 154 * 155 * This has to add the process to the _beginning_ of the 156 * run-queue, not the end. See the comment about "This is 157 * subtle" in the scheduler proper.. 158 */ 159 static inline void add_to_runqueue(struct task_struct * p) 160 { 161 list_add(&p->run_list, &runqueue_head); 162 nr_running++; 163 }

[출처] wait Queue|작성자 달려라


'Developer's Infos > Linux Programming' 카테고리의 다른 글

PCI 드라이버(PCI-Driver)  (0) 2011.10.12
pci-driver  (0) 2011.10.10
__attribute__  (0) 2011.10.10
[Linux] asmlinkage  (0) 2011.09.30
[Shared Memory] shmget() 공유 메모리 생성  (0) 2011.09.06
Posted by 삼성동고양이