test-signal-multiple-loops.c
Go to the documentation of this file.
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 _WIN32
25 
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 24
44 #define NUM_LOOP_CREATING_THREADS 10
45 
50 };
51 
52 static uv_sem_t sem;
54 static volatile int stop = 0;
55 
56 static volatile int signal1_cb_counter = 0;
57 static volatile int signal2_cb_counter = 0;
58 static volatile int loop_creation_counter = 0;
59 
60 
61 static void increment_counter(volatile int* counter) {
63  ++(*counter);
65 }
66 
67 
68 static void signal1_cb(uv_signal_t* handle, int signum) {
69  ASSERT(signum == SIGUSR1);
72 }
73 
74 
75 static void signal2_cb(uv_signal_t* handle, int signum) {
76  ASSERT(signum == SIGUSR2);
79 }
80 
81 
82 static void signal_handling_worker(void* context) {
83  enum signal_action action;
84  uv_signal_t signal1a;
85  uv_signal_t signal1b;
86  uv_signal_t signal2;
88  int r;
89 
91 
92  ASSERT(0 == uv_loop_init(&loop));
93 
94  /* Setup the signal watchers and start them. */
96  r = uv_signal_init(&loop, &signal1a);
97  ASSERT(r == 0);
98  r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
99  ASSERT(r == 0);
100  r = uv_signal_init(&loop, &signal1b);
101  ASSERT(r == 0);
102  r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
103  ASSERT(r == 0);
104  }
105 
107  r = uv_signal_init(&loop, &signal2);
108  ASSERT(r == 0);
109  r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
110  ASSERT(r == 0);
111  }
112 
113  /* Signal watchers are now set up. */
114  uv_sem_post(&sem);
115 
116  /* Wait for all signals. The signal callbacks stop the watcher, so uv_run
117  * will return when all signal watchers caught a signal.
118  */
120  ASSERT(r == 0);
121 
122  /* Restart the signal watchers. */
124  r = uv_signal_start(&signal1a, signal1_cb, SIGUSR1);
125  ASSERT(r == 0);
126  r = uv_signal_start(&signal1b, signal1_cb, SIGUSR1);
127  ASSERT(r == 0);
128  }
129 
131  r = uv_signal_start(&signal2, signal2_cb, SIGUSR2);
132  ASSERT(r == 0);
133  }
134 
135  /* Wait for signals once more. */
136  uv_sem_post(&sem);
137 
139  ASSERT(r == 0);
140 
141  /* Close the watchers. */
143  uv_close((uv_handle_t*) &signal1a, NULL);
144  uv_close((uv_handle_t*) &signal1b, NULL);
145  }
146 
148  uv_close((uv_handle_t*) &signal2, NULL);
149  }
150 
151  /* Wait for the signal watchers to close. */
153  ASSERT(r == 0);
154 
156 }
157 
158 
159 static void signal_unexpected_cb(uv_signal_t* handle, int signum) {
160  ASSERT(0 && "signal_unexpected_cb should never be called");
161 }
162 
163 
164 static void loop_creating_worker(void* context) {
165  (void) context;
166 
167  do {
168  uv_loop_t *loop;
170  int r;
171 
172  loop = malloc(sizeof(*loop));
173  ASSERT(loop != NULL);
174  ASSERT(0 == uv_loop_init(loop));
175 
177  ASSERT(r == 0);
178 
180  ASSERT(r == 0);
181 
182  uv_close((uv_handle_t*) &signal, NULL);
183 
185  ASSERT(r == 0);
186 
188  free(loop);
189 
191  } while (!stop);
192 }
193 
194 
195 TEST_IMPL(signal_multiple_loops) {
196 #if defined(__CYGWIN__) || defined(__MSYS__)
197  /* FIXME: This test needs more investigation. Somehow the `read` in
198  uv__signal_lock fails spuriously with EACCES or even EAGAIN even
199  though it is supposed to be blocking. Also the test hangs during
200  thread setup occasionally. */
201  RETURN_SKIP("FIXME: This test needs more investigation on Cygwin");
202 #endif
203  uv_thread_t loop_creating_threads[NUM_LOOP_CREATING_THREADS];
204  uv_thread_t signal_handling_threads[NUM_SIGNAL_HANDLING_THREADS];
205  enum signal_action action;
206  sigset_t sigset;
207  int i;
208  int r;
209 
210  r = uv_sem_init(&sem, 0);
211  ASSERT(r == 0);
212 
214  ASSERT(r == 0);
215 
216  /* Create a couple of threads that create a destroy loops continuously. */
217  for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {
218  r = uv_thread_create(&loop_creating_threads[i],
220  NULL);
221  ASSERT(r == 0);
222  }
223 
224  /* Create a couple of threads that actually handle signals. */
225  for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {
226  switch (i % 3) {
227  case 0: action = ONLY_SIGUSR1; break;
228  case 1: action = ONLY_SIGUSR2; break;
229  case 2: action = SIGUSR1_AND_SIGUSR2; break;
230  }
231 
232  r = uv_thread_create(&signal_handling_threads[i],
234  (void*) (uintptr_t) action);
235  ASSERT(r == 0);
236  }
237 
238  /* Wait until all threads have started and set up their signal watchers. */
239  for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)
240  uv_sem_wait(&sem);
241 
242  r = kill(getpid(), SIGUSR1);
243  ASSERT(r == 0);
244  r = kill(getpid(), SIGUSR2);
245  ASSERT(r == 0);
246 
247  /* Wait for all threads to handle these signals. */
248  for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++)
249  uv_sem_wait(&sem);
250 
251  /* Block all signals to this thread, so we are sure that from here the signal
252  * handler runs in another thread. This is more likely to catch thread and
253  * signal safety issues if there are any.
254  */
255  sigfillset(&sigset);
256  pthread_sigmask(SIG_SETMASK, &sigset, NULL);
257 
258  r = kill(getpid(), SIGUSR1);
259  ASSERT(r == 0);
260  r = kill(getpid(), SIGUSR2);
261  ASSERT(r == 0);
262 
263  /* Wait for all signal handling threads to exit. */
264  for (i = 0; i < NUM_SIGNAL_HANDLING_THREADS; i++) {
265  r = uv_thread_join(&signal_handling_threads[i]);
266  ASSERT(r == 0);
267  }
268 
269  /* Tell all loop creating threads to stop. */
270  stop = 1;
271 
272  /* Wait for all loop creating threads to exit. */
273  for (i = 0; i < NUM_LOOP_CREATING_THREADS; i++) {
274  r = uv_thread_join(&loop_creating_threads[i]);
275  ASSERT(r == 0);
276  }
277 
279  printf("signal1_cb calls: %d\n", signal1_cb_counter);
280  printf("signal2_cb calls: %d\n", signal2_cb_counter);
281  printf("loops created and destroyed: %d\n", loop_creation_counter);
282 
283  /* The division by three reflects the fact that we spawn three different
284  * thread groups of (NUM_SIGNAL_HANDLING_THREADS / 3) threads each.
285  */
288 
289  /* We don't know exactly how much loops will be created and destroyed, but at
290  * least there should be 1 for every loop creating thread.
291  */
293 
295  return 0;
296 }
297 
298 #else
299 
300 typedef int file_has_no_tests; /* ISO C forbids an empty translation unit. */
301 
302 #endif /* !_WIN32 */
async_greeter_server_with_graceful_shutdown.loop
loop
Definition: async_greeter_server_with_graceful_shutdown.py:59
sem
static uv_sem_t sem
Definition: test-signal-multiple-loops.c:52
ONLY_SIGUSR1
@ ONLY_SIGUSR1
Definition: test-signal-multiple-loops.c:47
task.h
uv_mutex_init
UV_EXTERN int uv_mutex_init(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:281
uv_signal_init
UV_EXTERN int uv_signal_init(uv_loop_t *loop, uv_signal_t *handle)
Definition: unix/signal.c:317
string.h
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
ASSERT
#define ASSERT(expr)
Definition: task.h:102
uv_thread_join
UV_EXTERN int uv_thread_join(uv_thread_t *tid)
Definition: libuv/src/unix/thread.c:271
uv_run
UV_EXTERN int uv_run(uv_loop_t *, uv_run_mode mode)
Definition: unix/core.c:361
signal2_cb
static void signal2_cb(uv_signal_t *handle, int signum)
Definition: test-signal-multiple-loops.c:75
stop
static volatile int stop
Definition: test-signal-multiple-loops.c:54
uv_close
UV_EXTERN void uv_close(uv_handle_t *handle, uv_close_cb close_cb)
Definition: unix/core.c:112
increment_counter
static void increment_counter(volatile int *counter)
Definition: test-signal-multiple-loops.c:61
uv_loop_close
UV_EXTERN int uv_loop_close(uv_loop_t *loop)
Definition: uv-common.c:761
signal
static void signal(notification *n)
Definition: alts_tsi_handshaker_test.cc:107
NUM_SIGNAL_HANDLING_THREADS
#define NUM_SIGNAL_HANDLING_THREADS
Definition: test-signal-multiple-loops.c:43
UV_RUN_DEFAULT
@ UV_RUN_DEFAULT
Definition: uv.h:254
counter
static int counter
Definition: abseil-cpp/absl/flags/reflection_test.cc:131
counter_lock
static uv_mutex_t counter_lock
Definition: test-signal-multiple-loops.c:53
uv_mutex_t
pthread_mutex_t uv_mutex_t
Definition: unix.h:135
uv_loop_init
UV_EXTERN int uv_loop_init(uv_loop_t *loop)
Definition: loop.c:30
uv_thread_create
UV_EXTERN int uv_thread_create(uv_thread_t *tid, uv_thread_cb entry, void *arg)
Definition: libuv/src/unix/thread.c:209
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
uv_mutex_unlock
UV_EXTERN void uv_mutex_unlock(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:349
uv_sem_t
UV_PLATFORM_SEM_T uv_sem_t
Definition: unix.h:137
uv_signal_stop
UV_EXTERN int uv_signal_stop(uv_signal_t *handle)
Definition: unix/signal.c:511
uv_sem_post
UV_EXTERN void uv_sem_post(uv_sem_t *sem)
Definition: libuv/src/unix/thread.c:669
uv_sem_init
UV_EXTERN int uv_sem_init(uv_sem_t *sem, unsigned int value)
Definition: libuv/src/unix/thread.c:649
loop_creating_worker
static void loop_creating_worker(void *context)
Definition: test-signal-multiple-loops.c:164
uv.h
MAKE_VALGRIND_HAPPY
#define MAKE_VALGRIND_HAPPY()
Definition: task.h:229
uv_signal_s
Definition: uv.h:1561
loop_creation_counter
static volatile int loop_creation_counter
Definition: test-signal-multiple-loops.c:58
client.action
action
Definition: examples/python/xds/client.py:49
signal1_cb
static void signal1_cb(uv_signal_t *handle, int signum)
Definition: test-signal-multiple-loops.c:68
signal1_cb_counter
static volatile int signal1_cb_counter
Definition: test-signal-multiple-loops.c:56
uv_sem_destroy
UV_EXTERN void uv_sem_destroy(uv_sem_t *sem)
Definition: libuv/src/unix/thread.c:661
uv_mutex_lock
UV_EXTERN void uv_mutex_lock(uv_mutex_t *handle)
Definition: libuv/src/unix/thread.c:329
file_has_no_tests
int file_has_no_tests
Definition: test-fs-fd-hash.c:131
fix_build_deps.r
r
Definition: fix_build_deps.py:491
signal_unexpected_cb
static void signal_unexpected_cb(uv_signal_t *handle, int signum)
Definition: test-signal-multiple-loops.c:159
signal_handling_worker
static void signal_handling_worker(void *context)
Definition: test-signal-multiple-loops.c:82
ONLY_SIGUSR2
@ ONLY_SIGUSR2
Definition: test-signal-multiple-loops.c:48
NUM_LOOP_CREATING_THREADS
#define NUM_LOOP_CREATING_THREADS
Definition: test-signal-multiple-loops.c:44
signal_action
signal_action
Definition: test-signal-multiple-loops.c:46
RETURN_SKIP
#define RETURN_SKIP(explanation)
Definition: task.h:262
handle
static csh handle
Definition: test_arm_regression.c:16
context
grpc::ClientContext context
Definition: istio_echo_server_lib.cc:61
uv_handle_s
Definition: uv.h:441
uv_thread_t
pthread_t uv_thread_t
Definition: unix.h:134
uv_loop_s
Definition: uv.h:1767
uv_sem_wait
UV_EXTERN void uv_sem_wait(uv_sem_t *sem)
Definition: libuv/src/unix/thread.c:677
SIGUSR1_AND_SIGUSR2
@ SIGUSR1_AND_SIGUSR2
Definition: test-signal-multiple-loops.c:49
TEST_IMPL
TEST_IMPL(signal_multiple_loops)
Definition: test-signal-multiple-loops.c:195
signal2_cb_counter
static volatile int signal2_cb_counter
Definition: test-signal-multiple-loops.c:57
errno.h
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
uv_signal_start
UV_EXTERN int uv_signal_start(uv_signal_t *handle, uv_signal_cb signal_cb, int signum)
Definition: unix/signal.c:338


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:30