void lwp_rwlock_rdlock(struct lwp_rwlock *rwlock) { if (rwlock->count < 0 || rwlock->wq.head) { lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for reading", rwlock->name); lwpAddTail(&rwlock->rq, LwpCurrent); lwpReschedule(); } CANT_HAPPEN(rwlock->count < 0); rwlock->count++; lwpStatus(LwpCurrent, "acquired rwlock %s for reading", rwlock->name); }
void lwp_rwlock_wrlock(struct lwp_rwlock *rwlock) { if (rwlock->count) { lwpAddTail(&rwlock->wq, LwpCurrent); lwpStatus(LwpCurrent, "blocked to acquire rwlock %s for writing", rwlock->name); lwpReschedule(); } CANT_HAPPEN(rwlock->count != 0); rwlock->count = -1; lwpStatus(LwpCurrent, "acquired rwlock %s for writing", rwlock->name); }
int lwpSleepUntil(time_t until) { int res; lwpStatus(LwpCurrent, "sleeping for %ld sec", (long)(until - time(NULL))); LwpCurrent->runtime = until; if (LwpMaxfd == 0 && !LwpDelayq.head) { /* select process is sleeping until first waiter arrives */ lwpReady(LwpSelProc); } lwpAddTail(&LwpDelayq, LwpCurrent); lwpReschedule(); res = LwpCurrent->runtime ? 0 : -1; LwpCurrent->runtime = (time_t)-1; return res; }
int lwpSleepFd(int fd, int mask, struct timeval *timeout) { lwpStatus(LwpCurrent, "sleeping on fd %d for %d", fd, mask); if (CANT_HAPPEN(fd < 0 || fd >= FD_SETSIZE)) { errno = EBADF; return -1; } if (LwpFdwait[fd]) { lwpStatus(LwpCurrent, "multiple sleeps attempted on file descriptor %d", fd); errno = EBADF; return -1; } if (mask & LWP_FD_READ) FD_SET(fd, &LwpReadfds); if (mask & LWP_FD_WRITE) FD_SET(fd, &LwpWritefds); LwpNfds++; if (LwpMaxfd == 0 && !LwpDelayq.head) { /* select process is sleeping until first waiter arrives */ lwpStatus(LwpCurrent, "going to resched fd %d", fd); lwpReady(LwpSelProc); } lwpStatus(LwpCurrent, "going to wait on fd %d", fd); if (timeout) { LwpCurrent->runtime = time(NULL) + timeout->tv_sec + (timeout->tv_usec > 0); lwpAddTail(&LwpDelayq, LwpCurrent); } else LwpCurrent->runtime = (time_t)-1; if (fd > LwpMaxfd) LwpMaxfd = fd; LwpFdwait[fd] = LwpCurrent; LwpCurrent->fd = fd; LwpCurrent->fd_ready = 0; lwpReschedule(); return LwpCurrent->fd_ready != 0; }
/*ARGSUSED*/ void lwpSelect(void *arg) { struct lwpProc *us = LwpCurrent; fd_set readmask; fd_set writemask; int n; int fd; time_t now; time_t delta; struct lwpProc *proc; struct timeval tv; lwpStatus(us, "starting select loop"); FD_ZERO(&readmask); FD_ZERO(&writemask); while (1) { while (1) { if (LwpNfds) break; if (LwpDelayq.head) break; /* wait for someone to lwpSleepFd or lwpSleepUntil */ LwpMaxfd = 0; lwpStatus(us, "no fds or sleepers, waiting"); lwpReschedule(); } tv.tv_sec = 1000000; tv.tv_usec = 0; if (LwpDelayq.head) { time(&now); for (proc = LwpDelayq.head; proc; proc = proc->next) { delta = proc->runtime - now; if (delta < tv.tv_sec) tv.tv_sec = delta; } if (tv.tv_sec < 0) tv.tv_sec = 0; } lwpStatus(us, "selecting; sleep %ld secs", (long)tv.tv_sec); memcpy(&readmask, &LwpReadfds, sizeof(fd_set)); memcpy(&writemask, &LwpWritefds, sizeof(fd_set)); n = select(LwpMaxfd + 1, &readmask, &writemask, NULL, &tv); if (n < 0) { if (errno != EINTR) { logerror("select failed (%s)", strerror(errno)); exit(1); } /* go handle the signal */ lwpReady(us); lwpReschedule(); continue; } if (n > 0) { /* file descriptor activity */ for (fd = 0; fd <= LwpMaxfd; fd++) { if (!LwpFdwait[fd]) continue; if (FD_ISSET(fd, &readmask)) { lwpStatus(LwpFdwait[fd], "input ready"); LwpFdwait[fd]->fd_ready = 1; lwpWakeupFd(LwpFdwait[fd]); continue; } if (FD_ISSET(fd, &writemask)) { lwpStatus(LwpFdwait[fd], "output ready"); LwpFdwait[fd]->fd_ready = 1; lwpWakeupFd(LwpFdwait[fd]); continue; } } } lwpWakeupSleep(); lwpStatus(us, "fd dispatch completed"); lwpReady(LwpCurrent); lwpReschedule(); } }