[4] | 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 | }
|
---|