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 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    pthread_sigmask                                     PORTABLE C      */
35 /*                                                           6.2.0        */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    William E. Lamie, Microsoft Corporation                             */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    This function shall examine or change (or both) the calling         */
43 /*    thread's signal mask.                                               */
44 /*                                                                        */
45 /*  INPUT                                                                 */
46 /*                                                                        */
47 /*    how                            how the set will be changed          */
48 /*    newmask                        pointer to new set of signals        */
49 /*    oldmask                        pointer to store previous signals    */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    OK                        If successful                             */
54 /*    EINVAL                    If error occurs                           */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    posix_set_pthread_errno                                             */
59 /*    tx_thread_identify                                                  */
60 /*    pthread_kill                                                        */
61 /*    _tx_thread_system_preempt_check                                     */
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 /*  10-31-2022      Scott Larson            Update pthread_kill argument  */
73 /*                                            cast,                       */
74 /*                                            resulting in version 6.2.0  */
75 /*                                                                        */
76 /**************************************************************************/
77 
pthread_sigmask(int how,const sigset_t * newmask,sigset_t * oldmask)78 int   pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask)
79 {
80 
81 TX_INTERRUPT_SAVE_AREA
82 
83 ULONG       blocked_signals;
84 ULONG       released_signals;
85 ULONG       signal_number;
86 ULONG       previous_mask;
87 POSIX_TCB   *base_thread;
88 ULONG       reissue_flag;
89 
90 
91     /* Check for a valid how parameter.  */
92     if ((how != SIG_BLOCK) && (how != SIG_SETMASK) & (how != SIG_UNBLOCK))
93     {
94 
95         /* Return an error.  */
96         posix_set_pthread_errno(EINVAL);
97         return(EINVAL);
98     }
99 
100     /* Check for valid signal masks.  */
101     if ((newmask == NULL) || (oldmask == NULL))
102     {
103 
104         /* Return an error.  */
105         posix_set_pthread_errno(EINVAL);
106         return(EINVAL);
107     }
108 
109     /* Pickup base thread, since the base thread and all signal threads will pend off the same
110        event flag group.  */
111     base_thread =  (POSIX_TCB *) tx_thread_identify();
112 
113     /* Is it non-NULL?  */
114     if (!base_thread)
115     {
116 
117         /* System error!  */
118         posix_set_pthread_errno(ESRCH);
119         return(EINVAL);
120     }
121 
122     /* Determine if the current thread is a signal handler thread.  */
123     if (base_thread -> signals.signal_handler)
124     {
125 
126         /* Pickup target thread.  */
127         base_thread =  base_thread -> signals.base_thread_ptr;
128     }
129 
130     /* Save the current signal mask for return.  */
131     previous_mask =  base_thread -> signals.signal_mask.signal_set;
132 
133     /* Now process based on how the mask is to be changed.  */
134     if (how == SIG_BLOCK)
135     {
136 
137         /* Simply set the mask to block the signal(s). */
138         base_thread -> signals.signal_mask.signal_set =  base_thread -> signals.signal_mask.signal_set | newmask -> signal_set;
139     }
140     else
141     {
142 
143         /* Now calculate the set of currently pending signals there are waiting based on the current mask.  */
144         blocked_signals = base_thread -> signals.signal_mask.signal_set & base_thread -> signals.signal_pending.signal_set;
145 
146         /* Now modify the singal mask correspondingly.  */
147         if (how == SIG_UNBLOCK)
148         {
149 
150             /* Clear only the signals specified in the new signal mask.  */
151             base_thread -> signals.signal_mask.signal_set =  base_thread -> signals.signal_mask.signal_set & ~(newmask -> signal_set);
152         }
153         else
154         {
155 
156             /* Simply set the signal mask to the new signal mask value.  */
157             base_thread -> signals.signal_mask.signal_set =  newmask -> signal_set;
158         }
159 
160         /* Now determine if there are any signals that need to be activated.  */
161         released_signals =  blocked_signals & ~(base_thread -> signals.signal_mask.signal_set);
162 
163         /* Are there any signals that need to be activated?  */
164         if (released_signals)
165         {
166 
167             /* Temporarily disable interrupts.  */
168             TX_DISABLE
169 
170             /* Temporarily disable preemption.  */
171             _tx_thread_preempt_disable++;
172 
173             /* Restore interrupts.  */
174             TX_RESTORE
175 
176             /* Set the reissue flag to false.  */
177             reissue_flag =  TX_FALSE;
178 
179             /* Loop to process all the blocked signals.  */
180             signal_number = 0;
181             while ((released_signals) && (signal_number < 32))
182             {
183 
184                 /* Determine if this signal was released.  */
185                 if (released_signals & 1)
186                 {
187 
188                     /* Yes, this signal was released.  We need to make it active again.  */
189 
190                     /* Clear the pending bit so the pthread_kill call will not discard the signal (signals are not queued in this implementation).  */
191                     base_thread -> signals.signal_pending.signal_set  =  base_thread -> signals.signal_pending.signal_set & ~(((unsigned long) 1) << signal_number);
192 
193                     /* Call pthread_kill to reissue the signal.  */
194                     pthread_kill((ALIGN_TYPE) base_thread, signal_number);
195 
196                     /* Set the reissue flag.  */
197                     reissue_flag =  TX_TRUE;
198                 }
199 
200                 /* Look for next signal.  */
201                 released_signals =  released_signals >> 1;
202                 signal_number++;
203             }
204 
205             /* Temporarily disable interrupts.  */
206             TX_DISABLE
207 
208             /* Release preemption.  */
209             _tx_thread_preempt_disable--;
210 
211             /* Restore interrupts.  */
212             TX_RESTORE
213 
214             /* Check for a preemption condition.  */
215             _tx_thread_system_preempt_check();
216 
217             /* Determine if the reissue flag is set.  */
218             if (reissue_flag == TX_TRUE)
219             {
220 
221                 /* Relinquish to allow signal thread at same priority to run before we return.  */
222                 _tx_thread_relinquish();
223             }
224         }
225     }
226 
227     /* Setup return mask.  */
228     oldmask -> signal_set =  previous_mask;
229 
230     return(OK);
231 }
232