1 /**
2  * D header file for POSIX.
3  *
4  * Copyright: Copyright Sean Kelly 2005 - 2016.
5  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6  * Authors:   Sean Kelly, Alex Rønne Petersen
7  * Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
8  */
9 module core.sys.posix.sys.select;
10 
11 private import core.sys.posix.config;
12 public import core.stdc.time;           // for timespec
13 public import core.sys.posix.sys.time;  // for timeval
14 public import core.sys.posix.sys.types; // for time_t
15 public import core.sys.posix.signal;    // for sigset_t
16 
17 //debug=select;  // uncomment to turn on debugging printf's
18 version (unittest) import core.stdc.stdio: printf;
19 
20 version (OSX)
21     version = Darwin;
22 else version (iOS)
23     version = Darwin;
24 else version (TVOS)
25     version = Darwin;
26 else version (WatchOS)
27     version = Darwin;
28 
version(Posix)29 version (Posix):
30 extern (C) nothrow @nogc:
31 
32 //
33 // Required
34 //
35 /*
36 NOTE: This module requires timeval from core.sys.posix.sys.time, but timeval
37       is supposedly an XOpen extension.  As a result, this header will not
38       compile on platforms that are not XSI-compliant.  This must be resolved
39       on a per-platform basis.
40 
41 fd_set
42 
43 void FD_CLR(int fd, fd_set* fdset);
44 int FD_ISSET(int fd, const(fd_set)* fdset);
45 void FD_SET(int fd, fd_set* fdset);
46 void FD_ZERO(fd_set* fdset);
47 
48 FD_SETSIZE
49 
50 int  pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
51 int  select(int, fd_set*, fd_set*, fd_set*, timeval*);
52 */
53 
54 version (CRuntime_Glibc)
55 {
56     private
57     {
58         alias c_long __fd_mask;
59         enum uint __NFDBITS = 8 * __fd_mask.sizeof;
60 
61         extern (D) auto __FDELT( int d ) pure
62         {
63             return d / __NFDBITS;
64         }
65 
66         extern (D) auto __FDMASK( int d ) pure
67         {
68             return cast(__fd_mask) 1 << ( d % __NFDBITS );
69         }
70     }
71 
72     enum FD_SETSIZE = 1024;
73 
74     struct fd_set
75     {
76         __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits;
77     }
78 
79     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
80     {
81         fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd );
82     }
83 
84     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
85     {
86         return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0;
87     }
88 
89     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
90     {
91         fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd );
92     }
93 
94     extern (D) void FD_ZERO( fd_set* fdset ) pure
95     {
96         fdset.fds_bits[0 .. $] = 0;
97     }
98 
99     /+
100      + GNU ASM Implementation
101      +
102     # define __FD_ZERO(fdsp)                                \
103       do {                                                  \
104         int __d0, __d1;                                     \
105         __asm__ __volatile__ ("cld; rep; stosl"             \
106                   : "=c" (__d0), "=D" (__d1)                \
107                   : "a" (0), "0" (sizeof (fd_set)           \
108                           / sizeof (__fd_mask)),            \
109                     "1" (&__FDS_BITS (fdsp)[0])             \
110                   : "memory");                              \
111       } while (0)
112 
113     # define __FD_SET(fd, fdsp)                             \
114       __asm__ __volatile__ ("btsl %1,%0"                    \
115                 : "=m" (__FDS_BITS (fdsp)[__FDELT (fd)])    \
116                 : "r" (((int) (fd)) % __NFDBITS)            \
117                 : "cc","memory")
118     # define __FD_CLR(fd, fdsp)                             \
119       __asm__ __volatile__ ("btrl %1,%0"                    \
120                 : "=m" (__FDS_BITS (fdsp)[__FDELT (fd)])    \
121                 : "r" (((int) (fd)) % __NFDBITS)            \
122                 : "cc","memory")
123     # define __FD_ISSET(fd, fdsp)                           \
124       (__extension__                                        \
125        ({register char __result;                            \
126          __asm__ __volatile__ ("btl %1,%2 ; setcb %b0"      \
127                    : "=q" (__result)                        \
128                    : "r" (((int) (fd)) % __NFDBITS),        \
129                      "m" (__FDS_BITS (fdsp)[__FDELT (fd)])  \
130                    : "cc");                                 \
131          __result; }))
132      +/
133 
134     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
135     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
136 }
version(Darwin)137 else version (Darwin)
138 {
139     private
140     {
141         enum uint __DARWIN_NBBY    = 8;                            /* bits in a byte */
142         enum uint __DARWIN_NFDBITS = (int.sizeof * __DARWIN_NBBY); /* bits per mask */
143     }
144 
145     enum FD_SETSIZE = 1024;
146 
147     struct fd_set
148     {
149         int[(FD_SETSIZE + (__DARWIN_NFDBITS - 1)) / __DARWIN_NFDBITS] fds_bits;
150     }
151 
152     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
153     {
154         fdset.fds_bits[fd / __DARWIN_NFDBITS] &= ~(1 << (fd % __DARWIN_NFDBITS));
155     }
156 
157     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
158     {
159         return (fdset.fds_bits[fd / __DARWIN_NFDBITS] & (1 << (fd % __DARWIN_NFDBITS))) != 0;
160     }
161 
162     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
163     {
164         fdset.fds_bits[fd / __DARWIN_NFDBITS] |= 1 << (fd % __DARWIN_NFDBITS);
165     }
166 
167     extern (D) void FD_ZERO( fd_set* fdset ) pure
168     {
169         fdset.fds_bits[0 .. $] = 0;
170     }
171 
172     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
173     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
174 }
version(FreeBSD)175 else version (FreeBSD)
176 {
177     private
178     {
179         alias c_ulong __fd_mask;
180         enum _NFDBITS = __fd_mask.sizeof * 8;
181     }
182 
183     enum uint FD_SETSIZE = 1024;
184 
185     struct fd_set
186     {
187         __fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
188     }
189 
190     extern (D) __fd_mask __fdset_mask(uint n) pure
191     {
192         return cast(__fd_mask) 1 << (n % _NFDBITS);
193     }
194 
195     extern (D) void FD_CLR( int n, fd_set* p ) pure
196     {
197         p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
198     }
199 
200     extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
201     {
202         return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
203     }
204 
205     extern (D) void FD_SET( int n, fd_set* p ) pure
206     {
207         p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
208     }
209 
210     extern (D) void FD_ZERO( fd_set* p ) pure
211     {
212         fd_set *_p;
213         size_t _n;
214 
215         _p = p;
216         _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
217         while (_n > 0)
218             _p.__fds_bits[--_n] = 0;
219     }
220 
221     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
222     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
223 }
version(NetBSD)224 else version (NetBSD)
225 {
226     private
227     {
228         alias c_ulong __fd_mask;
229         enum _NFDBITS = __fd_mask.sizeof * 8;
230     }
231 
232     enum uint FD_SETSIZE = 256;
233 
234     struct fd_set
235     {
236         __fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
237     }
238 
239     extern (D) __fd_mask __fdset_mask(uint n) pure
240     {
241         return cast(__fd_mask) 1 << (n % _NFDBITS);
242     }
243 
244     extern (D) void FD_CLR( int n, fd_set* p ) pure
245     {
246         p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
247     }
248 
249     extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
250     {
251         return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
252     }
253 
254     extern (D) void FD_SET( int n, fd_set* p ) pure
255     {
256         p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
257     }
258 
259     extern (D) void FD_ZERO( fd_set* p ) pure
260     {
261         fd_set *_p;
262         size_t _n;
263 
264         _p = p;
265         _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
266         while (_n > 0)
267             _p.__fds_bits[--_n] = 0;
268     }
269 
270     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
271     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
272 }
version(DragonFlyBSD)273 else version (DragonFlyBSD)
274 {
275     private
276     {
277         alias c_ulong __fd_mask;
278         enum _NFDBITS = __fd_mask.sizeof * 8;
279     }
280 
281     enum uint FD_SETSIZE = 1024;
282 
283     struct fd_set
284     {
285         __fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
286     }
287 
288     extern (D) __fd_mask __fdset_mask(uint n) pure
289     {
290         return cast(__fd_mask) 1 << (n % _NFDBITS);
291     }
292 
293     extern (D) void FD_CLR( int n, fd_set* p ) pure
294     {
295         p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
296     }
297 
298     extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
299     {
300         return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
301     }
302 
303     extern (D) void FD_SET( int n, fd_set* p ) pure
304     {
305         p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
306     }
307 
308     extern (D) void FD_ZERO( fd_set* p ) pure
309     {
310         fd_set *_p;
311         size_t _n;
312 
313         _p = p;
314         _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
315         while (_n > 0)
316             _p.__fds_bits[--_n] = 0;
317     }
318 
319     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
320     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
321 }
version(Solaris)322 else version (Solaris)
323 {
324     private
325     {
326         alias c_long fds_mask;
327 
328         enum _NBBY = 8;
329         enum FD_NFDBITS = fds_mask.sizeof * _NBBY;
330     }
331 
332     version (D_LP64)
333         enum uint FD_SETSIZE = 65536;
334     else
335         enum uint FD_SETSIZE = 1024;
336 
337     struct fd_set
338     {
339         c_long[(FD_SETSIZE + (FD_NFDBITS - 1)) / FD_NFDBITS] fds_bits;
340     }
341 
342     extern (D) void FD_SET(int __n, fd_set* __p) pure
343     {
344         __p.fds_bits[__n / FD_NFDBITS] |= 1UL << (__n % FD_NFDBITS);
345     }
346 
347     extern (D) void FD_CLR(int __n, fd_set* __p) pure
348     {
349         __p.fds_bits[__n / FD_NFDBITS] &= ~(1UL << (__n % FD_NFDBITS));
350     }
351 
352     extern (D) bool FD_ISSET(int __n, const(fd_set)* __p) pure
353     {
354         return (__p.fds_bits[__n / FD_NFDBITS] & (1UL << (__n % FD_NFDBITS))) != 0;
355     }
356 
357     extern (D) void FD_ZERO(fd_set* __p) pure
358     {
359         __p.fds_bits[0 .. $] = 0;
360     }
361 
362     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
363     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
364 }
version(CRuntime_Bionic)365 else version (CRuntime_Bionic)
366 {
367     private
368     {
369         alias c_ulong __fd_mask;
370         enum uint __NFDBITS = 8 * __fd_mask.sizeof;
371 
372         extern (D) auto __FDELT( int d ) pure
373         {
374             return d / __NFDBITS;
375         }
376 
377         extern (D) auto __FDMASK( int d ) pure
378         {
379             return cast(__fd_mask) 1 << ( d % __NFDBITS );
380         }
381     }
382 
383     enum FD_SETSIZE = 1024;
384 
385     struct fd_set
386     {
387         __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits;
388     }
389 
390     // These functions are generated in assembly in bionic.
391     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
392     {
393         fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd );
394     }
395 
396     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
397     {
398         return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0;
399     }
400 
401     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
402     {
403         fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd );
404     }
405 
406     extern (D) void FD_ZERO( fd_set* fdset ) pure
407     {
408         fdset.fds_bits[0 .. $] = 0;
409     }
410 
411     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
412     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
413 }
version(CRuntime_Musl)414 else version (CRuntime_Musl)
415 {
416     enum FD_SETSIZE = 1024;
417 
418     alias ulong fd_mask;
419 
420     private
421     {
422         enum uint __NFDBITS = 8 * fd_mask.sizeof;
423 
424         extern (D) auto __FDELT( int d ) pure
425         {
426             return d / __NFDBITS;
427         }
428 
429         extern (D) auto __FDMASK( int d ) pure
430         {
431             return cast(fd_mask) 1 << ( d % __NFDBITS );
432         }
433     }
434 
435     struct fd_set {
436         ulong[FD_SETSIZE / 8 / long.sizeof] fds_bits;
437     }
438 
439     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
440     {
441         fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd );
442     }
443 
444     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
445     {
446         return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0;
447     }
448 
449     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
450     {
451         fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd );
452     }
453 
454     extern (D) void FD_ZERO( fd_set* fdset ) pure
455     {
456         fdset.fds_bits[0 .. $] = 0;
457     }
458     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
459     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
460 }
version(CRuntime_UClibc)461 else version (CRuntime_UClibc)
462 {
463     private
464     {
465         alias c_long __fd_mask;
466         enum uint __NFDBITS = 8 * __fd_mask.sizeof;
467 
468         extern (D) auto __FDELT( int d ) pure
469         {
470             return d / __NFDBITS;
471         }
472 
473         extern (D) auto __FDMASK( int d ) pure
474         {
475             return cast(__fd_mask) 1 << ( d % __NFDBITS );
476         }
477     }
478 
479     enum FD_SETSIZE = 1024;
480 
481     struct fd_set
482     {
483         __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits;
484     }
485 
486     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
487     {
488         fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd );
489     }
490 
491     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
492     {
493         return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0;
494     }
495 
496     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
497     {
498         fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd );
499     }
500 
501     extern (D) void FD_ZERO( fd_set* fdset ) pure
502     {
503         fdset.fds_bits[0 .. $] = 0;
504     }
505 
506     int pselect(int, fd_set*, fd_set*, fd_set*, in timespec*, in sigset_t*);
507     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
508 }
509 else
510 {
511     static assert(false, "Unsupported platform");
512 }
513 
514 pure unittest
515 {
516     debug(select) printf("core.sys.posix.sys.select unittest\n");
517 
518     fd_set fd;
519 
520     for (auto i = 0; i < FD_SETSIZE; i++)
521     {
522         assert(!FD_ISSET(i, &fd));
523     }
524 
525     for (auto i = 0; i < FD_SETSIZE; i++)
526     {
527         if ((i & -i) == i)
528             FD_SET(i, &fd);
529     }
530 
531     for (auto i = 0; i < FD_SETSIZE; i++)
532     {
533         if ((i & -i) == i)
534             assert(FD_ISSET(i, &fd));
535         else
536             assert(!FD_ISSET(i, &fd));
537     }
538 
539     for (auto i = 0; i < FD_SETSIZE; i++)
540     {
541         if ((i & -i) == i)
542             FD_CLR(i, &fd);
543         else
544             FD_SET(i, &fd);
545     }
546 
547     for (auto i = 0; i < FD_SETSIZE; i++)
548     {
549         if ((i & -i) == i)
550             assert(!FD_ISSET(i, &fd));
551         else
552             assert(FD_ISSET(i, &fd));
553     }
554 
555     FD_ZERO(&fd);
556 
557     for (auto i = 0; i < FD_SETSIZE; i++)
558     {
559         assert(!FD_ISSET(i, &fd));
560     }
561 }
562 
563