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