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 
version(Posix)28 version (Posix):
29 extern (C) nothrow @nogc:
30 @system:
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*, const scope timespec*, const scope 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*, const scope timespec*, const scope 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*, const scope timespec*, const scope 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*, const scope timespec*, const scope 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*, const scope timespec*, const scope sigset_t*);
271     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
272 }
version(OpenBSD)273 else version (OpenBSD)
274 {
275     private
276     {
277         alias uint __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 = p;
311         size_t _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
312 
313         while (_n > 0)
314             _p.__fds_bits[--_n] = 0;
315     }
316 
317     int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
318     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
319 }
version(DragonFlyBSD)320 else version (DragonFlyBSD)
321 {
322     private
323     {
324         alias c_ulong __fd_mask;
325         enum _NFDBITS = __fd_mask.sizeof * 8;
326     }
327 
328     enum uint FD_SETSIZE = 1024;
329 
330     struct fd_set
331     {
332         __fd_mask[(FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS] __fds_bits;
333     }
334 
335     extern (D) __fd_mask __fdset_mask(uint n) pure
336     {
337         return cast(__fd_mask) 1 << (n % _NFDBITS);
338     }
339 
340     extern (D) void FD_CLR( int n, fd_set* p ) pure
341     {
342         p.__fds_bits[n / _NFDBITS] &= ~__fdset_mask(n);
343     }
344 
345     extern (D) bool FD_ISSET( int n, const(fd_set)* p ) pure
346     {
347         return (p.__fds_bits[n / _NFDBITS] & __fdset_mask(n)) != 0;
348     }
349 
350     extern (D) void FD_SET( int n, fd_set* p ) pure
351     {
352         p.__fds_bits[n / _NFDBITS] |= __fdset_mask(n);
353     }
354 
355     extern (D) void FD_ZERO( fd_set* p ) pure
356     {
357         fd_set *_p;
358         size_t _n;
359 
360         _p = p;
361         _n = (FD_SETSIZE + (_NFDBITS - 1)) / _NFDBITS;
362         while (_n > 0)
363             _p.__fds_bits[--_n] = 0;
364     }
365 
366     int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
367     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
368 }
version(Solaris)369 else version (Solaris)
370 {
371     private
372     {
373         alias c_long fds_mask;
374 
375         enum _NBBY = 8;
376         enum FD_NFDBITS = fds_mask.sizeof * _NBBY;
377     }
378 
379     version (D_LP64)
380         enum uint FD_SETSIZE = 65536;
381     else
382         enum uint FD_SETSIZE = 1024;
383 
384     struct fd_set
385     {
386         c_long[(FD_SETSIZE + (FD_NFDBITS - 1)) / FD_NFDBITS] fds_bits;
387     }
388 
389     extern (D) void FD_SET(int __n, fd_set* __p) pure
390     {
391         __p.fds_bits[__n / FD_NFDBITS] |= 1UL << (__n % FD_NFDBITS);
392     }
393 
394     extern (D) void FD_CLR(int __n, fd_set* __p) pure
395     {
396         __p.fds_bits[__n / FD_NFDBITS] &= ~(1UL << (__n % FD_NFDBITS));
397     }
398 
399     extern (D) bool FD_ISSET(int __n, const(fd_set)* __p) pure
400     {
401         return (__p.fds_bits[__n / FD_NFDBITS] & (1UL << (__n % FD_NFDBITS))) != 0;
402     }
403 
404     extern (D) void FD_ZERO(fd_set* __p) pure
405     {
406         __p.fds_bits[0 .. $] = 0;
407     }
408 
409     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
410     int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
411 }
version(CRuntime_Bionic)412 else version (CRuntime_Bionic)
413 {
414     private
415     {
416         alias c_ulong __fd_mask;
417         enum uint __NFDBITS = 8 * __fd_mask.sizeof;
418 
419         extern (D) auto __FDELT( int d ) pure
420         {
421             return d / __NFDBITS;
422         }
423 
424         extern (D) auto __FDMASK( int d ) pure
425         {
426             return cast(__fd_mask) 1 << ( d % __NFDBITS );
427         }
428     }
429 
430     enum FD_SETSIZE = 1024;
431 
432     struct fd_set
433     {
434         __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits;
435     }
436 
437     // These functions are generated in assembly in bionic.
438     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
439     {
440         fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd );
441     }
442 
443     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
444     {
445         return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0;
446     }
447 
448     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
449     {
450         fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd );
451     }
452 
453     extern (D) void FD_ZERO( fd_set* fdset ) pure
454     {
455         fdset.fds_bits[0 .. $] = 0;
456     }
457 
458     int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
459     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
460 }
version(CRuntime_Musl)461 else version (CRuntime_Musl)
462 {
463     enum FD_SETSIZE = 1024;
464 
465     alias ulong fd_mask;
466 
467     private
468     {
469         enum uint __NFDBITS = 8 * fd_mask.sizeof;
470 
471         extern (D) auto __FDELT( int d ) pure
472         {
473             return d / __NFDBITS;
474         }
475 
476         extern (D) auto __FDMASK( int d ) pure
477         {
478             return cast(fd_mask) 1 << ( d % __NFDBITS );
479         }
480     }
481 
482     struct fd_set {
483         ulong[FD_SETSIZE / 8 / long.sizeof] 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     int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
506     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
507 }
version(CRuntime_UClibc)508 else version (CRuntime_UClibc)
509 {
510     private
511     {
512         alias c_long __fd_mask;
513         enum uint __NFDBITS = 8 * __fd_mask.sizeof;
514 
515         extern (D) auto __FDELT( int d ) pure
516         {
517             return d / __NFDBITS;
518         }
519 
520         extern (D) auto __FDMASK( int d ) pure
521         {
522             return cast(__fd_mask) 1 << ( d % __NFDBITS );
523         }
524     }
525 
526     enum FD_SETSIZE = 1024;
527 
528     struct fd_set
529     {
530         __fd_mask[FD_SETSIZE / __NFDBITS] fds_bits;
531     }
532 
533     extern (D) void FD_CLR( int fd, fd_set* fdset ) pure
534     {
535         fdset.fds_bits[__FDELT( fd )] &= ~__FDMASK( fd );
536     }
537 
538     extern (D) bool FD_ISSET( int fd, const(fd_set)* fdset ) pure
539     {
540         return (fdset.fds_bits[__FDELT( fd )] & __FDMASK( fd )) != 0;
541     }
542 
543     extern (D) void FD_SET( int fd, fd_set* fdset ) pure
544     {
545         fdset.fds_bits[__FDELT( fd )] |= __FDMASK( fd );
546     }
547 
548     extern (D) void FD_ZERO( fd_set* fdset ) pure
549     {
550         fdset.fds_bits[0 .. $] = 0;
551     }
552 
553     int pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
554     int select(int, fd_set*, fd_set*, fd_set*, timeval*);
555 }
556 else
557 {
558     static assert(false, "Unsupported platform");
559 }
560 
561 pure unittest
562 {
563     import core.stdc.stdio: printf;
564 
565     debug(select) printf("core.sys.posix.sys.select unittest\n");
566 
567     fd_set fd;
568 
569     for (auto i = 0; i < FD_SETSIZE; i++)
570     {
571         assert(!FD_ISSET(i, &fd));
572     }
573 
574     for (auto i = 0; i < FD_SETSIZE; i++)
575     {
576         if ((i & -i) == i)
577             FD_SET(i, &fd);
578     }
579 
580     for (auto i = 0; i < FD_SETSIZE; i++)
581     {
582         if ((i & -i) == i)
583             assert(FD_ISSET(i, &fd));
584         else
585             assert(!FD_ISSET(i, &fd));
586     }
587 
588     for (auto i = 0; i < FD_SETSIZE; i++)
589     {
590         if ((i & -i) == i)
591             FD_CLR(i, &fd);
592         else
593             FD_SET(i, &fd);
594     }
595 
596     for (auto i = 0; i < FD_SETSIZE; i++)
597     {
598         if ((i & -i) == i)
599             assert(!FD_ISSET(i, &fd));
600         else
601             assert(FD_ISSET(i, &fd));
602     }
603 
604     FD_ZERO(&fd);
605 
606     for (auto i = 0; i < FD_SETSIZE; i++)
607     {
608         assert(!FD_ISSET(i, &fd));
609     }
610 }
611 
612