1
0
mirror of https://github.com/azure-rtos/threadx synced 2025-01-30 08:02:57 +08:00
2022-10-26 23:41:13 +00:00

232 lines
10 KiB
C

/**************************************************************************/
/* */
/* Copyright (c) Microsoft Corporation. All rights reserved. */
/* */
/* This software is licensed under the Microsoft Software License */
/* Terms for Microsoft Azure RTOS. Full text of the license can be */
/* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
/* and in the root directory of this software. */
/* */
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** POSIX wrapper for THREADX */
/** */
/** */
/** */
/**************************************************************************/
/**************************************************************************/
/* Include necessary system files. */
#include "tx_api.h" /* Threadx API */
#include "pthread.h" /* Posix API */
#include "px_int.h" /* Posix helper functions */
#include "tx_thread.h" /* Internal ThreadX thread management. */
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* pthread_sigmask PORTABLE C */
/* 6.2.0 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function shall examine or change (or both) the calling */
/* thread's signal mask. */
/* */
/* INPUT */
/* */
/* how how the set will be changed */
/* newmask pointer to new set of signals */
/* oldmask pointer to store previous signals */
/* */
/* OUTPUT */
/* */
/* OK If successful */
/* EINVAL If error occurs */
/* */
/* CALLS */
/* */
/* posix_set_pthread_errno */
/* tx_thread_identify */
/* pthread_kill */
/* _tx_thread_system_preempt_check */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
/* 10-31-2022 Scott Larson Update pthread_kill argument */
/* cast, */
/* resulting in version 6.2.0 */
/* */
/**************************************************************************/
int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask)
{
TX_INTERRUPT_SAVE_AREA
ULONG blocked_signals;
ULONG released_signals;
ULONG signal_number;
ULONG previous_mask;
POSIX_TCB *base_thread;
ULONG reissue_flag;
/* Check for a valid how parameter. */
if ((how != SIG_BLOCK) && (how != SIG_SETMASK) & (how != SIG_UNBLOCK))
{
/* Return an error. */
posix_set_pthread_errno(EINVAL);
return(EINVAL);
}
/* Check for valid signal masks. */
if ((newmask == NULL) || (oldmask == NULL))
{
/* Return an error. */
posix_set_pthread_errno(EINVAL);
return(EINVAL);
}
/* Pickup base thread, since the base thread and all signal threads will pend off the same
event flag group. */
base_thread = (POSIX_TCB *) tx_thread_identify();
/* Is it non-NULL? */
if (!base_thread)
{
/* System error! */
posix_set_pthread_errno(ESRCH);
return(EINVAL);
}
/* Determine if the current thread is a signal handler thread. */
if (base_thread -> signals.signal_handler)
{
/* Pickup target thread. */
base_thread = base_thread -> signals.base_thread_ptr;
}
/* Save the current signal mask for return. */
previous_mask = base_thread -> signals.signal_mask.signal_set;
/* Now process based on how the mask is to be changed. */
if (how == SIG_BLOCK)
{
/* Simply set the mask to block the signal(s). */
base_thread -> signals.signal_mask.signal_set = base_thread -> signals.signal_mask.signal_set | newmask -> signal_set;
}
else
{
/* Now calculate the set of currently pending signals there are waiting based on the current mask. */
blocked_signals = base_thread -> signals.signal_mask.signal_set & base_thread -> signals.signal_pending.signal_set;
/* Now modify the singal mask correspondingly. */
if (how == SIG_UNBLOCK)
{
/* Clear only the signals specified in the new signal mask. */
base_thread -> signals.signal_mask.signal_set = base_thread -> signals.signal_mask.signal_set & ~(newmask -> signal_set);
}
else
{
/* Simply set the signal mask to the new signal mask value. */
base_thread -> signals.signal_mask.signal_set = newmask -> signal_set;
}
/* Now determine if there are any signals that need to be activated. */
released_signals = blocked_signals & ~(base_thread -> signals.signal_mask.signal_set);
/* Are there any signals that need to be activated? */
if (released_signals)
{
/* Temporarily disable interrupts. */
TX_DISABLE
/* Temporarily disable preemption. */
_tx_thread_preempt_disable++;
/* Restore interrupts. */
TX_RESTORE
/* Set the reissue flag to false. */
reissue_flag = TX_FALSE;
/* Loop to process all the blocked signals. */
signal_number = 0;
while ((released_signals) && (signal_number < 32))
{
/* Determine if this signal was released. */
if (released_signals & 1)
{
/* Yes, this signal was released. We need to make it active again. */
/* Clear the pending bit so the pthread_kill call will not discard the signal (signals are not queued in this implementation). */
base_thread -> signals.signal_pending.signal_set = base_thread -> signals.signal_pending.signal_set & ~(((unsigned long) 1) << signal_number);
/* Call pthread_kill to reissue the signal. */
pthread_kill((ALIGN_TYPE) base_thread, signal_number);
/* Set the reissue flag. */
reissue_flag = TX_TRUE;
}
/* Look for next signal. */
released_signals = released_signals >> 1;
signal_number++;
}
/* Temporarily disable interrupts. */
TX_DISABLE
/* Release preemption. */
_tx_thread_preempt_disable--;
/* Restore interrupts. */
TX_RESTORE
/* Check for a preemption condition. */
_tx_thread_system_preempt_check();
/* Determine if the reissue flag is set. */
if (reissue_flag == TX_TRUE)
{
/* Relinquish to allow signal thread at same priority to run before we return. */
_tx_thread_relinquish();
}
}
}
/* Setup return mask. */
oldmask -> signal_set = previous_mask;
return(OK);
}