1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include "uv.h" 23 #include "task.h" 24 #include <stdio.h> 25 #include <stdlib.h> 26 #include <errno.h> 27 28 #ifndef HAVE_KQUEUE 29 # if defined(__APPLE__) || \ 30 defined(__DragonFly__) || \ 31 defined(__FreeBSD__) || \ 32 defined(__FreeBSD_kernel__) || \ 33 defined(__OpenBSD__) || \ 34 defined(__NetBSD__) 35 # define HAVE_KQUEUE 1 36 # endif 37 #endif 38 39 #ifndef HAVE_EPOLL 40 # if defined(__linux__) 41 # define HAVE_EPOLL 1 42 # endif 43 #endif 44 45 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) 46 47 #if defined(HAVE_KQUEUE) 48 # include <sys/types.h> 49 # include <sys/event.h> 50 # include <sys/time.h> 51 #endif 52 53 #if defined(HAVE_EPOLL) 54 # include <sys/epoll.h> 55 #endif 56 57 static uv_thread_t embed_thread; 58 static uv_sem_t embed_sem; 59 static uv_timer_t embed_timer; 60 static uv_async_t embed_async; 61 static volatile int embed_closed; 62 63 static int embed_timer_called; 64 65 66 static void embed_thread_runner(void* arg) { 67 int r; 68 int fd; 69 int timeout; 70 71 while (!embed_closed) { 72 fd = uv_backend_fd(uv_default_loop()); 73 timeout = uv_backend_timeout(uv_default_loop()); 74 75 do { 76 #if defined(HAVE_KQUEUE) 77 struct timespec ts; 78 ts.tv_sec = timeout / 1000; 79 ts.tv_nsec = (timeout % 1000) * 1000000; 80 r = kevent(fd, NULL, 0, NULL, 0, &ts); 81 #elif defined(HAVE_EPOLL) 82 { 83 struct epoll_event ev; 84 r = epoll_wait(fd, &ev, 1, timeout); 85 } 86 #endif 87 } while (r == -1 && errno == EINTR); 88 uv_async_send(&embed_async); 89 uv_sem_wait(&embed_sem); 90 } 91 } 92 93 94 static void embed_cb(uv_async_t* async) { 95 uv_run(uv_default_loop(), UV_RUN_ONCE); 96 97 uv_sem_post(&embed_sem); 98 } 99 100 101 static void embed_timer_cb(uv_timer_t* timer) { 102 embed_timer_called++; 103 embed_closed = 1; 104 105 uv_close((uv_handle_t*) &embed_async, NULL); 106 } 107 #endif 108 109 110 TEST_IMPL(embed) { 111 #if defined(HAVE_KQUEUE) || defined(HAVE_EPOLL) 112 uv_loop_t external; 113 114 ASSERT(0 == uv_loop_init(&external)); 115 116 embed_timer_called = 0; 117 embed_closed = 0; 118 119 uv_async_init(&external, &embed_async, embed_cb); 120 121 /* Start timer in default loop */ 122 uv_timer_init(uv_default_loop(), &embed_timer); 123 uv_timer_start(&embed_timer, embed_timer_cb, 250, 0); 124 125 /* Start worker that will interrupt external loop */ 126 uv_sem_init(&embed_sem, 0); 127 uv_thread_create(&embed_thread, embed_thread_runner, NULL); 128 129 /* But run external loop */ 130 uv_run(&external, UV_RUN_DEFAULT); 131 132 uv_thread_join(&embed_thread); 133 uv_loop_close(&external); 134 135 ASSERT(embed_timer_called == 1); 136 #endif 137 138 return 0; 139 } 140