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