void lwp_rwlock_unlock(struct lwp_rwlock *rwlock) { struct lwpProc *p; int maxpri; lwpStatus(LwpCurrent, "unlocking rwlock %s", rwlock->name); if (CANT_HAPPEN(rwlock->count == 0)) return; if (rwlock->count < 0) rwlock->count = 0; else rwlock->count--; if (rwlock->count == 0 && rwlock->wq.head) { p = lwpGetFirst(&rwlock->wq); lwpStatus(p, "wake up next writer of rwlock %s", rwlock->name); maxpri = p->pri; lwpReady(p); } else if (rwlock->count >= 0 && rwlock->rq.head && !rwlock->wq.head) { maxpri = 0; while ((p = lwpGetFirst(&rwlock->rq))) { lwpStatus(p, "wake up next reader of rwlock %s", rwlock->name); maxpri = MAX(maxpri, p->pri); lwpReady(p); } } else return; if (LwpCurrent->pri < maxpri) { lwpStatus(LwpCurrent, "yielding to thread with higher priority"); lwpYield(); } }
/* * Wake up threads in LwpDelayq whose time has come. */ void lwpWakeupSleep(void) { time_t now; struct lwpQueue save; struct lwpProc *proc; if (LwpDelayq.head) { now = time(NULL); save.tail = save.head = NULL; while (NULL != (proc = lwpGetFirst(&LwpDelayq))) { if (now >= proc->runtime) { lwpStatus(proc, "sleep done"); if (proc->runtime != 0) proc->runtime = (time_t)-1; if (proc->fd >= 0) lwpWakeupFd(proc); else lwpReady(proc); } else { lwpAddTail(&save, proc); } } LwpDelayq = save; } }
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; }
/* * Wake up @proc if it is sleeping in lwpSleepFd(). * Must be followed by lwpWakeupSleep() before the next lwpReschedule(). */ static void lwpWakeupFd(struct lwpProc *proc) { if (CANT_HAPPEN(proc->fd < 0 || proc->fd > LwpMaxfd)) return; if (proc->runtime != (time_t)-1 && proc->runtime != 0) { /* is in LwpDelayq; leave the job to lwpWakeupSleep() */ proc->runtime = (time_t)-1; return; } lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd); FD_CLR(proc->fd, &LwpReadfds); FD_CLR(proc->fd, &LwpWritefds); LwpNfds--; LwpFdwait[proc->fd] = NULL; proc->fd = -1; lwpReady(proc); }
/*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(); } }