00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <config.h>
00037
00038 #include <errno.h>
00039 #include <sys/time.h>
00040 #include <time.h>
00041 #include <unistd.h>
00042 #include "lwp.h"
00043 #include "lwpint.h"
00044 #include "prototypes.h"
00045
00046
00047 static int LwpMaxfd;
00048
00049
00050 static int LwpNfds;
00051
00052
00053 static fd_set LwpReadfds, LwpWritefds;
00054
00055
00056 static struct lwpProc **LwpFdwait;
00057
00058
00059 static struct lwpQueue LwpDelayq;
00060
00061
00062 static struct lwpProc *LwpSelProc;
00063
00064 void
00065 lwpInitSelect(struct lwpProc *proc)
00066 {
00067 LwpMaxfd = 0;
00068 LwpNfds = 0;
00069 FD_ZERO(&LwpReadfds);
00070 FD_ZERO(&LwpWritefds);
00071 LwpFdwait = calloc(FD_SETSIZE, sizeof(struct lwpProc *));
00072 LwpDelayq.head = 0;
00073 LwpDelayq.tail = 0;
00074 LwpSelProc = proc;
00075 }
00076
00077 void
00078 lwpSleepFd(int fd, int mask)
00079 {
00080 lwpStatus(LwpCurrent, "sleeping on fd %d for %d", fd, mask);
00081
00082 if (CANT_HAPPEN(fd > FD_SETSIZE))
00083 return;
00084 if (LwpFdwait[fd] != 0) {
00085 lwpStatus(LwpCurrent,
00086 "multiple sleeps attempted on file descriptor %d", fd);
00087 return;
00088 }
00089 if (mask & LWP_FD_READ)
00090 FD_SET(fd, &LwpReadfds);
00091 if (mask & LWP_FD_WRITE)
00092 FD_SET(fd, &LwpWritefds);
00093
00094 LwpNfds++;
00095
00096 if (LwpMaxfd == 0 && LwpDelayq.head == 0) {
00097
00098 lwpStatus(LwpCurrent, "going to resched fd %d", fd);
00099 lwpReady(LwpSelProc);
00100 }
00101 lwpStatus(LwpCurrent, "going to wait on fd %d", fd);
00102 if (fd > LwpMaxfd)
00103 LwpMaxfd = fd;
00104 LwpFdwait[fd] = LwpCurrent;
00105 LwpCurrent->fd = fd;
00106 lwpReschedule();
00107 }
00108
00109 static void
00110 lwpWakeupFd(struct lwpProc *proc)
00111 {
00112 if (proc->fd < 0)
00113 return;
00114
00115 lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd);
00116 FD_CLR(proc->fd, &LwpReadfds);
00117 FD_CLR(proc->fd, &LwpWritefds);
00118 LwpNfds--;
00119 LwpFdwait[proc->fd] = 0;
00120 proc->fd = -1;
00121 lwpReady(proc);
00122 }
00123
00124 void
00125 lwpWakeupSleep(void)
00126 {
00127 time_t now;
00128 struct lwpQueue save;
00129 struct lwpProc *proc;
00130
00131 if (LwpDelayq.head) {
00132 now = time(NULL);
00133 save.tail = save.head = 0;
00134 while (NULL != (proc = lwpGetFirst(&LwpDelayq))) {
00135 if (now >= proc->runtime) {
00136 lwpStatus(proc, "sleep done");
00137 lwpReady(proc);
00138 } else {
00139 lwpAddTail(&save, proc);
00140 }
00141 }
00142 LwpDelayq = save;
00143 }
00144 }
00145
00146 void
00147 lwpWakeup(struct lwpProc *proc)
00148 {
00149 if (proc->fd >= 0)
00150 lwpWakeupFd(proc);
00151 else if (proc->runtime != (time_t)-1) {
00152 proc->runtime = 0;
00153 lwpWakeupSleep();
00154 }
00155 }
00156
00157 int
00158 lwpSleepUntil(time_t until)
00159 {
00160 int res;
00161
00162 lwpStatus(LwpCurrent, "sleeping for %ld sec",
00163 (long)(until - time(NULL)));
00164 LwpCurrent->runtime = until;
00165 if (LwpMaxfd == 0 && LwpDelayq.head == 0) {
00166
00167 lwpReady(LwpSelProc);
00168 }
00169 lwpAddTail(&LwpDelayq, LwpCurrent);
00170 lwpReschedule();
00171 res = LwpCurrent->runtime ? 0 : -1;
00172 LwpCurrent->runtime = (time_t)-1;
00173 return res;
00174 }
00175
00176
00177 void
00178 lwpSelect(void *arg)
00179 {
00180 struct lwpProc *us = LwpCurrent;
00181 fd_set readmask;
00182 fd_set writemask;
00183 int n;
00184 int fd;
00185 time_t now;
00186 time_t delta;
00187 struct lwpProc *proc;
00188 struct timeval tv;
00189
00190 lwpStatus(us, "starting select loop");
00191 FD_ZERO(&readmask);
00192 FD_ZERO(&writemask);
00193 while (1) {
00194 while (1) {
00195 if (LwpNfds)
00196 break;
00197 if (LwpDelayq.head)
00198 break;
00199
00200 LwpMaxfd = 0;
00201 lwpStatus(us, "no fds or sleepers, waiting");
00202 lwpReschedule();
00203 }
00204 tv.tv_sec = 1000000;
00205 tv.tv_usec = 0;
00206 if (LwpDelayq.head) {
00207 time(&now);
00208 proc = LwpDelayq.head;
00209 for (; proc != 0; proc = proc->next) {
00210 delta = proc->runtime - now;
00211 if (delta < tv.tv_sec)
00212 tv.tv_sec = delta;
00213 }
00214 if (tv.tv_sec < 0)
00215 tv.tv_sec = 0;
00216 }
00217 lwpStatus(us, "selecting; sleep %ld secs", tv.tv_sec);
00218
00219 memcpy(&readmask, &LwpReadfds, sizeof(fd_set));
00220 memcpy(&writemask, &LwpWritefds, sizeof(fd_set));
00221 n = select(LwpMaxfd + 1, &readmask, &writemask, NULL, &tv);
00222 if (n < 0) {
00223 if (errno != EINTR) {
00224 logerror("select failed (%s)", strerror(errno));
00225 exit(1);
00226 }
00227
00228 lwpReady(us);
00229 lwpReschedule();
00230 continue;
00231 }
00232
00233 lwpWakeupSleep();
00234 if (n > 0) {
00235
00236 for (fd = 0; fd <= LwpMaxfd; fd++) {
00237 if (LwpFdwait[fd] == 0)
00238 continue;
00239 if (FD_ISSET(fd, &readmask)) {
00240 lwpStatus(LwpFdwait[fd], "input ready");
00241 lwpWakeupFd(LwpFdwait[fd]);
00242 continue;
00243 }
00244 if (FD_ISSET(fd, &writemask)) {
00245 lwpStatus(LwpFdwait[fd], "output ready");
00246 lwpWakeupFd(LwpFdwait[fd]);
00247 continue;
00248 }
00249 }
00250 }
00251 lwpStatus(us, "fd dispatch completed");
00252 lwpReady(LwpCurrent);
00253 lwpReschedule();
00254 }
00255
00256 }