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_PTR_EQ(handle, &poll_handle); 107 ASSERT_EQ(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_EQ(status, UV_ENOENT); 114 ASSERT_OK(memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 115 ASSERT_OK(memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 116 touch_file(FIXTURE); 117 break; 118 119 case 1: 120 ASSERT_OK(status); 121 ASSERT_OK(memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 122 ASSERT_NE(0, memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 123 ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 20, 0)); 124 break; 125 126 case 2: 127 ASSERT_OK(status); 128 ASSERT_NE(0, memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 129 ASSERT_NE(0, memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 130 ASSERT_OK(uv_timer_start(&timer_handle, timer_cb, 200, 0)); 131 break; 132 133 case 3: 134 ASSERT_OK(status); 135 ASSERT_NE(0, memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 136 ASSERT_NE(0, memcmp(curr, &zero_statbuf, sizeof(zero_statbuf))); 137 remove(FIXTURE); 138 break; 139 140 case 4: 141 ASSERT_EQ(status, UV_ENOENT); 142 ASSERT_NE(0, memcmp(prev, &zero_statbuf, sizeof(zero_statbuf))); 143 ASSERT_OK(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_OK(uv_timer_init(loop, &timer_handle)); 159 ASSERT_OK(uv_fs_poll_init(loop, &poll_handle)); 160 ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb, FIXTURE, 100)); 161 ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); 162 163 ASSERT_EQ(5, poll_cb_called); 164 ASSERT_EQ(2, timer_cb_called); 165 ASSERT_EQ(1, close_cb_called); 166 167 MAKE_VALGRIND_HAPPY(loop); 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_OK(uv_fs_poll_init(loop, &poll_handle)); 180 len = sizeof buf; 181 ASSERT_EQ(UV_EINVAL, uv_fs_poll_getpath(&poll_handle, buf, &len)); 182 ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 183 len = sizeof buf; 184 ASSERT_OK(uv_fs_poll_getpath(&poll_handle, buf, &len)); 185 ASSERT_NE(0, buf[len - 1]); 186 ASSERT_EQ(buf[len], '\0'); 187 ASSERT_OK(memcmp(buf, FIXTURE, len)); 188 189 uv_close((uv_handle_t*) &poll_handle, close_cb); 190 191 ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT)); 192 193 ASSERT_EQ(1, close_cb_called); 194 195 MAKE_VALGRIND_HAPPY(loop); 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_OK(uv_loop_init(&loop)); 207 208 ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); 209 ASSERT_OK(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_EQ(1, close_cb_called); 214 215 MAKE_VALGRIND_HAPPY(&loop); 216 return 0; 217 } 218 219 TEST_IMPL(fs_poll_close_request_multi_start_stop) { 220 uv_loop_t loop; 221 uv_fs_poll_t poll_handle; 222 int i; 223 224 remove(FIXTURE); 225 226 ASSERT_OK(uv_loop_init(&loop)); 227 228 ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); 229 230 for (i = 0; i < 10; ++i) { 231 ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 232 ASSERT_OK(uv_fs_poll_stop(&poll_handle)); 233 } 234 uv_close((uv_handle_t*) &poll_handle, close_cb); 235 while (close_cb_called == 0) 236 uv_run(&loop, UV_RUN_ONCE); 237 ASSERT_EQ(1, close_cb_called); 238 239 MAKE_VALGRIND_HAPPY(&loop); 240 return 0; 241 } 242 243 TEST_IMPL(fs_poll_close_request_multi_stop_start) { 244 uv_loop_t loop; 245 uv_fs_poll_t poll_handle; 246 int i; 247 248 remove(FIXTURE); 249 250 ASSERT_OK(uv_loop_init(&loop)); 251 252 ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); 253 254 for (i = 0; i < 10; ++i) { 255 ASSERT_OK(uv_fs_poll_stop(&poll_handle)); 256 ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_fail, FIXTURE, 100)); 257 } 258 uv_close((uv_handle_t*) &poll_handle, close_cb); 259 while (close_cb_called == 0) 260 uv_run(&loop, UV_RUN_ONCE); 261 ASSERT_EQ(1, close_cb_called); 262 263 MAKE_VALGRIND_HAPPY(&loop); 264 return 0; 265 } 266 267 TEST_IMPL(fs_poll_close_request_stop_when_active) { 268 /* Regression test for https://github.com/libuv/libuv/issues/2287. */ 269 uv_loop_t loop; 270 uv_fs_poll_t poll_handle; 271 272 remove(FIXTURE); 273 274 ASSERT_OK(uv_loop_init(&loop)); 275 276 /* Set up all handles. */ 277 ASSERT_OK(uv_fs_poll_init(&loop, &poll_handle)); 278 ASSERT_OK(uv_fs_poll_start(&poll_handle, poll_cb_noop, FIXTURE, 100)); 279 uv_run(&loop, UV_RUN_ONCE); 280 281 /* Close the timer handle, and do not crash. */ 282 ASSERT_OK(uv_fs_poll_stop(&poll_handle)); 283 uv_run(&loop, UV_RUN_ONCE); 284 285 /* Clean up after the test. */ 286 uv_close((uv_handle_t*) &poll_handle, close_cb); 287 uv_run(&loop, UV_RUN_ONCE); 288 ASSERT_EQ(1, close_cb_called); 289 290 MAKE_VALGRIND_HAPPY(&loop); 291 return 0; 292 } 293