Mercurial
comparison third_party/libuv/test/test-loop-handles.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 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 /* Tests commented out with XXX are ones that are failing on Linux */ | |
| 23 | |
| 24 /* | |
| 25 * Purpose of this test is to check semantics of starting and stopping | |
| 26 * prepare, check and idle watchers. | |
| 27 * | |
| 28 * - A watcher must be able to safely stop or close itself; | |
| 29 * - Once a watcher is stopped or closed its callback should never be called. | |
| 30 * - If a watcher is closed, it is implicitly stopped and its close_cb should | |
| 31 * be called exactly once. | |
| 32 * - A watcher can safely start and stop other watchers of the same type. | |
| 33 * - Prepare and check watchers are called once per event loop iterations. | |
| 34 * - All active idle watchers are queued when the event loop has no more work | |
| 35 * to do. This is done repeatedly until all idle watchers are inactive. | |
| 36 * - If a watcher starts another watcher of the same type its callback is not | |
| 37 * immediately queued. For check and prepare watchers, that means that if | |
| 38 * a watcher makes another of the same type active, it'll not be called until | |
| 39 * the next event loop iteration. For idle. watchers this means that the | |
| 40 * newly activated idle watcher might not be queued immediately. | |
| 41 * - Prepare, check, idle watchers keep the event loop alive even when they're | |
| 42 * not active. | |
| 43 * | |
| 44 * This is what the test globally does: | |
| 45 * | |
| 46 * - prepare_1 is always active and counts event loop iterations. It also | |
| 47 * creates and starts prepare_2 every other iteration. Finally it verifies | |
| 48 * that no idle watchers are active before polling. | |
| 49 * - prepare_2 is started by prepare_1 every other iteration. It immediately | |
| 50 * stops itself. It verifies that a watcher is not queued immediately | |
| 51 * if created by another watcher of the same type. | |
| 52 * - There's a check watcher that stops the event loop after a certain number | |
| 53 * of iterations. It starts a varying number of idle_1 watchers. | |
| 54 * - Idle_1 watchers stop themselves after being called a few times. All idle_1 | |
| 55 * watchers try to start the idle_2 watcher if it is not already started or | |
| 56 * awaiting its close callback. | |
| 57 * - The idle_2 watcher always exists but immediately closes itself after | |
| 58 * being started by a check_1 watcher. It verifies that a watcher is | |
| 59 * implicitly stopped when closed, and that a watcher can close itself | |
| 60 * safely. | |
| 61 * - There is a repeating timer. It does not keep the event loop alive | |
| 62 * (ev_unref) but makes sure that the loop keeps polling the system for | |
| 63 * events. | |
| 64 */ | |
| 65 | |
| 66 | |
| 67 #include "uv.h" | |
| 68 #include "task.h" | |
| 69 | |
| 70 #include <math.h> | |
| 71 | |
| 72 | |
| 73 #define IDLE_COUNT 7 | |
| 74 #define ITERATIONS 21 | |
| 75 #define TIMEOUT 100 | |
| 76 | |
| 77 | |
| 78 static uv_prepare_t prepare_1_handle; | |
| 79 static uv_prepare_t prepare_2_handle; | |
| 80 | |
| 81 static uv_check_t check_handle; | |
| 82 | |
| 83 static uv_idle_t idle_1_handles[IDLE_COUNT]; | |
| 84 static uv_idle_t idle_2_handle; | |
| 85 | |
| 86 static uv_timer_t timer_handle; | |
| 87 | |
| 88 | |
| 89 static int loop_iteration = 0; | |
| 90 | |
| 91 static int prepare_1_cb_called = 0; | |
| 92 static int prepare_1_close_cb_called = 0; | |
| 93 | |
| 94 static int prepare_2_cb_called = 0; | |
| 95 static int prepare_2_close_cb_called = 0; | |
| 96 | |
| 97 static int check_cb_called = 0; | |
| 98 static int check_close_cb_called = 0; | |
| 99 | |
| 100 static int idle_1_cb_called = 0; | |
| 101 static int idle_1_close_cb_called = 0; | |
| 102 static int idles_1_active = 0; | |
| 103 | |
| 104 static int idle_2_cb_called = 0; | |
| 105 static int idle_2_close_cb_called = 0; | |
| 106 static int idle_2_cb_started = 0; | |
| 107 static int idle_2_is_active = 0; | |
| 108 | |
| 109 | |
| 110 static void timer_cb(uv_timer_t* handle) { | |
| 111 ASSERT_PTR_EQ(handle, &timer_handle); | |
| 112 } | |
| 113 | |
| 114 | |
| 115 static void idle_2_close_cb(uv_handle_t* handle) { | |
| 116 fprintf(stderr, "%s", "IDLE_2_CLOSE_CB\n"); | |
| 117 fflush(stderr); | |
| 118 | |
| 119 ASSERT_PTR_EQ(handle, (uv_handle_t*)&idle_2_handle); | |
| 120 | |
| 121 ASSERT(idle_2_is_active); | |
| 122 | |
| 123 idle_2_close_cb_called++; | |
| 124 idle_2_is_active = 0; | |
| 125 } | |
| 126 | |
| 127 | |
| 128 static void idle_2_cb(uv_idle_t* handle) { | |
| 129 fprintf(stderr, "%s", "IDLE_2_CB\n"); | |
| 130 fflush(stderr); | |
| 131 | |
| 132 ASSERT_PTR_EQ(handle, &idle_2_handle); | |
| 133 | |
| 134 idle_2_cb_called++; | |
| 135 | |
| 136 uv_close((uv_handle_t*)handle, idle_2_close_cb); | |
| 137 } | |
| 138 | |
| 139 | |
| 140 static void idle_1_cb(uv_idle_t* handle) { | |
| 141 int r; | |
| 142 | |
| 143 fprintf(stderr, "%s", "IDLE_1_CB\n"); | |
| 144 fflush(stderr); | |
| 145 | |
| 146 ASSERT_NOT_NULL(handle); | |
| 147 ASSERT_GT(idles_1_active, 0); | |
| 148 | |
| 149 /* Init idle_2 and make it active */ | |
| 150 if (!idle_2_is_active && !uv_is_closing((uv_handle_t*)&idle_2_handle)) { | |
| 151 r = uv_idle_init(uv_default_loop(), &idle_2_handle); | |
| 152 ASSERT_OK(r); | |
| 153 r = uv_idle_start(&idle_2_handle, idle_2_cb); | |
| 154 ASSERT_OK(r); | |
| 155 idle_2_is_active = 1; | |
| 156 idle_2_cb_started++; | |
| 157 } | |
| 158 | |
| 159 idle_1_cb_called++; | |
| 160 | |
| 161 if (idle_1_cb_called % 5 == 0) { | |
| 162 r = uv_idle_stop((uv_idle_t*)handle); | |
| 163 ASSERT_OK(r); | |
| 164 idles_1_active--; | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 | |
| 169 static void idle_1_close_cb(uv_handle_t* handle) { | |
| 170 fprintf(stderr, "%s", "IDLE_1_CLOSE_CB\n"); | |
| 171 fflush(stderr); | |
| 172 | |
| 173 ASSERT_NOT_NULL(handle); | |
| 174 | |
| 175 idle_1_close_cb_called++; | |
| 176 } | |
| 177 | |
| 178 | |
| 179 static void prepare_1_close_cb(uv_handle_t* handle) { | |
| 180 fprintf(stderr, "%s", "PREPARE_1_CLOSE_CB"); | |
| 181 fflush(stderr); | |
| 182 ASSERT_PTR_EQ(handle, (uv_handle_t*)&prepare_1_handle); | |
| 183 | |
| 184 prepare_1_close_cb_called++; | |
| 185 } | |
| 186 | |
| 187 | |
| 188 static void check_close_cb(uv_handle_t* handle) { | |
| 189 fprintf(stderr, "%s", "CHECK_CLOSE_CB\n"); | |
| 190 fflush(stderr); | |
| 191 ASSERT_PTR_EQ(handle, (uv_handle_t*)&check_handle); | |
| 192 | |
| 193 check_close_cb_called++; | |
| 194 } | |
| 195 | |
| 196 | |
| 197 static void prepare_2_close_cb(uv_handle_t* handle) { | |
| 198 fprintf(stderr, "%s", "PREPARE_2_CLOSE_CB\n"); | |
| 199 fflush(stderr); | |
| 200 ASSERT_PTR_EQ(handle, (uv_handle_t*)&prepare_2_handle); | |
| 201 | |
| 202 prepare_2_close_cb_called++; | |
| 203 } | |
| 204 | |
| 205 | |
| 206 static void check_cb(uv_check_t* handle) { | |
| 207 int i, r; | |
| 208 | |
| 209 fprintf(stderr, "%s", "CHECK_CB\n"); | |
| 210 fflush(stderr); | |
| 211 ASSERT_PTR_EQ(handle, &check_handle); | |
| 212 | |
| 213 if (loop_iteration < ITERATIONS) { | |
| 214 /* Make some idle watchers active */ | |
| 215 for (i = 0; i < 1 + (loop_iteration % IDLE_COUNT); i++) { | |
| 216 r = uv_idle_start(&idle_1_handles[i], idle_1_cb); | |
| 217 ASSERT_OK(r); | |
| 218 idles_1_active++; | |
| 219 } | |
| 220 | |
| 221 } else { | |
| 222 /* End of the test - close all handles */ | |
| 223 uv_close((uv_handle_t*)&prepare_1_handle, prepare_1_close_cb); | |
| 224 uv_close((uv_handle_t*)&check_handle, check_close_cb); | |
| 225 uv_close((uv_handle_t*)&prepare_2_handle, prepare_2_close_cb); | |
| 226 | |
| 227 for (i = 0; i < IDLE_COUNT; i++) { | |
| 228 uv_close((uv_handle_t*)&idle_1_handles[i], idle_1_close_cb); | |
| 229 } | |
| 230 | |
| 231 /* This handle is closed/recreated every time, close it only if it is | |
| 232 * active. */ | |
| 233 if (idle_2_is_active) { | |
| 234 uv_close((uv_handle_t*)&idle_2_handle, idle_2_close_cb); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 check_cb_called++; | |
| 239 } | |
| 240 | |
| 241 | |
| 242 static void prepare_2_cb(uv_prepare_t* handle) { | |
| 243 int r; | |
| 244 | |
| 245 fprintf(stderr, "%s", "PREPARE_2_CB\n"); | |
| 246 fflush(stderr); | |
| 247 ASSERT_PTR_EQ(handle, &prepare_2_handle); | |
| 248 | |
| 249 /* Prepare_2 gets started by prepare_1 when (loop_iteration % 2 == 0), and it | |
| 250 * stops itself immediately. A started watcher is not queued until the next | |
| 251 * round, so when this callback is made (loop_iteration % 2 == 0) cannot be | |
| 252 * true. */ | |
| 253 ASSERT_NE(0, loop_iteration % 2); | |
| 254 | |
| 255 r = uv_prepare_stop((uv_prepare_t*)handle); | |
| 256 ASSERT_OK(r); | |
| 257 | |
| 258 prepare_2_cb_called++; | |
| 259 } | |
| 260 | |
| 261 | |
| 262 static void prepare_1_cb(uv_prepare_t* handle) { | |
| 263 int r; | |
| 264 | |
| 265 fprintf(stderr, "%s", "PREPARE_1_CB\n"); | |
| 266 fflush(stderr); | |
| 267 ASSERT_PTR_EQ(handle, &prepare_1_handle); | |
| 268 | |
| 269 if (loop_iteration % 2 == 0) { | |
| 270 r = uv_prepare_start(&prepare_2_handle, prepare_2_cb); | |
| 271 ASSERT_OK(r); | |
| 272 } | |
| 273 | |
| 274 prepare_1_cb_called++; | |
| 275 loop_iteration++; | |
| 276 | |
| 277 printf("Loop iteration %d of %d.\n", loop_iteration, ITERATIONS); | |
| 278 } | |
| 279 | |
| 280 | |
| 281 TEST_IMPL(loop_handles) { | |
| 282 int i; | |
| 283 int r; | |
| 284 | |
| 285 r = uv_prepare_init(uv_default_loop(), &prepare_1_handle); | |
| 286 ASSERT_OK(r); | |
| 287 r = uv_prepare_start(&prepare_1_handle, prepare_1_cb); | |
| 288 ASSERT_OK(r); | |
| 289 | |
| 290 r = uv_check_init(uv_default_loop(), &check_handle); | |
| 291 ASSERT_OK(r); | |
| 292 r = uv_check_start(&check_handle, check_cb); | |
| 293 ASSERT_OK(r); | |
| 294 | |
| 295 /* initialize only, prepare_2 is started by prepare_1_cb */ | |
| 296 r = uv_prepare_init(uv_default_loop(), &prepare_2_handle); | |
| 297 ASSERT_OK(r); | |
| 298 | |
| 299 for (i = 0; i < IDLE_COUNT; i++) { | |
| 300 /* initialize only, idle_1 handles are started by check_cb */ | |
| 301 r = uv_idle_init(uv_default_loop(), &idle_1_handles[i]); | |
| 302 ASSERT_OK(r); | |
| 303 } | |
| 304 | |
| 305 /* don't init or start idle_2, both is done by idle_1_cb */ | |
| 306 | |
| 307 /* The timer callback is there to keep the event loop polling unref it as it | |
| 308 * is not supposed to keep the loop alive */ | |
| 309 r = uv_timer_init(uv_default_loop(), &timer_handle); | |
| 310 ASSERT_OK(r); | |
| 311 r = uv_timer_start(&timer_handle, timer_cb, TIMEOUT, TIMEOUT); | |
| 312 ASSERT_OK(r); | |
| 313 uv_unref((uv_handle_t*)&timer_handle); | |
| 314 | |
| 315 r = uv_run(uv_default_loop(), UV_RUN_DEFAULT); | |
| 316 ASSERT_OK(r); | |
| 317 | |
| 318 ASSERT_EQ(loop_iteration, ITERATIONS); | |
| 319 | |
| 320 ASSERT_EQ(prepare_1_cb_called, ITERATIONS); | |
| 321 ASSERT_EQ(1, prepare_1_close_cb_called); | |
| 322 | |
| 323 ASSERT_EQ(prepare_2_cb_called, ITERATIONS / 2); | |
| 324 ASSERT_EQ(1, prepare_2_close_cb_called); | |
| 325 | |
| 326 ASSERT_EQ(check_cb_called, ITERATIONS); | |
| 327 ASSERT_EQ(1, check_close_cb_called); | |
| 328 | |
| 329 /* idle_1_cb should be called a lot */ | |
| 330 ASSERT_EQ(idle_1_close_cb_called, IDLE_COUNT); | |
| 331 | |
| 332 ASSERT_EQ(idle_2_close_cb_called, idle_2_cb_started); | |
| 333 ASSERT_OK(idle_2_is_active); | |
| 334 | |
| 335 MAKE_VALGRIND_HAPPY(uv_default_loop()); | |
| 336 return 0; | |
| 337 } |