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