00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #define DEBUG_SELECT 0
00014
00015 #include "fs.h"
00016 #include "select.h"
00017 #include "file.h"
00018 #include "inode.h"
00019
00020 #include <sys/time.h>
00021 #include <sys/select.h>
00022 #include <minix/com.h>
00023 #include <string.h>
00024
00025
00026 #define MAXSELECTS 25
00027
00028 PRIVATE struct selectentry {
00029 struct fproc *requestor;
00030 int req_endpt;
00031 fd_set readfds, writefds, errorfds;
00032 fd_set ready_readfds, ready_writefds, ready_errorfds;
00033 fd_set *vir_readfds, *vir_writefds, *vir_errorfds;
00034 struct filp *filps[FD_SETSIZE];
00035 int type[FD_SETSIZE];
00036 int nfds, nreadyfds;
00037 clock_t expiry;
00038 timer_t timer;
00039 } selecttab[MAXSELECTS];
00040
00041 #define SELFD_FILE 0
00042 #define SELFD_PIPE 1
00043 #define SELFD_TTY 2
00044 #define SELFD_INET 3
00045 #define SELFD_LOG 4
00046 #define SEL_FDS 5
00047
00048 FORWARD _PROTOTYPE(int select_reevaluate, (struct filp *fp));
00049
00050 FORWARD _PROTOTYPE(int select_request_file,
00051 (struct filp *f, int *ops, int block));
00052 FORWARD _PROTOTYPE(int select_match_file, (struct filp *f));
00053
00054 FORWARD _PROTOTYPE(int select_request_general,
00055 (struct filp *f, int *ops, int block));
00056 FORWARD _PROTOTYPE(int select_major_match,
00057 (int match_major, struct filp *file));
00058
00059 FORWARD _PROTOTYPE(void select_cancel_all, (struct selectentry *e));
00060 FORWARD _PROTOTYPE(void select_wakeup, (struct selectentry *e, int r));
00061 FORWARD _PROTOTYPE(void select_return, (struct selectentry *, int));
00062
00063
00064
00065
00066
00067
00068
00069 PRIVATE struct fdtype {
00070 int (*select_request)(struct filp *, int *ops, int block);
00071 int (*select_match)(struct filp *);
00072 int select_major;
00073 } fdtypes[SEL_FDS] = {
00074
00075 { select_request_file, select_match_file, 0 },
00076
00077 { select_request_general, NULL, TTY_MAJOR },
00078
00079 { select_request_general, NULL, INET_MAJOR },
00080
00081 { select_request_pipe, select_match_pipe, 0 },
00082
00083 { select_request_general, NULL, LOG_MAJOR },
00084 };
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 PRIVATE int select_request_file(struct filp *f, int *ops, int block)
00095 {
00096
00097 return SEL_OK;
00098 }
00099
00100
00101
00102
00103 PRIVATE int select_match_file(struct filp *file)
00104 {
00105 if (file && file->filp_ino && (file->filp_ino->i_mode & I_REGULAR))
00106 return 1;
00107 return 0;
00108 }
00109
00110
00111
00112
00113 PRIVATE int select_request_general(struct filp *f, int *ops, int block)
00114 {
00115 int rops = *ops;
00116 if (block) rops |= SEL_NOTIFY;
00117 *ops = dev_io(DEV_SELECT, f->filp_ino->i_zone[0], rops, NULL, 0, 0, 0);
00118 if (*ops < 0)
00119 return SEL_ERR;
00120 return SEL_OK;
00121 }
00122
00123
00124
00125
00126 PRIVATE int select_major_match(int match_major, struct filp *file)
00127 {
00128 int major;
00129 if (!(file && file->filp_ino &&
00130 (file->filp_ino->i_mode & I_TYPE) == I_CHAR_SPECIAL))
00131 return 0;
00132 major = (file->filp_ino->i_zone[0] >> MAJOR) & BYTE;
00133 if (major == match_major)
00134 return 1;
00135 return 0;
00136 }
00137
00138
00139
00140
00141 PRIVATE int tab2ops(int fd, struct selectentry *e)
00142 {
00143 return (FD_ISSET(fd, &e->readfds) ? SEL_RD : 0) |
00144 (FD_ISSET(fd, &e->writefds) ? SEL_WR : 0) |
00145 (FD_ISSET(fd, &e->errorfds) ? SEL_ERR : 0);
00146 }
00147
00148
00149
00150
00151 PRIVATE void ops2tab(int ops, int fd, struct selectentry *e)
00152 {
00153 if ((ops & SEL_RD) && e->vir_readfds && FD_ISSET(fd, &e->readfds)
00154 && !FD_ISSET(fd, &e->ready_readfds)) {
00155 FD_SET(fd, &e->ready_readfds);
00156 e->nreadyfds++;
00157 }
00158 if ((ops & SEL_WR) && e->vir_writefds && FD_ISSET(fd, &e->writefds)
00159 && !FD_ISSET(fd, &e->ready_writefds)) {
00160 FD_SET(fd, &e->ready_writefds);
00161 e->nreadyfds++;
00162 }
00163 if ((ops & SEL_ERR) && e->vir_errorfds && FD_ISSET(fd, &e->errorfds)
00164 && !FD_ISSET(fd, &e->ready_errorfds)) {
00165 FD_SET(fd, &e->ready_errorfds);
00166 e->nreadyfds++;
00167 }
00168
00169 return;
00170 }
00171
00172
00173
00174
00175 PRIVATE void copy_fdsets(struct selectentry *e)
00176 {
00177 if (e->vir_readfds)
00178 sys_vircopy(SELF, D, (vir_bytes) &e->ready_readfds,
00179 e->req_endpt, D, (vir_bytes) e->vir_readfds, sizeof(fd_set));
00180 if (e->vir_writefds)
00181 sys_vircopy(SELF, D, (vir_bytes) &e->ready_writefds,
00182 e->req_endpt, D, (vir_bytes) e->vir_writefds, sizeof(fd_set));
00183 if (e->vir_errorfds)
00184 sys_vircopy(SELF, D, (vir_bytes) &e->ready_errorfds,
00185 e->req_endpt, D, (vir_bytes) e->vir_errorfds, sizeof(fd_set));
00186
00187 return;
00188 }
00189
00190
00191
00192
00193 PUBLIC int do_select(void)
00194 {
00195 int r, nfds, is_timeout = 1, nonzero_timeout = 0,
00196 fd, s, block = 0;
00197 struct timeval timeout;
00198 nfds = m_in.SEL_NFDS;
00199
00200 if (nfds < 0 || nfds > FD_SETSIZE)
00201 return EINVAL;
00202
00203 for(s = 0; s < MAXSELECTS; s++)
00204 if (!selecttab[s].requestor)
00205 break;
00206
00207 if (s >= MAXSELECTS)
00208 return ENOSPC;
00209
00210 selecttab[s].req_endpt = who_e;
00211 selecttab[s].nfds = 0;
00212 selecttab[s].nreadyfds = 0;
00213 memset(selecttab[s].filps, 0, sizeof(selecttab[s].filps));
00214
00215
00216 FD_ZERO(&selecttab[s].readfds);
00217 FD_ZERO(&selecttab[s].writefds);
00218 FD_ZERO(&selecttab[s].errorfds);
00219 FD_ZERO(&selecttab[s].ready_readfds);
00220 FD_ZERO(&selecttab[s].ready_writefds);
00221 FD_ZERO(&selecttab[s].ready_errorfds);
00222
00223 selecttab[s].vir_readfds = (fd_set *) m_in.SEL_READFDS;
00224 selecttab[s].vir_writefds = (fd_set *) m_in.SEL_WRITEFDS;
00225 selecttab[s].vir_errorfds = (fd_set *) m_in.SEL_ERRORFDS;
00226
00227
00228 if (selecttab[s].vir_readfds
00229 && (r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_READFDS,
00230 SELF, D, (vir_bytes) &selecttab[s].readfds, sizeof(fd_set))) != OK)
00231 return r;
00232
00233 if (selecttab[s].vir_writefds
00234 && (r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_WRITEFDS,
00235 SELF, D, (vir_bytes) &selecttab[s].writefds, sizeof(fd_set))) != OK)
00236 return r;
00237
00238 if (selecttab[s].vir_errorfds
00239 && (r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_ERRORFDS,
00240 SELF, D, (vir_bytes) &selecttab[s].errorfds, sizeof(fd_set))) != OK)
00241 return r;
00242
00243 if (!m_in.SEL_TIMEOUT)
00244 is_timeout = nonzero_timeout = 0;
00245 else
00246 if ((r=sys_vircopy(who_e, D, (vir_bytes) m_in.SEL_TIMEOUT,
00247 SELF, D, (vir_bytes) &timeout, sizeof(timeout))) != OK)
00248 return r;
00249
00250
00251 if (is_timeout && (timeout.tv_sec < 0 || timeout.tv_usec < 0))
00252 return EINVAL;
00253
00254
00255
00256
00257
00258 if (is_timeout && (timeout.tv_sec > 0 || timeout.tv_usec > 0))
00259 nonzero_timeout = 1;
00260
00261 if (nonzero_timeout || !is_timeout)
00262 block = 1;
00263 else
00264 block = 0;
00265
00266
00267 selecttab[s].expiry = 0;
00268
00269 for(fd = 0; fd < nfds; fd++) {
00270 int orig_ops, ops, t, type = -1, r;
00271 struct filp *filp;
00272
00273 if (!(orig_ops = ops = tab2ops(fd, &selecttab[s])))
00274 continue;
00275 if (!(filp = selecttab[s].filps[fd] = get_filp(fd))) {
00276 select_cancel_all(&selecttab[s]);
00277 return EBADF;
00278 }
00279
00280 for(t = 0; t < SEL_FDS; t++) {
00281 if (fdtypes[t].select_match) {
00282 if (fdtypes[t].select_match(filp)) {
00283 #if DEBUG_SELECT
00284 printf("select: fd %d is type %d ", fd, t);
00285 #endif
00286 if (type != -1)
00287 printf("select: double match\n");
00288 type = t;
00289 }
00290 } else if (select_major_match(fdtypes[t].select_major, filp)) {
00291 type = t;
00292 }
00293 }
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 if (type == -1)
00306 {
00307 #if DEBUG_SELECT
00308 printf("do_select: bad type\n");
00309 #endif
00310 return EBADF;
00311 }
00312
00313 selecttab[s].type[fd] = type;
00314
00315 if ((selecttab[s].filps[fd]->filp_select_ops & ops) != ops) {
00316 int wantops;
00317
00318 #if DEBUG_SELECT
00319 printf("%p requesting ops %d -> ",
00320 selecttab[s].filps[fd],
00321 selecttab[s].filps[fd]->filp_select_ops);
00322 #endif
00323 wantops = (selecttab[s].filps[fd]->filp_select_ops |= ops);
00324 #if DEBUG_SELECT
00325 printf("%d\n", selecttab[s].filps[fd]->filp_select_ops);
00326 #endif
00327 if ((r = fdtypes[type].select_request(filp,
00328 &wantops, block)) != SEL_OK) {
00329
00330 select_cancel_all(&selecttab[s]);
00331 printf("select: select_request returned error\n");
00332 return EINVAL;
00333 }
00334 if (wantops) {
00335 if (wantops & ops) {
00336
00337
00338
00339 ops2tab(wantops, fd, &selecttab[s]);
00340 }
00341
00342
00343
00344
00345 select_callback(filp, ops);
00346 }
00347 #if DEBUG_SELECT
00348 printf("select request ok; ops returned %d\n", wantops);
00349 #endif
00350 } else {
00351 #if DEBUG_SELECT
00352 printf("select already happening on that filp\n");
00353 #endif
00354 }
00355
00356 selecttab[s].nfds = fd+1;
00357 selecttab[s].filps[fd]->filp_selectors++;
00358
00359 #if DEBUG_SELECT
00360 printf("[fd %d ops: %d] ", fd, ops);
00361 #endif
00362 }
00363
00364 if (selecttab[s].nreadyfds > 0 || !block) {
00365
00366
00367
00368
00369 copy_fdsets(&selecttab[s]);
00370 select_cancel_all(&selecttab[s]);
00371 selecttab[s].requestor = NULL;
00372
00373
00374
00375
00376
00377
00378 #if DEBUG_SELECT
00379 printf("returning\n");
00380 #endif
00381
00382 return selecttab[s].nreadyfds;
00383 }
00384 #if DEBUG_SELECT
00385 printf("not returning (%d, %d)\n", selecttab[s].nreadyfds, block);
00386 #endif
00387
00388
00389
00390
00391 if (is_timeout) {
00392 int ticks;
00393
00394
00395
00396
00397
00398
00399 #define USECPERSEC 1000000
00400 while(timeout.tv_usec >= USECPERSEC) {
00401
00402 timeout.tv_usec -= USECPERSEC;
00403 timeout.tv_sec++;
00404 }
00405 ticks = timeout.tv_sec * HZ +
00406 (timeout.tv_usec * HZ + USECPERSEC-1) / USECPERSEC;
00407 selecttab[s].expiry = ticks;
00408 fs_set_timer(&selecttab[s].timer, ticks, select_timeout_check, s);
00409 #if DEBUG_SELECT
00410 printf("%d: blocking %d ticks\n", s, ticks);
00411 #endif
00412 }
00413
00414
00415 selecttab[s].requestor = fp;
00416
00417
00418 suspend(XSELECT);
00419 return SUSPEND;
00420 }
00421
00422
00423
00424
00425 PRIVATE void select_cancel_all(struct selectentry *e)
00426 {
00427 int fd;
00428
00429 for(fd = 0; fd < e->nfds; fd++) {
00430 struct filp *fp;
00431 fp = e->filps[fd];
00432 if (!fp) {
00433 #if DEBUG_SELECT
00434 printf("[ fd %d/%d NULL ] ", fd, e->nfds);
00435 #endif
00436 continue;
00437 }
00438 if (fp->filp_selectors < 1) {
00439 #if DEBUG_SELECT
00440 printf("select: %d selectors?!\n", fp->filp_selectors);
00441 #endif
00442 continue;
00443 }
00444 fp->filp_selectors--;
00445 e->filps[fd] = NULL;
00446 select_reevaluate(fp);
00447 }
00448
00449 if (e->expiry > 0) {
00450 #if DEBUG_SELECT
00451 printf("cancelling timer %d\n", e - selecttab);
00452 #endif
00453 fs_cancel_timer(&e->timer);
00454 e->expiry = 0;
00455 }
00456
00457 return;
00458 }
00459
00460
00461
00462
00463 PRIVATE void select_wakeup(struct selectentry *e, int r)
00464 {
00465 revive(e->req_endpt, r);
00466 }
00467
00468
00469
00470
00471 PRIVATE int select_reevaluate(struct filp *fp)
00472 {
00473 int s, remain_ops = 0, fd, type = -1;
00474
00475 if (!fp) {
00476 printf("fs: select: reevalute NULL fp\n");
00477 return 0;
00478 }
00479
00480 for(s = 0; s < MAXSELECTS; s++) {
00481 if (!selecttab[s].requestor)
00482 continue;
00483 for(fd = 0; fd < selecttab[s].nfds; fd++)
00484 if (fp == selecttab[s].filps[fd]) {
00485 remain_ops |= tab2ops(fd, &selecttab[s]);
00486 type = selecttab[s].type[fd];
00487 }
00488 }
00489
00490
00491
00492
00493
00494 fp->filp_select_ops = remain_ops;
00495 #if DEBUG_SELECT
00496 printf("remaining operations on fp are %d\n", fp->filp_select_ops);
00497 #endif
00498
00499 return remain_ops;
00500 }
00501
00502
00503
00504
00505 PRIVATE void select_return(struct selectentry *s, int r)
00506 {
00507 select_cancel_all(s);
00508 copy_fdsets(s);
00509 select_wakeup(s, r ? r : s->nreadyfds);
00510 s->requestor = NULL;
00511 }
00512
00513
00514
00515
00516 PUBLIC int select_callback(struct filp *fp, int ops)
00517 {
00518 int s, fd, want_ops, type;
00519
00520
00521
00522
00523
00524
00525 want_ops = 0;
00526 type = -1;
00527 for(s = 0; s < MAXSELECTS; s++) {
00528 int wakehim = 0;
00529 if (!selecttab[s].requestor)
00530 continue;
00531 for(fd = 0; fd < selecttab[s].nfds; fd++) {
00532 if (!selecttab[s].filps[fd])
00533 continue;
00534 if (selecttab[s].filps[fd] == fp) {
00535 int this_want_ops;
00536 this_want_ops = tab2ops(fd, &selecttab[s]);
00537 want_ops |= this_want_ops;
00538 if (this_want_ops & ops) {
00539
00540 ops2tab(ops, fd, &selecttab[s]);
00541 wakehim = 1;
00542 }
00543 type = selecttab[s].type[fd];
00544 }
00545 }
00546 if (wakehim)
00547 select_return(&selecttab[s], 0);
00548 }
00549
00550 return 0;
00551 }
00552
00553
00554
00555
00556 PUBLIC int select_notified(int major, int minor, int selected_ops)
00557 {
00558 int s, f, t;
00559
00560 #if DEBUG_SELECT
00561 printf("select callback: %d, %d: %d\n", major, minor, selected_ops);
00562 #endif
00563
00564 for(t = 0; t < SEL_FDS; t++)
00565 if (!fdtypes[t].select_match && fdtypes[t].select_major == major)
00566 break;
00567
00568 if (t >= SEL_FDS) {
00569 #if DEBUG_SELECT
00570 printf("select callback: no fdtype found for device %d\n", major);
00571 #endif
00572 return OK;
00573 }
00574
00575
00576
00577
00578
00579 for(s = 0; s < MAXSELECTS; s++) {
00580 int s_minor, ops;
00581 if (!selecttab[s].requestor)
00582 continue;
00583 for(f = 0; f < selecttab[s].nfds; f++) {
00584 if (!selecttab[s].filps[f] ||
00585 !select_major_match(major, selecttab[s].filps[f]))
00586 continue;
00587 ops = tab2ops(f, &selecttab[s]);
00588 s_minor =
00589 (selecttab[s].filps[f]->filp_ino->i_zone[0] >> MINOR)
00590 & BYTE;
00591 if ((s_minor == minor) &&
00592 (selected_ops & ops)) {
00593 select_callback(selecttab[s].filps[f], (selected_ops & ops));
00594 }
00595 }
00596 }
00597
00598 return OK;
00599 }
00600
00601
00602
00603
00604 PUBLIC void init_select(void)
00605 {
00606 int s;
00607
00608 for(s = 0; s < MAXSELECTS; s++)
00609 fs_init_timer(&selecttab[s].timer);
00610 }
00611
00612
00613
00614
00615 PUBLIC void select_forget(int proc_e)
00616 {
00617
00618
00619
00620 int s;
00621
00622 for(s = 0; s < MAXSELECTS; s++) {
00623 if (selecttab[s].requestor &&
00624 selecttab[s].req_endpt == proc_e) {
00625 break;
00626 }
00627
00628 }
00629
00630 if (s >= MAXSELECTS) {
00631 #if DEBUG_SELECT
00632 printf("select: cancelled select() not found");
00633 #endif
00634 return;
00635 }
00636
00637 select_cancel_all(&selecttab[s]);
00638 selecttab[s].requestor = NULL;
00639
00640 return;
00641 }
00642
00643
00644
00645
00646 PUBLIC void select_timeout_check(timer_t *timer)
00647 {
00648 int s;
00649
00650 s = tmr_arg(timer)->ta_int;
00651
00652 if (s < 0 || s >= MAXSELECTS) {
00653 #if DEBUG_SELECT
00654 printf("select: bogus slot arg to watchdog %d\n", s);
00655 #endif
00656 return;
00657 }
00658
00659 if (!selecttab[s].requestor) {
00660 #if DEBUG_SELECT
00661 printf("select: no requestor in watchdog\n");
00662 #endif
00663 return;
00664 }
00665
00666 if (selecttab[s].expiry <= 0) {
00667 #if DEBUG_SELECT
00668 printf("select: strange expiry value in watchdog\n", s);
00669 #endif
00670 return;
00671 }
00672
00673 selecttab[s].expiry = 0;
00674 select_return(&selecttab[s], 0);
00675
00676 return;
00677 }
00678
00679
00680
00681
00682 PUBLIC void select_unsuspend_by_endpt(int proc_e)
00683 {
00684 int fd, s;
00685
00686 for(s = 0; s < MAXSELECTS; s++) {
00687 if (!selecttab[s].requestor)
00688 continue;
00689 for(fd = 0; fd < selecttab[s].nfds; fd++) {
00690 int maj;
00691 if (!selecttab[s].filps[fd] || !selecttab[s].filps[fd]->filp_ino)
00692 continue;
00693 maj = (selecttab[s].filps[fd]->filp_ino->i_zone[0] >> MAJOR)&BYTE;
00694 if(dmap_driver_match(proc_e, maj)) {
00695 select_return(&selecttab[s], EAGAIN);
00696 }
00697 }
00698 }
00699
00700 return;
00701 }
00702