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