Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement pthread_cancel -- DO NOT MERGE, ARCHIVE ONLY. #3

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#define configTICK_RATE_HZ ( 1000 ) /* In this non-real time simulated environment the tick frequency has to be at least a multiple of the Win32 tick frequency, and therefore very slow. */
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 60 ) /* In this simulated case, the stack only has to hold one small structure as the real stack is part of the Win32 thread. */
#define configMAX_TASK_NAME_LEN ( 7 )
#define configUSE_TRACE_FACILITY 0
#define configUSE_TRACE_FACILITY 1
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
#define configUSE_CO_ROUTINES 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -409,11 +409,19 @@ int pthread_join( pthread_t pthread,
int iStatus = 0;
pthread_internal_t * pxThread = ( pthread_internal_t * ) pthread;

if (pxThread == NULL)
{
iStatus = ESRCH;
yuhui-zheng marked this conversation as resolved.
Show resolved Hide resolved
}

/* Make sure pthread is joinable. Otherwise, this function would block
* forever waiting for an unjoinable thread. */
if( !pthreadIS_JOINABLE( pxThread->xAttr.usSchedPriorityDetachState ) )
if (iStatus == 0)
{
iStatus = EDEADLK;
if( !pthreadIS_JOINABLE(pxThread->xAttr.usSchedPriorityDetachState) )
{
iStatus = EDEADLK;
}
}

/* Only one thread may attempt to join another. Lock the join mutex
Expand Down Expand Up @@ -473,6 +481,43 @@ int pthread_join( pthread_t pthread,
return iStatus;
}

/*-----------------------------------------------------------*/
int pthread_cancel( pthread_t pthread )
{
int iStatus = 0;
pthread_internal_t * pxThread = (pthread_internal_t *) pthread;

if (pxThread == NULL || pxThread->xTaskHandle == NULL)
yuhui-zheng marked this conversation as resolved.
Show resolved Hide resolved
{
iStatus = ESRCH;
}

/* Threads may already be successfully ended elsewhere and pending full deletion in idle task. */
/* Note the the xJoinBarrier is a binary sem, so no new queue items are made once its already given */
if (iStatus == 0 && eDeleted != eTaskGetState(pxThread->xTaskHandle))
{
if (pxThread == pthread_self())
{
prvExitThread();
}
else
{
if (pthreadIS_JOINABLE(pxThread->xAttr.usSchedPriorityDetachState))
{
xSemaphoreGive((SemaphoreHandle_t)&pxThread->xJoinBarrier);
vTaskSuspend(pxThread->xTaskHandle);
}
else
{
vTaskDelete(pxThread->xTaskHandle);
vPortFree(pxThread);
}
}
}

return iStatus;
}

/*-----------------------------------------------------------*/

pthread_t pthread_self( void )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,16 @@ int pthread_barrier_init( pthread_barrier_t * barrier,
*/
int pthread_barrier_wait( pthread_barrier_t * barrier );

/**
* @brief Request cancellation of thread.
*
* @see https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cancel.html
*
* @retval 0 - Upon successful completion.
* @retval ESRCH - Upon attempt to cancel null thread.
*/
int pthread_cancel( pthread_t thread );

/**
* @brief Thread creation.
*
Expand Down Expand Up @@ -354,6 +364,7 @@ int pthread_getschedparam( pthread_t thread,
* to a joinable thread OR multiple simultaneous calls to pthread_join()
* specifying the same target thread OR the value specified by the thread argument
* to pthread_join() refers to the calling thread.
* @retval ESRCH - Upon attempt to join null thread.
*/
int pthread_join( pthread_t thread,
void ** retval );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

/* FreeRTOS includes. */
#include "FreeRTOS_POSIX.h"
#include "FreeRTOS.h"

/* System headers. */
#include <stdbool.h>
Expand Down Expand Up @@ -370,5 +371,143 @@ void vStartPOSIXDemo( void *pvParameters )

/* This task was created with the native xTaskCreate() API function, so
must not run off the end of its implementing thread. */
printf("\n------ SUMMARY ------\n");
static char status[40 * 100] = { 0 };
vTaskList(status);
printf(status);
printf("\n");
vTaskDelete( NULL );
}


/*-----------------------------------------------------------*/
#define N_DUMMY_THREADS 10
#define N_DUMMY_LOOPS 100

static void * prvDummyThread(void* pvArgs)
{
int id = (int)pvArgs;

struct timespec ts = {
.tv_sec = 1,
.tv_nsec = 0
};

for (int i = 0; i < N_DUMMY_LOOPS; i++)
{
printf("Thread[%02d] loop[%02d]\n", id, i);
nanosleep(&ts, NULL);
}

while (1);

return 0;
}

static void * prvSelfDestructThread(void* pvArgs)
{
struct timespec ts = {
.tv_sec = 1,
.tv_nsec = 0
};

nanosleep(&ts, NULL);
configASSERT(0 == pthread_cancel(pthread_self()));

ts.tv_sec = 1;
while (1) {
nanosleep(&ts, NULL);
}
}

/*
* Create various joinable/detached threads and cancel/join them in various orders
*/
void vTestPthreadCancel(void* pvParameters)
yuhui-zheng marked this conversation as resolved.
Show resolved Hide resolved
{
pthread_attr_t pattr;
struct sched_param sched_config;
pthread_t threads[N_DUMMY_THREADS] = { 0 };
pthread_attr_init(&pattr);

/* Want these tasks of equal priority so they can preempt eachother. The spawner task (THIS) will
exhaustively cancel all the threads with pthread_cancel */
sched_config.sched_priority = uxTaskPriorityGet(NULL);
pthread_attr_setschedparam(&pattr, &sched_config);
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);


printf("Creating %d threads looping %d times\n", N_DUMMY_THREADS, N_DUMMY_LOOPS);
/* The first half is default (joinable) the second half is detached*/
for (int i = 0; i < N_DUMMY_THREADS; i++)
{
if (i == (N_DUMMY_THREADS / 2))
{
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
}

pthread_create(&threads[i], &pattr, prvDummyThread, (void *)i);
}

struct timespec ts = {
.tv_sec = 1,
.tv_nsec = 0
};

/*Let the test threads run for a bit, then exercise typical cancellation*/
for (int i=0; i < N_DUMMY_THREADS; i++)
{
nanosleep(&ts, NULL);

if (i < (N_DUMMY_THREADS / 2))
{
/* A cancelled joinable thread won't have relinquished its resources, but instead will suspend to joining */
configASSERT(0 == pthread_cancel(threads[i]));
configASSERT(0 == pthread_join(threads[i], NULL));
}
else
{
/* A detached thread will fully relinquish resources its responsible for */
configASSERT(0 == pthread_cancel(threads[i]));
}
}

/* Excercise cancelling a NULL thread */
configASSERT(ESRCH == pthread_cancel(NULL));

/* Exercise a thread cancelling itself using pthread_cancel */
pthread_t self_desctructor = NULL;
/* detached thread */
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
pthread_create(&self_desctructor, &pattr, prvSelfDestructThread, NULL);
/* joinable thread */
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
pthread_create(&self_desctructor, &pattr, prvSelfDestructThread, NULL);
configASSERT(0 == pthread_join(self_desctructor, NULL));

/* Excercise double cancellation of: */
pthread_t doubly_cancelled = NULL;
/* detached thread */
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_DETACHED);
pthread_create(&doubly_cancelled, &pattr, prvDummyThread, NULL);
pthread_cancel(doubly_cancelled);
pthread_cancel(doubly_cancelled);

/* joinable thread */
pthread_attr_setdetachstate(&pattr, PTHREAD_CREATE_JOINABLE);
pthread_create(&doubly_cancelled, &pattr, prvDummyThread, NULL);
pthread_cancel(doubly_cancelled);
pthread_cancel(doubly_cancelled);
configASSERT(0 == pthread_join(doubly_cancelled, NULL));

/* All threads should be cancelled by now, leaving only this, main, idle, and timer tasks*/
printf("\n------ SUMMARY ------\n");
nanosleep(&ts, NULL);
static char status[40 * (N_DUMMY_THREADS + 5 + 3)] = { 0 };
vTaskList(status);
printf(status);
printf("\n");
vTaskDelete(NULL);
}


Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@
#ifndef _POSIX_DEMO_H_
#define _POSIX_DEMO_H_
void vStartPOSIXDemo( void * pvParameters );
void vTestPthreadCancel(void* pvParameters);

#endif /* _POSIX_DEMO_H_ */