����12-18 linux/fs/select.c
1 /*
2 * This file contains the procedures for the handling of select
3 *
4 * Created for Linux based loosely upon Mathius Lattner's minix
5 * patches by Peter MacDonald. Heavily edited by Linus.
6 */
/*
* ���ļ����д���select()ϵͳ���õĹ��̡�
*
* ����Peter MacDonald����Mathius Lattner�ṩ��MINIXϵͳ�IJ���
* �����Ķ��ɡ�
*/
7
8 #include <linux/fs.h>
9 #include <linux/kernel.h>
10 #include <linux/tty.h>
11 #include <linux/sched.h>
12
13 #include <asm/segment.h>
14 #include <asm/system.h>
15
16 #include <sys/stat.h>
17 #include <sys/types.h>
18 #include <string.h>
19 #include <const.h>
20 #include <errno.h>
21 #include <sys/time.h>
22 #include <signal.h>
23
24 /*
25 * Ok, Peter made a complicated, but straightforward multiple_wait() function.
26 * I have rewritten this, taking some shortcuts: This code may not be easy to
27 * follow, but it should be free of race-conditions, and it's practical. If you
28 * understand what I'm doing here, then you understand how the linux sleep/wakeup
29 * mechanism works.
30 *
31 * Two very simple procedures, add_wait() and free_wait() make all the work. We
32 * have to have interrupts disabled throughout the select, but that's not really
33 * such a loss: sleeping automatically frees interrupts when we aren't in this
34 * task.
35 */
/*
* OK��Peter�����˸��ӵ���ֱ�۵Ķ��_wait()�������Ҷ���Щ���������˸�д����ʹ֮
* ����ࣺ��Щ������ܲ�����������������Ӧ�ò�����ھ����������⣬���Һ�ʵ�ʡ�
* �����������������ƵĴ��룬��ô��˵�����Ѿ�����Linux��˯��/���ѵĹ������ơ�
*
* �����ܼĹ��̣�add_wait()��free_wait()ִ������Ҫ������������select����
* ���������Dz��ò���ֹ�жϡ��������������������̫�����ʧ����Ϊ�����Dz���ִ��
* ������ʱ˯��״̬���Զ����ͷ��жϣ������������ʹ���Լ�EFLAGS�е��жϱ�־����
*/
36
37 typedef struct {
38 struct task_struct * old_task;
39 struct task_struct ** wait_address;
40 } wait_entry;
41
42 typedef struct {
43 int nr;
44 wait_entry entry[NR_OPEN*3];
45 } select_table;
46
// ��δ�����������ĵȴ�����ָ�����ȴ���wait_table�С�����*wait_address��������
// ����صĵȴ�����ͷָ�롣����tty���������secondary�ĵȴ�����ͷָ����proc_list��
// ���� p��do_select()�ж���ĵȴ����ṹָ�롣
47 static void add_wait(struct task_struct ** wait_address, select_table * p)
48 {
49 int i;
50
// �����ж��������Ƿ��ж�Ӧ�ĵȴ����У������ء�Ȼ���ڵȴ�������������ָ���ĵȴ�
// ����ָ���Ƿ��Ѿ��ڵȴ��������ù��������ù�Ҳ���̷��ء�����ж���Ҫ����Թܵ��ļ�
// ��������������һ���ܵ��ڵȴ����Խ��ж���������ô��ض��������̽���д������
51 if (!wait_address)
52 return;
53 for (i = 0 ; i < p->nr ; i++)
54 if (p->entry[i].wait_address == wait_address)
55 return;
// Ȼ�����ǰ���������Ӧ�ȴ����е�ͷָ�뱣���ڵȴ���wait_table�У�ͬʱ�õȴ������
// old_task�ֶ�ָ��ȴ�����ͷָ��ָ�������������ΪNULL�������õȴ�����ͷָ��ָ
// ��ǰ�������ѵȴ�����Ч�����ֵnr��1�����ڵ�179�б���ʼ��Ϊ0����
56 p->entry[p->nr].wait_address = wait_address;
57 p->entry[p->nr].old_task = * wait_address;
58 *wait_address = current;
59 p->nr++;
60 }
61
// ��յȴ����������ǵȴ����ṹָ�롣��������do_select()������˯�ߺ��ѷ���ʱ������
// ����204��207�У������ڻ��ѵȴ����д��ڸ����ȴ������ϵ�������������kernel/sched.c
// ��sleep_on()�����ĺ�벿�ִ��뼸����ȫ��ͬ����ο���sleep_on()������˵����
62 static void free_wait(select_table * p)
63 {
64 int i;
65 struct task_struct ** tpp;
66
// ����ȴ����и����nr ����Ч���¼�ĵȴ�����ͷָ��������������������ӽ��ĵȴ�
// ���������������̵��� sleep_on() ������˯���ڸõȴ������ϣ������ʱ�ȴ�����ͷָ��
// ָ��IJ��ǵ�ǰ���̣���ô���Ǿ���Ҫ�Ȼ�����Щ�����������ǽ��ȴ�����ͷ��ָ������
// ��Ϊ����״̬��state = 0���������Լ�����Ϊ�����жϵȴ�״̬�����Լ�Ҫ�ȴ���Щ��������
// �е������Ѷ�ִ��ʱ�����ѱ�����Ȼ������ִ�е��ȳ���
67 for (i = 0; i < p->nr ; i++) {
68 tpp = p->entry[i].wait_address;
69 while (*tpp && *tpp != current) {
70 (*tpp)->state = 0;
71 current->state = TASK_UNINTERRUPTIBLE;
72 schedule();
73 }
// ִ�е����˵���ȴ�����ǰ�������еĵȴ�����ͷָ���ֶ�wait_addressָ��ǰ����
// ����Ϊ�գ���������������⣬������ʾ������Ϣ��Ȼ�������õȴ�����ͷָ��ָ��������
// ǰ�������е�����76�У�������ʱ��ͷָ��ȷʵָ��һ�����������NULL����˵��
// �����л�������*tpp��Ϊ�գ������ǽ����������óɾ���״̬������֮�����ѵȴ�����
// ��Ч��������ֶ�nr���㡣
74 if (!*tpp)
75 printk("free_wait: NULL");
76 if (*tpp = p->entry[i].old_task)
77 (**tpp).state = 0;
78 }
79 p->nr = 0;
80 }
81
// �����ļ�i�ڵ��ж��ļ��Ƿ����ַ��ն��豸�ļ�����������tty�ṹָ�룬����NULL��
82 static struct tty_struct * get_tty(struct m_inode * inode)
83 {
84 int major, minor;
85
// ��������ַ��豸�ļ���NULL��������豸�Ų���5�������նˣ���4����NULL��
86 if (!S_ISCHR(inode->i_mode))
87 return NULL;
88 if ((major = MAJOR(inode->i_zone[0])) != 5 && major != 4)
89 return NULL;
// ������豸����5����ô���ն��豸�ŵ��ڽ��̵�tty�ֶ�ֵ������͵����ַ��豸�ļ����豸�š�
// ����ն��豸��С��0����ʾ����û�п����ն˻�û��ʹ���նˣ����Ƿ���NULL�����ض�Ӧ��
// tty�ṹָ�롣
90 if (major == 5)
91 minor = current->tty;
92 else
93 minor = MINOR(inode->i_zone[0]);
94 if (minor < 0)
95 return NULL;
96 return TTY_TABLE(minor);
97 }
98
99 /*
100 * The check_XX functions check out a file. We know it's either
101 * a pipe, a character device or a fifo (fifo's not implemented)
102 */
/*
* check_XX�������ڼ��һ���ļ�������֪�����ļ�Ҫô�ǹܵ��ļ���
* Ҫô���ַ��豸�ļ�������Ҫô��һ��FIFO��FIFO��δʵ�֣���
*/
// �����ļ������Ƿ����ã����ն˶��������secondary�Ƿ����ַ��ɶ������߹ܵ��ļ��Ƿ�
// ���ա�����wait�ǵȴ���ָ�룻inode���ļ�i�ڵ�ָ�롣���������ɽ��ж�������1����
// ��0��
103 static int check_in(select_table * wait, struct m_inode * inode)
104 {
105 struct tty_struct * tty;
106
// ���ȸ����ļ�i�ڵ����get_tty()����ļ��Ƿ���һ��tty�նˣ��ַ����豸�ļ����������
// �����ն˶��������secondary���Ƿ����ַ��ɹ���ȡ��������1������ʱsecondaryΪ
// ����ѵ�ǰ�������ӵ�secondary�ĵȴ�����proc_list�ϲ�����0������ǹܵ��ļ������ж�
// Ŀǰ�ܵ����Ƿ����ַ��ɶ���������1����û�У��ܵ��գ���ѵ�ǰ�������ӵ��ܵ�i�ڵ�
// �ĵȴ������ϲ�����0��ע�⣬PIPE_EMPTY()��ʹ�ùܵ���ǰͷβָ��λ�����жϹܵ��Ƿ�ա�
// �ܵ�i�ڵ��i_zone[0]��i_zone[1]�ֶηֱ����Źܵ���ǰ��ͷβָ�롣
107 if (tty = get_tty(inode))
108 if (!EMPTY(tty->secondary))
109 return 1;
110 else
111 add_wait(&tty->secondary->proc_list, wait);
112 else if (inode->i_pipe)
113 if (!PIPE_EMPTY(*inode))
114 return 1;
115 else
116 add_wait(&inode->i_wait, wait);
117 return 0;
118 }
119
// ����ļ�д�����Ƿ����ã����ն�д�������write_q���Ƿ��п���λ�ÿ�д�����ߴ�ʱ��
// ���ļ��Ƿ���������wait�ǵȴ���ָ�룻inode���ļ�i�ڵ�ָ�롣���������ɽ���д������
// ����1������0��
120 static int check_out(select_table * wait, struct m_inode * inode)
121 {
122 struct tty_struct * tty;
123
// ���ȸ����ļ�i�ڵ����get_tty()����ļ��Ƿ���һ��tty�նˣ��ַ����豸�ļ����������
// �����ն�д�������write_q���Ƿ��пռ��д�룬������1����û�пտռ���ѵ�ǰ��
// �����ӵ�write_q�ĵȴ�����proc_list�ϲ�����0������ǹܵ��ļ����ж�Ŀǰ�ܵ����Ƿ���
// ���пռ��д���ַ���������1����û�У��ܵ�������ѵ�ǰ�������ӵ��ܵ�i�ڵ�ĵȴ�
// �����ϲ�����0��
124 if (tty = get_tty(inode))
125 if (!FULL(tty->write_q))
126 return 1;
127 else
128 add_wait(&tty->write_q->proc_list, wait);
129 else if (inode->i_pipe)
130 if (!PIPE_FULL(*inode))
131 return 1;
132 else
133 add_wait(&inode->i_wait, wait);
134 return 0;
135 }
136
// ����ļ��Ƿ����쳣״̬�������ն��豸�ļ���Ŀǰ�ں����Ƿ���0�����ڹܵ��ļ������
// ��ʱ�����ܵ�����������һ�����ѱ��رգ���1������Ͱѵ�ǰ�������ӵ��ܵ�i�ڵ�
// �ĵȴ������ϲ�����0������0������wait�ǵȴ���ָ�룻inode���ļ�i�ڵ�ָ�롣������
// �쳣������1������0��
137 static int check_ex(select_table * wait, struct m_inode * inode)
138 {
139 struct tty_struct * tty;
140
141 if (tty = get_tty(inode))
142 if (!FULL(tty->write_q))
143 return 0;
144 else
145 return 0;
146 else if (inode->i_pipe)
147 if (inode->i_count < 2)
148 return 1;
149 else
150 add_wait(&inode->i_wait,wait);
151 return 0;
152 }
153
// do_select() ���ں�ִ��select()ϵͳ���õ�ʵ�ʴ����������ú������ȼ�����������и���
// ����������Ч�ԣ�Ȼ��ֱ�����������������������麯��check_XX()��ÿ�����������м�
// �飬ͬʱͳ�����������е�ǰ�Ѿ����õ������������������κ�һ���������Ѿ����ã���
// �����ͻ����̷��أ�������̾ͻ��ڱ������н���˯��״̬�����ڹ��˳�ʱʱ���������ij��
// ���������ڵȴ������ϵĽ��̱����Ѷ�ʹ�����̼������С�
154 int do_select(fd_set in, fd_set out, fd_set ex,
155 fd_set *inp, fd_set *outp, fd_set *exp)
156 {
157 int count; // �����õ���������������ֵ��
158 select_table wait_table; // �ȴ����ṹ��
159 int i;
160 fd_set mask;
161
// ���Ȱ�3�������������л��������mask�еõ�������������Ч����������λ�����롣 Ȼ��
// ѭ���жϵ�ǰ���̸����������Ƿ���Ч���Ұ��������������ڡ���ѭ���У�ÿ�ж���һ������
// ���ͻ��mask����1λ����˸���mask�������Ч����λ���ǾͿ����ж���Ӧ�������Ƿ���
// �û����������������С���Ч��������Ӧ����һ���ܵ��ļ���������������һ���ַ��豸�ļ�
// ��������������һ��FIFO���������������͵Ķ���Ϊ��Ч������������EBADF����
162 mask = in | out | ex;
163 for (i = 0 ; i < NR_OPEN ; i++,mask >>= 1) {
164 if (!(mask & 1)) // ����������������������ж���һ����
165 continue;
166 if (!current->filp[i]) // �����ļ�δ��������������
167 return -EBADF;
168 if (!current->filp[i]->f_inode) // ���ļ�i�ڵ�ָ��գ��ش���š�
169 return -EBADF;
170 if (current->filp[i]->f_inode->i_pipe) // ���ǹܵ��ļ�������������Ч��
171 continue;
172 if (S_ISCHR(current->filp[i]->f_inode->i_mode)) // �ַ��豸�ļ���Ч��
173 continue;
174 if (S_ISFIFO(current->filp[i]->f_inode->i_mode)) // FIFOҲ��Ч��
175 continue;
176 return -EBADF; // �����Ϊ��Ч�����������ء�
177 }
// ���濪ʼѭ�����3�����������еĸ����������Ƿ����ã����Բ���������ʱmask������ǰ
// ���ڴ����������������롣ѭ���е�3������check_in()��check_out()��check_ex()�ֱ���
// ���ж��������Ƿ��Ѿ����á���һ���������Ѿ����ã���������������������ö�Ӧ����
// λ�����Ұ���������������������ֵcount��1����183��forѭ������е� mask += mask
// ���� mask<< 1��
178 repeat:
179 wait_table.nr = 0;
180 *inp = *outp = *exp = 0;
181 count = 0;
182 mask = 1;
183 for (i = 0 ; i < NR_OPEN ; i++, mask += mask) {
// �����ʱ�жϵ��������ڶ��������������У����Ҹ��������Ѿ����ÿ��Խ��ж����������
// ������������������in�ж�Ӧ����λ��Ϊ1��ͬʱ����������������������ֵcount��1��
184 if (mask & in)
185 if (check_in(&wait_table,current->filp[i]->f_inode)) {
186 *inp |= mask; // �������������ö�Ӧ����λ��
187 count++; // ����������������������
188 }
// �����ʱ�жϵ���������д�������������У����Ҹ��������Ѿ����ÿ��Խ���д���������
// ������������������out�ж�Ӧ����λ��Ϊ1��ͬʱ����������������������ֵcount��1��
189 if (mask & out)
190 if (check_out(&wait_table,current->filp[i]->f_inode)) {
191 *outp |= mask;
192 count++;
193 }
// �����ʱ�жϵ����������쳣���������У����Ҹ��������Ѿ����쳣���֣���Ѹ�����������
// ������ex�ж�Ӧ����λ��Ϊ1��ͬʱ����������������������ֵcount��1��
194 if (mask & ex)
195 if (check_ex(&wait_table,current->filp[i]->f_inode)) {
196 *exp |= mask;
197 count++;
198 }
199 }
// �ڶԽ��������������жϴ���������û�з����������õ���������count==0�������Ҵ�ʱ
// ����û���յ��κη������źţ����Ҵ�ʱ�еȴ��ŵ����������ߵȴ�ʱ�仹û�г�ʱ����ô��
// �ǾͰѵ�ǰ����״̬���óɿ��ж�˯��״̬��Ȼ��ִ�е��Ⱥ���ȥִ�����������ں���һ
// �ε���ִ�б�����ʱ�͵���free_wait()������صȴ������ϱ�����ǰ�������Ȼ����ת��
// repeat��Ŵ���178�У��ٴ����¼���Ƿ������ǹ��ĵģ����������еģ������������á�
200 if (!(current->signal & ~current->blocked) &&
201 (wait_table.nr || current->timeout) && !count) {
202 current->state = TASK_INTERRUPTIBLE;
203 schedule();
204 free_wait(&wait_table); // �������ѷ��غ�����↑ʼִ�С�
205 goto repeat;
206 }
// �����ʱcount������0�����߽��յ����źţ����ߵȴ�ʱ�䵽����û����Ҫ�ȴ�����������
// ��ô���Ǿ͵���free_wait()���ѵȴ������ϵ�����Ȼ�������õ�����������ֵ��
207 free_wait(&wait_table);
208 return count;
209 }
210
211 /*
212 * Note that we cannot return -ERESTARTSYS, as we change our input
213 * parameters. Sad, but there you are. We could do some tweaking in
214 * the library function ...
215 */
/*
* ע�����Dz��ܷ���-ERESTARTSYS����Ϊ���ǻ���select���й����иı�
* �������ֵ��*timeout�����ܲ��ң�����Ҳֻ�ܽ��������ʵ����������
* �����ڿ⺯������Щ����...
*/
// selectϵͳ���ú������ú����еĴ�����Ҫ�������select���ܲ���ǰ��IJ������ƺ�ת��
// ������select��Ҫ�Ĺ�����do_select()��������ɡ�sys_select()�����ȸ��ݲ�����������
// ������ָ����û����ݿռ�� select() �������õIJ����ֽ⸴�Ƶ��ں˿ռ䣬Ȼ��������Ҫ
// �ȴ��ij�ʱʱ��ֵtimeout�����ŵ���do_select() ִ�� select���ܣ����غ�ͰѴ������
// �ٸ��ƻ��û��ռ��С�
// ����bufferָ���û���������select()�����ĵ�1�����������������ֵС��0��ʾִ��ʱ
// ���ִ����������ֵ����0�����ʾ�ڹ涨�ȴ�ʱ����û�����������ò������������ֵ
// ����0�����ʾ�����õ�������������
216 int sys_select( unsigned long *buffer )
217 {
218 /* Perform the select(nd, in, out, ex, tv) system call. */
/* ִ��select(nd, in, out, ex, tv)ϵͳ���� */
// ���ȶ��弸���ֲ����������ڰ�ָ�������������select()���������ֽ����
219 int i;
220 fd_set res_in, in = 0, *inp; // ����������������
221 fd_set res_out, out = 0, *outp; // �������������
222 fd_set res_ex, ex = 0, *exp; // �쳣��������������
223 fd_set mask; // ��������������ֵ��Χ��nd�������롣
224 struct timeval *tvp; // �ȴ�ʱ��ṹָ�롣
225 unsigned long timeout;
226
// Ȼ����û��������Ѳ����ֱ���븴�Ƶ��ֲ�ָ������У���������������ָ���Ƿ���Ч�ֱ�
// ȡ��3����������in��������out��д����ex���쳣�������� mask Ҳ��һ����������������
// ����3�����������������������ֵ+1������1������nd��ֵ�����������ó��û�������ĵ�
// �����������������롣���磬��nd = 4����mask = 0b00001111����32���أ���
227 mask = ~((~0) << get_fs_long(buffer++));
228 inp = (fd_set *) get_fs_long(buffer++);
229 outp = (fd_set *) get_fs_long(buffer++);
230 exp = (fd_set *) get_fs_long(buffer++);
231 tvp = (struct timeval *) get_fs_long(buffer);
232
233 if (inp) // ��ָ����Ч����ȡ����������������
234 in = mask & get_fs_long(inp);
235 if (outp) // ��ָ����Ч����ȡд��������������
236 out = mask & get_fs_long(outp);
237 if (exp) // ��ָ����Ч����ȡ�쳣����������
238 ex = mask & get_fs_long(exp);
// ���������dz��Դ�ʱ��ṹ��ȡ���ȴ���˯�ߣ�ʱ��ֵtimeout�����Ȱ�timeout��ʼ�������
// �����ޣ�ֵ��Ȼ����û����ݿռ�ȡ�ø�ʱ��ṹ�����õ�ʱ��ֵ����ת���ͼ���ϵͳ��ǰ�δ�
// ֵjiffies�����õ���Ҫ�ȴ���ʱ��δ���ֵ timeout�������ô�ֵ�����õ�ǰ����Ӧ�õȴ�
// ����ʱ�����⣬��241����tv_usec�ֶ�����ֵ����������1000000��ɵõ���Ӧ�������ٳ�
// ��ϵͳÿ��δ���HZ������tv_usecת���ɵδ�ֵ��
239 timeout = 0xffffffff;
240 if (tvp) {
241 timeout = get_fs_long((unsigned long *)&tvp->tv_usec)/(1000000/HZ);
242 timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ;
243 timeout += jiffies;
244 }
245 current->timeout = timeout; // ���õ�ǰ����Ӧ����ʱ�ĵδ�ֵ��
// select()��������Ҫ������do_select()����ɡ��ڵ��øú���֮��Ĵ������ڰѴ����������
// ���û��������У����ظ��û���Ϊ�˱�����־����������ڵ���do_select()ǰ��Ҫ��ֹ�жϣ�
// ���ڸú������غ��ٿ����жϡ�
// �����do_select()����֮����̵ĵȴ���ʱ�ֶ�timeout�����ڵ�ǰϵͳ��ʱ�δ�ֵjiffies��
// ˵���ڳ�ʱ֮ǰ�Ѿ������������ã��������������ȼ��µ���ʱ��ʣ���ʱ��ֵ��������ǻ�
// �����ֵ���ظ��û���������̵ĵȴ���ʱ�ֶ�timeout�Ѿ�С�ڻ���ڵ�ǰϵͳjiffies����
// ʾdo_select()���������ڳ�ʱ�����أ���˰�ʣ��ʱ��ֵ����Ϊ0��
246 cli(); // ��ֹ��Ӧ�жϡ�
247 i = do_select(in, out, ex, &res_in, &res_out, &res_ex);
248 if (current->timeout > jiffies)
249 timeout = current->timeout - jiffies;
250 else
251 timeout = 0;
252 sti(); // �����ж���Ӧ��
// ���������ǰѽ��̵ij�ʱ�ֶ����㡣���do_select()���ص�����������������С��0����ʾ
// ִ�г��������Ƿ����������š�Ȼ�����ǰѴ������������������ݺ��ӳ�ʱ��ṹ����д�ص�
// �û����ݻ���ռ䡣��дʱ��ṹ����ʱ����Ҫ�Ƚ��δ�ʱ�䵥λ��ʾ��ʣ���ӳ�ʱ��ת������
// ����ֵ��
253 current->timeout = 0;
254 if (i < 0)
255 return i;
256 if (inp) {
257 verify_area(inp, 4);
258 put_fs_long(res_in,inp); // �ɶ�����������
259 }
260 if (outp) {
261 verify_area(outp,4);
262 put_fs_long(res_out,outp); // �����������
263 }
264 if (exp) {
265 verify_area(exp,4);
266 put_fs_long(res_ex,exp); // �����쳣��������������
267 }
268 if (tvp) {
269 verify_area(tvp, sizeof(*tvp));
270 put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec); // �롣
271 timeout %= HZ;
272 timeout *= (1000000/HZ);
273 put_fs_long(timeout, (unsigned long *) &tvp->tv_usec); // �롣
274 }
// �����ʱ��û�������õ��������������յ���ij���������źţ��ر��жϴ���š�
// ���������õ�����������ֵ��
275 if (!i && (current->signal & ~current->blocked))
276 return -EINTR;
277 return i;
278 }
279