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