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 25 #include <string.h> 26 27 #define FIXTURE "testfile" 28 29 static void timer_cb(uv_timer_t* handle); 30 static void close_cb(uv_handle_t* handle); 31 static void poll_cb(uv_fs_poll_t* handle, 32 int status, 33 const uv_stat_t* prev, 34 const uv_stat_t* curr); 35 36 static void poll_cb_fail(uv_fs_poll_t* handle, 37 int status, 38 const uv_stat_t* prev, 39 const uv_stat_t* curr); 40 static void poll_cb_noop(uv_fs_poll_t* handle, 41 int status, 42 const uv_stat_t* prev, 43 const uv_stat_t* curr); 44 45 static uv_fs_poll_t poll_handle; 46 static uv_timer_t timer_handle; 47 static uv_loop_t* loop; 48 49 static int poll_cb_called; 50 static int timer_cb_called; 51 static int close_cb_called; 52 53 54 static void touch_file(const char* path) { 55 static int count; 56 FILE* fp; 57 int i; 58 59 ASSERT((fp = fopen(FIXTURE, "w+"))); 60 61 /* Need to change the file size because the poller may not pick up 62 * sub-second mtime changes. 63 */ 64 i = ++count; 65 66 while (i--) 67 fputc('*', fp); 68 69 fclose(fp); 70 } 71 72 73 static void close_cb(uv_handle_t* handle) { 74 close_cb_called++; 75 } 76 77 78 static void timer_cb(uv_timer_t* handle) { 79 touch_file(FIXTURE); 80 timer_cb_called++; 81 } 82 83 84 static void poll_cb_fail(uv_fs_poll_t* handle, 85 int status, 86 const uv_stat_t* prev, 87 const uv_stat_t* curr) { 88 ASSERT(0 && "fail_cb called"); 89 } 90 91 static void poll_cb_noop(uv_fs_poll_t* handle, 92 int status, 93 const uv_stat_t* prev, 94 const uv_stat_t* curr) { 95 } 96 97 98 static void poll_cb(uv_fs_poll_t* handle, 99 int status, 100 const uv_stat_t* prev, 101 const uv_stat_t* curr) { 102 uv_stat_t zero_statbuf; 103 104 memset(&zero_statbuf, 0, sizeof(zero_statbuf)); 105 106 ASSERT(handle == &poll_handle); 107 ASSERT(1 == uv_is_active((uv_handle_t*) handle)); 108 ASSERT_NOT_NULL(prev); 109 ASSERT_NOT_NULL(curr); 110 111 switch (poll_cb_called++) { 112 case 0: 113 ASSERT(status == UV_ENOENT); 114 ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 115 ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 116 touch_file(FIXTURE); 117 break; 118 119 case 1: 120 ASSERT(status == 0); 121 ASSERT(0 == memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 122 ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 123 ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 20, 0)); 124 break; 125 126 case 2: 127 ASSERT(status == 0); 128 ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 129 ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 130 ASSERT(0 == uv_timer_start(&timer_handle, timer_cb, 200, 0)); 131 break; 132 133 case 3: 134 ASSERT(status == 0); 135 ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 136 ASSERT(0 != memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 137 remove(FIXTURE); 138 break; 139 140 case 4: 141 ASSERT(status == UV_ENOENT); 142 ASSERT(0 != memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 143 ASSERT(0 == memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 144 uv_close((uv_handle_t*)handle, close_cb); 145 break; 146 147 default: 148 ASSERT(0); 149 } 150 } 151 152 153 TEST_IMPL(fs_poll) { 154 loop = uv_default_loop(); 155 156 remove(FIXTURE); 157 158 ASSERT(0 == uv_timer_init(loop, &timer_handle)); 159 ASSERT(0 == uv_fs_poll_init(loop, &poll_handle)); 160 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100)); 161 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); 162 163 ASSERT(poll_cb_called == 5); 164 ASSERT(timer_cb_called == 2); 165 ASSERT(close_cb_called == 1); 166 167 MAKE_VALGRIND_HAPPY(); 168 return 0; 169 } 170 171 172 TEST_IMPL(fs_poll_getpath) { 173 char buf[1024]; 174 size_t len; 175 loop = uv_default_loop(); 176 177 remove(FIXTURE); 178 179 ASSERT(0 == uv_fs_poll_init(loop, &poll_handle)); 180 len = sizeof buf; 181 ASSERT(UV_EINVAL == uv_fs_poll_getpath(&poll_handle, buf, &len)); 182 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 183 len = sizeof buf; 184 ASSERT(0 == uv_fs_poll_getpath(&poll_handle, buf, &len)); 185 ASSERT(buf[len - 1] != 0); 186 ASSERT(buf[len] == '\0'); 187 ASSERT(0 == memcmp(buf, FIXTURE, len)); 188 189 uv_close((uv_handle_t*) &poll_handle, close_cb); 190 191 ASSERT(0 == uv_run(loop, UV_RUN_DEFAULT)); 192 193 ASSERT(close_cb_called == 1); 194 195 MAKE_VALGRIND_HAPPY(); 196 return 0; 197 } 198 199 200 TEST_IMPL(fs_poll_close_request) { 201 uv_loop_t loop; 202 uv_fs_poll_t poll_handle; 203 204 remove(FIXTURE); 205 206 ASSERT(0 == uv_loop_init(&loop)); 207 208 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); 209 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 210 uv_close((uv_handle_t*) &poll_handle, close_cb); 211 while (close_cb_called == 0) 212 uv_run(&loop, UV_RUN_ONCE); 213 ASSERT(close_cb_called == 1); 214 215 ASSERT(0 == uv_loop_close(&loop)); 216 217 MAKE_VALGRIND_HAPPY(); 218 return 0; 219 } 220 221 TEST_IMPL(fs_poll_close_request_multi_start_stop) { 222 uv_loop_t loop; 223 uv_fs_poll_t poll_handle; 224 int i; 225 226 remove(FIXTURE); 227 228 ASSERT(0 == uv_loop_init(&loop)); 229 230 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); 231 232 for (i = 0; i < 10; ++i) { 233 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 234 ASSERT(0 == uv_fs_poll_stop(&poll_handle)); 235 } 236 uv_close((uv_handle_t*) &poll_handle, close_cb); 237 while (close_cb_called == 0) 238 uv_run(&loop, UV_RUN_ONCE); 239 ASSERT(close_cb_called == 1); 240 241 ASSERT(0 == uv_loop_close(&loop)); 242 243 MAKE_VALGRIND_HAPPY(); 244 return 0; 245 } 246 247 TEST_IMPL(fs_poll_close_request_multi_stop_start) { 248 uv_loop_t loop; 249 uv_fs_poll_t poll_handle; 250 int i; 251 252 remove(FIXTURE); 253 254 ASSERT(0 == uv_loop_init(&loop)); 255 256 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); 257 258 for (i = 0; i < 10; ++i) { 259 ASSERT(0 == uv_fs_poll_stop(&poll_handle)); 260 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 261 } 262 uv_close((uv_handle_t*) &poll_handle, close_cb); 263 while (close_cb_called == 0) 264 uv_run(&loop, UV_RUN_ONCE); 265 ASSERT(close_cb_called == 1); 266 267 ASSERT(0 == uv_loop_close(&loop)); 268 269 MAKE_VALGRIND_HAPPY(); 270 return 0; 271 } 272 273 TEST_IMPL(fs_poll_close_request_stop_when_active) { 274 /* Regression test for https://github.com/libuv/libuv/issues/2287. */ 275 uv_loop_t loop; 276 uv_fs_poll_t poll_handle; 277 278 remove(FIXTURE); 279 280 ASSERT(0 == uv_loop_init(&loop)); 281 282 /* Set up all handles. */ 283 ASSERT(0 == uv_fs_poll_init(&loop, &poll_handle)); 284 ASSERT(0 == uv_fs_poll_start(&poll_handle, poll_cb_noop, FIXTURE, 100)); 285 uv_run(&loop, UV_RUN_ONCE); 286 287 /* Close the timer handle, and do not crash. */ 288 ASSERT(0 == uv_fs_poll_stop(&poll_handle)); 289 uv_run(&loop, UV_RUN_ONCE); 290 291 /* Clean up after the test. */ 292 uv_close((uv_handle_t*) &poll_handle, close_cb); 293 uv_run(&loop, UV_RUN_ONCE); 294 ASSERT(close_cb_called == 1); 295 296 ASSERT(0 == uv_loop_close(&loop)); 297 298 MAKE_VALGRIND_HAPPY(); 299 return 0; 300 } 301