libuv-svace-build
325 строк · 9.3 Кб
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
23/* This test does not pretend to be cross-platform. */
24#ifndef _WIN3225
26#include "uv.h"27#include "task.h"28
29#include <errno.h>30#include <signal.h>31#include <stdarg.h>32#include <stdio.h>33#include <stdlib.h>34#include <string.h>35#include <unistd.h>36
37/* The value of NUM_SIGNAL_HANDLING_THREADS is not arbitrary; it needs to be a
38* multiple of three for reasons that will become clear when you scroll down.
39* We're basically creating three different thread groups. The total needs
40* to be divisible by three in order for the numbers in the final check to
41* match up.
42*/
43#define NUM_SIGNAL_HANDLING_THREADS 2444#define NUM_LOOP_CREATING_THREADS 1045
46enum signal_action {47ONLY_SIGUSR1,48ONLY_SIGUSR2,49SIGUSR1_AND_SIGUSR2
50};51
52static uv_sem_t sem;53static uv_mutex_t lock;54static int stop = 0;55
56static int signal1_cb_counter = 0;57static int signal2_cb_counter = 0;58static int loop_creation_counter = 0;59
60
61static void increment_counter(int* counter) {62uv_mutex_lock(&lock);63++(*counter);64uv_mutex_unlock(&lock);65}
66
67
68static void signal1_cb(uv_signal_t* handle, int signum) {69ASSERT_EQ(signum, SIGUSR1);70increment_counter(&signal1_cb_counter);71uv_signal_stop(handle);72}
73
74
75static void signal2_cb(uv_signal_t* handle, int signum) {76ASSERT_EQ(signum, SIGUSR2);77increment_counter(&signal2_cb_counter);78uv_signal_stop(handle);79}
80
81
82static void signal_handling_worker(void* context) {83enum signal_action action;84uv_signal_t signal1a;85uv_signal_t signal1b;86uv_signal_t signal2;87uv_loop_t loop;88int r;89
90action = (enum signal_action) (uintptr_t) context;91
92ASSERT_OK(uv_loop_init(&loop));93
94/* Setup the signal watchers and start them. */95if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {96r = uv_signal_init(&loop, &signal1a);97ASSERT_OK(r);98r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);99ASSERT_OK(r);100r = uv_signal_init(&loop, &signal1b);101ASSERT_OK(r);102r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);103ASSERT_OK(r);104}105
106if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {107r = uv_signal_init(&loop, &signal2);108ASSERT_OK(r);109r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);110ASSERT_OK(r);111}112
113/* Signal watchers are now set up. */114uv_sem_post(&sem);115
116/* Wait for all signals. The signal callbacks stop the watcher, so uv_run117* will return when all signal watchers caught a signal.
118*/
119r = uv_run(&loop, UV_RUN_DEFAULT);120ASSERT_OK(r);121
122/* Restart the signal watchers. */123if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {124r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);125ASSERT_OK(r);126r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);127ASSERT_OK(r);128}129
130if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {131r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);132ASSERT_OK(r);133}134
135/* Wait for signals once more. */136uv_sem_post(&sem);137
138r = uv_run(&loop, UV_RUN_DEFAULT);139ASSERT_OK(r);140
141/* Close the watchers. */142if (action == ONLY_SIGUSR1 || action == SIGUSR1_AND_SIGUSR2) {143uv_close((uv_handle_t*) &signal1a, NULL);144uv_close((uv_handle_t*) &signal1b, NULL);145}146
147if (action == ONLY_SIGUSR2 || action == SIGUSR1_AND_SIGUSR2) {148uv_close((uv_handle_t*) &signal2, NULL);149}150
151/* Wait for the signal watchers to close. */152r = uv_run(&loop, UV_RUN_DEFAULT);153ASSERT_OK(r);154
155uv_loop_close(&loop);156}
157
158
159static void signal_unexpected_cb(uv_signal_t* handle, int signum) {160ASSERT(0 && "signal_unexpected_cb should never be called");161}
162
163
164static void loop_creating_worker(void* context) {165int done;166
167(void) context;168
169do {170uv_loop_t *loop;171uv_signal_t signal;172int r;173
174loop = malloc(sizeof(*loop));175ASSERT_NOT_NULL(loop);176ASSERT_OK(uv_loop_init(loop));177
178r = uv_signal_init(loop, &signal);179ASSERT_OK(r);180
181r = uv_signal_start(&signal, signal_unexpected_cb, SIGTERM);182ASSERT_OK(r);183
184uv_close((uv_handle_t*) &signal, NULL);185
186r = uv_run(loop, UV_RUN_DEFAULT);187ASSERT_OK(r);188
189uv_loop_close(loop);190free(loop);191
192increment_counter(&loop_creation_counter);193
194uv_mutex_lock(&lock);195done = stop;196uv_mutex_unlock(&lock);197} while (!done);198}
199
200
201TEST_IMPL(signal_multiple_loops) {202#if defined(__CYGWIN__) || defined(__MSYS__)203/* FIXME: This test needs more investigation. Somehow the `read` in204uv__signal_lock fails spuriously with EACCES or even EAGAIN even
205though it is supposed to be blocking. Also the test hangs during
206thread setup occasionally. */
207RETURN_SKIP("FIXME: This test needs more investigation on Cygwin");208#endif209/* TODO(gengjiawen): Fix test on QEMU. */
210#if defined(__QEMU__)211/* See https://github.com/libuv/libuv/issues/2859 */212RETURN_SKIP("QEMU's signal emulation code is notoriously tricky");213#endif214#if defined(__ASAN__) || defined(__MSAN__)215/* See https://github.com/libuv/libuv/issues/3956 */216RETURN_SKIP("Test is too slow to run under ASan or MSan");217#endif218#if defined(__TSAN__)219/* ThreadSanitizer complains - likely legitimately - about data races220* in uv__signal_compare() in src/unix/signal.c but that's pre-existing.
221*/
222RETURN_SKIP("Fix test under ThreadSanitizer");223#endif224uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS];225uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS];226enum signal_action action;227sigset_t sigset;228int i;229int r;230
231r = uv_sem_init(&sem, 0);232ASSERT_OK(r);233
234r = uv_mutex_init(&lock);235ASSERT_OK(r);236
237/* Create a couple of threads that create a destroy loops continuously. */238for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {239r = uv_thread_create(&loop_creating_threads[i],240loop_creating_worker,241NULL);242ASSERT_OK(r);243}244
245/* Create a couple of threads that actually handle signals. */246for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {247switch (i % 3) {248case 0: action = ONLY_SIGUSR1; break;249case 1: action = ONLY_SIGUSR2; break;250case 2: action = SIGUSR1_AND_SIGUSR2; break;251}252
253r = uv_thread_create(&signal_handling_threads[i],254signal_handling_worker,255(void*) (uintptr_t) action);256ASSERT_OK(r);257}258
259/* Wait until all threads have started and set up their signal watchers. */260for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)261uv_sem_wait(&sem);262
263r = kill(getpid(), SIGUSR1);264ASSERT_OK(r);265r = kill(getpid(), SIGUSR2);266ASSERT_OK(r);267
268/* Wait for all threads to handle these signals. */269for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)270uv_sem_wait(&sem);271
272/* Block all signals to this thread, so we are sure that from here the signal273* handler runs in another thread. This is more likely to catch thread and
274* signal safety issues if there are any.
275*/
276sigfillset(&sigset);277pthread_sigmask(SIG_SETMASK, &sigset, NULL);278
279r = kill(getpid(), SIGUSR1);280ASSERT_OK(r);281r = kill(getpid(), SIGUSR2);282ASSERT_OK(r);283
284/* Wait for all signal handling threads to exit. */285for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {286r = uv_thread_join(&signal_handling_threads[i]);287ASSERT_OK(r);288}289
290/* Tell all loop creating threads to stop. */291uv_mutex_lock(&lock);292stop = 1;293uv_mutex_unlock(&lock);294
295/* Wait for all loop creating threads to exit. */296for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {297r = uv_thread_join(&loop_creating_threads[i]);298ASSERT_OK(r);299}300
301uv_sem_destroy(&sem);302printf("signal1_cb calls: %d\n", signal1_cb_counter);303printf("signal2_cb calls: %d\n", signal2_cb_counter);304printf("loops created and destroyed: %d\n", loop_creation_counter);305
306/* The division by three reflects the fact that we spawn three different307* thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each.
308*/
309ASSERT_EQ(signal1_cb_counter, 8 * (NUM_SIGNAL_HANDLING_THREADS / 3));310ASSERT_EQ(signal2_cb_counter, 4 * (NUM_SIGNAL_HANDLING_THREADS / 3));311
312/* We don't know exactly how much loops will be created and destroyed, but at313* least there should be 1 for every loop creating thread.
314*/
315ASSERT_GE(loop_creation_counter, NUM_LOOP_CREATING_THREADS);316
317MAKE_VALGRIND_HAPPY(uv_default_loop());318return 0;319}
320
321#else322
323typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */324
325#endif /* !_WIN32 */326