����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