70f5d9edb447644ef57938c376cffd3586a3b2fb
[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       w = loop->watchers[fd];
171
172       /* Skip invalidated events, see uv__platform_invalidate_fd */
173       if (fd == -1)
174         continue;
175
176       if (w == NULL) {
177         /* File descriptor that we've stopped watching, disarm it. */
178         /* TODO batch up */
179         struct kevent events[1];
180
181         EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
182         if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
183           if (errno != EBADF && errno != ENOENT)
184             abort();
185
186         continue;
187       }
188
189       if (ev->filter == EVFILT_VNODE) {
190         assert(w->events == UV__POLLIN);
191         assert(w->pevents == UV__POLLIN);
192         w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
193         nevents++;
194         continue;
195       }
196
197       revents = 0;
198
199       if (ev->filter == EVFILT_READ) {
200         if (w->pevents & UV__POLLIN) {
201           revents |= UV__POLLIN;
202           w->rcount = ev->data;
203         } else {
204           /* TODO batch up */
205           struct kevent events[1];
206           EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
207           if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
208             if (errno != ENOENT)
209               abort();
210         }
211       }
212
213       if (ev->filter == EVFILT_WRITE) {
214         if (w->pevents & UV__POLLOUT) {
215           revents |= UV__POLLOUT;
216           w->wcount = ev->data;
217         } else {
218           /* TODO batch up */
219           struct kevent events[1];
220           EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
221           if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
222             if (errno != ENOENT)
223               abort();
224         }
225       }
226
227       if (ev->flags & EV_ERROR)
228         revents |= UV__POLLERR;
229
230       if (revents == 0)
231         continue;
232
233       w->cb(loop, w, revents);
234       nevents++;
235     }
236     loop->watchers[loop->nwatchers] = NULL;
237     loop->watchers[loop->nwatchers + 1] = NULL;
238
239     if (nevents != 0) {
240       if (nfds == ARRAY_SIZE(events) && --count != 0) {
241         /* Poll for more events but don't block this time. */
242         timeout = 0;
243         continue;
244       }
245       return;
246     }
247
248     if (timeout == 0)
249       return;
250
251     if (timeout == -1)
252       continue;
253
254 update_timeout:
255     assert(timeout > 0);
256
257     diff = loop->time - base;
258     if (diff >= (uint64_t) timeout)
259       return;
260
261     timeout -= diff;
262   }
263 }
264
265
266 void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
267   struct kevent* events;
268   uintptr_t i;
269   uintptr_t nfds;
270
271   assert(loop->watchers != NULL);
272
273   events = (struct kevent*) loop->watchers[loop->nwatchers];
274   nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
275   if (events == NULL)
276     return;
277
278   /* Invalidate events with same file descriptor */
279   for (i = 0; i < nfds; i++)
280     if ((int) events[i].ident == fd)
281       events[i].ident = -1;
282 }
283
284
285 static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
286   uv_fs_event_t* handle;
287   struct kevent ev;
288   int events;
289   const char* path;
290 #if defined(F_GETPATH)
291   /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
292   char pathbuf[MAXPATHLEN];
293 #endif
294
295   handle = container_of(w, uv_fs_event_t, event_watcher);
296
297   if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
298     events = UV_CHANGE;
299   else
300     events = UV_RENAME;
301
302   path = NULL;
303 #if defined(F_GETPATH)
304   /* Also works when the file has been unlinked from the file system. Passing
305    * in the path when the file has been deleted is arguably a little strange
306    * but it's consistent with what the inotify backend does.
307    */
308   if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
309     path = uv__basename_r(pathbuf);
310 #endif
311   handle->cb(handle, path, events, 0);
312
313   if (handle->event_watcher.fd == -1)
314     return;
315
316   /* Watcher operates in one-shot mode, re-arm it. */
317   fflags = NOTE_ATTRIB | NOTE_WRITE  | NOTE_RENAME
318          | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
319
320   EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
321
322   if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
323     abort();
324 }
325
326
327 int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
328   uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
329   return 0;
330 }
331
332
333 int uv_fs_event_start(uv_fs_event_t* handle,
334                       uv_fs_event_cb cb,
335                       const char* filename,
336                       unsigned int flags) {
337 #if defined(__APPLE__)
338   struct stat statbuf;
339 #endif /* defined(__APPLE__) */
340   int fd;
341
342   if (uv__is_active(handle))
343     return -EINVAL;
344
345   /* TODO open asynchronously - but how do we report back errors? */
346   fd = open(filename, O_RDONLY);
347   if (fd == -1)
348     return -errno;
349
350   uv__handle_start(handle);
351   uv__io_init(&handle->event_watcher, uv__fs_event, fd);
352   handle->filename = strdup(filename);
353   handle->cb = cb;
354
355 #if defined(__APPLE__)
356   /* Nullify field to perform checks later */
357   handle->cf_cb = NULL;
358   handle->realpath = NULL;
359   handle->realpath_len = 0;
360   handle->cf_flags = flags;
361
362   if (fstat(fd, &statbuf))
363     goto fallback;
364   /* FSEvents works only with directories */
365   if (!(statbuf.st_mode & S_IFDIR))
366     goto fallback;
367
368   return uv__fsevents_init(handle);
369
370 fallback:
371 #endif /* defined(__APPLE__) */
372
373   uv__io_start(handle->loop, &handle->event_watcher, UV__POLLIN);
374
375   return 0;
376 }
377
378
379 int uv_fs_event_stop(uv_fs_event_t* handle) {
380   if (!uv__is_active(handle))
381     return -EINVAL;
382
383   uv__handle_stop(handle);
384
385 #if defined(__APPLE__)
386   if (uv__fsevents_close(handle))
387     uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
388 #else
389   uv__io_stop(handle->loop, &handle->event_watcher, UV__POLLIN);
390 #endif /* defined(__APPLE__) */
391
392   free(handle->filename);
393   handle->filename = NULL;
394
395   uv__close(handle->event_watcher.fd);
396   handle->event_watcher.fd = -1;
397
398   return 0;
399 }
400
401
402 void uv__fs_event_close(uv_fs_event_t* handle) {
403   uv_fs_event_stop(handle);
404 }