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 /**************************************************************************/
22
23 /* Include necessary system files. */
24
25 #include "tx_api.h" /* Threadx API */
26 #include "pthread.h" /* Posix API */
27 #include "px_int.h" /* Posix helper functions */
28 #include "tx_thread.h" /* Internal ThreadX thread management. */
29
30
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* pthread_kill PORTABLE C */
36 /* 6.2.0 */
37 /* AUTHOR */
38 /* */
39 /* William E. Lamie, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function is used to request that a signal be delivered to */
44 /* the specified thread. */
45 /* */
46 /* INPUT */
47 /* */
48 /* thread_id Thread ID */
49 /* sig Signal */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* 0 if successful */
54 /* Value in case of any error */
55 /* */
56 /* CALLS */
57 /* */
58 /* posix_in_thread_context Make sure caller is thread */
59 /* posix_internal_error Generic error Handler */
60 /* tx_event_flags_set */
61 /* posix_memory_allocate Create a byte pool for stack */
62 /* tx_thread_create */
63 /* tx_event_flags_delete */
64 /* posix_memory_release */
65 /* tx_thread_suspend */
66 /* _tx_thread_system_preempt_check */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* Application Code */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
77 /* 10-31-2022 Scott Larson Remove double parenthesis, */
78 /* update argument type, */
79 /* resulting in version 6.2.0 */
80 /* */
81 /**************************************************************************/
pthread_kill(ALIGN_TYPE thread_id,int sig)82 int pthread_kill(ALIGN_TYPE thread_id, int sig)
83 {
84
85 TX_INTERRUPT_SAVE_AREA
86
87 POSIX_TCB *target_thread;
88 POSIX_TCB *new_signal_thread;
89 VOID (*handler)(int);
90 INT status;
91 UINT retval;
92
93
94 /* Make sure we're calling this routine from a thread context. */
95 if (!posix_in_thread_context())
96 {
97 /* return POSIX error. */
98 posix_internal_error(444);
99 return(ERROR);
100 }
101
102 /* Determine if the desired signal is valid. */
103 if ((sig < 0) || (sig > SIGRTMAX))
104 {
105
106 /* Return an error. */
107 posix_set_pthread_errno(EINVAL);
108 return(ERROR);
109 }
110
111 /* Pickup target thread. */
112 target_thread = (POSIX_TCB *) thread_id;
113
114 /* Is it non-NULL? */
115 if (!target_thread)
116 {
117
118 /* Invalid target pthread object */
119 posix_errno= ESRCH;
120 posix_set_pthread_errno(ESRCH);
121 return(ERROR);
122 }
123
124 /* Pickup signal handler function pointer. */
125 handler = target_thread -> signals.signal_func[sig];
126
127 /* See if there is a signal handler setup for this signal. */
128 if (!handler)
129 {
130
131 /* No handler, just set/clear the event flags to handle the sigwait condition. */
132
133 /* Set the event flag corresponding the signal. */
134 tx_event_flags_set(&(target_thread -> signals.signal_event_flags), (((ULONG) 1) << sig), TX_OR);
135
136 /* Ensure the flag is left in a clear state. */
137 tx_event_flags_set(&(target_thread -> signals.signal_event_flags), ~(((ULONG) 1) << sig), TX_AND);
138
139 /* We are done, just return success. */
140 return(OK);
141 }
142
143 /* Now, let's look to see if the same signal is already pending. */
144 if (target_thread -> signals.signal_pending.signal_set & (((unsigned long) 1) << sig))
145 {
146
147 /* Yes, the same signal is already pending, just return. */
148 return(OK);
149 }
150
151 /* Now determine if the thread's signals are masked by pthread_sigmask. */
152 if (target_thread -> signals.signal_mask.signal_set & (((unsigned long) 1) << sig))
153 {
154
155 /* Yes, simply set the pending bit so we know that the signal must be activated later when the
156 signal mask for this signal is cleared. */
157 target_thread -> signals.signal_pending.signal_set = target_thread -> signals.signal_pending.signal_set | (((unsigned long) 1) << sig);
158 return(OK);
159 }
160
161 /* At this point we know that we need to create a new signal handler thread for processing this signal. */
162
163 /* Get a pthread control block for this new signal pthread */
164
165 /* Disable interrupts for protection. */
166 TX_DISABLE
167
168 /* Disable preemption temporarily. */
169 _tx_thread_preempt_disable++;
170
171 /* Allocate a POSIX thread control block. */
172 status = posix_allocate_pthread_t(&new_signal_thread);
173
174 /* Restore interrupts. */
175 TX_RESTORE
176
177 /* Make sure we got a new thread control block */
178 if ((status == ERROR) || (!new_signal_thread))
179 {
180
181 /* Disable interrupts. */
182 TX_DISABLE
183
184 /* Enable preemption. */
185 _tx_thread_preempt_disable--;
186
187 /* Restore interrupts. */
188 TX_RESTORE
189
190 /* Configuration/resource error. */
191 posix_set_pthread_errno(EAGAIN);
192 return(ERROR);
193 }
194
195 /* Inherit the stack size for the new signal thread. */
196 new_signal_thread -> stack_size = target_thread -> stack_size ;
197
198 /* Allocate memory for stack. */
199 status = posix_memory_allocate(new_signal_thread -> stack_size, &new_signal_thread -> stack_address);
200
201 /* problem allocating stack space */
202 if (status == ERROR)
203 {
204
205 /* Mark the previously allocated control block as available. */
206 new_signal_thread -> in_use = FALSE;
207
208 /* Disable interrupts. */
209 TX_DISABLE
210
211 /* Enable preemption. */
212 _tx_thread_preempt_disable--;
213
214 /* Restore interrupts. */
215 TX_RESTORE
216
217 /* Configuration/resource error. */
218 posix_set_pthread_errno(EAGAIN);
219 return(ERROR);
220 }
221
222 /* Inherit scheduling attributes from base thread. */
223 new_signal_thread -> current_priority = target_thread -> current_priority ;
224 new_signal_thread -> detach_state = target_thread -> detach_state ;
225 new_signal_thread -> inherit_sched = target_thread -> inherit_sched ;
226 new_signal_thread -> orig_priority = target_thread -> orig_priority ;
227 new_signal_thread -> sched_attr.sched_priority= target_thread -> sched_attr.sched_priority ;
228 new_signal_thread -> pthread_flags = target_thread -> pthread_flags ;
229 new_signal_thread -> sched_policy = target_thread -> sched_policy;
230 new_signal_thread -> is_joined_by = TX_FALSE;
231 new_signal_thread -> joined_by_pthreadID = TX_FALSE;
232 new_signal_thread -> is_joined_to = TX_FALSE;
233 new_signal_thread -> joined_to_pthreadID = TX_FALSE;
234 new_signal_thread -> cancel_state = PTHREAD_CANCEL_ENABLE;
235 new_signal_thread -> cancel_type = PTHREAD_CANCEL_DEFERRED;
236 new_signal_thread -> cancel_request = FALSE;
237 new_signal_thread -> value_ptr = NULL;
238
239 /* Increment the target thread's signal nesting depth. */
240 target_thread -> signals.signal_nesting_depth++;
241
242 /* Mark this signal as pending in the signal set. */
243 target_thread -> signals.signal_pending.signal_set = target_thread -> signals.signal_pending.signal_set | (((unsigned long) 1) << sig);
244
245 /* Mark the new thread as a signal thread, clear signal info, and setup links. */
246 new_signal_thread -> signals.signal_handler = TRUE;
247 new_signal_thread -> signals.signal_nesting_depth = target_thread -> signals.signal_nesting_depth;
248 new_signal_thread -> signals.signal_pending.signal_set = target_thread -> signals.signal_pending.signal_set;
249 new_signal_thread -> signals.saved_thread_state = ((TX_THREAD *) target_thread) -> tx_thread_state;
250 new_signal_thread -> signals.base_thread_ptr = target_thread;
251 new_signal_thread -> signals.next_signal_thread = target_thread -> signals.top_signal_thread;
252
253 /* Remember the top signal thread in the base thread. */
254 target_thread -> signals.top_signal_thread = new_signal_thread;
255
256 /* Now actually create and start the signal thread. */
257 retval = tx_thread_create( (TX_THREAD *) new_signal_thread,
258 "signal pthr",
259 internal_signal_dispatch,
260 (ULONG) sig,
261 new_signal_thread -> stack_address,
262 new_signal_thread -> stack_size,
263 (TX_LOWEST_PRIORITY - new_signal_thread -> current_priority + 1),
264 (TX_LOWEST_PRIORITY - new_signal_thread -> current_priority + 1),
265 new_signal_thread -> time_slice,
266 TX_AUTO_START);
267
268 /* See if ThreadX encountered an error */
269 if (retval)
270 {
271
272 /* Create an event flags group. */
273 tx_event_flags_delete(&(new_signal_thread -> signals.signal_event_flags));
274
275 /* Release the stack memory. */
276 posix_memory_release(new_signal_thread -> stack_address);
277
278 /* Mark the previously allocated control block as available. */
279 new_signal_thread -> in_use = FALSE;
280
281 /* Disable interrupts. */
282 TX_DISABLE
283
284 /* Enable preemption. */
285 _tx_thread_preempt_disable--;
286
287 /* Restore interrupts. */
288 TX_RESTORE
289
290 /* Internal error */
291 posix_error_handler(3333);
292 posix_set_pthread_errno(EACCES);
293 return(ERROR);
294 }
295
296 /* Disable interrupts. */
297 TX_DISABLE
298
299 /* Enable preemption. */
300 _tx_thread_preempt_disable--;
301
302 /* At this point, we need to suspend the target thread if we are the first signal handler to run. */
303 if (new_signal_thread -> signals.signal_nesting_depth == 1)
304 {
305
306 /* Restore interrupts. */
307 TX_RESTORE
308
309 /* Suspend the base thread so that it doesn't run again until all the signals have been processed. */
310 tx_thread_suspend((TX_THREAD *) target_thread);
311 }
312 else if (new_signal_thread -> signals.next_signal_thread)
313 {
314
315 /* Restore interrupts. */
316 TX_RESTORE
317
318 /* Make sure the current top level signal handler thread is suspended. */
319 tx_thread_suspend((TX_THREAD *) new_signal_thread -> signals.next_signal_thread);
320 }
321
322 /* At this point, the new signal has been set and the signal handler is ready for execution. */
323
324 /* Check for a preemption condition. */
325 _tx_thread_system_preempt_check();
326
327 /* Return success! */
328 return(OK);
329 }
330