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 }