[9] | 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 |
|
---|