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