1 1.1 christos /* Copyright The libuv project and contributors. All rights reserved. 2 1.1 christos * 3 1.1 christos * Permission is hereby granted, free of charge, to any person obtaining a copy 4 1.1 christos * of this software and associated documentation files (the "Software"), to 5 1.1 christos * deal in the Software without restriction, including without limitation the 6 1.1 christos * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 1.1 christos * sell copies of the Software, and to permit persons to whom the Software is 8 1.1 christos * furnished to do so, subject to the following conditions: 9 1.1 christos * 10 1.1 christos * The above copyright notice and this permission notice shall be included in 11 1.1 christos * all copies or substantial portions of the Software. 12 1.1 christos * 13 1.1 christos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 1.1 christos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 1.1 christos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 1.1 christos * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 1.1 christos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 1.1 christos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 1.1 christos * IN THE SOFTWARE. 20 1.1 christos */ 21 1.1 christos 22 1.1 christos #include "uv.h" 23 1.1 christos #include "task.h" 24 1.1 christos 25 1.1 christos #include <string.h> 26 1.1 christos 27 1.1 christos 28 1.1 christos /* 29 1.1 christos * The idea behind the test is as follows. 30 1.1 christos * Certain handle types are stored in a queue internally. 31 1.1 christos * Extra care should be taken for removal of a handle from the queue while iterating over the queue. 32 1.1.1.2 christos * (i.e., uv__queue_remove() called within uv__queue_foreach()) 33 1.1 christos * This usually happens when someone closes or stops a handle from within its callback. 34 1.1 christos * So we need to check that we haven't screwed the queue on close/stop. 35 1.1 christos * To do so we do the following (for each handle type): 36 1.1 christos * 1. Create and start 3 handles (#0, #1, and #2). 37 1.1 christos * 38 1.1 christos * The queue after the start() calls: 39 1.1 christos * ..=> [queue head] <=> [handle] <=> [handle #1] <=> [handle] <=.. 40 1.1 christos * 41 1.1 christos * 2. Trigger handles to fire (for uv_idle_t, uv_prepare_t, and uv_check_t there is nothing to do). 42 1.1 christos * 43 1.1 christos * 3. In the callback for the first-executed handle (#0 or #2 depending on handle type) 44 1.1 christos * stop the handle and the next one (#1). 45 1.1 christos * (for uv_idle_t, uv_prepare_t, and uv_check_t callbacks are executed in the reverse order as they are start()'ed, 46 1.1 christos * so callback for handle #2 will be called first) 47 1.1 christos * 48 1.1 christos * The queue after the stop() calls: 49 1.1 christos * correct foreach "next" | 50 1.1 christos * \/ 51 1.1 christos * ..=> [queue head] <==============================> [handle] <=.. 52 1.1 christos * [ ] <- [handle] <=> [handle #1] -> [ ] 53 1.1 christos * /\ 54 1.1 christos * wrong foreach "next" | 55 1.1 christos * 56 1.1 christos * 4. The callback for handle #1 shouldn't be called because the handle #1 is stopped in the previous step. 57 1.1.1.2 christos * However, if uv__queue_remove() is not handled properly within uv__queue_foreach(), the callback _will_ 58 1.1.1.2 christos * be called. 59 1.1 christos */ 60 1.1 christos 61 1.1 christos static const unsigned first_handle_number_idle = 2; 62 1.1 christos static const unsigned first_handle_number_prepare = 2; 63 1.1 christos static const unsigned first_handle_number_check = 2; 64 1.1 christos #ifdef __linux__ 65 1.1 christos static const unsigned first_handle_number_fs_event = 0; 66 1.1 christos #endif 67 1.1 christos 68 1.1 christos 69 1.1 christos #define DEFINE_GLOBALS_AND_CBS(name, ...) \ 70 1.1 christos static uv_##name##_t (name)[3]; \ 71 1.1 christos static unsigned name##_cb_calls[3]; \ 72 1.1 christos \ 73 1.1 christos static void name##2_cb(__VA_ARGS__) { \ 74 1.1.1.2 christos ASSERT_PTR_EQ(handle, &(name)[2]); \ 75 1.1 christos if (first_handle_number_##name == 2) { \ 76 1.1 christos uv_close((uv_handle_t*)&(name)[2], NULL); \ 77 1.1 christos uv_close((uv_handle_t*)&(name)[1], NULL); \ 78 1.1 christos } \ 79 1.1 christos name##_cb_calls[2]++; \ 80 1.1 christos } \ 81 1.1 christos \ 82 1.1 christos static void name##1_cb(__VA_ARGS__) { \ 83 1.1.1.2 christos ASSERT_PTR_EQ(handle, &(name)[1]); \ 84 1.1 christos ASSERT(0 && "Shouldn't be called" && (&name[0])); \ 85 1.1 christos } \ 86 1.1 christos \ 87 1.1 christos static void name##0_cb(__VA_ARGS__) { \ 88 1.1.1.2 christos ASSERT_PTR_EQ(handle, &(name)[0]); \ 89 1.1 christos if (first_handle_number_##name == 0) { \ 90 1.1 christos uv_close((uv_handle_t*)&(name)[0], NULL); \ 91 1.1 christos uv_close((uv_handle_t*)&(name)[1], NULL); \ 92 1.1 christos } \ 93 1.1 christos name##_cb_calls[0]++; \ 94 1.1 christos } \ 95 1.1 christos \ 96 1.1 christos static const uv_##name##_cb name##_cbs[] = { \ 97 1.1 christos name##0_cb, \ 98 1.1 christos name##1_cb, \ 99 1.1 christos name##2_cb, \ 100 1.1 christos }; 101 1.1 christos 102 1.1 christos #define INIT_AND_START(name, loop) \ 103 1.1 christos do { \ 104 1.1 christos size_t i; \ 105 1.1 christos for (i = 0; i < ARRAY_SIZE(name); i++) { \ 106 1.1 christos int r; \ 107 1.1 christos r = uv_##name##_init((loop), &(name)[i]); \ 108 1.1.1.2 christos ASSERT_OK(r); \ 109 1.1 christos \ 110 1.1 christos r = uv_##name##_start(&(name)[i], name##_cbs[i]); \ 111 1.1.1.2 christos ASSERT_OK(r); \ 112 1.1 christos } \ 113 1.1 christos } while (0) 114 1.1 christos 115 1.1 christos #define END_ASSERTS(name) \ 116 1.1 christos do { \ 117 1.1.1.2 christos ASSERT_EQ(1, name##_cb_calls[0]); \ 118 1.1.1.2 christos ASSERT_OK(name##_cb_calls[1]); \ 119 1.1.1.2 christos ASSERT_EQ(1, name##_cb_calls[2]); \ 120 1.1 christos } while (0) 121 1.1 christos 122 1.1 christos DEFINE_GLOBALS_AND_CBS(idle, uv_idle_t* handle) 123 1.1 christos DEFINE_GLOBALS_AND_CBS(prepare, uv_prepare_t* handle) 124 1.1 christos DEFINE_GLOBALS_AND_CBS(check, uv_check_t* handle) 125 1.1 christos 126 1.1 christos #ifdef __linux__ 127 1.1 christos DEFINE_GLOBALS_AND_CBS(fs_event, 128 1.1 christos uv_fs_event_t* handle, 129 1.1 christos const char* filename, 130 1.1 christos int events, 131 1.1 christos int status) 132 1.1 christos 133 1.1 christos static const char watched_dir[] = "."; 134 1.1 christos static uv_timer_t timer; 135 1.1 christos static unsigned helper_timer_cb_calls; 136 1.1 christos 137 1.1 christos 138 1.1 christos static void init_and_start_fs_events(uv_loop_t* loop) { 139 1.1 christos size_t i; 140 1.1 christos for (i = 0; i < ARRAY_SIZE(fs_event); i++) { 141 1.1 christos int r; 142 1.1 christos r = uv_fs_event_init(loop, &fs_event[i]); 143 1.1.1.2 christos ASSERT_OK(r); 144 1.1 christos 145 1.1 christos r = uv_fs_event_start(&fs_event[i], 146 1.1 christos (uv_fs_event_cb)fs_event_cbs[i], 147 1.1 christos watched_dir, 148 1.1 christos 0); 149 1.1.1.2 christos ASSERT_OK(r); 150 1.1 christos } 151 1.1 christos } 152 1.1 christos 153 1.1 christos static void helper_timer_cb(uv_timer_t* thandle) { 154 1.1 christos int r; 155 1.1 christos uv_fs_t fs_req; 156 1.1 christos 157 1.1 christos /* fire all fs_events */ 158 1.1 christos r = uv_fs_utime(thandle->loop, &fs_req, watched_dir, 0, 0, NULL); 159 1.1.1.2 christos ASSERT_OK(r); 160 1.1.1.2 christos ASSERT_OK(fs_req.result); 161 1.1.1.2 christos ASSERT_EQ(fs_req.fs_type, UV_FS_UTIME); 162 1.1.1.2 christos ASSERT_OK(strcmp(fs_req.path, watched_dir)); 163 1.1 christos uv_fs_req_cleanup(&fs_req); 164 1.1 christos 165 1.1 christos helper_timer_cb_calls++; 166 1.1 christos } 167 1.1 christos #endif 168 1.1 christos 169 1.1 christos 170 1.1 christos TEST_IMPL(queue_foreach_delete) { 171 1.1 christos uv_loop_t* loop; 172 1.1 christos int r; 173 1.1 christos 174 1.1 christos loop = uv_default_loop(); 175 1.1 christos 176 1.1 christos INIT_AND_START(idle, loop); 177 1.1 christos INIT_AND_START(prepare, loop); 178 1.1 christos INIT_AND_START(check, loop); 179 1.1 christos 180 1.1 christos #ifdef __linux__ 181 1.1 christos init_and_start_fs_events(loop); 182 1.1 christos 183 1.1 christos /* helper timer to trigger async and fs_event callbacks */ 184 1.1 christos r = uv_timer_init(loop, &timer); 185 1.1.1.2 christos ASSERT_OK(r); 186 1.1 christos 187 1.1 christos r = uv_timer_start(&timer, helper_timer_cb, 0, 0); 188 1.1.1.2 christos ASSERT_OK(r); 189 1.1 christos #endif 190 1.1 christos 191 1.1 christos r = uv_run(loop, UV_RUN_NOWAIT); 192 1.1.1.2 christos ASSERT_EQ(1, r); 193 1.1 christos 194 1.1 christos END_ASSERTS(idle); 195 1.1 christos END_ASSERTS(prepare); 196 1.1 christos END_ASSERTS(check); 197 1.1 christos 198 1.1 christos #ifdef __linux__ 199 1.1.1.2 christos ASSERT_EQ(1, helper_timer_cb_calls); 200 1.1 christos #endif 201 1.1 christos 202 1.1.1.2 christos MAKE_VALGRIND_HAPPY(loop); 203 1.1 christos 204 1.1 christos return 0; 205 1.1 christos } 206