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