]> git.pond.sub.org Git - empserver/blob - src/lib/lwp/sel.c
COPYING duplicates information from README. Remove. Move GPL from
[empserver] / src / lib / lwp / sel.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1994-2006, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *  Copyright (C) 1991-3 Stephen Crane
6  *
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.
11  *
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.
16  *
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
20  *
21  *  ---
22  *
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.
26  *
27  *  ---
28  *
29  *  sel.c: arrange to block on read/write file descriptors using lwp
30  * 
31  *  Known contributors to this file:
32  *     Dave Pare, 1994
33  */
34
35 #include <config.h>
36
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <sys/uio.h>
41 #include <sys/file.h>
42 #include <sys/time.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include "lwp.h"
46 #include "lwpint.h"
47
48 struct lwpSelect {
49     int maxfd;
50     int nfds;
51     fd_set readmask;
52     fd_set writemask;
53     struct lwpProc **wait;
54     struct lwpQueue delayq;
55     struct lwpProc *proc;
56 };
57
58 struct lwpSelect LwpSelect;
59
60 void
61 lwpInitSelect(struct lwpProc *proc)
62 {
63     LwpSelect.maxfd = 0;
64     LwpSelect.nfds = 0;
65     FD_ZERO(&LwpSelect.readmask);
66     FD_ZERO(&LwpSelect.writemask);
67     LwpSelect.wait = calloc(FD_SETSIZE, sizeof(struct lwpProc *));
68     LwpSelect.delayq.head = 0;
69     LwpSelect.delayq.tail = 0;
70     LwpSelect.proc = proc;
71 }
72
73 void
74 lwpSleepFd(int fd, int mask)
75 {
76     lwpStatus(LwpCurrent, "sleeping on fd %d for %d", fd, mask);
77
78     if (CANT_HAPPEN(fd > FD_SETSIZE))
79         return;
80     if (LwpSelect.wait[fd] != 0) {
81         lwpStatus(LwpCurrent,
82                   "multiple sleeps attempted on file descriptor %d", fd);
83         return;
84     }
85     if (mask & LWP_FD_READ)
86         FD_SET(fd, &LwpSelect.readmask);
87     if (mask & LWP_FD_WRITE)
88         FD_SET(fd, &LwpSelect.writemask);
89
90     LwpSelect.nfds++;
91
92     if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
93         /* select process is sleeping until first waiter arrives */
94         lwpStatus(LwpCurrent, "going to resched fd %d", fd);
95         lwpReady(LwpSelect.proc);
96     }
97     lwpStatus(LwpCurrent, "going to wait on fd %d", fd);
98     if (fd > LwpSelect.maxfd)
99         LwpSelect.maxfd = fd;
100     LwpSelect.wait[fd] = LwpCurrent;
101     LwpCurrent->fd = fd;
102     lwpReschedule();
103 }
104
105 void
106 lwpWakeupFd(struct lwpProc *proc)
107 {
108     if (proc->fd < 0)
109         return;
110
111     lwpStatus(proc, "awakening; was sleeping on fd %d", proc->fd);
112     FD_CLR(proc->fd, &LwpSelect.readmask);
113     FD_CLR(proc->fd, &LwpSelect.writemask);
114     LwpSelect.nfds--;
115     LwpSelect.wait[proc->fd] = 0;
116     proc->fd = -1;
117     lwpReady(proc);
118 }
119
120 void
121 lwpSleepUntil(long int until)
122 {
123     lwpStatus(LwpCurrent, "sleeping for %ld sec", until - time(0));
124     LwpCurrent->runtime = until;
125     if (LwpSelect.maxfd == 0 && LwpSelect.delayq.head == 0) {
126         /* select process is sleeping until first waiter arrives */
127         lwpReady(LwpSelect.proc);
128     }
129     lwpAddTail(&LwpSelect.delayq, LwpCurrent);
130     lwpReschedule();
131 }
132
133 /*ARGSUSED*/
134 void
135 lwpSelect(void *arg)
136 {
137     struct lwpProc *us = LwpCurrent;
138     fd_set readmask;
139     fd_set writemask;
140     int n;
141     int fd;
142     time_t now;
143     time_t delta;
144     struct lwpProc *proc;
145     struct timeval tv;
146     struct lwpQueue save;
147
148     lwpStatus(us, "starting select loop");
149     FD_ZERO(&readmask);
150     FD_ZERO(&writemask);
151     while (1) {
152         while (1) {
153             if (LwpSelect.nfds)
154                 break;
155             if (LwpSelect.delayq.head)
156                 break;
157             /* wait for someone to lwpSleepFd or lwpSleepUntil */
158             LwpSelect.maxfd = 0;
159             lwpStatus(us, "no fds or sleepers, waiting");
160             lwpReschedule();
161         }
162         tv.tv_sec = 1000000;
163         tv.tv_usec = 0;
164         if (LwpSelect.delayq.head) {
165             time(&now);
166             proc = LwpSelect.delayq.head;
167             for (; proc != 0; proc = proc->next) {
168                 delta = proc->runtime - now;
169                 if (delta < tv.tv_sec)
170                     tv.tv_sec = delta;
171             }
172             if (tv.tv_sec < 0)
173                 tv.tv_sec = 0;
174         }
175         lwpStatus(us, "selecting; sleep %ld secs", tv.tv_sec);
176
177         memcpy(&readmask, &LwpSelect.readmask, sizeof(fd_set));
178         memcpy(&writemask, &LwpSelect.writemask, sizeof(fd_set));
179         n = select(LwpSelect.maxfd + 1, &readmask, &writemask,
180                    (fd_set *) 0, &tv);
181
182         if (n < 0) {
183             if (errno == EINTR) {
184                 /* go handle the signal */
185                 lwpReady(us);
186                 lwpReschedule();
187                 continue;
188             }
189             lwpStatus(us, "select failed (bad file descriptor?)");
190             exit(-1);
191         }
192
193         if (LwpSelect.delayq.head) {
194             /* sleeping proecss activity */
195             time(&now);
196             save.tail = save.head = 0;
197             while (NULL != (proc = lwpGetFirst(&LwpSelect.delayq))) {
198                 if (now >= proc->runtime) {
199                     lwpStatus(proc, "sleep done");
200                     lwpReady(proc);
201                 } else {
202                     lwpAddTail(&save, proc);
203                 }
204             }
205             LwpSelect.delayq = save;
206         }
207         if (n > 0) {
208             /* file descriptor activity */
209             for (fd = 0; fd <= LwpSelect.maxfd; fd++) {
210                 if (LwpSelect.wait[fd] == 0)
211                     continue;
212                 if (FD_ISSET(fd, &readmask)) {
213                     lwpStatus(LwpSelect.wait[fd], "input ready");
214                     lwpWakeupFd(LwpSelect.wait[fd]);
215                     continue;
216                 }
217                 if (FD_ISSET(fd, &writemask)) {
218                     lwpStatus(LwpSelect.wait[fd], "output ready");
219                     lwpWakeupFd(LwpSelect.wait[fd]);
220                     continue;
221                 }
222             }
223         }
224         lwpStatus(us, "fd dispatch completed");
225         lwpReady(LwpCurrent);
226         lwpReschedule();
227     }
228     /*NOTREACHED*/
229 }