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