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