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.
15 #include "sysdep/defines.h"
17 #include <sys/types.h>
19 #include <sys/socket.h>
28 * We only need this stuff is we are using the internal thread system.
30 #if defined(USE_INTERNAL_THREADS)
34 #define TH_ACCEPT TH_READ
35 #define TH_CONNECT TH_WRITE
38 static fd_set readsPending;
39 static fd_set writesPending;
40 static thread* readQ[FD_SETSIZE];
41 static thread* writeQ[FD_SETSIZE];
42 static struct timeval tm = { 0, 0 };
44 void blockOnFile(int, int);
45 void waitOnEvents(void);
47 extern thread* currentThread;
49 /* These are undefined because we do not yet support async I/O */
56 * Create a threaded file descriptor.
59 threadedFileDescriptor(int fd)
61 #if !defined(BLOCKING_CALLS)
66 /* Make non-blocking */
67 #if defined(HAVE_FCNTL) && defined(O_NONBLOCK)
68 r = fcntl(fd, F_GETFL, 0);
69 r = fcntl(fd, F_SETFL, r|O_NONBLOCK);
70 #elif defined(HAVE_IOCTL) && defined(FIONBIO)
71 r = ioctl(fd, FIONBIO, &on);
80 /* Allow socket to signal this process when new data is available */
82 #if defined(HAVE_FCNTL) && defined(F_SETOWN)
83 r = fcntl(fd, F_SETOWN, pid);
84 #elif defined(HAVE_IOCTL) && defined(FIOSETOWN)
85 r = ioctl(fd, FIOSETOWN, &pid);
94 #if defined(HAVE_FCNTL) && defined(O_ASYNC)
95 r = fcntl(fd, F_GETFL, 0);
96 r = fcntl(fd, F_SETFL, r|O_ASYNC);
97 #elif defined(HAVE_IOCTL) && defined(FIOASYNC)
98 r = ioctl(fd, FIOASYNC, &on);
110 void clear_thread_flags(void)
112 #if !defined(BLOCKING_CALLS)
115 #if defined(HAVE_FCNTL) && defined(O_NONBLOCK)
117 fl = fcntl(fd, F_GETFL, 0);
118 fl = fcntl(fd, F_SETFL, fl & (~O_NONBLOCK));
121 fl = fcntl(fd, F_GETFL, 0);
122 fl = fcntl(fd, F_SETFL, fl & (~O_NONBLOCK));
125 fl = fcntl(fd, F_GETFL, 0);
126 fl = fcntl(fd, F_SETFL, fl & (~O_NONBLOCK));
127 #elif defined(HAVE_IOCTL) && defined(FIONBIO)
130 (void) ioctl(fd, FIONBIO, &fl);
133 (void) ioctl(fd, FIONBIO, &fl);
136 (void) ioctl(fd, FIONBIO, &fl);
146 * Threaded create socket.
149 threadedSocket(int af, int type, int proto)
156 fd = socket(af, type, proto);
157 return (threadedFileDescriptor(fd));
161 * Threaded file open.
164 threadedOpen(char* path, int flags, int mode)
171 fd = open(path, flags, mode);
172 return (threadedFileDescriptor(fd));
176 * Threaded socket connect.
179 threadedConnect(int fd, struct sockaddr* addr, int len)
183 r = connect(fd, addr, len);
184 #if !defined(BLOCKING_CALLS)
186 && (errno == EINPROGRESS || errno == EALREADY
187 || errno == EWOULDBLOCK)) {
188 blockOnFile(fd, TH_CONNECT);
189 r = 0; /* Assume it's okay when we get released */
197 * Threaded socket accept.
200 threadedAccept(int fd, struct sockaddr* addr, int* len)
207 #if defined(BLOCKING_CALLS)
208 blockOnFile(fd, TH_ACCEPT);
210 r = accept(fd, addr, len);
212 || !(errno == EINPROGRESS || errno == EALREADY
213 || errno == EWOULDBLOCK))
217 #if !defined(BLOCKING_CALLS)
218 blockOnFile(fd, TH_ACCEPT);
221 return (threadedFileDescriptor(r));
225 * Read but only if we can.
228 threadedRead(int fd, char* buf, int len)
232 DBG( printf("threadedRead\n"); )
234 #if defined(BLOCKING_CALLS)
235 blockOnFile(fd, TH_READ);
239 r = read(fd, buf, len);
241 && (errno == EAGAIN || errno == EWOULDBLOCK
244 blockOnFile(fd, TH_READ);
252 * Write but only if we can.
255 threadedWrite(int fd, char* buf, int len)
263 DBG( printf("threadedWrite %dbytes\n",len); )
265 while (len > 0 && r > 0)
267 #if defined(BLOCKING_CALLS)
268 blockOnFile(fd, TH_WRITE);
270 r = write(fd, ptr, len);
272 && (errno == EAGAIN || errno == EWOULDBLOCK
275 #if !defined(BLOCKING_CALLS)
276 blockOnFile(fd, TH_WRITE);
290 * An attempt to access a file would block, so suspend the thread until
294 blockOnFile(int fd, int op)
296 DBG( printf("blockOnFile()\n"); )
306 FD_SET(fd, &readsPending);
307 suspendOnQThread(currentThread, &readQ[fd]);
308 FD_CLR(fd, &readsPending);
312 FD_SET(fd, &writesPending);
313 suspendOnQThread(currentThread, &writeQ[fd]);
314 FD_CLR(fd, &writesPending);
321 * Check if some file descriptor or other event to become ready.
322 * Block if required (but make sure we can still take timer interrupts).
325 checkEvents(bool block)
335 DBG( printf("checkEvents block:%d\n", block); )
338 FD_COPY(&readsPending, &rd);
339 FD_COPY(&writesPending, &wr);
341 memcpy(&rd, &readsPending, sizeof(rd));
342 memcpy(&wr, &writesPending, sizeof(wr));
346 * If select() is called with indefinite wait, we have to make sure
347 * we can get interrupted by timer events.
353 r = select(maxFd+1, &rd, &wr, 0, 0);
358 r = select(maxFd+1, &rd, &wr, 0, &tm);
361 /* We must be holding off interrupts before we start playing with
362 * the read and write queues. This should be already done but a
363 * quick check never hurt anyone.
365 assert(blockInts > 0);
367 DBG( printf("Select returns %d\n", r); )
369 for (i = 0; r > 0 && i <= maxFd; i++)
371 if (readQ[i] != 0 && FD_ISSET(i, &rd))
373 for (tid = readQ[i]; tid != 0; tid = ntid)
381 if (writeQ[i] != 0 && FD_ISSET(i, &wr))
383 for (tid = writeQ[i]; tid != 0; tid = ntid)