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