3 * Support for threaded ops which may block (read, write, connect, etc.).
5 * Copyright (c) 1996 T. J. Wilkinson & Associates, London, UK.
7 * See the file "license.terms" for information on usage and redistribution
8 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 * Written by Tim Wilkinson <tim@tjwassoc.demon.co.uk>, 1996.
19 #include <sys/types.h>
21 #include <sys/socket.h>
30 * We only need this stuff is we are using the internal thread system.
32 #if defined(USE_INTERNAL_THREADS)
36 #define TH_ACCEPT TH_READ
37 #define TH_CONNECT TH_WRITE
40 static fd_set readsPending;
41 static fd_set writesPending;
42 static thread* readQ[FD_SETSIZE];
43 static thread* writeQ[FD_SETSIZE];
44 static struct timeval tm = { 0, 0 };
46 void blockOnFile(int, int);
47 void waitOnEvents(void);
49 extern thread* currentThread;
51 /* These are undefined because we do not yet support async I/O */
58 * Create a threaded file descriptor.
61 threadedFileDescriptor(int fd)
63 #if !defined(BLOCKING_CALLS)
68 /* Make non-blocking */
69 #if defined(HAVE_FCNTL) && defined(O_NONBLOCK)
70 r = fcntl(fd, F_GETFL, 0);
71 r = fcntl(fd, F_SETFL, r|O_NONBLOCK);
72 #elif defined(HAVE_IOCTL) && defined(FIONBIO)
73 r = ioctl(fd, FIONBIO, &on);
82 /* Allow socket to signal this process when new data is available */
84 #if defined(HAVE_FCNTL) && defined(F_SETOWN)
85 r = fcntl(fd, F_SETOWN, pid);
86 #elif defined(HAVE_IOCTL) && defined(FIOSETOWN)
87 r = ioctl(fd, FIOSETOWN, &pid);
96 #if defined(HAVE_FCNTL) && defined(O_ASYNC)
97 r = fcntl(fd, F_GETFL, 0);
98 r = fcntl(fd, F_SETFL, r|O_ASYNC);
99 #elif defined(HAVE_IOCTL) && defined(FIOASYNC)
100 r = ioctl(fd, FIOASYNC, &on);
112 void clear_thread_flags(void)
114 #if !defined(BLOCKING_CALLS)
117 #if defined(HAVE_FCNTL) && defined(O_NONBLOCK)
119 fl = fcntl(fd, F_GETFL, 0);
120 fl = fcntl(fd, F_SETFL, fl & (~O_NONBLOCK));
123 fl = fcntl(fd, F_GETFL, 0);
124 fl = fcntl(fd, F_SETFL, fl & (~O_NONBLOCK));
127 fl = fcntl(fd, F_GETFL, 0);
128 fl = fcntl(fd, F_SETFL, fl & (~O_NONBLOCK));
129 #elif defined(HAVE_IOCTL) && defined(FIONBIO)
132 (void) ioctl(fd, FIONBIO, &fl);
135 (void) ioctl(fd, FIONBIO, &fl);
138 (void) ioctl(fd, FIONBIO, &fl);
148 * Threaded create socket.
151 threadedSocket(int af, int type, int proto)
158 fd = socket(af, type, proto);
159 return (threadedFileDescriptor(fd));
163 * Threaded file open.
166 threadedOpen(char* path, int flags, int mode)
173 fd = open(path, flags, mode);
174 return (threadedFileDescriptor(fd));
178 * Threaded socket connect.
181 threadedConnect(int fd, struct sockaddr* addr, int len)
185 r = connect(fd, addr, len);
186 #if !defined(BLOCKING_CALLS)
188 && (errno == EINPROGRESS || errno == EALREADY
189 || errno == EWOULDBLOCK)) {
190 blockOnFile(fd, TH_CONNECT);
191 r = 0; /* Assume it's okay when we get released */
199 * Threaded socket accept.
202 threadedAccept(int fd, struct sockaddr* addr, int* len)
209 #if defined(BLOCKING_CALLS)
210 blockOnFile(fd, TH_ACCEPT);
212 r = accept(fd, addr, (size_t*)len);
214 || !(errno == EINPROGRESS || errno == EALREADY
215 || errno == EWOULDBLOCK))
219 #if !defined(BLOCKING_CALLS)
220 blockOnFile(fd, TH_ACCEPT);
223 return (threadedFileDescriptor(r));
227 * Read but only if we can.
230 threadedRead(int fd, char* buf, int len)
234 DBG( printf("threadedRead\n"); )
236 #if defined(BLOCKING_CALLS)
237 blockOnFile(fd, TH_READ);
241 r = read(fd, buf, len);
243 && (errno == EAGAIN || errno == EWOULDBLOCK
246 blockOnFile(fd, TH_READ);
254 * Write but only if we can.
257 threadedWrite(int fd, char* buf, int len)
265 DBG( printf("threadedWrite %dbytes\n",len); )
267 while (len > 0 && r > 0)
269 #if defined(BLOCKING_CALLS)
270 blockOnFile(fd, TH_WRITE);
272 r = write(fd, ptr, len);
274 && (errno == EAGAIN || errno == EWOULDBLOCK
277 #if !defined(BLOCKING_CALLS)
278 blockOnFile(fd, TH_WRITE);
292 * An attempt to access a file would block, so suspend the thread until
296 blockOnFile(int fd, int op)
298 DBG( printf("blockOnFile()\n"); )
308 FD_SET(fd, &readsPending);
309 suspendOnQThread(currentThread, &readQ[fd]);
310 FD_CLR(fd, &readsPending);
314 FD_SET(fd, &writesPending);
315 suspendOnQThread(currentThread, &writeQ[fd]);
316 FD_CLR(fd, &writesPending);
323 * Check if some file descriptor or other event to become ready.
324 * Block if required (but make sure we can still take timer interrupts).
327 checkEvents(bool block)
337 DBG( printf("checkEvents block:%d\n", block); )
340 FD_COPY(&readsPending, &rd);
341 FD_COPY(&writesPending, &wr);
343 memcpy(&rd, &readsPending, sizeof(rd));
344 memcpy(&wr, &writesPending, sizeof(wr));
348 * If select() is called with indefinite wait, we have to make sure
349 * we can get interrupted by timer events.
355 r = select(maxFd+1, &rd, &wr, 0, 0);
360 r = select(maxFd+1, &rd, &wr, 0, &tm);
363 /* We must be holding off interrupts before we start playing with
364 * the read and write queues. This should be already done but a
365 * quick check never hurt anyone.
367 assert(blockInts > 0);
369 DBG( printf("Select returns %d\n", r); )
371 for (i = 0; r > 0 && i <= maxFd; i++)
373 if (readQ[i] != 0 && FD_ISSET(i, &rd))
375 for (tid = readQ[i]; tid != 0; tid = ntid)
383 if (writeQ[i] != 0 && FD_ISSET(i, &wr))
385 for (tid = writeQ[i]; tid != 0; tid = ntid)