1 /******************************************************************************* 2 3 Linux custom file descriptor event. 4 5 eventfd man page follows: 6 7 Creates an "eventfd object" that can be used as an event wait/notify 8 mechanism by userspace applications, and by the kernel to notify userspace 9 applications of events. The object contains an unsigned 64-bit integer 10 (ulong) counter that is maintained by the kernel. 11 12 The following operations can be performed on the file descriptor: 13 14 read(2) 15 If the eventfd counter has a nonzero value, then a read(2) returns 8 16 bytes containing that value, and the counter's value is reset to zero. 17 (The returned value is in host byte order, i.e., the native byte order 18 for integers on the host machine.) 19 If the counter is zero at the time of the read(2), then the call either 20 blocks until the counter becomes nonzero, or fails with the error EAGAIN 21 if the file descriptor has been made non-blocking (via the use of the 22 fcntl(2) F_SETFL operation to set the O_NONBLOCK flag). 23 24 A read(2) will fail with the error EINVAL if the size of the supplied 25 buffer is less than 8 bytes. 26 27 write(2) 28 A write(2) call adds the 8-byte integer value supplied in its buffer to 29 the counter. The maximum value that may be stored in the counter is the 30 largest unsigned 64-bit value minus 1 (i.e., 0xfffffffffffffffe). If 31 the addition would cause the counter's value to exceed the maximum, 32 then the write(2) either blocks until a read(2) is performed on the file 33 descriptor, or fails with the error EAGAIN if the file descriptor has 34 been made non-blocking. 35 A write(2) will fail with the error EINVAL if the size of the supplied 36 buffer is less than 8 bytes, or if an attempt is made to write the value 37 0xffffffffffffffff. 38 39 poll(2), select(2) (and similar) 40 The returned file descriptor supports poll(2) (and analogously epoll(7)) 41 and select(2), as follows: 42 43 The file descriptor is readable (the select(2) readfds argument; the 44 poll(2) POLLIN flag) if the counter has a value greater than 0. 45 46 The file descriptor is writable (the select(2) writefds argument; the 47 poll(2) POLLOUT flag) if it is possible to write a value of at least 48 "1" without blocking. 49 50 The file descriptor indicates an exceptional condition (the select(2) 51 exceptfds argument; the poll(2) POLLERR flag) if an overflow of the 52 counter value was detected. As noted above, write(2) can never overflow 53 the counter. However an overflow can occur if 2^64 eventfd "signal 54 posts" were performed by the KAIO subsystem (theoretically possible, 55 but practically unlikely). If an overflow has occurred, then read(2) 56 will return that maximum uint64_t value (i.e., 0xffffffffffffffff). The 57 eventfd file descriptor also supports the other file-descriptor 58 multiplexing APIs: pselect(2), ppoll(2), and epoll(7). 59 60 close(2) 61 When the file descriptor is no longer required it should be closed. 62 When all file descriptors associated with the same eventfd object have 63 been closed, the resources for object are freed by the kernel. 64 65 A copy of the file descriptor created by eventfd() is inherited by the child 66 produced by fork(2). The duplicate file descriptor is associated with the 67 same eventfd object. File descriptors created by eventfd() are preserved 68 across execve(2). 69 70 Copyright: 71 Copyright (c) 2009-2016 dunnhumby Germany GmbH. 72 All rights reserved. 73 74 License: 75 Boost Software License Version 1.0. See LICENSE_BOOST.txt for details. 76 Alternatively, this file may be distributed under the terms of the Tango 77 3-Clause BSD License (see LICENSE_BSD.txt for details). 78 79 *******************************************************************************/ 80 81 module ocean.sys.EventFD; 82 83 84 85 86 import ocean.io.model.IConduit; 87 88 import ocean.stdc.posix.sys.types: ssize_t; 89 90 import core.sys.posix.unistd: read, write, close; 91 92 93 94 95 /******************************************************************************* 96 97 Definition of external functions required to manage custom events. 98 99 Params: 100 initval = initial counter value 101 flags = Starting with Linux 2.6.27: 0 or a bitwise OR combination of 102 - EFD_NONBLOCK: Set the O_NONBLOCK file status flag on the 103 new open file description. 104 - EFD_CLOEXEC: Set the close-on-exec (FD_CLOEXEC) flag on 105 the new file descriptor. (See the description of the 106 O_CLOEXEC flag in open(2) for reasons why this may be 107 useful.) 108 109 Up to Linux version 2.6.26: Must be 0. 110 111 Returns: 112 new file descriptor that can be used to refer to the eventfd object 113 114 *******************************************************************************/ 115 116 private extern ( C ) 117 { 118 int eventfd ( uint initval, int flags ); 119 static immutable EFD_CLOEXEC = 0x80000; 120 } 121 122 123 124 /******************************************************************************* 125 126 Event fd class 127 128 *******************************************************************************/ 129 130 public class EventFD : ISelectable 131 { 132 import ocean.sys.CloseOnExec; 133 134 /*************************************************************************** 135 136 Integer file descriptor provided by the operating system and used to 137 manage the custom event. 138 139 ***************************************************************************/ 140 141 private int fd; 142 143 144 /*************************************************************************** 145 146 Constructor. Creates a custom event file descriptor. 147 148 ***************************************************************************/ 149 150 public this ( ) 151 { 152 this.fd = .eventfd(0, setCloExec(0, EFD_CLOEXEC)); 153 } 154 155 156 /*************************************************************************** 157 158 Destructor. Destroys the event file descriptor. 159 160 ***************************************************************************/ 161 162 ~this ( ) 163 { 164 .close(this.fd); 165 } 166 167 168 /*************************************************************************** 169 170 Required by ISelectable interface. 171 172 Returns: 173 file descriptor used to manage custom event 174 175 ***************************************************************************/ 176 177 public Handle fileHandle ( ) 178 { 179 return cast(Handle)this.fd; 180 } 181 182 183 /*************************************************************************** 184 185 Triggers the custom event one or more times. 186 187 Params: 188 n = number of times to trigger the event (defaults to 1) 189 190 ***************************************************************************/ 191 192 public void trigger ( ulong n = 1 ) 193 { 194 this.write(n); 195 } 196 197 198 /*************************************************************************** 199 200 Should be called when the custom event has fired. 201 202 Returns: 203 the number of times the event has been triggered since the last call 204 to handle(). 205 206 ***************************************************************************/ 207 208 public ulong handle ( ) 209 { 210 ulong n; 211 this.read(n); 212 213 return n; 214 } 215 216 217 /*************************************************************************** 218 219 Writes to the custom event file descriptor. 220 221 A write() call adds the ulong value supplied in its buffer to the 222 counter. The maximum value that may be stored in the counter is 223 ulong.max - 1. If the addition would cause the counter's value to 224 exceed the maximum, write() either blocks until a read() is 225 performed or fails with the error EAGAIN if the file descriptor has 226 been made non-blocking. 227 A write() will fail with the error EINVAL if an attempt is made to 228 write the value ulong.max. 229 230 Params: 231 n = value to write 232 233 Returns: 234 ulong.sizeof on success or -1 on error. For -1 errno is set 235 appropriately. 236 237 ***************************************************************************/ 238 239 private ssize_t write ( ulong n ) 240 { 241 return .write(this.fd, &n, n.sizeof); 242 } 243 244 245 /*************************************************************************** 246 247 Reads from the custom event file descriptor. 248 249 If the eventfd counter has a nonzero value, then a read() returns 250 that value, and the counter's value is reset to zero. 251 If the counter is zero at the time of the read(), then the call 252 either blocks until the counter becomes nonzero, or fails with the 253 error EAGAIN if the file descriptor has been made non-blocking. 254 255 Params: 256 n = value output 257 258 Returns: 259 ulong.sizeof on success, 0 on end-of-file condition or -1 on 260 error. For 0 and -1 errno is set appropriately. 261 262 ***************************************************************************/ 263 264 private ssize_t read ( out ulong n ) 265 { 266 return .read(this.fd, &n, n.sizeof); 267 } 268 } 269