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