]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/sel.c
Import of Empire 4.2.12
[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 lwpInitSelect(proc)
66         struct lwpProc *proc;
67 {
68         LwpSelect.maxfd = 0;
69         LwpSelect.nfds = 0;
70 #ifdef hpux
71         LwpSelect.nfile = _NFILE;
72 #else
73         LwpSelect.nfile = getdtablesize();
74 #endif
75         FD_ZERO(&LwpSelect.readmask); 
76         FD_ZERO(&LwpSelect.writemask);
77         LwpSelect.wait = (struct lwpProc **)
78                 calloc(LwpSelect.nfile, sizeof(char *));
79         LwpSelect.delayq.head = 0;
80         LwpSelect.delayq.tail = 0;
81         LwpSelect.proc = proc;
82 }
83
84 void lwpSleepFd(fd, mask)
85         int     fd;
86         int     mask;
87 {
88         extern struct lwpProc *LwpCurrent;
89
90         lwpStatus(LwpCurrent, "sleeping on fd %d", fd);
91
92         if (LwpSelect.wait[fd] != 0) {
93                 lwpStatus(LwpCurrent,
94                          "multiple sleeps attempted on file descriptor %d", fd);
95                 return;
96         }
97         if (mask & LWP_FD_READ)
98                 FD_SET(fd, &LwpSelect.readmask);
99         if (mask & LWP_FD_WRITE)
100                 FD_SET(fd, &LwpSelect.writemask);
101
102         LwpSelect.nfds++;
103
104         if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
105                 /* select process is sleeping until first waiter arrives */
106                 lwpStatus(LwpCurrent, "going to resched fd %d", fd);
107                 lwpReady(LwpSelect.proc);
108         }
109         lwpStatus(LwpCurrent, "going to wait on fd %d", fd);
110         if (fd > LwpSelect.maxfd)
111                 LwpSelect.maxfd = fd;
112         LwpSelect.wait[fd] = LwpCurrent;
113         LwpCurrent->fd = fd;
114         lwpReschedule();
115 }
116
117 void lwpWakeupFd(proc)
118         struct lwpProc *proc;
119 {
120         if (proc->fd < 0)
121                 return;
122
123         lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd);
124         FD_CLR(proc->fd, &LwpSelect.readmask);
125         FD_CLR(proc->fd, &LwpSelect.writemask);
126         LwpSelect.nfds--;
127         LwpSelect.wait[proc->fd] = 0;
128         proc->fd = -1;
129         lwpReady(proc);
130 }
131
132 void lwpSleepUntil(until)
133         long    until;
134 {
135         extern struct lwpProc *LwpCurrent;
136
137         lwpStatus(LwpCurrent, "sleeping for %d sec", until - time(0));
138         LwpCurrent->runtime = until;
139         if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
140                 /* select process is sleeping until first waiter arrives */
141                 lwpReady(LwpSelect.proc);
142         }
143         lwpAddTail(&LwpSelect.delayq, LwpCurrent);
144         lwpReschedule();
145 }
146
147 /*ARGSUSED*/
148 void
149 lwpSelect(argc, argv)
150         int     argc;
151         char    **argv;
152 {
153         extern struct lwpProc *LwpCurrent;
154         struct lwpProc *us = LwpCurrent;
155         fd_set readmask;
156         fd_set writemask;
157         int     n;
158         int     fd;
159         time_t  now;
160         time_t  delta;
161         struct lwpProc *proc;
162         struct timeval tv;
163         struct lwpQueue save;
164
165         lwpStatus(us, "starting select loop");
166         FD_ZERO(&readmask);
167         FD_ZERO(&writemask);
168         while (1) {
169                 while (1) {
170                         if (LwpSelect.nfds)
171                                 break;
172                         if (LwpSelect.delayq.head)
173                                 break;
174                         /* wait for someone to lwpSleepFd or lwpSleepUntil */
175                         LwpSelect.maxfd = 0;
176                         lwpStatus(us, "no fds or sleepers, waiting");
177                         lwpReschedule();
178                 }
179                 tv.tv_sec = 1000000;
180                 tv.tv_usec = 0;
181                 if (LwpSelect.delayq.head) {
182                         time(&now);
183                         proc = LwpSelect.delayq.head;
184                         for ( ; proc != 0; proc = proc->next) {
185                                 delta = proc->runtime - now;
186                                 if (delta < tv.tv_sec)
187                                         tv.tv_sec = delta;
188                         }
189                         if (tv.tv_sec < 0)
190                                 tv.tv_sec = 0;
191                 }
192                 lwpStatus(us, "selecting; sleep %ld secs", (long)delta);
193
194                 bcopy((s_char *)&LwpSelect.readmask, (s_char *)&readmask, sizeof(fd_set));
195                 bcopy((s_char *)&LwpSelect.writemask, (s_char *)&writemask, sizeof(fd_set));
196                 n = select(LwpSelect.maxfd + 1, &readmask, &writemask,
197                            (fd_set *)0, &tv);
198                 
199                 if (n < 0) {
200                         if (errno == EINTR) {
201                                 /* go handle the signal */
202                                 lwpReady(us);
203                                 lwpReschedule();
204                                 continue;
205                         }
206                         lwpStatus(us,
207                                   "select failed (bad file descriptor?)");
208                         exit(-1);
209                 }
210                 
211                 if (LwpSelect.delayq.head) {
212                         /* sleeping proecss activity */
213                         time(&now);
214                         save.tail = save.head = 0;
215                         while (NULL != (proc = lwpGetFirst(&LwpSelect.delayq))) {
216                                 if (now >= proc->runtime) {
217                                         lwpStatus(proc, "sleep done");
218                                         lwpReady(proc);
219                                 } else {
220                                         lwpAddTail(&save, proc);
221                                 }
222                         }
223                         LwpSelect.delayq = save;
224                 }
225                 if (n > 0) {
226                         /* file descriptor activity */
227                         for(fd = 0; fd <= LwpSelect.maxfd; fd++) {
228                                 if (LwpSelect.wait[fd] == 0)
229                                         continue;
230                                 if (FD_ISSET(fd, &readmask)) {
231                                         lwpStatus(LwpSelect.wait[fd],
232                                                   "input ready");
233                                         lwpWakeupFd(LwpSelect.wait[fd]);
234                                         continue;
235                                 }
236                                 if (FD_ISSET(fd, &writemask)) {
237                                         lwpStatus(LwpSelect.wait[fd],
238                                                   "output ready");
239                                         lwpWakeupFd(LwpSelect.wait[fd]);
240                                         continue;
241                                 }
242                         }
243                 }
244                 lwpStatus(us, "fd dispatch completed");
245                 lwpReady(LwpCurrent);
246                 lwpReschedule();
247         }
248         /*NOTREACHED*/
249 }
250 #endif