1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11
12 /**************************************************************************/
13 /**************************************************************************/
14 /** */
15 /** POSIX wrapper for THREADX */
16 /** */
17 /**************************************************************************/
18 /**************************************************************************/
19
20 /* Include necessary system files. */
21
22 #include "tx_api.h" /* Threadx API */
23 #include "pthread.h" /* Posix API */
24 #include "px_int.h" /* Posix helper functions */
25 #include "tx_thread.h" /* Internal ThreadX thread management. */
26
27
28 /**************************************************************************/
29 /* */
30 /* FUNCTION RELEASE */
31 /* */
32 /* sigwait PORTABLE C */
33 /* 6.1.7 */
34 /* AUTHOR */
35 /* */
36 /* William E. Lamie, Microsoft Corporation */
37 /* */
38 /* DESCRIPTION */
39 /* */
40 /* This function selects a pending signal from set, atomically */
41 /* clears it from the system's set of pending signals, and returns the */
42 /* signal number in the location referenced by sig. */
43 /* */
44 /* INPUT */
45 /* */
46 /* set Pointer to set of signals */
47 /* sig Pointer to returned signal number */
48 /* */
49 /* OUTPUT */
50 /* */
51 /* OK If successful */
52 /* EINVAL If error occurs */
53 /* */
54 /* CALLS */
55 /* */
56 /* tx_thread_identify */
57 /* posix_internal_error */
58 /* pthread_sigmask */
59 /* tx_event_flags_get */
60 /* TX_LOWEST_SET_BIT_CALCULATE */
61 /* */
62 /* CALLED BY */
63 /* */
64 /* Application Code */
65 /* */
66 /* RELEASE HISTORY */
67 /* */
68 /* DATE NAME DESCRIPTION */
69 /* */
70 /* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
71 /* */
72 /**************************************************************************/
sigwait(const sigset_t * set,int * sig)73 int sigwait(const sigset_t *set, int *sig)
74 {
75
76 UINT status;
77 ULONG signal_bit_map;
78 ULONG signal_number;
79 ULONG saved_mask;
80 ULONG changed_mask;
81 ULONG pending_signals;
82 sigset_t original_set;
83 POSIX_TCB *base_thread;
84
85
86 /* Pickup base thread, since the base thread and all signal threads will pend off the same
87 event flag group. */
88 base_thread = (POSIX_TCB *) tx_thread_identify();
89
90 /* Is it non-NULL? */
91 if (!base_thread)
92 {
93
94 /* System error! */
95 posix_internal_error(444);
96 return(EINVAL);
97 }
98
99 /* Determine if the current thread is a signal handler thread. */
100 if (base_thread -> signals.signal_handler)
101 {
102
103 /* Pickup target thread. */
104 base_thread = base_thread -> signals.base_thread_ptr;
105 }
106
107 /* Initialize the saved and changed mask values to zero. */
108 saved_mask = 0;
109 changed_mask = 0;
110
111 /* Determine if there are any pending signals that are pertinent to this request. */
112 pending_signals = base_thread -> signals.signal_mask.signal_set & base_thread -> signals.signal_pending.signal_set & set -> signal_set;
113
114 /* Are there any. */
115 if (pending_signals)
116 {
117
118 /* Yes, there are signals being masked currently that would satisfy this request. */
119
120 /* Save the current mask. */
121 saved_mask = base_thread -> signals.signal_mask.signal_set;
122
123 /* Calculate the changed mask. */
124 changed_mask = saved_mask & ~(set -> signal_set);
125
126 /* Call pthread_sigmask to temporarily unblock these signals which will release them as well. */
127 pthread_sigmask(SIG_UNBLOCK, set, &original_set);
128
129 /* Now determine if the changed mask is still in effect, i.e., there wasn't a pthread_sigmask call from any subsequent signal handlers. */
130 if (base_thread -> signals.signal_mask.signal_set == changed_mask)
131 {
132
133 /* Yes, restore the previous signal mask. */
134 base_thread -> signals.signal_mask.signal_set = saved_mask;
135 }
136
137 /* Derived the signal number from the bit map. */
138 TX_LOWEST_SET_BIT_CALCULATE(pending_signals, signal_number);
139
140 /* Return the signal number. */
141 *sig = (int) signal_number;
142
143 /* Return success! */
144 return(OK);
145 }
146
147 /* Determine if there are any signals that have to be temporarily cleared. */
148 if (base_thread -> signals.signal_mask.signal_set & set -> signal_set)
149 {
150
151 /* Yes, there are signals being masked needed to satisfy this request. */
152
153 /* Save the current mask. */
154 saved_mask = base_thread -> signals.signal_mask.signal_set;
155
156 /* Calculate the changed mask. */
157 changed_mask = saved_mask & ~(set -> signal_set);
158
159 /* Apply the changed signal mask. */
160 base_thread -> signals.signal_mask.signal_set = changed_mask;
161 }
162
163 /* Suspend on the signal specified by the input. */
164 status = tx_event_flags_get(&(base_thread -> signals.signal_event_flags), (ULONG) set -> signal_set, TX_OR_CLEAR, &signal_bit_map, TX_WAIT_FOREVER);
165
166 /* Determine if we need to restore the signal mask. */
167 if ((saved_mask) && (changed_mask == base_thread -> signals.signal_mask.signal_set))
168 {
169
170 /* Yes, the signal mask should be restored. */
171 base_thread -> signals.signal_mask.signal_set = saved_mask;
172 }
173
174 /* Check for successful status. */
175 if (status == TX_SUCCESS)
176 {
177
178 /* Derived the signal number from the bit map. */
179 TX_LOWEST_SET_BIT_CALCULATE(signal_bit_map, signal_number);
180
181 /* Return the signal number. */
182 *sig = (int) signal_number;
183
184 /* Return success! */
185 return(OK);
186 }
187 else
188 {
189
190 /* Return error! */
191 return(EINVAL);
192 }
193 }
194