From 927a0a1f990c19a3e7295bb001896b3f3c75a77e Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Mon, 2 Dec 2013 08:33:35 +0100 Subject: posix: Use cleanup contexts on the stack Provide support for latest Newlib change. The cleanup contexts are stored on the thread stack. This is conformant with the POSIX requirements for the pthread_cleanup_push() and pthread_cleanup_pop() statement pair. Passing an invalid pointer as the routine to pthread_cleanup_push() is now a usage error and the behaviour is undefined. --- cpukit/configure.ac | 1 + cpukit/posix/include/rtems/posix/cancel.h | 2 ++ cpukit/posix/include/rtems/posix/threadsup.h | 7 +++++ cpukit/posix/src/cancelrun.c | 40 ++++++++++++++++++++++++---- cpukit/posix/src/cleanuppop.c | 33 ++++++++++++++++++++--- cpukit/posix/src/cleanuppush.c | 37 ++++++++++++++++++++++--- cpukit/posix/src/pthread.c | 4 +++ testsuites/psxtests/psxcleanup/psxcleanup.c | 7 ----- 8 files changed, 111 insertions(+), 20 deletions(-) diff --git a/cpukit/configure.ac b/cpukit/configure.ac index e111fdd0fc..38d2dd9eba 100644 --- a/cpukit/configure.ac +++ b/cpukit/configure.ac @@ -140,6 +140,7 @@ AC_CHECK_HEADER([pthread.h],[ AC_CHECK_TYPES([pthread_rwlock_t]) AC_CHECK_TYPES([pthread_barrier_t]) AC_CHECK_TYPES([pthread_spinlock_t]) + AC_CHECK_TYPES([struct _pthread_cleanup_context],[],[],[#include ]) ]) AC_CHECK_HEADER([signal.h],[ diff --git a/cpukit/posix/include/rtems/posix/cancel.h b/cpukit/posix/include/rtems/posix/cancel.h index c1fff9c04d..7b2ab5ca42 100644 --- a/cpukit/posix/include/rtems/posix/cancel.h +++ b/cpukit/posix/include/rtems/posix/cancel.h @@ -21,6 +21,7 @@ #include +#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT /** * This structure is used to manage the cancelation handlers. */ @@ -32,6 +33,7 @@ typedef struct { /** This field is the argument to the cancelation routine. */ void *arg; } POSIX_Cancel_Handler_control; +#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ /** * @brief POSIX run thread cancelation. diff --git a/cpukit/posix/include/rtems/posix/threadsup.h b/cpukit/posix/include/rtems/posix/threadsup.h index 7bd1f934ad..6bb3b844cc 100644 --- a/cpukit/posix/include/rtems/posix/threadsup.h +++ b/cpukit/posix/include/rtems/posix/threadsup.h @@ -80,8 +80,15 @@ typedef struct { int cancelability_type; /** This indicates if a cancelation has been requested. */ int cancelation_requested; +#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT /** This is the set of cancelation handlers. */ Chain_Control Cancellation_Handlers; +#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ + /** + * @brief LIFO list of cleanup contexts. + */ + struct _pthread_cleanup_context *last_cleanup_context; +#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ /** * This is the thread key value chain's control, which is used diff --git a/cpukit/posix/src/cancelrun.c b/cpukit/posix/src/cancelrun.c index 9d158627de..4fe4d732ae 100644 --- a/cpukit/posix/src/cancelrun.c +++ b/cpukit/posix/src/cancelrun.c @@ -19,16 +19,18 @@ #endif #include -#include -#include +#include +#include +#include +#include + +#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT + #include #include -#include #include -#include #include -#include void _POSIX_Threads_cancel_run( Thread_Control *the_thread @@ -57,3 +59,31 @@ void _POSIX_Threads_cancel_run( _Workspace_Free( handler ); } } + +#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ + +void _POSIX_Threads_cancel_run( + Thread_Control *the_thread +) +{ + struct _pthread_cleanup_context *context; + POSIX_API_Control *thread_support; + + _Thread_Disable_dispatch(); + + thread_support = the_thread->API_Extensions[ THREAD_API_POSIX ]; + thread_support->cancelability_state = PTHREAD_CANCEL_DISABLE; + + context = thread_support->last_cleanup_context; + thread_support->last_cleanup_context = NULL; + + _Thread_Enable_dispatch(); + + while ( context != NULL ) { + ( *context->_routine )( context->_arg ); + + context = context->_previous; + } +} + +#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ diff --git a/cpukit/posix/src/cleanuppop.c b/cpukit/posix/src/cleanuppop.c index 4ec7084fdd..7afe9e6cd0 100644 --- a/cpukit/posix/src/cleanuppop.c +++ b/cpukit/posix/src/cleanuppop.c @@ -19,16 +19,18 @@ #endif #include -#include -#include +#include +#include +#include + +#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT + #include #include -#include #include #include #include -#include /* * 18.2.3.1 Establishing Cancellation Handlers, P1003.1c/Draft 10, p. 184 @@ -79,3 +81,26 @@ void pthread_cleanup_pop( if ( execute ) (*tmp_handler.routine)( tmp_handler.arg ); } + +#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ + +void _pthread_cleanup_pop( + struct _pthread_cleanup_context *context, + int execute +) +{ + POSIX_API_Control *thread_support; + + if ( execute != 0 ) { + ( *context->_routine )( context->_arg ); + } + + _Thread_Disable_dispatch(); + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + thread_support->last_cleanup_context = context->_previous; + + _Thread_Enable_dispatch(); +} + +#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ diff --git a/cpukit/posix/src/cleanuppush.c b/cpukit/posix/src/cleanuppush.c index 84dbc0043d..9d11c0553f 100644 --- a/cpukit/posix/src/cleanuppush.c +++ b/cpukit/posix/src/cleanuppush.c @@ -19,16 +19,18 @@ #endif #include -#include -#include +#include +#include +#include + +#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT + #include #include -#include #include #include #include -#include /* * 18.2.3.1 Establishing Cancellation Handlers, P1003.1c/Draft 10, p. 184 @@ -66,3 +68,30 @@ void pthread_cleanup_push( } _Thread_Enable_dispatch(); } + +#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ + +void _pthread_cleanup_push( + struct _pthread_cleanup_context *context, + void ( *routine )( void * ), + void *arg +) +{ + POSIX_API_Control *thread_support; + + context->_routine = routine; + context->_arg = arg; + + /* This value is unused, just provide a deterministic value */ + context->_canceltype = -1; + + _Thread_Disable_dispatch(); + + thread_support = _Thread_Executing->API_Extensions[ THREAD_API_POSIX ]; + context->_previous = thread_support->last_cleanup_context; + thread_support->last_cleanup_context = context; + + _Thread_Enable_dispatch(); +} + +#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ diff --git a/cpukit/posix/src/pthread.c b/cpukit/posix/src/pthread.c index 408bb07dc4..4d8f95f150 100644 --- a/cpukit/posix/src/pthread.c +++ b/cpukit/posix/src/pthread.c @@ -200,7 +200,11 @@ static bool _POSIX_Threads_Create_extension( api->cancelation_requested = 0; api->cancelability_state = PTHREAD_CANCEL_ENABLE; api->cancelability_type = PTHREAD_CANCEL_DEFERRED; +#ifndef HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT _Chain_Initialize_empty (&api->Cancellation_Handlers); +#else /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ + api->last_cleanup_context = NULL; +#endif /* HAVE_STRUCT__PTHREAD_CLEANUP_CONTEXT */ /* * If the thread is not a posix thread, then all posix signals are blocked diff --git a/testsuites/psxtests/psxcleanup/psxcleanup.c b/testsuites/psxtests/psxcleanup/psxcleanup.c index 568e897a76..123e76692c 100644 --- a/testsuites/psxtests/psxcleanup/psxcleanup.c +++ b/testsuites/psxtests/psxcleanup/psxcleanup.c @@ -250,13 +250,6 @@ void *POSIX_Init( sleep(1); - /*************** ERROR CASES ***************/ - puts("Call pthread_cleanup_push with NULL handler"); - pthread_cleanup_push(NULL, NULL); - - puts("Call pthread_cleanup_pop with no push"); - pthread_cleanup_pop(1); - /*************** END OF TEST *****************/ puts( "*** END OF POSIX CLEANUP TEST ***\n" ); rtems_test_exit(0); -- cgit v1.2.3