/* internally to wait for one object. Also used as a shortcut to wait on events and semaphores */ static int _DkObjectWaitOne (PAL_HANDLE handle, PAL_NUM timeout) { /* only for all these handle which has a file descriptor, or a eventfd. events and semaphores will skip this part */ if (HANDLE_HDR(handle)->flags & HAS_FDS) { struct pollfd fds[MAX_FDS]; int off[MAX_FDS]; int nfds = 0; for (int i = 0 ; i < MAX_FDS ; i++) { int events = 0; if ((HANDLE_HDR(handle)->flags & RFD(i)) && !(HANDLE_HDR(handle)->flags & ERROR(i))) events |= POLLIN; if ((HANDLE_HDR(handle)->flags & WFD(i)) && !(HANDLE_HDR(handle)->flags & WRITEABLE(i)) && !(HANDLE_HDR(handle)->flags & ERROR(i))) events |= POLLOUT; if (events) { fds[nfds].fd = handle->generic.fds[i]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; off[nfds] = i; nfds++; } } if (!nfds) return -PAL_ERROR_TRYAGAIN; int64_t waittime = timeout; int ret = ocall_poll(fds, nfds, timeout != NO_TIMEOUT ? &waittime : NULL); if (IS_ERR(ret)) return unix_to_pal_error(ERRNO(ret)); if (!ret) return -PAL_ERROR_TRYAGAIN; for (int i = 0 ; i < nfds ; i++) { if (!fds[i].revents) continue; if (fds[i].revents & POLLOUT) HANDLE_HDR(handle)->flags |= WRITEABLE(off[i]); if (fds[i].revents & (POLLHUP|POLLERR)) HANDLE_HDR(handle)->flags |= ERROR(off[i]); } return 0; } const struct handle_ops * ops = HANDLE_OPS(handle); if (!ops || !ops->wait) return -PAL_ERROR_NOTSUPPORT; return ops->wait(handle, timeout); }
/* internally to wait for one object. Also used as a shortcut to wait on events and semaphores */ static int _DkObjectWaitOne (PAL_HANDLE handle, int timeout) { /* only for all these handle which has a file descriptor, or a eventfd. events and semaphores will skip this part */ if (handle->__in.flags & HAS_FDS) { struct pollfd fds[MAX_FDS]; int off[MAX_FDS]; int nfds = 0; for (int i = 0 ; i < MAX_FDS ; i++) { int events = 0; if ((handle->__in.flags & RFD(i)) && !(handle->__in.flags & ERROR(i))) events |= POLLIN; if ((handle->__in.flags & WFD(i)) && !(handle->__in.flags & WRITEABLE(i)) && !(handle->__in.flags & ERROR(i))) events |= POLLOUT; if (events) { fds[nfds].fd = handle->__in.fds[i]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; off[nfds] = i; nfds++; } } if (!nfds) return -PAL_ERROR_TRYAGAIN; int ret = INLINE_SYSCALL(poll, 3, &fds, nfds, timeout ? timeout : -1); if (IS_ERR(ret)) switch (ERRNO(ret)) { case EINTR: return -PAL_ERROR_INTERRUPTED; default: return unix_to_pal_error(ERRNO(ret)); } if (!ret) return -PAL_ERROR_TRYAGAIN; for (int i = 0 ; i < nfds ; i++) { if (!fds[i].revents) continue; if (fds[i].revents & POLLOUT) handle->__in.flags |= WRITEABLE(off[i]); if (fds[i].revents & (POLLHUP|POLLERR)) handle->__in.flags |= ERROR(off[i]); } return 0; } const struct handle_ops * ops = HANDLE_OPS(handle); if (!ops->wait) return -PAL_ERROR_NOTSUPPORT; return ops->wait(handle, timeout); }
/* _DkObjectsWaitAny for internal use. The function wait for any of the handle in the handle array. timeout can be set for the wait. */ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout, PAL_HANDLE * polled) { if (count <= 0) return 0; if (count == 1) { *polled = handleArray[0]; return _DkObjectWaitOne(handleArray[0], timeout); } int i, j, ret, maxfds = 0, nfds = 0; /* we are not gonna to allow any polling on muliple synchronous objects, doing this is simply violating the division of labor between PAL and library OS */ for (i = 0 ; i < count ; i++) { PAL_HANDLE hdl = handleArray[i]; if (!hdl) continue; if (!(hdl->__in.flags & HAS_FDS)) return -PAL_ERROR_NOTSUPPORT; /* eliminate repeated entries */ for (j = 0 ; j < i ; j++) if (hdl == handleArray[j]) break; if (j == i) { for (j = 0 ; j < MAX_FDS ; j++) if (hdl->__in.flags & (RFD(j)|WFD(j))) maxfds++; } } struct pollfd * fds = __alloca(sizeof(struct pollfd) * maxfds); PAL_HANDLE * hdls = __alloca(sizeof(PAL_HANDLE) * maxfds); for (i = 0 ; i < count ; i++) { PAL_HANDLE hdl = handleArray[i]; if (!hdl) continue; for (j = 0 ; j < i ; j++) if (hdl == handleArray[j]) break; if (j < i) continue; for (j = 0 ; j < MAX_FDS ; j++) { int events = 0; if ((hdl->__in.flags & RFD(j)) && !(hdl->__in.flags & ERROR(j))) events |= POLLIN; if ((hdl->__in.flags & WFD(j)) && !(hdl->__in.flags & WRITEABLE(j)) && !(hdl->__in.flags & ERROR(j))) events |= POLLOUT; if (events && hdl->__in.fds[j] != PAL_IDX_POISON) { fds[nfds].fd = hdl->__in.fds[j]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; hdls[nfds] = hdl; nfds++; } } } if (!nfds) return -PAL_ERROR_TRYAGAIN; ret = INLINE_SYSCALL(poll, 3, fds, nfds, timeout ? timeout : -1); if (IS_ERR(ret)) switch (ERRNO(ret)) { case EINTR: return -PAL_ERROR_INTERRUPTED; default: return unix_to_pal_error(ERRNO(ret)); } if (!ret) return -PAL_ERROR_TRYAGAIN; PAL_HANDLE polled_hdl = NULL; for (i = 0 ; i < nfds ; i++) { if (!fds[i].revents) continue; PAL_HANDLE hdl = hdls[i]; if (polled_hdl) { if (hdl != polled_hdl) continue; } else { polled_hdl = hdl; } for (j = 0 ; j < MAX_FDS ; j++) if ((hdl->__in.flags & (RFD(j)|WFD(j))) && hdl->__in.fds[j] == fds[i].fd) break; if (j == MAX_FDS) continue; if (fds[i].revents & POLLOUT) hdl->__in.flags |= WRITEABLE(j); if (fds[i].revents & (POLLHUP|POLLERR)) hdl->__in.flags |= ERROR(j); } *polled = polled_hdl; return polled_hdl ? 0 : -PAL_ERROR_TRYAGAIN; }
/* _DkObjectsWaitAny for internal use. The function wait for any of the handle in the handle array. timeout can be set for the wait. */ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, PAL_NUM timeout, PAL_HANDLE * polled) { if (count <= 0) return 0; if (count == 1) { // It is possible to have NULL pointers in the handle array. // In this case, assume nothing is polled. if (!handleArray[0]) return -PAL_ERROR_TRYAGAIN; int rv = _DkObjectWaitOne(handleArray[0], timeout); if (rv == 0) *polled = handleArray[0]; return rv; } int i, j, ret, maxfds = 0, nfds = 0; /* we are not gonna to allow any polling on muliple synchronous objects, doing this is simply violating the division of labor between PAL and library OS */ for (i = 0 ; i < count ; i++) { PAL_HANDLE hdl = handleArray[i]; if (!hdl) continue; if (!(HANDLE_HDR(hdl)->flags & HAS_FDS)) return -PAL_ERROR_NOTSUPPORT; /* eliminate repeated entries */ for (j = 0 ; j < i ; j++) if (hdl == handleArray[j]) break; if (j == i) { for (j = 0 ; j < MAX_FDS ; j++) if (HANDLE_HDR(hdl)->flags & (RFD(j)|WFD(j))) maxfds++; } } struct pollfd * fds = __alloca(sizeof(struct pollfd) * maxfds); PAL_HANDLE * hdls = __alloca(sizeof(PAL_HANDLE) * maxfds); for (i = 0 ; i < count ; i++) { PAL_HANDLE hdl = handleArray[i]; if (!hdl) continue; for (j = 0 ; j < i ; j++) if (hdl == handleArray[j]) break; if (j < i) continue; for (j = 0 ; j < MAX_FDS ; j++) { int events = 0; if ((HANDLE_HDR(hdl)->flags & RFD(j)) && !(HANDLE_HDR(hdl)->flags & ERROR(j))) events |= POLLIN; if ((HANDLE_HDR(hdl)->flags & WFD(j)) && !(HANDLE_HDR(hdl)->flags & WRITEABLE(j)) && !(HANDLE_HDR(hdl)->flags & ERROR(j))) events |= POLLOUT; if (events && hdl->generic.fds[j] != PAL_IDX_POISON) { fds[nfds].fd = hdl->generic.fds[j]; fds[nfds].events = events|POLLHUP|POLLERR; fds[nfds].revents = 0; hdls[nfds] = hdl; nfds++; } } } if (!nfds) return -PAL_ERROR_TRYAGAIN; int64_t waittime = timeout; ret = ocall_poll(fds, nfds, timeout != NO_TIMEOUT ? &waittime : NULL); if (IS_ERR(ret)) return unix_to_pal_error(ERRNO(ret)); if (!ret) return -PAL_ERROR_TRYAGAIN; PAL_HANDLE polled_hdl = NULL; for (i = 0 ; i < nfds ; i++) { if (!fds[i].revents) continue; PAL_HANDLE hdl = hdls[i]; if (polled_hdl) { if (hdl != polled_hdl) continue; } else { polled_hdl = hdl; } for (j = 0 ; j < MAX_FDS ; j++) if ((HANDLE_HDR(hdl)->flags & (RFD(j)|WFD(j))) && hdl->generic.fds[j] == (PAL_IDX)fds[i].fd) break; if (j == MAX_FDS) continue; if (fds[i].revents & POLLOUT) HANDLE_HDR(hdl)->flags |= WRITEABLE(j); if (fds[i].revents & (POLLHUP|POLLERR)) HANDLE_HDR(hdl)->flags |= ERROR(j); } *polled = polled_hdl; return polled_hdl ? 0 : -PAL_ERROR_TRYAGAIN; }