1 /***************************************************************************** 2 3 Linux Epoll API binding and utility struct. 4 5 Copyright: 6 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 7 All rights reserved. 8 9 License: 10 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 11 Alternatively, this file may be distributed under the terms of the Tango 12 3-Clause BSD License (see LICENSE_BSD.txt for details). 13 14 *****************************************************************************/ 15 16 module ocean.sys.Epoll; 17 18 19 import ocean.meta.types.Qualifiers; 20 import ocean.core.Verify; 21 import core.sys.posix.unistd: close; 22 23 version (unittest) 24 { 25 debug = EpollFdSanity; 26 import ocean.core.Test; 27 } 28 29 /***************************************************************************** 30 31 Struct bundling the event to register a file descriptor for with an 32 attachment. 33 34 *****************************************************************************/ 35 36 align (1) struct epoll_event_t 37 { 38 /************************************************************************** 39 40 Events supported by epoll, can be OR-combined. 41 42 **************************************************************************/ 43 44 enum Event : uint 45 { 46 None = 0, 47 48 /********************************************************************** 49 50 The associated file is available for read(2) operations. 51 52 **********************************************************************/ 53 54 EPOLLIN = 0x001, 55 56 /********************************************************************** 57 58 There is urgent data available for read(2) operations. 59 60 **********************************************************************/ 61 62 EPOLLPRI = 0x002, 63 64 /********************************************************************** 65 66 The associated file is available for write(2) operations. 67 68 **********************************************************************/ 69 70 EPOLLOUT = 0x004, 71 72 EPOLLRDNORM = 0x040, 73 EPOLLRDBAND = 0x080, 74 EPOLLWRNORM = 0x100, 75 EPOLLWRBAND = 0x200, 76 EPOLLMSG = 0x400, 77 78 /********************************************************************** 79 80 Error condition happened on the associated file descriptor. 81 epoll_wait(2) will always wait for this event; it is not necessary 82 to set it in events. 83 84 **********************************************************************/ 85 86 EPOLLERR = 0x008, 87 88 /********************************************************************** 89 90 Hang up happened on the associated file descriptor. epoll_wait(2) 91 will always wait for this event; it is not necessary to set it in 92 events. 93 94 **********************************************************************/ 95 96 EPOLLHUP = 0x010, 97 98 /********************************************************************** 99 100 (since Linux 2.6.17) 101 Stream socket peer closed connection, or shut down writing half of 102 connection. (This flag is especially useful for writing simple code 103 to detect peer shutdown when using Edge Triggered monitoring.) 104 105 **********************************************************************/ 106 107 EPOLLRDHUP = 0x2000, 108 109 /********************************************************************** 110 111 (since Linux 2.6.2) 112 Sets the one-shot behavior for the associated file descriptor. This 113 means that after an event is pulled out with epoll_wait(2) the 114 associated file descriptor is internally disabled and no other 115 events will be reported by the epoll interface. The user must call 116 epoll_ctl() with EPOLL_CTL_MOD to rearm the file descriptor with a 117 new event mask. 118 119 **********************************************************************/ 120 121 EPOLLONESHOT = 1u << 30, 122 123 /********************************************************************** 124 125 Sets the Edge Triggered behavior for the associated file descriptor. 126 The default behavior for epoll is Level Triggered. See epoll(7) for 127 more detailed information about Edge and Level Triggered event 128 distribution architectures. 129 130 **********************************************************************/ 131 132 EPOLLET = 1u << 31 133 } 134 135 /************************************************************************** 136 137 Mapping from Event -> string, useful for printouts 138 139 **************************************************************************/ 140 141 static istring[Event] event_to_name; 142 143 static this ( ) 144 { 145 with ( Event ) 146 { 147 event_to_name[EPOLLIN] = "Re"; 148 event_to_name[EPOLLPRI] = "Pr"; 149 event_to_name[EPOLLOUT] = "Wr"; 150 event_to_name[EPOLLRDNORM] = "Rn"; 151 event_to_name[EPOLLRDBAND] = "Rb"; 152 event_to_name[EPOLLWRNORM] = "Wn"; 153 event_to_name[EPOLLWRBAND] = "Wb"; 154 event_to_name[EPOLLMSG] = "Ms"; 155 event_to_name[EPOLLERR] = "Er"; 156 event_to_name[EPOLLHUP] = "Hu"; 157 event_to_name[EPOLLRDHUP] = "Rh"; 158 event_to_name[EPOLLONESHOT] = "Os"; 159 event_to_name[EPOLLET] = "Et"; 160 } 161 event_to_name.rehash; 162 } 163 164 /************************************************************************** 165 166 Convenience type alias 167 168 **************************************************************************/ 169 170 alias .epoll_data_t Data; 171 172 /************************************************************************** 173 174 Epoll events 175 176 **************************************************************************/ 177 178 Event events; 179 180 /************************************************************************** 181 182 User data variable 183 184 **************************************************************************/ 185 186 Data data; 187 } 188 189 /****************************************************************************** 190 191 Epoll user data union 192 193 ******************************************************************************/ 194 195 align (1) union epoll_data_t 196 { 197 void* ptr; 198 int fd; 199 uint u32; 200 ulong u64; 201 202 /************************************************************************** 203 204 Sets ptr to o. 205 206 Params: 207 o = object to set ptr to 208 209 Returns: 210 ptr cast back to Object 211 212 **************************************************************************/ 213 214 Object obj ( Object o ) 215 { 216 return cast (Object) (this.ptr = cast (void*) o); 217 } 218 219 /************************************************************************** 220 221 Obtains the object to which ptr should previously have been set. 222 223 Returns: 224 ptr cast back to Object 225 226 **************************************************************************/ 227 228 Object obj ( ) 229 { 230 return cast (Object) this.ptr; 231 } 232 } 233 234 /****************************************************************************** 235 236 Flags accepted by epoll_create1(), can be OR-combined. 237 238 ******************************************************************************/ 239 240 enum EpollCreateFlags 241 { 242 None = 0, 243 244 /************************************************************************** 245 246 Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. 247 See the description of the O_CLOEXEC flag in open(2) for reasons why 248 this may be useful. 249 250 **************************************************************************/ 251 252 EPOLL_CLOEXEC = 0x8_0000, // 02000000 253 254 EPOLL_NONBLOCK = 0x800 // 04000 255 } 256 257 /****************************************************************************** 258 259 epoll_ctl opcodes. 260 261 ******************************************************************************/ 262 263 enum EpollCtlOp : int 264 { 265 /************************************************************************** 266 267 Register the target file descriptor fd on the epoll instance referred to 268 by the file descriptor epfd and associate the event event with the 269 internal file linked to fd. 270 271 **************************************************************************/ 272 273 EPOLL_CTL_ADD = 1, 274 275 /************************************************************************** 276 277 Remove (deregister) the target file descriptor fd from the epoll 278 instance referred to by epfd. The event is ignored; it and can be null 279 on Linux 2.6.9 or later. 280 281 **************************************************************************/ 282 283 EPOLL_CTL_DEL = 2, 284 285 /************************************************************************** 286 287 Change the event event associated with the target file descriptor fd. 288 289 **************************************************************************/ 290 291 EPOLL_CTL_MOD = 3 292 } 293 294 295 extern (C) 296 { 297 /************************************************************************** 298 299 Description 300 301 epoll_create1() creates an epoll "instance", requesting the kernel to 302 allocate an event backing store dimensioned for size descriptors. 303 epoll_create1() returns a file descriptor referring to the new epoll 304 instance. This file descriptor is used for all the subsequent calls to 305 the epoll interface. When no longer required, the file descriptor 306 returned by epoll_create1() should be closed by using close(2). When all 307 file descriptors referring to an epoll instance have been closed, the 308 kernel destroys the instance and releases the associated resources for 309 reuse. 310 311 The following value can be included in flags: 312 313 EPOLL_CLOEXEC 314 Set the close-on-exec (FD_CLOEXEC) flag on the new file descriptor. 315 See the description of the O_CLOEXEC flag in open(2) for reasons why 316 this may be useful. 317 318 Return Value 319 320 On success, these system calls return a nonnegative file descriptor. 321 On error, -1 is returned, and errno is set to indicate the error. 322 323 Errors 324 325 EINVAL 326 size is not positive. 327 EINVAL 328 Invalid value specified in flags. 329 EMFILE 330 The per-user limit on the number of epoll instances imposed by 331 /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) 332 for further details. 333 ENFILE 334 The system limit on the total number of open files has been reached. 335 ENOMEM 336 There was insufficient memory to create the kernel object. 337 338 Versions 339 epoll_create1() was added to the kernel in version 2.6.27. Library 340 support is provided in glibc starting with version 2.9. 341 342 **************************************************************************/ 343 344 int epoll_create1(EpollCreateFlags flags = EpollCreateFlags.None); 345 346 /************************************************************************** 347 348 Description 349 350 This system call performs control operations on the epoll instance 351 referred to by the file descriptor epfd. It requests that the operation 352 op be performed for the target file descriptor, fd. 353 354 Valid values for the op argument are: 355 356 EPOLL_CTL_ADD 357 Register the target file descriptor fd on the epoll instance 358 referred to by the file descriptor epfd and associate the event 359 event with the internal file linked to fd. 360 EPOLL_CTL_MOD 361 Change the event event associated with the target file descriptor 362 fd. 363 EPOLL_CTL_DEL 364 Remove (deregister) the target file descriptor fd from the epoll 365 instance referred to by epfd. The event is ignored; it and can be null 366 on Linux 2.6.9 or later. 367 368 The event argument describes the object linked to the file descriptor 369 fd. The events member is a bit set composed using the following 370 available event types: 371 372 EPOLLIN 373 The associated file is available for read(2) operations. 374 EPOLLOUT 375 The associated file is available for write(2) operations. 376 EPOLLRDHUP (since Linux 2.6.17) 377 Stream socket peer closed connection, or shut down writing half of 378 connection. (This flag is especially useful for writing simple code 379 to detect peer shutdown when using Edge Triggered monitoring.) 380 EPOLLPRI 381 There is urgent data available for read(2) operations. 382 EPOLLERR 383 Error condition happened on the associated file descriptor. 384 epoll_wait(2) will always wait for this event; it is not necessary 385 to set it in events. 386 EPOLLHUP 387 Hang up happened on the associated file descriptor. epoll_wait(2) 388 will always wait for this event; it is not necessary to set it in 389 events. 390 EPOLLET 391 Sets the Edge Triggered behavior for the associated file descriptor. 392 The default behavior for epoll is Level Triggered. See epoll(7) for 393 more detailed information about Edge and Level Triggered event 394 distribution architectures. 395 EPOLLONESHOT (since Linux 2.6.2) 396 Sets the one-shot behavior for the associated file descriptor. This 397 means that after an event is pulled out with epoll_wait(2) the 398 associated file descriptor is internally disabled and no other 399 events will be reported by the epoll interface. The user must call 400 epoll_ctl() with EPOLL_CTL_MOD to rearm the file descriptor with a 401 new event mask. 402 403 Return Value 404 405 When successful, epoll_ctl() returns zero. When an error occurs, 406 epoll_ctl() returns -1 and errno is set appropriately. 407 408 Errors 409 410 EBADF 411 epfd or fd is not a valid file descriptor. 412 EEXIST 413 op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already 414 registered with this epoll instance. 415 EINVAL 416 epfd is not an epoll file descriptor, or fd is the same as epfd, or 417 the requested operation op is not supported by this interface. 418 ENOENT 419 op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with 420 this epoll instance. 421 ENOMEM 422 There was insufficient memory to handle the requested op control 423 operation. 424 ENOSPC 425 The limit imposed by /proc/sys/fs/epoll/max_user_watches was 426 encountered while trying to register (EPOLL_CTL_ADD) a new file 427 descriptor on an epoll instance. See epoll(7) for further details. 428 EPERM 429 The target file fd does not support epoll. 430 431 Versions 432 433 epoll_ctl() was added to the kernel in version 2.6. 434 435 **************************************************************************/ 436 437 int epoll_ctl(int epfd, EpollCtlOp op, int fd, epoll_event_t* event); 438 439 /************************************************************************** 440 441 Description 442 443 The epoll_wait() system call waits for events on the epoll instance 444 referred to by the file descriptor epfd. The memory area pointed to by 445 events will contain the events that will be available for the caller. 446 Up to maxevents are returned by epoll_wait(). The maxevents argument 447 must be greater than zero. 448 449 The call waits for a maximum time of timeout milliseconds. Specifying a 450 timeout of -1 makes epoll_wait() wait indefinitely, while specifying a 451 timeout equal to zero makes epoll_wait() to return immediately even if 452 no events are available (return code equal to zero). 453 454 The data of each returned structure will contain the same data the user 455 set with an epoll_ctl(2) (EPOLL_CTL_ADD,EPOLL_CTL_MOD) while the events 456 member will contain the returned event bit field. 457 458 Return Value 459 460 When successful, epoll_wait() returns the number of file descriptors 461 ready for the requested I/O, or zero if no file descriptor became ready 462 during the requested timeout milliseconds. When an error occurs, 463 epoll_wait() returns -1 and errno is set appropriately. 464 465 Errors 466 467 EBADF 468 epfd is not a valid file descriptor. 469 EFAULT 470 The memory area pointed to by events is not accessible with write 471 permissions. 472 EINTR 473 The call was interrupted by a signal handler before any of the 474 requested events occurred or the timeout expired; see signal(7). 475 EINVAL 476 epfd is not an epoll file descriptor, or maxevents is less than or 477 equal to zero. 478 479 Versions 480 481 epoll_wait() was added to the kernel in version 2.6. Library support is 482 provided in glibc starting with version 2.3.2. 483 484 **************************************************************************/ 485 486 int epoll_wait(int epfd, epoll_event_t* events, int maxevents, int timeout); 487 } 488 489 /****************************************************************************** 490 491 Epoll utility struct, memorises the file descriptor obtained by create(). 492 493 ******************************************************************************/ 494 495 struct Epoll 496 { 497 import ocean.sys.CloseOnExec; 498 499 /************************************************************************** 500 501 Convenience aliases 502 503 **************************************************************************/ 504 505 public alias .EpollCreateFlags CreateFlags; 506 public alias .EpollCtlOp CtlOp; 507 public alias .epoll_event_t epoll_event_t; 508 public alias .epoll_event_t.Event Event; 509 510 /************************************************************************** 511 512 Initial file descriptor value. 513 514 **************************************************************************/ 515 516 public enum int fd_init = -1; 517 518 /************************************************************************** 519 520 epoll file descriptor. 521 522 **************************************************************************/ 523 524 public int fd = fd_init; 525 526 /************************************************************************** 527 528 Calls epoll_create1() and memorises the returned file descriptor, which 529 is -1 in case of an error. 530 531 Params: 532 flags = epoll_create1() flags 533 534 Returns: 535 the obtained file descriptor on success or, -1 on error. 536 On error errno is set appropriately and the returned -1 is memorised 537 as file descriptor. 538 539 **************************************************************************/ 540 541 public int create ( CreateFlags flags = CreateFlags.None ) 542 { 543 return this.fd = epoll_create1( 544 setCloExec(flags, EpollCreateFlags.EPOLL_CLOEXEC) 545 ); 546 } 547 548 /************************************************************************** 549 550 Calls epoll_ctl() using the current epoll file descriptor. 551 552 The current epoll file descriptor should have been sucessfully obtained 553 by create() or epoll_create1() and not already been closed, otherwise 554 epoll_ctl() will fail so that this method returns -1. 555 556 Params: 557 op = epoll_ctl opcode 558 fd = file descriptor to register for events 559 event = epoll_event_t struct instance containing the events to 560 register fd for and optional user data 561 562 Returns: 563 0 on success or -1 on error. On error errno is set appropriately. 564 565 **************************************************************************/ 566 567 public int ctl ( CtlOp op, int fd, epoll_event_t event ) 568 { 569 return epoll_ctl(this.fd, op, fd, &event); 570 } 571 572 template ctlT ( size_t i = 0 ) 573 { 574 static if (i < epoll_event_t.data.tupleof.length) 575 { 576 577 578 /************************************************************************** 579 580 Calls epoll_ctl() using the current epoll file descriptor to modify the 581 registration of fd for events with data as user data. 582 583 Creates the epoll_event_t instance passed to epoll_ctl() from events and 584 data where the type of data must match one of the epoll_data_t members. 585 586 The current epoll file descriptor should have been sucessfully obtained 587 by create() or epoll_create1() and not already been closed, otherwise 588 epoll_ctl() will fail so that this method returns -1. 589 590 Params: 591 op = epoll_ctl opcode 592 fd = file descriptor to register for events 593 events = events to register fd for 594 data = user data; the member of the data field of the created 595 epoll_data_t instance that matches the type is set to it 596 597 Returns: 598 0 on success or -1 on error. On error errno is set appropriately. 599 600 **************************************************************************/ 601 602 int ctl ( CtlOp op, int fd, Event events, typeof (epoll_event_t.data.tupleof[i]) data ) 603 { 604 epoll_event_t event; 605 606 event.events = events; 607 event.data.tupleof[i] = data; 608 609 return epoll_ctl(this.fd, op, fd, &event); 610 } 611 612 mixin ctlT!(i + 1); 613 } 614 } 615 616 mixin ctlT!(); 617 618 /************************************************************************** 619 620 Calls epoll_ctl() using the current epoll file descriptor to modify the 621 registration of fd for events with fd as user data. 622 623 Creates the epoll_event_t instance passed to epoll_ctl() from events and 624 fd where data.fd is set to fd. 625 626 The current epoll file descriptor should have been sucessfully obtained 627 by create() or epoll_create1() and not already been closed, otherwise 628 epoll_ctl() will fail so that this method returns -1. 629 630 Params: 631 op = epoll_ctl opcode 632 fd = file descriptor to register for events and to set data.fd 633 of the created epoll_data_t instance to 634 events = events to register fd for 635 636 Returns: 637 0 on success or -1 on error. On error errno is set appropriately. 638 639 **************************************************************************/ 640 641 public int ctl ( CtlOp op, int fd, Event events ) 642 { 643 // FIXME: Apparently the mixin ctlT!() doesn't overload properly :( 644 645 // return this.ctl(op, fd, events, fd); 646 return ctlT!(1).ctl(op, fd, events, fd); 647 } 648 649 /************************************************************************** 650 651 Calls epoll_ctl() using the current epoll file descriptor to modify the 652 registration of fd for events with obj as user data. 653 654 Creates the epoll_event_t instance passed to epoll_ctl() from events and 655 obj where data.obj is set to obj. 656 657 The current epoll file descriptor should have been sucessfully obtained 658 by create() or epoll_create1() and not already been closed, otherwise 659 epoll_ctl() will fail so that this method returns -1. 660 661 Params: 662 op = epoll_ctl opcode 663 fd = file descriptor to register for events 664 events = events to register fd for 665 obj = user object to set data.obj of the created epoll_data_t 666 instance to 667 668 Returns: 669 0 on success or -1 on error. On error errno is set appropriately. 670 671 **************************************************************************/ 672 673 public int ctl ( CtlOp op, int fd, Event events, Object obj ) 674 { 675 epoll_event_t event; 676 677 event.events = events; 678 event.data.obj = obj; 679 680 return epoll_ctl(this.fd, op, fd, &event); 681 } 682 683 /************************************************************************** 684 685 Calls epoll_ctl() using the current epoll file descriptor to modify the 686 registration of fd for events with obj as user data. 687 688 Creates the epoll_event_t instance passed to epoll_ctl() from events and 689 obj where data.obj is set to obj. 690 691 The current epoll file descriptor should have been sucessfully obtained 692 by create() or epoll_create1() and not already been closed, otherwise 693 epoll_ctl() will fail so that this method returns -1. 694 695 Params: 696 op = epoll_ctl opcode 697 fd = file descriptor to register for events 698 events = events to register fd for 699 u64 = user value to set data.u64 of the created epoll_data_t 700 instance to 701 702 Returns: 703 0 on success or -1 on error. On error errno is set appropriately. 704 705 **************************************************************************/ 706 707 public int ctl ( CtlOp op, int fd, Event events, ulong u64 ) 708 { 709 epoll_event_t event; 710 711 event.events = events; 712 event.data.u64 = u64; 713 714 return epoll_ctl(this.fd, op, fd, &event); 715 } 716 717 /************************************************************************** 718 719 Calls epoll_wait() using the current epoll file descriptor. 720 721 events.length specifies the maximum number of file descriptors for which 722 events can be reported with this epoll_wait() call. 723 724 The current epoll file descriptor should have been sucessfully obtained 725 by create() or epoll_create1() and not already been closed, otherwise 726 epoll_ctl() will fail so that this method returns -1. 727 728 Params: 729 events = destination array for the reported events 730 timeout_ms = timeout in ms or -1 to disable timing out 731 732 Returns: 733 on success the number of file descriptors for which at least one 734 event was reported. 0 indicates that this call timed out before an 735 event on any file descriptor occurred. 736 On error -1 is returned and errno set appropriately. 737 738 **************************************************************************/ 739 740 public int wait ( epoll_event_t[] events, int timeout_ms = -1 ) 741 out (n) 742 { 743 assert (n <= cast (int) events.length); 744 } 745 do 746 { 747 verify(events.length <= int.max); 748 return epoll_wait(this.fd, events.ptr, cast (int) events.length, timeout_ms); 749 } 750 751 /************************************************************************** 752 753 Calls close() to close the current epoll file descriptor. 754 755 Returns: 756 0 on success or -1 on error. On error errno is set appropriately. 757 758 **************************************************************************/ 759 760 public int close ( ) 761 { 762 return .close(this.fd); 763 } 764 }