Correct initial POSIX signals mask

+ Modify POSIX thread create extension to ensure expected
	  initial signal mask is provided to system threads, initial
	  tasks and threads, and inheritied by tasks and threads.
	+ Adds psxsignal07 to verify functionality when using a POSIX
	  Initialization thread and POSIX threads.
	+ Adds psxsignal08 to verify functionality when using a Classic API
	  Initialization task and Classic API tasks.

Closes #3794.
This commit is contained in:
Joel Sherrill
2019-09-24 16:27:57 -05:00
parent 33ed4123c0
commit 8798372261
14 changed files with 561 additions and 5 deletions
+48 -5
View File
@@ -86,7 +86,6 @@ int pthread_create(
int low_prio;
Priority_Control core_low_prio;
POSIX_API_Control *api;
const POSIX_API_Control *executing_api;
#endif
if ( !start_routine )
@@ -260,9 +259,6 @@ int pthread_create(
* finish initializing the per API structure
*/
api = the_thread->API_Extensions[ THREAD_API_POSIX ];
executing_api = executing->API_Extensions[ THREAD_API_POSIX ];
api->signals_unblocked = executing_api->signals_unblocked;
_Priority_Node_set_priority( &api->Sporadic.Low_priority, core_low_prio );
api->Sporadic.sched_ss_repl_period =
@@ -376,7 +372,7 @@ void _POSIX_Threads_Sporadic_budget_callout( Thread_Control *the_thread )
}
static bool _POSIX_Threads_Create_extension(
Thread_Control *executing RTEMS_UNUSED,
Thread_Control *executing,
Thread_Control *created
)
{
@@ -389,6 +385,53 @@ static bool _POSIX_Threads_Create_extension(
_Watchdog_Initialize( &api->Sporadic.Timer, _POSIX_Threads_Sporadic_timer );
_Priority_Node_set_inactive( &api->Sporadic.Low_priority );
#if defined(RTEMS_POSIX_API)
/*
* There are some subtle rules which need to be followed for
* the value of the created thread's signal mask. Because signals
* are part of C99 and enhanced by POSIX, both Classic API tasks
* and POSIX threads have to have them enabled.
*
* + Internal system threads should have no signals enabled. They
* have no business executing user signal handlers -- especially IDLE.
* + The initial signal mask for other threads needs to follow the
* implication of a pure C99 environment which only has the methods
* raise() and signal(). This implies that all signals are unmasked
* until the thread explicitly uses a POSIX methods to block some.
* This applies to both Classic tasks and POSIX threads created
* as initalization tasks/threads (e.g. before the system is up).
* + After the initial threads are created, the signal mask should
* be inherited from the creator.
*
* NOTE: The default signal mask does not matter for any application
* that does not use POSIX signals.
*/
if ( _Objects_Get_API(created->Object.id) == OBJECTS_INTERNAL_API ) {
/*
* Ensure internal (especially IDLE) is handled first.
*
* Block signals for all internal threads -- especially IDLE.
*/
api->signals_unblocked = 0;
} else if ( _Objects_Get_API(executing->Object.id) == OBJECTS_INTERNAL_API ) {
/*
* Threads being created while an internal thread is executing
* should only happen for the initialization threads/tasks.
*
* Default state (signals unblocked) for all Initialization tasks
* and POSIX threads. We should not inherit from IDLE which is
* what appears to be executing during initialization.
*/
api->signals_unblocked = SIGNAL_ALL_MASK;
} else {
const POSIX_API_Control *executing_api;
/*
* RTEMS is running so follow the POSIX rules to inherit the signal mask.
*/
executing_api = executing->API_Extensions[ THREAD_API_POSIX ];
api->signals_unblocked = executing_api->signals_unblocked;
}
#endif
return true;
}
+22
View File
@@ -881,6 +881,28 @@ psxsignal06_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxsignal06) \
endif
endif
if HAS_POSIX
if TEST_psxsignal07
psx_tests += psxsignal07
psx_screens += psxsignal07/psxsignal07.scn
psx_docs += psxsignal07/psxsignal07.doc
psxsignal07_SOURCES = psxsignal07/main.c psxsignal07/rtems_config.c
psxsignal07_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxsignal07) \
$(support_includes) -I$(top_srcdir)/include
endif
endif
if HAS_POSIX
if TEST_psxsignal08
psx_tests += psxsignal08
psx_screens += psxsignal08/psxsignal08.scn
psx_docs += psxsignal08/psxsignal08.doc
psxsignal08_SOURCES = psxsignal08/main.c psxsignal08/rtems_config.c
psxsignal08_CPPFLAGS = $(AM_CPPFLAGS) $(TEST_FLAGS_psxsignal08) \
$(support_includes) -I$(top_srcdir)/include
endif
endif
if TEST_psxspin01
psx_tests += psxspin01
psx_screens += psxspin01/psxspin01.scn
+2
View File
@@ -135,6 +135,8 @@ RTEMS_TEST_CHECK([psxsignal03])
RTEMS_TEST_CHECK([psxsignal04])
RTEMS_TEST_CHECK([psxsignal05])
RTEMS_TEST_CHECK([psxsignal06])
RTEMS_TEST_CHECK([psxsignal07])
RTEMS_TEST_CHECK([psxsignal08])
RTEMS_TEST_CHECK([psxspin01])
RTEMS_TEST_CHECK([psxstack01])
RTEMS_TEST_CHECK([psxstack02])
+14
View File
@@ -36,6 +36,18 @@ extern void _POSIX_signals_Abnormal_termination_handler( int signo );
volatile int Signal_occurred;
volatile int Signal_count;
static void block_all_signals(void)
{
int sc;
sigset_t mask;
sc = sigfillset( &mask );
rtems_test_assert( !sc );
sc = pthread_sigmask( SIG_BLOCK, &mask, NULL );
rtems_test_assert( !sc );
}
void Handler_1(
int signo
)
@@ -108,6 +120,8 @@ void *POSIX_Init(
TEST_BEGIN();
block_all_signals();
/* set the time of day, and print our buffer in multiple ways */
set_time( TM_FRIDAY, TM_MAY, 24, 96, 11, 5, 0 );
+14
View File
@@ -28,6 +28,18 @@ void Install_Signal_Handler(const char *task_name);
volatile bool Signal_occurred;
volatile pthread_t Signal_thread;
static void block_all_signals(void)
{
int sc;
sigset_t mask;
sc = sigfillset( &mask );
rtems_test_assert( !sc );
sc = pthread_sigmask( SIG_BLOCK, &mask, NULL );
rtems_test_assert( !sc );
}
void Signal_handler(
int signo
)
@@ -140,6 +152,8 @@ void *POSIX_Init(
Signal_occurred = false;
block_all_signals();
act.sa_handler = Signal_handler;
act.sa_flags = 0;
sigaction( SIGUSR1, &act, NULL );
+14
View File
@@ -64,6 +64,18 @@ const char *signal_name(int signo);
volatile bool Signal_occurred;
volatile pthread_t Signal_thread;
static void block_all_signals(void)
{
int sc;
sigset_t mask;
sc = sigfillset( &mask );
rtems_test_assert( !sc );
sc = pthread_sigmask( SIG_BLOCK, &mask, NULL );
rtems_test_assert( !sc );
}
void Signal_handler(
int signo,
siginfo_t *info,
@@ -166,6 +178,8 @@ void *POSIX_Init(
TEST_BEGIN();
puts( "Init - Variation is: " TEST_STRING );
block_all_signals();
Signal_occurred = false;
act.sa_handler = NULL;
+136
View File
@@ -0,0 +1,136 @@
/*
* @brief psxsignal07 - Ensure initial signal mask and thread inheritance
*/
/*
* COPYRIGHT (c) 2019.
* On-Line Applications Research Corporation (OAR).
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <tmacros.h>
#include "test_support.h"
#include <errno.h>
#include <pthread.h>
#include <signal.h>
const char rtems_test_name[] = "PSXSIGNAL 7";
static sigset_t main_sigmask;
#define SIGSET_NBYTES (sizeof(sigset_t))
/* #define DEBUG_TEST */
static void fetch_sigmask(const char *name, sigset_t *sigset_p)
{
int rc;
rc = sigemptyset(sigset_p);
rtems_test_assert(rc == 0);
rc = sigprocmask(SIG_SETMASK, NULL, sigset_p);
rtems_test_assert(rc == 0);
#ifdef DEBUG_TEST
/*
* There is no assurance that sigset_t is a primitive type so
* we have to print it a long at a time.
*/
int i;
unsigned char *p = (unsigned char *) sigset_p;
printf("%s signal mask (in hex):\n ", name);
for (i=0 ; i < SIGSET_NBYTES ; i++) {
printf("%02x%s", *p++, (i % 16 == 15) ? "\n " : " ");
}
printf("\n");
#endif
}
static void block_sigmask(int signo, sigset_t *sigset_p)
{
sigset_t sigset;
int rc;
/*
* Block the requested signal
*/
rc = sigemptyset(&sigset);
rtems_test_assert(rc == 0);
rc = sigaddset(&sigset, signo);
rtems_test_assert(rc == 0);
rc = sigprocmask(SIG_BLOCK, &sigset, NULL);
rtems_test_assert(rc == 0);
/*
* Fetch the current signal mask reflecting the requested update
*/
sigemptyset(sigset_p);
rc = sigprocmask(SIG_SETMASK, NULL, sigset_p);
rtems_test_assert(rc == 0);
}
static void *thread_body(void *arg)
{
sigset_t mask;
/*
* There is no assurance that sigset_t is a primitive type so
* we have to use memcmp().
*/
fetch_sigmask("main", &main_sigmask);
fetch_sigmask(arg, &mask);
rtems_test_assert(main_sigmask == mask);
return NULL;
}
int main(int argc, char **argv)
{
int rc;
pthread_t id;
sigset_t empty;
TEST_BEGIN();
/*
* Verify first thread has empty signal mask
*/
fetch_sigmask("main", &main_sigmask);
sigemptyset(&empty);
fetch_sigmask("empty", &empty);
puts("Ensure main thread's mask equals sigemptyset");
rtems_test_assert(main_sigmask == empty);
/*
* Verify first thread has empty signal mask
*/
puts("Ensure parent's empty mask is inherited by thread");
rc = pthread_create(&id, NULL, thread_body, "thread1");
rtems_test_assert(rc == 0);
sleep(1);
/*
* Create a thread and see if it inherits non-empty signal mask.
*/
puts("Ensure parent's mask with SIGUSR1 mask is inherited by thread");
block_sigmask(SIGUSR1, &main_sigmask);
rc = pthread_create(&id, NULL, thread_body, "thread2");
rtems_test_assert(rc == 0);
sleep(1);
TEST_END();
rtems_test_exit(0);
return 0;
}
@@ -0,0 +1,23 @@
# COPYRIGHT (c) 2019.
# On-Line Applications Research Corporation (OAR).
#
# SPDX-License-Identifier: BSD-2-Clause
#
This file describes the directives and concepts tested by this test set.
test set name: psxsignal07
directives:
sigprocmask
sigemptyset
sigaddset
concepts:
+ Ensure that the initial signal mask is empty (all unmasked).
+ Ensure that a POSIX thread inherits an empty signal mask.
+ Ensure that a POSIX thread inherits an non-empty signal mask.
@@ -0,0 +1,7 @@
*** BEGIN OF TEST PSXSIGNAL 7 ***
Ensure main thread's mask equals sigemptyset
Ensure parent's empty mask is inherited by thread
Ensure parent's mask with SIGUSR1 mask is inherited by thread
*** END OF TEST PSXSIGNAL 7 ***
@@ -0,0 +1,44 @@
/*
* COPYRIGHT (c) 2019.
* On-Line Applications Research Corporation (OAR).
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <stdlib.h>
int main(int argc, char **argv);
static char *argv_list[] = {
"psxsignal07",
""
};
static void *POSIX_Init(void *arg)
{
(void) arg; /* deliberately ignored */
/*
* Initialize optional services
*/
/*
* Could get arguments from command line or have a static set.
*/
(void) main(1, argv_list);
return NULL;
}
#include <bsp.h> /* for device driver prototypes */
/* NOTICE: the clock driver is explicitly disabled */
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_POSIX_INIT_THREAD_TABLE
#define CONFIGURE_UNLIMITED_OBJECTS
#define CONFIGURE_UNIFIED_WORK_AREAS
#define CONFIGURE_INIT
#include <rtems/confdefs.h>
+163
View File
@@ -0,0 +1,163 @@
/*
* @brief psxsignal08 - Ensure initial signal mask and Classic Task inheritance
*/
/*
* COPYRIGHT (c) 2019.
* On-Line Applications Research Corporation (OAR).
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <tmacros.h>
#include "test_support.h"
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <rtems.h>
const char rtems_test_name[] = "PSXSIGNAL 8";
static sigset_t main_sigmask;
#define SIGSET_NBYTES (sizeof(sigset_t))
/* #define DEBUG_TEST */
static void fetch_sigmask(const char *name, sigset_t *sigset_p)
{
int rc;
rc = sigemptyset(sigset_p);
rtems_test_assert(rc == 0);
rc = sigprocmask(SIG_SETMASK, NULL, sigset_p);
rtems_test_assert(rc == 0);
#ifdef DEBUG_TEST
/*
* There is no assurance that sigset_t is a primitive type so
* we have to print it a long at a time.
*/
int i;
unsigned char *p = (unsigned char *) sigset_p;
printf("%s signal mask (in hex):\n ", name);
for (i=0 ; i < SIGSET_NBYTES ; i++) {
printf("%02x%s", *p++, (i % 16 == 15) ? "\n " : " ");
}
printf("\n");
#endif
}
static void block_sigmask(int signo, sigset_t *sigset_p)
{
sigset_t sigset;
int rc;
/*
* Block the requested signal
*/
rc = sigemptyset(&sigset);
rtems_test_assert(rc == 0);
rc = sigaddset(&sigset, signo);
rtems_test_assert(rc == 0);
rc = sigprocmask(SIG_BLOCK, &sigset, NULL);
rtems_test_assert(rc == 0);
/*
* Fetch the current signal mask reflecting the requested update
*/
sigemptyset(sigset_p);
rc = sigprocmask(SIG_SETMASK, NULL, sigset_p);
rtems_test_assert(rc == 0);
}
static rtems_task task_body(rtems_task_argument arg)
{
sigset_t mask;
/*
* There is no assurance that sigset_t is a primitive type so
* we have to use memcmp().
*/
fetch_sigmask("main", &main_sigmask);
fetch_sigmask((void *)arg, &mask);
rtems_test_assert(main_sigmask == mask);
(void) rtems_task_delete(RTEMS_SELF);
}
int main(int argc, char **argv)
{
sigset_t empty;
rtems_status_code status;
rtems_id id;
TEST_BEGIN();
/*
* Verify first task has empty signal mask
*/
fetch_sigmask("main", &main_sigmask);
sigemptyset(&empty);
fetch_sigmask("empty", &empty);
puts("Ensure main task's mask equals sigemptyset");
rtems_test_assert(main_sigmask == empty);
/*
* Create a task and see if it inherits empty signal mask.
*/
puts("Ensure parent's empty mask is inherited by thread");
status = rtems_task_create(
rtems_build_name( 'T', 'A', '1', ' ' ),
1,
RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&id
);
directive_failed( status, "rtems_task_create" );
status = rtems_task_start( id, task_body, 1 );
directive_failed( status, "rtems_task_start" );
sleep(1);
/*
* Create a task and see if it inherits non-empty signal mask.
*/
puts("Ensure parent's mask with SIGUSR1 mask is inherited by thread");
block_sigmask(SIGUSR1, &main_sigmask);
status = rtems_task_create(
rtems_build_name( 'T', 'A', '1', ' ' ),
1,
RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&id
);
directive_failed( status, "rtems_task_create" );
status = rtems_task_start( id, task_body, 1 );
directive_failed( status, "rtems_task_start" );
sleep(1);
TEST_END();
rtems_test_exit(0);
return 0;
}
@@ -0,0 +1,22 @@
# COPYRIGHT (c) 2019.
# On-Line Applications Research Corporation (OAR).
#
# SPDX-License-Identifier: BSD-2-Clause
This file describes the directives and concepts tested by this test set.
test set name: psxsignal07
directives:
sigprocmask
sigemptyset
sigaddset
concepts:
+ Ensure that the initial signal mask is empty (all unmasked).
+ Ensure that a Classic API task inherits an empty signal mask.
+ Ensure that a Classic API task inherits an non-empty signal mask.
@@ -0,0 +1,7 @@
** BEGIN OF TEST PSXSIGNAL 8 ***
Ensure main task's mask equals sigemptyset
Ensure parent's empty mask is inherited by thread
Ensure parent's mask with SIGUSR1 mask is inherited by thread
*** END OF TEST PSXSIGNAL 8 ***
@@ -0,0 +1,45 @@
/*
* COPYRIGHT (c) 2019.
* On-Line Applications Research Corporation (OAR).
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <rtems.h>
#include <stdlib.h>
int main(int argc, char **argv);
static char *argv_list[] = {
"report",
""
};
static rtems_task Init(rtems_task_argument arg)
{
(void) arg; /* deliberately ignored */
/*
* Initialize optional services
*/
/*
* Could get arguments from command line or have a static set.
*/
(void) main(1, argv_list);
exit(0);
}
#include <bsp.h> /* for device driver prototypes */
/* NOTICE: the clock driver is explicitly disabled */
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_UNLIMITED_OBJECTS
#define CONFIGURE_UNIFIED_WORK_AREAS
#define CONFIGURE_INIT
#include <rtems/confdefs.h>