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 */
9module core.sys.posix.sys.select;
10
11import core.sys.posix.config;
12public import core.stdc.time;           // for timespec
13public import core.sys.posix.sys.time;  // for timeval
14public import core.sys.posix.sys.types; // for time_t
15public import core.sys.posix.signal;    // for sigset_t
16
17//debug=select;  // uncomment to turn on debugging printf's
18
19version (OSX)
20    version = Darwin;
21else version (iOS)
22    version = Darwin;
23else version (TVOS)
24    version = Darwin;
25else version (WatchOS)
26    version = Darwin;
27
28version (Posix):
29extern (C) nothrow @nogc:
30@system:
31
32//
33// Required
34//
35/*
36NOTE: 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
41fd_set
42
43void FD_CLR(int fd, fd_set* fdset);
44int FD_ISSET(int fd, const(fd_set)* fdset);
45void FD_SET(int fd, fd_set* fdset);
46void FD_ZERO(fd_set* fdset);
47
48FD_SETSIZE
49
50int  pselect(int, fd_set*, fd_set*, fd_set*, const scope timespec*, const scope sigset_t*);
51int  select(int, fd_set*, fd_set*, fd_set*, timeval*);
52*/
53
54version (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}
137else 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}
175else 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}
224else 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}
273else 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}
320else 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}
369else 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}
412else 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}
461else 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}
508else 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}
556else
557{
558    static assert(false, "Unsupported platform");
559}
560
561pure 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