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