Index: ossp-pkg/pth/ChangeLog RCS File: /v/ossp/cvs/ossp-pkg/pth/ChangeLog,v rcsdiff -q -kk '-r1.595' '-r1.596' -u '/v/ossp/cvs/ossp-pkg/pth/ChangeLog,v' 2>/dev/null --- ChangeLog 2002/11/08 16:17:47 1.595 +++ ChangeLog 2002/11/08 19:12:13 1.596 @@ -21,6 +21,10 @@ Changes between 2.0b0 and 2.0b1 (07-Nov-2002 to xx-Nov-2002) + *) Make pth_select(2) more compliant to POSIX.1-2001/SUSv3 select(2). + This especially fixes the polling-only situation (timeout = (0,0)). + [Ralf S. Engelschall] + *) Make sure that in the even manager a polling-only select(2) call uses a correctly initialized timeout parameter. [Ralf S. Engelschall] Index: ossp-pkg/pth/pth_high.c RCS File: /v/ossp/cvs/ossp-pkg/pth/pth_high.c,v rcsdiff -q -kk '-r1.102' '-r1.103' -u '/v/ossp/cvs/ossp-pkg/pth/pth_high.c,v' 2>/dev/null --- pth_high.c 2002/11/08 16:20:15 1.102 +++ pth_high.c 2002/11/08 19:12:13 1.103 @@ -297,28 +297,27 @@ pth_implicit_init(); pth_debug2("pth_select_ev: called from thread \"%s\"", pth_current->name); - /* POSIX compliance */ + /* POSIX.1-2001/SUSv3 compliance */ if (nfd < 0 || nfd > FD_SETSIZE) return pth_error(-1, EINVAL); if (timeout != NULL) { if ( timeout->tv_sec < 0 - || timeout->tv_sec > 100000000 /* about 3 years */ || timeout->tv_usec < 0 - || timeout->tv_usec >= 1000000 /* a full second */) + || timeout->tv_usec >= 1000000 /* a full second */) return pth_error(-1, EINVAL); + if (timeout->tv_sec > 31*24*60*60) + timeout->tv_sec = 31*24*60*60; } /* first deal with the special situation of a plain microsecond delay */ if (nfd == 0 && rfds == NULL && wfds == NULL && efds == NULL && timeout != NULL) { - if (timeout->tv_sec < 0 || timeout->tv_usec < 0) - return pth_error(-1, EINVAL); - if (timeout->tv_sec == 0 && timeout->tv_usec < 500000) { + if (timeout->tv_sec == 0 && timeout->tv_usec <= 10000 /* 1/100 second */) { /* very small delays are acceptable to be performed directly */ while ( pth_sc(select)(0, NULL, NULL, NULL, timeout) < 0 && errno == EINTR) ; } else { - /* larger delays have to use the scheduler */ + /* larger delays have to go through the scheduler */ ev = pth_event(PTH_EVENT_TIME|PTH_MODE_STATIC, &ev_key_timeout, pth_timeout(timeout->tv_sec, timeout->tv_usec)); if (ev_extra != NULL) @@ -330,58 +329,57 @@ return pth_error(-1, EINTR); } } - /* POSIX compliance */ + /* POSIX.1-2001/SUSv3 compliance */ if (rfds != NULL) FD_ZERO(rfds); if (wfds != NULL) FD_ZERO(wfds); if (efds != NULL) FD_ZERO(efds); return 0; } - /* now directly poll filedescriptor sets to avoid unneccessary + /* now directly poll filedescriptor sets to avoid unnecessary (and resource consuming because of context switches, etc) event handling through the scheduler. We've to be carefully here, because not - all platforms guarranty us that the sets are unmodified if an error - or timeout occured. */ + all platforms guaranty us that the sets are unmodified if an error + or timeout occurred. */ delay.tv_sec = 0; delay.tv_usec = 0; rtmp = NULL; if (rfds != NULL) { - rspare = *rfds; + memcpy(&rspare, rfds, sizeof(fd_set)); rtmp = &rspare; } wtmp = NULL; if (wfds != NULL) { - wspare = *wfds; + memcpy(&wspare, wfds, sizeof(fd_set)); wtmp = &wspare; } etmp = NULL; if (efds != NULL) { - espare = *efds; + memcpy(&espare, efds, sizeof(fd_set)); etmp = &espare; } - while ((rc = pth_sc(select)(nfd, rtmp, wtmp, etmp, &delay)) < 0 && errno == EINTR) ; - if (rc > 0) { + while ((rc = pth_sc(select)(nfd, rtmp, wtmp, etmp, &delay)) < 0 + && errno == EINTR) + ; + if (rc < 0) + /* pass-through immediate error */ + return pth_error(-1, errno); + else if ( rc > 0 + || ( rc == 0 + && timeout != NULL + && pth_time_cmp(timeout, PTH_TIME_ZERO) == 0)) { + /* pass-through immediate success */ if (rfds != NULL) - *rfds = rspare; + memcpy(rfds, &rspare, sizeof(fd_set)); if (wfds != NULL) - *wfds = wspare; + memcpy(wfds, &wspare, sizeof(fd_set)); if (efds != NULL) - *efds = espare; + memcpy(efds, &espare, sizeof(fd_set)); return rc; } - if (rc == 0 && timeout != NULL) { - if (pth_time_cmp(timeout, PTH_TIME_ZERO) == 0) { - /* POSIX compliance */ - if (rfds != NULL) FD_ZERO(rfds); - if (wfds != NULL) FD_ZERO(wfds); - if (efds != NULL) FD_ZERO(efds); - return 0; - } - } - if (rc < 0 && (errno == EINVAL || errno == EBADF)) - return pth_error(-1, errno); - /* suspend current thread until one fd is ready or the timeout occurred */ + /* suspend current thread until one filedescriptor + is ready or the timeout occurred */ rc = -1; ev = ev_select = pth_event(PTH_EVENT_SELECT|PTH_MODE_STATIC, &ev_key_select, &rc, nfd, rfds, wfds, efds); @@ -394,25 +392,29 @@ if (ev_extra != NULL) pth_event_concat(ev, ev_extra, NULL); pth_wait(ev); + if (ev_extra != NULL) + pth_event_isolate(ev_extra); + if (timeout != NULL) + pth_event_isolate(ev_timeout); + + /* select return code semantics */ + if (pth_event_status(ev_select) == PTH_STATUS_FAILED) + return pth_error(-1, EBADF); selected = FALSE; - pth_event_isolate(ev_select); if (pth_event_status(ev_select) == PTH_STATUS_OCCURRED) selected = TRUE; - if (timeout != NULL) { - pth_event_isolate(ev_timeout); - if (pth_event_status(ev_timeout) == PTH_STATUS_OCCURRED) { - selected = TRUE; - /* POSIX compliance */ - if (rfds != NULL) FD_ZERO(rfds); - if (wfds != NULL) FD_ZERO(wfds); - if (efds != NULL) FD_ZERO(efds); - rc = 0; - } + if ( timeout != NULL + && pth_event_status(ev_timeout) == PTH_STATUS_OCCURRED) { + selected = TRUE; + /* POSIX.1-2001/SUSv3 compliance */ + if (rfds != NULL) FD_ZERO(rfds); + if (wfds != NULL) FD_ZERO(wfds); + if (efds != NULL) FD_ZERO(efds); + rc = 0; } - if (pth_event_status(ev_select) == PTH_STATUS_FAILED) - return pth_error(-1, EBADF); if (ev_extra != NULL && !selected) return pth_error(-1, EINTR); + return rc; }