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