1 /**
2 * diag_threshold_test_logging.c
3 * diag_mem_threshold_logging_test
4 *
5 * Test that logs while sending signals between threads. That will
6 * validate that test logging functionality will not have a reentrancy
7 * issue.
8 *
9 * Copyright (c) 2023 Apple Inc. All rights reserved.
10 */
11
12
13
14 #include <stdio.h>
15 #include "diag_threshold_test.h"
16 #include <sys/kern_memorystatus.h>
17 #include <pthread.h>
18 #include <signal.h>
19 #include <stdatomic.h>
20 #include <TargetConditionals.h>
21
22
23 pthread_t thread_logger, thread_kicker;
24 static void *logger_thread(void *);
25 static void signal_handler(__unused int signo, __unused siginfo_t *info, __unused void *extra);
26 static struct sigaction original_action; /** Original signal handler for the process */
27 static void set_sig_handler(void);
28 static void *kicker_thread(__unused void *param);
29
30 static const double TESTING_TIME = 5.;
31 T_GLOBAL_META(
32 T_META_ENABLED(TARGET_OS_IPHONE),
33 T_META_NAMESPACE("xnu.vm.100432442"),
34 T_META_RADAR_COMPONENT_NAME("xnu"),
35 T_META_OWNER("jsolsona"),
36 T_META_RADAR_COMPONENT_VERSION("VM")
37 );
38
39
40
41 T_DECL(diag_mem_threshold_logging_test,
42 "Logging test, log while handling posix signals")
43 {
44 //diag_mem_threshold_set_setup(&diag_mem_threshold_logging_test);
45 int iret1, iret2;
46 iret1 = pthread_create( &thread_logger, NULL, logger_thread, (void*) NULL);
47 T_QUIET; T_ASSERT_POSIX_ZERO(iret1, "Creation of the logging thread");
48 iret2 = pthread_create( &thread_kicker, NULL, kicker_thread, (void*) NULL);
49 T_QUIET; T_ASSERT_POSIX_ZERO(iret2, "Creation of the kick thread");
50 pthread_join(thread_logger, NULL);
51 pthread_join(thread_kicker, NULL);
52 }
53
54 /**
55 * Simple logger thread, sets a signal handler and logs for 10s
56 */
57 static void *
logger_thread(__unused void * param)58 logger_thread(__unused void *param)
59 {
60 set_sig_handler();
61 time_t t = time(NULL);
62 while (difftime(time(NULL), t) < TESTING_TIME) {
63 diag_mem_threshold_log_test("I am logging from a thread %f seconds ", difftime(time(NULL), t));
64 }
65 return NULL;
66 }
67
68
69 /**
70 * Simple kicker thread, just send signals to the logger thread
71 */
72 static void *
kicker_thread(__unused void * param)73 kicker_thread(__unused void *param)
74 {
75 time_t t = time(NULL);
76 while (difftime(time(NULL), t) < TESTING_TIME) {
77 pthread_kill(thread_logger, SIGUSR1);
78 }
79 return NULL;
80 }
81
82 /**
83 * Standard function to set a singal handler routine. Sets the handler for SIGUSR1 to the
84 * termination_handler routine, and indeed terminates current thread.
85 */
86 static void
set_sig_handler(void)87 set_sig_handler(void)
88 {
89 struct sigaction action;
90
91 action.sa_flags = SA_SIGINFO;
92 action.sa_sigaction = signal_handler;
93
94 T_QUIET; T_ASSERT_MACH_SUCCESS(sigaction(SIGUSR1, &action, &original_action), "Verification of adjustment of signal handler");
95 }
96
97 /**
98 * Handler of the SIGUSR1 signal, just terminates the current thread.
99 */
100 static void
signal_handler(__unused int signo,__unused siginfo_t * info,__unused void * extra)101 signal_handler(__unused int signo, __unused siginfo_t *info, __unused void *extra)
102 {
103 static atomic_int recursion_level = 0;
104 atomic_fetch_add_explicit(&recursion_level, 1, memory_order_relaxed);
105 if (recursion_level == 1) {
106 diag_mem_threshold_log_test("Logging from a signal handler");
107 }
108 atomic_fetch_sub_explicit(&recursion_level, 1, memory_order_relaxed);
109 }
110