Files
threadx/utility/rtos_compatibility_layers/posix/px_sig_wait.c
Bo Chen (from Dev Box) 8276bcf711 Update copyright.
2024-01-29 13:51:15 +08:00

194 lines
8.4 KiB
C

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** 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 */
/* */
/* sigwait PORTABLE C */
/* 6.1.7 */
/* AUTHOR */
/* */
/* William E. Lamie, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* This function selects a pending signal from set, atomically */
/* clears it from the system's set of pending signals, and returns the */
/* signal number in the location referenced by sig. */
/* */
/* INPUT */
/* */
/* set Pointer to set of signals */
/* sig Pointer to returned signal number */
/* */
/* OUTPUT */
/* */
/* OK If successful */
/* EINVAL If error occurs */
/* */
/* CALLS */
/* */
/* tx_thread_identify */
/* posix_internal_error */
/* pthread_sigmask */
/* tx_event_flags_get */
/* TX_LOWEST_SET_BIT_CALCULATE */
/* */
/* CALLED BY */
/* */
/* Application Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 06-02-2021 William E. Lamie Initial Version 6.1.7 */
/* */
/**************************************************************************/
int sigwait(const sigset_t *set, int *sig)
{
UINT status;
ULONG signal_bit_map;
ULONG signal_number;
ULONG saved_mask;
ULONG changed_mask;
ULONG pending_signals;
sigset_t original_set;
POSIX_TCB *base_thread;
/* 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_internal_error(444);
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;
}
/* Initialize the saved and changed mask values to zero. */
saved_mask = 0;
changed_mask = 0;
/* Determine if there are any pending signals that are pertinent to this request. */
pending_signals = base_thread -> signals.signal_mask.signal_set & base_thread -> signals.signal_pending.signal_set & set -> signal_set;
/* Are there any. */
if (pending_signals)
{
/* Yes, there are signals being masked currently that would satisfy this request. */
/* Save the current mask. */
saved_mask = base_thread -> signals.signal_mask.signal_set;
/* Calculate the changed mask. */
changed_mask = saved_mask & ~(set -> signal_set);
/* Call pthread_sigmask to temporarily unblock these signals which will release them as well. */
pthread_sigmask(SIG_UNBLOCK, set, &original_set);
/* Now determine if the changed mask is still in effect, i.e., there wasn't a pthread_sigmask call from any subsequent signal handlers. */
if (base_thread -> signals.signal_mask.signal_set == changed_mask)
{
/* Yes, restore the previous signal mask. */
base_thread -> signals.signal_mask.signal_set = saved_mask;
}
/* Derived the signal number from the bit map. */
TX_LOWEST_SET_BIT_CALCULATE(pending_signals, signal_number);
/* Return the signal number. */
*sig = (int) signal_number;
/* Return success! */
return(OK);
}
/* Determine if there are any signals that have to be temporarily cleared. */
if (base_thread -> signals.signal_mask.signal_set & set -> signal_set)
{
/* Yes, there are signals being masked needed to satisfy this request. */
/* Save the current mask. */
saved_mask = base_thread -> signals.signal_mask.signal_set;
/* Calculate the changed mask. */
changed_mask = saved_mask & ~(set -> signal_set);
/* Apply the changed signal mask. */
base_thread -> signals.signal_mask.signal_set = changed_mask;
}
/* Suspend on the signal specified by the input. */
status = tx_event_flags_get(&(base_thread -> signals.signal_event_flags), (ULONG) set -> signal_set, TX_OR_CLEAR, &signal_bit_map, TX_WAIT_FOREVER);
/* Determine if we need to restore the signal mask. */
if ((saved_mask) && (changed_mask == base_thread -> signals.signal_mask.signal_set))
{
/* Yes, the signal mask should be restored. */
base_thread -> signals.signal_mask.signal_set = saved_mask;
}
/* Check for successful status. */
if (status == TX_SUCCESS)
{
/* Derived the signal number from the bit map. */
TX_LOWEST_SET_BIT_CALCULATE(signal_bit_map, signal_number);
/* Return the signal number. */
*sig = (int) signal_number;
/* Return success! */
return(OK);
}
else
{
/* Return error! */
return(EINVAL);
}
}