uv: Upgrade to v0.11.17
[platform/upstream/nodejs.git] / deps / uv / src / unix / kqueue.c
1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
2  * Permission is hereby granted, free of charge, to any person obtaining a copy
3  * of this software and associated documentation files (the "Software"), to
4  * deal in the Software without restriction, including without limitation the
5  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6  * sell copies of the Software, and to permit persons to whom the Software is
7  * furnished to do so, subject to the following conditions:
8  *
9  * The above copyright notice and this permission notice shall be included in
10  * all copies or substantial portions of the Software.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
18  * IN THE SOFTWARE.
19  */
20
21 #include "uv.h"
22 #include "internal.h"
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include <sys/sysctl.h>
30 #include <sys/types.h>
31 #include <sys/event.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <time.h>
36
37 static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
38
39
40 int uv__kqueue_init(uv_loop_t* loop) {
41   loop->backend_fd = kqueue();
42   if (loop->backend_fd == -1)
43     return -errno;
44
45   uv__cloexec(loop->backend_fd, 1);
46
47   return 0;
48 }
49
50
51 void uv__io_poll(uv_loop_t* loop, int timeout) {
52   struct kevent events[1024];
53   struct kevent* ev;
54   struct timespec spec;
55   unsigned int nevents;
56   unsigned int revents;
57   QUEUE* q;
58   uint64_t base;
59   uint64_t diff;
60   uv__io_t* w;
61   int filter;
62   int fflags;
63   int count;
64   int nfds;
65   int fd;
66   int op;
67   int i;
68
69   if (loop->nfds == 0) {
70     assert(QUEUE_EMPTY(&loop->watcher_queue));
71     return;
72   }
73
74   nevents = 0;
75
76   while (!QUEUE_EMPTY(&loop->watcher_queue)) {
77     q = QUEUE_HEAD(&loop->watcher_queue);
78     QUEUE_REMOVE(q);
79     QUEUE_INIT(q);
80
81     w = QUEUE_DATA(q, uv__io_t, watcher_queue);
82     assert(w->pevents != 0);
83     assert(w->fd >= 0);
84     assert(w->fd < (int) loop->nwatchers);
85
86     if ((w->events & UV__POLLIN) == 0 && (w->pevents & UV__POLLIN) != 0) {
87       filter = EVFILT_READ;
88       fflags = 0;
89       op = EV_ADD;
90
91       if (w->cb == uv__fs_event) {
92         filter = EVFILT_VNODE;
93         fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
94                | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
95         op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
96       }
97
98       EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
99
100       if (++nevents == ARRAY_SIZE(events)) {
101         if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
102           abort();
103         nevents = 0;
104       }
105     }
106
107     if ((w->events & UV__POLLOUT) == 0 && (w->pevents & UV__POLLOUT) != 0) {
108       EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
109
110       if (++nevents == ARRAY_SIZE(events)) {
111         if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
112           abort();
113         nevents = 0;
114       }
115     }
116
117     w->events = w->pevents;
118   }
119
120   assert(timeout >= -1);
121   base = loop->time;
122   count = 48; /* Benchmarks suggest this gives the best throughput. */
123
124   for (;; nevents = 0) {
125     if (timeout != -1) {
126       spec.tv_sec = timeout / 1000;
127       spec.tv_nsec = (timeout % 1000) * 1000000;
128     }
129
130     nfds = kevent(loop->backend_fd,
131                   events,
132                   nevents,
133                   events,
134                   ARRAY_SIZE(events),
135                   timeout == -1 ? NULL : &spec);
136
137     /* Update loop->time unconditionally. It's tempting to skip the update when
138      * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
139      * operating system didn't reschedule our process while in the syscall.
140      */
141     SAVE_ERRNO(uv__update_time(loop));
142
143     if (nfds == 0) {
144       assert(timeout != -1);
145       return;
146     }
147
148     if (nfds == -1) {
149       if (errno != EINTR)
150         abort();
151
152       if (timeout == 0)
153         return;
154
155       if (timeout == -1)
156         continue;
157
158       /* Interrupted by a signal. Update timeout and poll again. */
159       goto update_timeout;
160     }
161
162     nevents = 0;
163
164     assert(loop->watchers != NULL);
165     loop->watchers[loop->nwatchers] = (void*) events;
166     loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
167     for (i = 0; i < nfds; i++) {
168       ev = events + i;
169       fd = ev->ident;
170       /* Skip invalidated events, see uv__platform_invalidate_fd */
171       if (fd == -1)
172         continue;
173       w = loop->watchers[fd];
174
175       if (w == NULL) {
176         /* File descriptor that we've stopped watching, disarm it. */
177         /* TODO batch up */
178         struct kevent events[1];
179
180         EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
181         if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
182           if (errno != EBADF && errno != ENOENT)
183             abort();
184
185         continue;
186       }
187
188       if (ev->filter == EVFILT_VNODE) {
189         assert(w->events == UV__POLLIN);
190         assert(w->pevents == UV__POLLIN);
191         w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
192         nevents++;
193         continue;
194       }
195
196       revents = 0;
197
198       if (ev->filter == EVFILT_READ) {
199         if (w->pevents & UV__POLLIN) {
200           revents |= UV__POLLIN;
201           w->rcount = ev->data;
202         } else {
203           /* TODO batch up */
204           struct kevent events[1];
205           EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
206           if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
207             if (errno != ENOENT)
208               abort();
209         }
210       }
211
212       if (ev->filter == EVFILT_WRITE) {
213         if (w->pevents & UV__POLLOUT) {
214           revents |= UV__POLLOUT;
215           w->wcount = ev->data;
216         } else {
217           /* TODO batch up */
218           struct kevent events[1];
219           EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
220           if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
221             if (errno != ENOENT)
222               abort();
223         }
224       }
225
226       if (ev->flags & EV_ERROR)
227         revents |= UV__POLLERR;
228
229       if (revents == 0)
230         continue;
231
232       w->cb(loop, w, revents);
233       nevents++;
234     }
235     loop->watchers[loop->nwatchers] = NULL;
236     loop->watchers[loop->nwatchers + 1] = NULL;
237
238     if (nevents != 0) {
239       if (nfds == ARRAY_SIZE(events) && --count != 0) {
240         /* Poll for more events but don't block this time. */
241         timeout = 0;
242         continue;
243       }
244       return;
245     }
246
247     if (timeout == 0)
248       return;
249
250     if (timeout == -1)
251       continue;
252
253 update_timeout:
254     assert(timeout > 0);
255
256     diff = loop->time - base;
257     if (diff >= (uint64_t) timeout)
258       return;
259
260     timeout -= diff;
261   }
262 }
263
264
265 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
266   struct kevent* events;
267   uintptr_t i;
268   uintptr_t nfds;
269
270   assert(loop->watchers != NULL);
271
272   events = (struct kevent*) loop->watchers[loop->nwatchers];
273   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
274   if (events == NULL)
275     return;
276
277   /* Invalidate events with same file descriptor */
278   for (i = 0; i < nfds; i++)
279     if ((int) events[i].ident == fd)
280       events[i].ident = -1;
281 }
282
283
284 static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
285   uv_fs_event_t* handle;
286   struct kevent ev;
287   int events;
288   const char* path;
289 #if defined(F_GETPATH)
290   /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
291   char pathbuf[MAXPATHLEN];
292 #endif
293
294   handle = container_of(w, uv_fs_event_t, event_watcher);
295
296   if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
297     events = UV_CHANGE;
298   else
299     events = UV_RENAME;
300
301   path = NULL;
302 #if defined(F_GETPATH)
303   /* Also works when the file has been unlinked from the file system. Passing
304    * in the path when the file has been deleted is arguably a little strange
305    * but it's consistent with what the inotify backend does.
306    */
307   if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
308     path = uv__basename_r(pathbuf);
309 #endif
310   handle->cb(handle, path, events, 0);
311
312   if (handle->event_watcher.fd == -1)
313     return;
314
315   /* Watcher operates in one-shot mode, re-arm it. */
316   fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
317          | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
318
319   EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
320
321   if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
322     abort();
323 }
324
325
326 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
327   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
328   return 0;
329 }
330
331
332 int uv_fs_event_start(uv_fs_event_t* handle,
333                       uv_fs_event_cb cb,
334                       const char* filename,
335                       unsigned int flags) {
336 #if defined(__APPLE__)
337   struct stat statbuf;
338 #endif /* defined(__APPLE__) */
339   int fd;
340
341   if (uv__is_active(handle))
342     return -EINVAL;
343
344   /* TODO open asynchronously - but how do we report back errors? */
345   fd = open(filename, O_RDONLY);
346   if (fd == -1)
347     return -errno;
348
349   uv__handle_start(handle);
350   uv__io_init(&handle->event_watcher, uv__fs_event, fd);
351   handle->filename = strdup(filename);
352   handle->cb = cb;
353
354 #if defined(__APPLE__)
355   /* Nullify field to perform checks later */
356   handle->cf_cb = NULL;
357   handle->realpath = NULL;
358   handle->realpath_len = 0;
359   handle->cf_flags = flags;
360
361   if (fstat(fd, &statbuf))
362     goto fallback;
363   /* FSEvents works only with directories */
364   if (!(statbuf.st_mode & S_IFDIR))
365     goto fallback;
366
367   return uv__fsevents_init(handle);
368
369 fallback:
370 #endif /* defined(__APPLE__) */
371
372   uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
373
374   return 0;
375 }
376
377
378 int uv_fs_event_stop(uv_fs_event_t* handle) {
379   if (!uv__is_active(handle))
380     return -EINVAL;
381
382   uv__handle_stop(handle);
383
384 #if defined(__APPLE__)
385   if (uv__fsevents_close(handle))
386     uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
387 #else
388   uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
389 #endif /* defined(__APPLE__) */
390
391   free(handle->filename);
392   handle->filename = NULL;
393
394   uv__close(handle->event_watcher.fd);
395   handle->event_watcher.fd = -1;
396
397   return 0;
398 }
399
400
401 void uv__fs_event_close(uv_fs_event_t* handle) {
402   uv_fs_event_stop(handle);
403 }