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)78int 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