2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1994-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure
5 * Copyright (C) 1991-3 Stephen Crane
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * See files README, COPYING and CREDITS in the root of the source
24 * tree for related information and legal notices. It is expected
25 * that future projects/authors will amend these files as needed.
29 * sel.c: arrange to block on read/write file descriptors using lwp
31 * Known contributors to this file:
45 #include "prototypes.h"
47 /* Largest fd in LwpReadfds, LwpWritefds */
50 /* Number of file descriptors in LwpReadfds, LwpWritefds */
53 /* File descriptors waited for in lwpSleepFd() */
54 static fd_set LwpReadfds, LwpWritefds;
56 /* Map file descriptor to thread sleeping in lwpSleepFd() */
57 static struct lwpProc **LwpFdwait;
59 /* Threads sleeping in lwpSleepUntil(), in no particular order */
60 static struct lwpQueue LwpDelayq;
62 /* The thread executing lwpSelect() */
63 static struct lwpProc *LwpSelProc;
66 lwpInitSelect(struct lwpProc *proc)
71 FD_ZERO(&LwpWritefds);
72 LwpFdwait = calloc(FD_SETSIZE, sizeof(struct lwpProc *));
79 lwpSleepFd(int fd, int mask)
81 lwpStatus(LwpCurrent, "sleeping on fd %d for %d", fd, mask);
83 if (CANT_HAPPEN(fd > FD_SETSIZE))
85 if (LwpFdwait[fd] != 0) {
87 "multiple sleeps attempted on file descriptor %d", fd);
90 if (mask & LWP_FD_READ)
91 FD_SET(fd, &LwpReadfds);
92 if (mask & LWP_FD_WRITE)
93 FD_SET(fd, &LwpWritefds);
97 if (LwpMaxfd == 0 && LwpDelayq.head == 0) {
98 /* select process is sleeping until first waiter arrives */
99 lwpStatus(LwpCurrent, "going to resched fd %d", fd);
100 lwpReady(LwpSelProc);
102 lwpStatus(LwpCurrent, "going to wait on fd %d", fd);
105 LwpFdwait[fd] = LwpCurrent;
111 lwpWakeupFd(struct lwpProc *proc)
116 lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd);
117 FD_CLR(proc->fd, &LwpReadfds);
118 FD_CLR(proc->fd, &LwpWritefds);
120 LwpFdwait[proc->fd] = 0;
126 lwpSleepUntil(long until)
128 lwpStatus(LwpCurrent, "sleeping for %ld sec", until - time(0));
129 LwpCurrent->runtime = until;
130 if (LwpMaxfd == 0 && LwpDelayq.head == 0) {
131 /* select process is sleeping until first waiter arrives */
132 lwpReady(LwpSelProc);
134 lwpAddTail(&LwpDelayq, LwpCurrent);
142 struct lwpProc *us = LwpCurrent;
149 struct lwpProc *proc;
151 struct lwpQueue save;
153 lwpStatus(us, "starting select loop");
162 /* wait for someone to lwpSleepFd or lwpSleepUntil */
164 lwpStatus(us, "no fds or sleepers, waiting");
169 if (LwpDelayq.head) {
171 proc = LwpDelayq.head;
172 for (; proc != 0; proc = proc->next) {
173 delta = proc->runtime - now;
174 if (delta < tv.tv_sec)
180 lwpStatus(us, "selecting; sleep %ld secs", tv.tv_sec);
182 memcpy(&readmask, &LwpReadfds, sizeof(fd_set));
183 memcpy(&writemask, &LwpWritefds, sizeof(fd_set));
184 n = select(LwpMaxfd + 1, &readmask, &writemask, NULL, &tv);
186 if (errno != EINTR) {
187 logerror("select failed (%s)", strerror(errno));
190 /* go handle the signal */
196 if (LwpDelayq.head) {
197 /* sleeping proecss activity */
199 save.tail = save.head = 0;
200 while (NULL != (proc = lwpGetFirst(&LwpDelayq))) {
201 if (now >= proc->runtime) {
202 lwpStatus(proc, "sleep done");
205 lwpAddTail(&save, proc);
211 /* file descriptor activity */
212 for (fd = 0; fd <= LwpMaxfd; fd++) {
213 if (LwpFdwait[fd] == 0)
215 if (FD_ISSET(fd, &readmask)) {
216 lwpStatus(LwpFdwait[fd], "input ready");
217 lwpWakeupFd(LwpFdwait[fd]);
220 if (FD_ISSET(fd, &writemask)) {
221 lwpStatus(LwpFdwait[fd], "output ready");
222 lwpWakeupFd(LwpFdwait[fd]);
227 lwpStatus(us, "fd dispatch completed");
228 lwpReady(LwpCurrent);