1 | /* Implement entry point to select system call.
|
---|
2 | *
|
---|
3 | * The entry points into this file are
|
---|
4 | * do_select: perform the SELECT system call
|
---|
5 | * select_callback: notify select system of possible fd operation
|
---|
6 | * select_notified: low-level entry for device notifying select
|
---|
7 | *
|
---|
8 | * Changes:
|
---|
9 | * 6 june 2005 Created (Ben Gras)
|
---|
10 | */
|
---|
11 |
|
---|
12 | #include "fs.h"
|
---|
13 | #include "select.h"
|
---|
14 | #include "file.h"
|
---|
15 | #include "inode.h"
|
---|
16 |
|
---|
17 | #include <sys/time.h>
|
---|
18 | #include <sys/select.h>
|
---|
19 | #include <minix/com.h>
|
---|
20 | #include <string.h>
|
---|
21 |
|
---|
22 | /* max. number of simultaneously pending select() calls */
|
---|
23 | #define MAXSELECTS 25
|
---|
24 |
|
---|
25 | PRIVATE struct selectentry {
|
---|
26 | struct fproc *requestor; /* slot is free iff this is NULL */
|
---|
27 | int req_procnr;
|
---|
28 | fd_set readfds, writefds, errorfds;
|
---|
29 | fd_set ready_readfds, ready_writefds, ready_errorfds;
|
---|
30 | fd_set *vir_readfds, *vir_writefds, *vir_errorfds;
|
---|
31 | struct filp *filps[FD_SETSIZE];
|
---|
32 | int type[FD_SETSIZE];
|
---|
33 | int nfds, nreadyfds;
|
---|
34 | clock_t expiry;
|
---|
35 | timer_t timer; /* if expiry > 0 */
|
---|
36 | } selecttab[MAXSELECTS];
|
---|
37 |
|
---|
38 | #define SELFD_FILE 0
|
---|
39 | #define SELFD_PIPE 1
|
---|
40 | #define SELFD_TTY 2
|
---|
41 | #define SELFD_INET 3
|
---|
42 | #define SELFD_LOG 4
|
---|
43 | #define SEL_FDS 5
|
---|
44 |
|
---|
45 | FORWARD _PROTOTYPE(int select_reevaluate, (struct filp *fp));
|
---|
46 |
|
---|
47 | FORWARD _PROTOTYPE(int select_request_file,
|
---|
48 | (struct filp *f, int *ops, int block));
|
---|
49 | FORWARD _PROTOTYPE(int select_match_file, (struct filp *f));
|
---|
50 |
|
---|
51 | FORWARD _PROTOTYPE(int select_request_general,
|
---|
52 | (struct filp *f, int *ops, int block));
|
---|
53 | FORWARD _PROTOTYPE(int select_major_match,
|
---|
54 | (int match_major, struct filp *file));
|
---|
55 |
|
---|
56 | FORWARD _PROTOTYPE(void select_cancel_all, (struct selectentry *e));
|
---|
57 | FORWARD _PROTOTYPE(void select_wakeup, (struct selectentry *e));
|
---|
58 |
|
---|
59 | /* The Open Group:
|
---|
60 | * "The pselect() and select() functions shall support
|
---|
61 | * regular files, terminal and pseudo-terminal devices,
|
---|
62 | * STREAMS-based files, FIFOs, pipes, and sockets."
|
---|
63 | */
|
---|
64 |
|
---|
65 | PRIVATE struct fdtype {
|
---|
66 | int (*select_request)(struct filp *, int *ops, int block);
|
---|
67 | int (*select_match)(struct filp *);
|
---|
68 | int select_major;
|
---|
69 | } fdtypes[SEL_FDS] = {
|
---|
70 | /* SELFD_FILE */
|
---|
71 | { select_request_file, select_match_file, 0 },
|
---|
72 | /* SELFD_TTY (also PTY) */
|
---|
73 | { select_request_general, NULL, TTY_MAJOR },
|
---|
74 | /* SELFD_INET */
|
---|
75 | { select_request_general, NULL, INET_MAJOR },
|
---|
76 | /* SELFD_PIPE (pipe(2) pipes and FS FIFOs) */
|
---|
77 | { select_request_pipe, select_match_pipe, 0 },
|
---|
78 | /* SELFD_LOG (/dev/klog) */
|
---|
79 | { select_request_general, NULL, LOG_MAJOR },
|
---|
80 | };
|
---|
81 |
|
---|
82 | /* Open Group:
|
---|
83 | * "File descriptors associated with regular files shall always select true
|
---|
84 | * for ready to read, ready to write, and error conditions."
|
---|
85 | */
|
---|
86 |
|
---|
87 | /*===========================================================================*
|
---|
88 | * select_request_file *
|
---|
89 | *===========================================================================*/
|
---|
90 | PRIVATE int select_request_file(struct filp *f, int *ops, int block)
|
---|
91 | {
|
---|
92 | /* output *ops is input *ops */
|
---|
93 | return SEL_OK;
|
---|
94 | }
|
---|
95 |
|
---|
96 | /*===========================================================================*
|
---|
97 | * select_match_file *
|
---|
98 | *===========================================================================*/
|
---|
99 | PRIVATE int select_match_file(struct filp *file)
|
---|
100 | {
|
---|
101 | if (file && file->filp_ino && (file->filp_ino->i_mode & I_REGULAR))
|
---|
102 | return 1;
|
---|
103 | return 0;
|
---|
104 | }
|
---|
105 |
|
---|
106 | /*===========================================================================*
|
---|
107 | * select_request_general *
|
---|
108 | *===========================================================================*/
|
---|
109 | PRIVATE int select_request_general(struct filp *f, int *ops, int block)
|
---|
110 | {
|
---|
111 | int rops = *ops;
|
---|
112 | if (block) rops |= SEL_NOTIFY;
|
---|
113 | *ops = dev_io(DEV_SELECT, f->filp_ino->i_zone[0], rops, NULL, 0, 0, 0);
|
---|
114 | if (*ops < 0)
|
---|
115 | return SEL_ERR;
|
---|
116 | return SEL_OK;
|
---|
117 | }
|
---|
118 |
|
---|
119 | /*===========================================================================*
|
---|
120 | * select_major_match *
|
---|
121 | *===========================================================================*/
|
---|
122 | PRIVATE int select_major_match(int match_major, struct filp *file)
|
---|
123 | {
|
---|
124 | int major;
|
---|
125 | if (!(file && file->filp_ino &&
|
---|
126 | (file->filp_ino->i_mode & I_TYPE) == I_CHAR_SPECIAL))
|
---|
127 | return 0;
|
---|
128 | major = (file->filp_ino->i_zone[0] >> MAJOR) & BYTE;
|
---|
129 | if (major == match_major)
|
---|
130 | return 1;
|
---|
131 | return 0;
|
---|
132 | }
|
---|
133 |
|
---|
134 | /*===========================================================================*
|
---|
135 | * tab2ops *
|
---|
136 | *===========================================================================*/
|
---|
137 | PRIVATE int tab2ops(int fd, struct selectentry *e)
|
---|
138 | {
|
---|
139 | return (FD_ISSET(fd, &e->readfds) ? SEL_RD : 0) |
|
---|
140 | (FD_ISSET(fd, &e->writefds) ? SEL_WR : 0) |
|
---|
141 | (FD_ISSET(fd, &e->errorfds) ? SEL_ERR : 0);
|
---|
142 | }
|
---|
143 |
|
---|
144 | /*===========================================================================*
|
---|
145 | * ops2tab *
|
---|
146 | *===========================================================================*/
|
---|
147 | PRIVATE void ops2tab(int ops, int fd, struct selectentry *e)
|
---|
148 | {
|
---|
149 | if ((ops & SEL_RD) && e->vir_readfds && FD_ISSET(fd, &e->readfds)
|
---|
150 | && !FD_ISSET(fd, &e->ready_readfds)) {
|
---|
151 | FD_SET(fd, &e->ready_readfds);
|
---|
152 | e->nreadyfds++;
|
---|
153 | }
|
---|
154 | if ((ops & SEL_WR) && e->vir_writefds && FD_ISSET(fd, &e->writefds)
|
---|
155 | && !FD_ISSET(fd, &e->ready_writefds)) {
|
---|
156 | FD_SET(fd, &e->ready_writefds);
|
---|
157 | e->nreadyfds++;
|
---|
158 | }
|
---|
159 | if ((ops & SEL_ERR) && e->vir_errorfds && FD_ISSET(fd, &e->errorfds)
|
---|
160 | && !FD_ISSET(fd, &e->ready_errorfds)) {
|
---|
161 | FD_SET(fd, &e->ready_errorfds);
|
---|
162 | e->nreadyfds++;
|
---|
163 | }
|
---|
164 | return;
|
---|
165 | }
|
---|
166 |
|
---|
167 | /*===========================================================================*
|
---|
168 | * copy_fdsets *
|
---|
169 | *===========================================================================*/
|
---|
170 | PRIVATE void copy_fdsets(struct selectentry *e)
|
---|
171 | {
|
---|
172 | if (e->vir_readfds)
|
---|
173 | sys_vircopy(SELF, D, (vir_bytes) &e->ready_readfds,
|
---|
174 | e->req_procnr, D, (vir_bytes) e->vir_readfds, sizeof(fd_set));
|
---|
175 | if (e->vir_writefds)
|
---|
176 | sys_vircopy(SELF, D, (vir_bytes) &e->ready_writefds,
|
---|
177 | e->req_procnr, D, (vir_bytes) e->vir_writefds, sizeof(fd_set));
|
---|
178 | if (e->vir_errorfds)
|
---|
179 | sys_vircopy(SELF, D, (vir_bytes) &e->ready_errorfds,
|
---|
180 | e->req_procnr, D, (vir_bytes) e->vir_errorfds, sizeof(fd_set));
|
---|
181 | return;
|
---|
182 | }
|
---|
183 |
|
---|
184 | /*===========================================================================*
|
---|
185 | * do_select *
|
---|
186 | *===========================================================================*/
|
---|
187 | PUBLIC int do_select(void)
|
---|
188 | {
|
---|
189 | int r, nfds, is_timeout = 1, nonzero_timeout = 0,
|
---|
190 | fd, s, block = 0;
|
---|
191 | struct timeval timeout;
|
---|
192 | nfds = m_in.SEL_NFDS;
|
---|
193 |
|
---|
194 | if (nfds < 0 || nfds > FD_SETSIZE)
|
---|
195 | return EINVAL;
|
---|
196 |
|
---|
197 | for(s = 0; s < MAXSELECTS; s++)
|
---|
198 | if (!selecttab[s].requestor)
|
---|
199 | break;
|
---|
200 |
|
---|
201 | if (s >= MAXSELECTS)
|
---|
202 | return ENOSPC;
|
---|
203 |
|
---|
204 | selecttab[s].req_procnr = who;
|
---|
205 | selecttab[s].nfds = 0;
|
---|
206 | selecttab[s].nreadyfds = 0;
|
---|
207 | memset(selecttab[s].filps, 0, sizeof(selecttab[s].filps));
|
---|
208 |
|
---|
209 | /* defaults */
|
---|
210 | FD_ZERO(&selecttab[s].readfds);
|
---|
211 | FD_ZERO(&selecttab[s].writefds);
|
---|
212 | FD_ZERO(&selecttab[s].errorfds);
|
---|
213 | FD_ZERO(&selecttab[s].ready_readfds);
|
---|
214 | FD_ZERO(&selecttab[s].ready_writefds);
|
---|
215 | FD_ZERO(&selecttab[s].ready_errorfds);
|
---|
216 |
|
---|
217 | selecttab[s].vir_readfds = (fd_set *) m_in.SEL_READFDS;
|
---|
218 | selecttab[s].vir_writefds = (fd_set *) m_in.SEL_WRITEFDS;
|
---|
219 | selecttab[s].vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS;
|
---|
220 |
|
---|
221 | /* copy args */
|
---|
222 | if (selecttab[s].vir_readfds
|
---|
223 | && (r=sys_vircopy(who, D, (vir_bytes) m_in.SEL_READFDS,
|
---|
224 | SELF, D, (vir_bytes) &selecttab[s].readfds, sizeof(fd_set))) != OK)
|
---|
225 | return r;
|
---|
226 |
|
---|
227 | if (selecttab[s].vir_writefds
|
---|
228 | && (r=sys_vircopy(who, D, (vir_bytes) m_in.SEL_WRITEFDS,
|
---|
229 | SELF, D, (vir_bytes) &selecttab[s].writefds, sizeof(fd_set))) != OK)
|
---|
230 | return r;
|
---|
231 |
|
---|
232 | if (selecttab[s].vir_errorfds
|
---|
233 | && (r=sys_vircopy(who, D, (vir_bytes) m_in.SEL_ERRORFDS,
|
---|
234 | SELF, D, (vir_bytes) &selecttab[s].errorfds, sizeof(fd_set))) != OK)
|
---|
235 | return r;
|
---|
236 |
|
---|
237 | if (!m_in.SEL_TIMEOUT)
|
---|
238 | is_timeout = nonzero_timeout = 0;
|
---|
239 | else
|
---|
240 | if ((r=sys_vircopy(who, D, (vir_bytes) m_in.SEL_TIMEOUT,
|
---|
241 | SELF, D, (vir_bytes) &timeout, sizeof(timeout))) != OK)
|
---|
242 | return r;
|
---|
243 |
|
---|
244 | /* No nonsense in the timeval please. */
|
---|
245 | if (is_timeout && (timeout.tv_sec < 0 || timeout.tv_usec < 0))
|
---|
246 | return EINVAL;
|
---|
247 |
|
---|
248 | /* if is_timeout if 0, we block forever. otherwise, if nonzero_timeout
|
---|
249 | * is 0, we do a poll (don't block). otherwise, we block up to the
|
---|
250 | * specified time interval.
|
---|
251 | */
|
---|
252 | if (is_timeout && (timeout.tv_sec > 0 || timeout.tv_usec > 0))
|
---|
253 | nonzero_timeout = 1;
|
---|
254 |
|
---|
255 | if (nonzero_timeout || !is_timeout)
|
---|
256 | block = 1;
|
---|
257 | else
|
---|
258 | block = 0; /* timeout set as (0,0) - this effects a poll */
|
---|
259 |
|
---|
260 | /* no timeout set (yet) */
|
---|
261 | selecttab[s].expiry = 0;
|
---|
262 |
|
---|
263 | for(fd = 0; fd < nfds; fd++) {
|
---|
264 | int orig_ops, ops, t, type = -1, r;
|
---|
265 | struct filp *filp;
|
---|
266 |
|
---|
267 | if (!(orig_ops = ops = tab2ops(fd, &selecttab[s])))
|
---|
268 | continue;
|
---|
269 | if (!(filp = selecttab[s].filps[fd] = get_filp(fd))) {
|
---|
270 | select_cancel_all(&selecttab[s]);
|
---|
271 | return EBADF;
|
---|
272 | }
|
---|
273 |
|
---|
274 | for(t = 0; t < SEL_FDS; t++) {
|
---|
275 | if (fdtypes[t].select_match) {
|
---|
276 | if (fdtypes[t].select_match(filp)) {
|
---|
277 | if (type != -1)
|
---|
278 | printf("select: double match\n");
|
---|
279 | type = t;
|
---|
280 | }
|
---|
281 | } else if (select_major_match(fdtypes[t].select_major, filp)) {
|
---|
282 | type = t;
|
---|
283 | }
|
---|
284 | }
|
---|
285 |
|
---|
286 | /* Open Group:
|
---|
287 | * "The pselect() and select() functions shall support
|
---|
288 | * regular files, terminal and pseudo-terminal devices,
|
---|
289 | * STREAMS-based files, FIFOs, pipes, and sockets. The
|
---|
290 | * behavior of pselect() and select() on file descriptors
|
---|
291 | * that refer to other types of file is unspecified."
|
---|
292 | *
|
---|
293 | * If all types are implemented, then this is another
|
---|
294 | * type of file and we get to do whatever we want.
|
---|
295 | */
|
---|
296 | if (type == -1)
|
---|
297 | {
|
---|
298 | return EBADF;
|
---|
299 | }
|
---|
300 |
|
---|
301 | selecttab[s].type[fd] = type;
|
---|
302 |
|
---|
303 | if ((selecttab[s].filps[fd]->filp_select_ops & ops) != ops) {
|
---|
304 | int wantops;
|
---|
305 | /* Request the select on this fd. */
|
---|
306 | wantops = (selecttab[s].filps[fd]->filp_select_ops |= ops);
|
---|
307 | if ((r = fdtypes[type].select_request(filp,
|
---|
308 | &wantops, block)) != SEL_OK) {
|
---|
309 | /* error or bogus return code.. backpaddle */
|
---|
310 | select_cancel_all(&selecttab[s]);
|
---|
311 | printf("select: select_request returned error\n");
|
---|
312 | return EINVAL;
|
---|
313 | }
|
---|
314 | if (wantops) {
|
---|
315 | if (wantops & ops) {
|
---|
316 | /* operations that were just requested
|
---|
317 | * are ready to go right away
|
---|
318 | */
|
---|
319 | ops2tab(wantops, fd, &selecttab[s]);
|
---|
320 | }
|
---|
321 | /* if there are any other select()s blocking
|
---|
322 | * on these operations of this fp, they can
|
---|
323 | * be awoken too
|
---|
324 | */
|
---|
325 | select_callback(filp, ops);
|
---|
326 | }
|
---|
327 | } else {
|
---|
328 | }
|
---|
329 | selecttab[s].nfds = fd+1;
|
---|
330 | selecttab[s].filps[fd]->filp_selectors++;
|
---|
331 | }
|
---|
332 |
|
---|
333 | if (selecttab[s].nreadyfds > 0 || !block) {
|
---|
334 | /* fd's were found that were ready to go right away, and/or
|
---|
335 | * we were instructed not to block at all. Must return
|
---|
336 | * immediately.
|
---|
337 | */
|
---|
338 | copy_fdsets(&selecttab[s]);
|
---|
339 | select_cancel_all(&selecttab[s]);
|
---|
340 | selecttab[s].requestor = NULL;
|
---|
341 |
|
---|
342 | /* Open Group:
|
---|
343 | * "Upon successful completion, the pselect() and select()
|
---|
344 | * functions shall return the total number of bits
|
---|
345 | * set in the bit masks."
|
---|
346 | */
|
---|
347 | return selecttab[s].nreadyfds;
|
---|
348 | }
|
---|
349 |
|
---|
350 | /* Convert timeval to ticks and set the timer. If it fails, undo
|
---|
351 | * all, return error.
|
---|
352 | */
|
---|
353 | if (is_timeout) {
|
---|
354 | int ticks;
|
---|
355 | /* Open Group:
|
---|
356 | * "If the requested timeout interval requires a finer
|
---|
357 | * granularity than the implementation supports, the
|
---|
358 | * actual timeout interval shall be rounded up to the next
|
---|
359 | * supported value."
|
---|
360 | */
|
---|
361 | #define USECPERSEC 1000000
|
---|
362 | while(timeout.tv_usec >= USECPERSEC) {
|
---|
363 | /* this is to avoid overflow with *HZ below */
|
---|
364 | timeout.tv_usec -= USECPERSEC;
|
---|
365 | timeout.tv_sec++;
|
---|
366 | }
|
---|
367 | ticks = timeout.tv_sec * HZ +
|
---|
368 | (timeout.tv_usec * HZ + USECPERSEC-1) / USECPERSEC;
|
---|
369 | selecttab[s].expiry = ticks;
|
---|
370 | fs_set_timer(&selecttab[s].timer, ticks, select_timeout_check, s);
|
---|
371 | }
|
---|
372 |
|
---|
373 | /* if we're blocking, the table entry is now valid. */
|
---|
374 | selecttab[s].requestor = fp;
|
---|
375 |
|
---|
376 | /* process now blocked */
|
---|
377 | suspend(XSELECT);
|
---|
378 | return SUSPEND;
|
---|
379 | }
|
---|
380 |
|
---|
381 | /*===========================================================================*
|
---|
382 | * select_cancel_all *
|
---|
383 | *===========================================================================*/
|
---|
384 | PRIVATE void select_cancel_all(struct selectentry *e)
|
---|
385 | {
|
---|
386 | int fd;
|
---|
387 |
|
---|
388 | for(fd = 0; fd < e->nfds; fd++) {
|
---|
389 | struct filp *fp;
|
---|
390 | fp = e->filps[fd];
|
---|
391 | if (!fp) {
|
---|
392 | continue;
|
---|
393 | }
|
---|
394 | if (fp->filp_selectors < 1) {
|
---|
395 | continue;
|
---|
396 | }
|
---|
397 | fp->filp_selectors--;
|
---|
398 | e->filps[fd] = NULL;
|
---|
399 | select_reevaluate(fp);
|
---|
400 | }
|
---|
401 |
|
---|
402 | if (e->expiry > 0) {
|
---|
403 | fs_cancel_timer(&e->timer);
|
---|
404 | e->expiry = 0;
|
---|
405 | }
|
---|
406 |
|
---|
407 | return;
|
---|
408 | }
|
---|
409 |
|
---|
410 | /*===========================================================================*
|
---|
411 | * select_wakeup *
|
---|
412 | *===========================================================================*/
|
---|
413 | PRIVATE void select_wakeup(struct selectentry *e)
|
---|
414 | {
|
---|
415 | /* Open Group:
|
---|
416 | * "Upon successful completion, the pselect() and select()
|
---|
417 | * functions shall return the total number of bits
|
---|
418 | * set in the bit masks."
|
---|
419 | */
|
---|
420 | revive(e->req_procnr, e->nreadyfds);
|
---|
421 | }
|
---|
422 |
|
---|
423 | /*===========================================================================*
|
---|
424 | * select_reevaluate *
|
---|
425 | *===========================================================================*/
|
---|
426 | PRIVATE int select_reevaluate(struct filp *fp)
|
---|
427 | {
|
---|
428 | int s, remain_ops = 0, fd, type = -1;
|
---|
429 |
|
---|
430 | if (!fp) {
|
---|
431 | printf("fs: select: reevalute NULL fp\n");
|
---|
432 | return 0;
|
---|
433 | }
|
---|
434 |
|
---|
435 | for(s = 0; s < MAXSELECTS; s++) {
|
---|
436 | if (!selecttab[s].requestor)
|
---|
437 | continue;
|
---|
438 | for(fd = 0; fd < selecttab[s].nfds; fd++)
|
---|
439 | if (fp == selecttab[s].filps[fd]) {
|
---|
440 | remain_ops |= tab2ops(fd, &selecttab[s]);
|
---|
441 | type = selecttab[s].type[fd];
|
---|
442 | }
|
---|
443 | }
|
---|
444 |
|
---|
445 | /* If there are any select()s open that want any operations on
|
---|
446 | * this fd that haven't been satisfied by this callback, then we're
|
---|
447 | * still in the market for it.
|
---|
448 | */
|
---|
449 | fp->filp_select_ops = remain_ops;
|
---|
450 |
|
---|
451 | return remain_ops;
|
---|
452 | }
|
---|
453 |
|
---|
454 | /*===========================================================================*
|
---|
455 | * select_callback *
|
---|
456 | *===========================================================================*/
|
---|
457 | PUBLIC int select_callback(struct filp *fp, int ops)
|
---|
458 | {
|
---|
459 | int s, fd, want_ops, type;
|
---|
460 |
|
---|
461 | /* We are being notified that file pointer fp is available for
|
---|
462 | * operations 'ops'. We must re-register the select for
|
---|
463 | * operations that we are still interested in, if any.
|
---|
464 | */
|
---|
465 |
|
---|
466 | want_ops = 0;
|
---|
467 | type = -1;
|
---|
468 | for(s = 0; s < MAXSELECTS; s++) {
|
---|
469 | int wakehim = 0;
|
---|
470 | if (!selecttab[s].requestor)
|
---|
471 | continue;
|
---|
472 | for(fd = 0; fd < selecttab[s].nfds; fd++) {
|
---|
473 | if (!selecttab[s].filps[fd])
|
---|
474 | continue;
|
---|
475 | if (selecttab[s].filps[fd] == fp) {
|
---|
476 | int this_want_ops;
|
---|
477 | this_want_ops = tab2ops(fd, &selecttab[s]);
|
---|
478 | want_ops |= this_want_ops;
|
---|
479 | if (this_want_ops & ops) {
|
---|
480 | /* this select() has been satisfied. */
|
---|
481 | ops2tab(ops, fd, &selecttab[s]);
|
---|
482 | wakehim = 1;
|
---|
483 | }
|
---|
484 | type = selecttab[s].type[fd];
|
---|
485 | }
|
---|
486 | }
|
---|
487 | if (wakehim) {
|
---|
488 | select_cancel_all(&selecttab[s]);
|
---|
489 | copy_fdsets(&selecttab[s]);
|
---|
490 | selecttab[s].requestor = NULL;
|
---|
491 | select_wakeup(&selecttab[s]);
|
---|
492 | }
|
---|
493 | }
|
---|
494 |
|
---|
495 | return 0;
|
---|
496 | }
|
---|
497 |
|
---|
498 | /*===========================================================================*
|
---|
499 | * select_notified *
|
---|
500 | *===========================================================================*/
|
---|
501 | PUBLIC int select_notified(int major, int minor, int selected_ops)
|
---|
502 | {
|
---|
503 | int s, f, t;
|
---|
504 |
|
---|
505 | for(t = 0; t < SEL_FDS; t++)
|
---|
506 | if (!fdtypes[t].select_match && fdtypes[t].select_major == major)
|
---|
507 | break;
|
---|
508 |
|
---|
509 | if (t >= SEL_FDS) {
|
---|
510 | return OK;
|
---|
511 | }
|
---|
512 |
|
---|
513 | /* We have a select callback from major device no.
|
---|
514 | * d, which corresponds to our select type t.
|
---|
515 | */
|
---|
516 |
|
---|
517 | for(s = 0; s < MAXSELECTS; s++) {
|
---|
518 | int s_minor, ops;
|
---|
519 | if (!selecttab[s].requestor)
|
---|
520 | continue;
|
---|
521 | for(f = 0; f < selecttab[s].nfds; f++) {
|
---|
522 | if (!selecttab[s].filps[f] ||
|
---|
523 | !select_major_match(major, selecttab[s].filps[f]))
|
---|
524 | continue;
|
---|
525 | ops = tab2ops(f, &selecttab[s]);
|
---|
526 | s_minor = selecttab[s].filps[f]->filp_ino->i_zone[0] & BYTE;
|
---|
527 | if ((s_minor == minor) &&
|
---|
528 | (selected_ops & ops)) {
|
---|
529 | select_callback(selecttab[s].filps[f], (selected_ops & ops));
|
---|
530 | }
|
---|
531 | }
|
---|
532 | }
|
---|
533 |
|
---|
534 | return OK;
|
---|
535 | }
|
---|
536 |
|
---|
537 | /*===========================================================================*
|
---|
538 | * init_select *
|
---|
539 | *===========================================================================*/
|
---|
540 | PUBLIC void init_select(void)
|
---|
541 | {
|
---|
542 | int s;
|
---|
543 |
|
---|
544 | for(s = 0; s < MAXSELECTS; s++)
|
---|
545 | fs_init_timer(&selecttab[s].timer);
|
---|
546 | }
|
---|
547 |
|
---|
548 | /*===========================================================================*
|
---|
549 | * select_forget *
|
---|
550 | *===========================================================================*/
|
---|
551 | PUBLIC void select_forget(int proc)
|
---|
552 | {
|
---|
553 | /* something has happened (e.g. signal delivered that interrupts
|
---|
554 | * select()). totally forget about the select().
|
---|
555 | */
|
---|
556 | int s;
|
---|
557 |
|
---|
558 | for(s = 0; s < MAXSELECTS; s++) {
|
---|
559 | if (selecttab[s].requestor &&
|
---|
560 | selecttab[s].req_procnr == proc) {
|
---|
561 | break;
|
---|
562 | }
|
---|
563 |
|
---|
564 | }
|
---|
565 |
|
---|
566 | if (s >= MAXSELECTS) {
|
---|
567 | return;
|
---|
568 | }
|
---|
569 |
|
---|
570 | select_cancel_all(&selecttab[s]);
|
---|
571 | selecttab[s].requestor = NULL;
|
---|
572 |
|
---|
573 | return;
|
---|
574 | }
|
---|
575 |
|
---|
576 | /*===========================================================================*
|
---|
577 | * select_timeout_check *
|
---|
578 | *===========================================================================*/
|
---|
579 | PUBLIC void select_timeout_check(timer_t *timer)
|
---|
580 | {
|
---|
581 | int s;
|
---|
582 |
|
---|
583 | s = tmr_arg(timer)->ta_int;
|
---|
584 |
|
---|
585 | if (s < 0 || s >= MAXSELECTS) {
|
---|
586 | return;
|
---|
587 | }
|
---|
588 |
|
---|
589 | if (!selecttab[s].requestor) {
|
---|
590 | return;
|
---|
591 | }
|
---|
592 |
|
---|
593 | if (selecttab[s].expiry <= 0) {
|
---|
594 | return;
|
---|
595 | }
|
---|
596 |
|
---|
597 | selecttab[s].expiry = 0;
|
---|
598 | copy_fdsets(&selecttab[s]);
|
---|
599 | select_cancel_all(&selecttab[s]);
|
---|
600 | selecttab[s].requestor = NULL;
|
---|
601 | select_wakeup(&selecttab[s]);
|
---|
602 |
|
---|
603 | return;
|
---|
604 | }
|
---|