]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/sel.c
fcbd80ec44090dbc28b83d6987b999374e447e08
[empserver] / src / lib / lwp / sel.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  sel.c: arrange to block on read/write file descriptors using lwp
29  * 
30  *  Known contributors to this file:
31  *     Dave Pare, 1994
32  */
33
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <sys/uio.h>
38 #include <sys/file.h>
39 #include <sys/time.h>
40
41 #ifdef hpux
42 #include <stdio.h>
43 #endif
44
45 #include "bit.h"
46 #include "lwp.h"
47 #include "lwpint.h"
48 #include "prototypes.h"
49
50 #if defined(_EMPTH_LWP)
51
52 struct lwpSelect {
53     int maxfd;
54     int nfds;
55     int nfile;
56     fd_set readmask;
57     fd_set writemask;
58     struct lwpProc **wait;
59     struct lwpQueue delayq;
60     struct lwpProc *proc;
61 };
62
63 struct lwpSelect LwpSelect;
64
65 void
66 lwpInitSelect(proc)
67 struct lwpProc *proc;
68 {
69     LwpSelect.maxfd = 0;
70     LwpSelect.nfds = 0;
71 #ifdef hpux
72     LwpSelect.nfile = _NFILE;
73 #else
74     LwpSelect.nfile = getdtablesize();
75 #endif
76     FD_ZERO(&LwpSelect.readmask);
77     FD_ZERO(&LwpSelect.writemask);
78     LwpSelect.wait = (struct lwpProc **)
79         calloc(LwpSelect.nfile, sizeof(char *));
80     LwpSelect.delayq.head = 0;
81     LwpSelect.delayq.tail = 0;
82     LwpSelect.proc = proc;
83 }
84
85 void
86 lwpSleepFd(fd, mask)
87 int fd;
88 int mask;
89 {
90     extern struct lwpProc *LwpCurrent;
91
92     lwpStatus(LwpCurrent, "sleeping on fd %d", fd);
93
94     if (LwpSelect.wait[fd] != 0) {
95         lwpStatus(LwpCurrent,
96                   "multiple sleeps attempted on file descriptor %d", fd);
97         return;
98     }
99     if (mask & LWP_FD_READ)
100         FD_SET(fd, &LwpSelect.readmask);
101     if (mask & LWP_FD_WRITE)
102         FD_SET(fd, &LwpSelect.writemask);
103
104     LwpSelect.nfds++;
105
106     if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
107         /* select process is sleeping until first waiter arrives */
108         lwpStatus(LwpCurrent, "going to resched fd %d", fd);
109         lwpReady(LwpSelect.proc);
110     }
111     lwpStatus(LwpCurrent, "going to wait on fd %d", fd);
112     if (fd > LwpSelect.maxfd)
113         LwpSelect.maxfd = fd;
114     LwpSelect.wait[fd] = LwpCurrent;
115     LwpCurrent->fd = fd;
116     lwpReschedule();
117 }
118
119 void
120 lwpWakeupFd(proc)
121 struct lwpProc *proc;
122 {
123     if (proc->fd < 0)
124         return;
125
126     lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd);
127     FD_CLR(proc->fd, &LwpSelect.readmask);
128     FD_CLR(proc->fd, &LwpSelect.writemask);
129     LwpSelect.nfds--;
130     LwpSelect.wait[proc->fd] = 0;
131     proc->fd = -1;
132     lwpReady(proc);
133 }
134
135 void
136 lwpSleepUntil(until)
137 long until;
138 {
139     extern struct lwpProc *LwpCurrent;
140
141     lwpStatus(LwpCurrent, "sleeping for %d sec", until - time(0));
142     LwpCurrent->runtime = until;
143     if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
144         /* select process is sleeping until first waiter arrives */
145         lwpReady(LwpSelect.proc);
146     }
147     lwpAddTail(&LwpSelect.delayq, LwpCurrent);
148     lwpReschedule();
149 }
150
151 /*ARGSUSED*/
152 void
153 lwpSelect(argc, argv)
154 int argc;
155 char **argv;
156 {
157     extern struct lwpProc *LwpCurrent;
158     struct lwpProc *us = LwpCurrent;
159     fd_set readmask;
160     fd_set writemask;
161     int n;
162     int fd;
163     time_t now;
164     time_t delta;
165     struct lwpProc *proc;
166     struct timeval tv;
167     struct lwpQueue save;
168
169     lwpStatus(us, "starting select loop");
170     FD_ZERO(&readmask);
171     FD_ZERO(&writemask);
172     while (1) {
173         while (1) {
174             if (LwpSelect.nfds)
175                 break;
176             if (LwpSelect.delayq.head)
177                 break;
178             /* wait for someone to lwpSleepFd or lwpSleepUntil */
179             LwpSelect.maxfd = 0;
180             lwpStatus(us, "no fds or sleepers, waiting");
181             lwpReschedule();
182         }
183         tv.tv_sec = 1000000;
184         tv.tv_usec = 0;
185         if (LwpSelect.delayq.head) {
186             time(&now);
187             proc = LwpSelect.delayq.head;
188             for (; proc != 0; proc = proc->next) {
189                 delta = proc->runtime - now;
190                 if (delta < tv.tv_sec)
191                     tv.tv_sec = delta;
192             }
193             if (tv.tv_sec < 0)
194                 tv.tv_sec = 0;
195         }
196         lwpStatus(us, "selecting; sleep %ld secs", (long)delta);
197
198         bcopy((s_char *)&LwpSelect.readmask, (s_char *)&readmask,
199               sizeof(fd_set));
200         bcopy((s_char *)&LwpSelect.writemask, (s_char *)&writemask,
201               sizeof(fd_set));
202         n = select(LwpSelect.maxfd + 1, &readmask, &writemask,
203                    (fd_set *) 0, &tv);
204
205         if (n < 0) {
206             if (errno == EINTR) {
207                 /* go handle the signal */
208                 lwpReady(us);
209                 lwpReschedule();
210                 continue;
211             }
212             lwpStatus(us, "select failed (bad file descriptor?)");
213             exit(-1);
214         }
215
216         if (LwpSelect.delayq.head) {
217             /* sleeping proecss activity */
218             time(&now);
219             save.tail = save.head = 0;
220             while (NULL != (proc = lwpGetFirst(&LwpSelect.delayq))) {
221                 if (now >= proc->runtime) {
222                     lwpStatus(proc, "sleep done");
223                     lwpReady(proc);
224                 } else {
225                     lwpAddTail(&save, proc);
226                 }
227             }
228             LwpSelect.delayq = save;
229         }
230         if (n > 0) {
231             /* file descriptor activity */
232             for (fd = 0; fd <= LwpSelect.maxfd; fd++) {
233                 if (LwpSelect.wait[fd] == 0)
234                     continue;
235                 if (FD_ISSET(fd, &readmask)) {
236                     lwpStatus(LwpSelect.wait[fd], "input ready");
237                     lwpWakeupFd(LwpSelect.wait[fd]);
238                     continue;
239                 }
240                 if (FD_ISSET(fd, &writemask)) {
241                     lwpStatus(LwpSelect.wait[fd], "output ready");
242                     lwpWakeupFd(LwpSelect.wait[fd]);
243                     continue;
244                 }
245             }
246         }
247         lwpStatus(us, "fd dispatch completed");
248         lwpReady(LwpCurrent);
249         lwpReschedule();
250     }
251     /*NOTREACHED*/
252 }
253 #endif