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