1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-12-01 09:24:10 +01:00

PiOS.posix - thread management - another variant to test on win32

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1043 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
corvus 2010-07-07 17:45:12 +00:00 committed by corvus
parent 5f174108b1
commit 5c7324a28b
2 changed files with 462 additions and 134 deletions

View File

@ -207,6 +207,7 @@ int real_pthread_mutex_unlock(pthread_mutex_t* mutex) {
} }
#define pthread_mutex_lock(...) ( (debug_printf(" -!- pthread_mutex_lock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_lock(__VA_ARGS__):0 ) #define pthread_mutex_lock(...) ( (debug_printf(" -!- pthread_mutex_lock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_lock(__VA_ARGS__):0 )
#define pthread_mutex_unlock(...) ( (debug_printf(" -=- pthread_mutex_unlock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_unlock(__VA_ARGS__):0 ) #define pthread_mutex_unlock(...) ( (debug_printf(" -=- pthread_mutex_unlock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_unlock(__VA_ARGS__):0 )
#define pthread_mutex_trylock(...) ( pthread_mutex_trylock(__VA_ARGS__)==0?((debug_printf(" -:)- pthread_mutex_trylock(%s) success\n",#__VA_ARGS__)|1)?0:0):-1)
#define pthread_kill(thread,signal) ( (debug_printf(" sending signal %i to thread %li!\n",(int)signal,(long)thread)|1)?pthread_kill(thread,signal):0 ) #define pthread_kill(thread,signal) ( (debug_printf(" sending signal %i to thread %li!\n",(int)signal,(long)thread)|1)?pthread_kill(thread,signal):0 )
#define vTaskSwitchContext() ( (debug_printf("SWITCHCONTEXT!\n")|1)?vTaskSwitchContext():vTaskSwitchContext() ) #define vTaskSwitchContext() ( (debug_printf("SWITCHCONTEXT!\n")|1)?vTaskSwitchContext():vTaskSwitchContext() )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -494,15 +495,20 @@ pthread_t xTaskToResume;
/** /**
* Sentinel - do not change context while the running task is not equal the task supposed to run * Sentinel - do not change context while the running task is not equal the task supposed to run
*/ */
if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) ) // if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) )
{ while ( 0 != pthread_mutex_trylock ( &xSuspendResumeThreadMutex ) ) {
sched_yield();
}
/** /**
* Make sure we don't create outdated resume signals * Make sure we don't create outdated resume signals
*/ */
while (hActiveThread!=hRequestedThread) { while (hActiveThread!=hRequestedThread) {
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex ); (void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
sched_yield(); sched_yield();
(void)pthread_mutex_lock( &xSuspendResumeThreadMutex ); while (0 != pthread_mutex_trylock( &xSuspendResumeThreadMutex )) {
sched_yield();
}
} }
xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() ); xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
@ -531,7 +537,6 @@ if (prvGetThreadHandle(xTaskGetCurrentTaskHandle())!=xTaskToResume) {
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex ); (void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
} }
} }
}
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vPortDisableInterrupts( void ) void vPortDisableInterrupts( void )
@ -644,8 +649,8 @@ struct timespec timeout;
prvSuspendThread( xTaskToSuspend ); prvSuspendThread( xTaskToSuspend );
//timeout.tv_sec=0; //timeout.tv_sec=0;
//timeout.tv_nsec=10000; //timeout.tv_nsec=10000;
sched_yield(); //sched_yield();
while ( 0 != pthread_mutex_trylock( &xRunningThreadMutex) ) { while ( 0 != pthread_mutex_lock( &xRunningThreadMutex) ) {
prvSuspendThread( xTaskToSuspend ); prvSuspendThread( xTaskToSuspend );
timeout.tv_sec=0; timeout.tv_sec=0;
timeout.tv_nsec=1; timeout.tv_nsec=1;

View File

@ -94,11 +94,17 @@ static xThreadState *pxThreads;
static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT; static pthread_once_t hSigSetupThread = PTHREAD_ONCE_INIT;
static pthread_attr_t xThreadAttributes; static pthread_attr_t xThreadAttributes;
static pthread_mutex_t xSuspendResumeThreadMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t xSuspendResumeThreadMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t xSingleThreadMutex = PTHREAD_MUTEX_INITIALIZER; //static pthread_mutex_t xSingleThreadMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t xRunningThreadMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t xPrintfMutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_t hMainThread = ( pthread_t )NULL; static pthread_t hMainThread = ( pthread_t )NULL;
static pthread_t hActiveThread = ( pthread_t )NULL;
static pthread_t hRequestedThread = ( pthread_t )NULL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static volatile portBASE_TYPE xSentinel = 0; static volatile portBASE_TYPE xSentinel = 0;
static volatile portBASE_TYPE xGeneralFuckedUpIndicator = 0;
static volatile portBASE_TYPE xVeryFirstTask = 1;
static volatile portBASE_TYPE xSchedulerEnd = pdFALSE; static volatile portBASE_TYPE xSchedulerEnd = pdFALSE;
static volatile portBASE_TYPE xInterruptsEnabled = pdTRUE; static volatile portBASE_TYPE xInterruptsEnabled = pdTRUE;
static volatile portBASE_TYPE xServicingTick = pdFALSE; static volatile portBASE_TYPE xServicingTick = pdFALSE;
@ -113,7 +119,7 @@ static volatile unsigned portBASE_TYPE uxCriticalNesting;
static void prvSetupTimerInterrupt( void ); static void prvSetupTimerInterrupt( void );
static void *prvWaitForStart( void * pvParams ); static void *prvWaitForStart( void * pvParams );
static void prvSuspendSignalHandler(int sig); static void prvSuspendSignalHandler(int sig);
static void prvResumeSignalHandler(int sig); //static void prvResumeSignalHandler(int sig);
static void prvSetupSignalsAndSchedulerPolicy( void ); static void prvSetupSignalsAndSchedulerPolicy( void );
static void prvSuspendThread( pthread_t xThreadId ); static void prvSuspendThread( pthread_t xThreadId );
static void prvResumeThread( pthread_t xThreadId ); static void prvResumeThread( pthread_t xThreadId );
@ -122,7 +128,123 @@ static portLONG prvGetFreeThreadState( void );
static void prvSetTaskCriticalNesting( pthread_t xThreadId, unsigned portBASE_TYPE uxNesting ); static void prvSetTaskCriticalNesting( pthread_t xThreadId, unsigned portBASE_TYPE uxNesting );
static unsigned portBASE_TYPE prvGetTaskCriticalNesting( pthread_t xThreadId ); static unsigned portBASE_TYPE prvGetTaskCriticalNesting( pthread_t xThreadId );
static void prvDeleteThread( void *xThreadId ); static void prvDeleteThread( void *xThreadId );
static void prvResolveFuckup( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
typedef struct tskTaskControlBlock
{
volatile portSTACK_TYPE *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE STRUCT. */
#if ( portUSING_MPU_WRAPPERS == 1 )
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE STRUCT. */
#endif
xListItem xGenericListItem; /*< List item used to place the TCB in ready and blocked queues. */
xListItem xEventListItem; /*< List item used to place the TCB in event lists. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the task where 0 is the lowest priority. */
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
signed char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */
#if ( portSTACK_GROWTH > 0 )
portSTACK_TYPE *pxEndOfStack; /*< Used for stack overflow checking on architectures where the stack grows up from low memory. */
#endif
#if ( portCRITICAL_NESTING_IN_TCB == 1 )
unsigned portBASE_TYPE uxCriticalNesting;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
unsigned portBASE_TYPE uxTCBNumber; /*< This is used for tracing the scheduler and making debugging easier only. */
#endif
#if ( configUSE_MUTEXES == 1 )
unsigned portBASE_TYPE uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
#endif
#if ( configUSE_APPLICATION_TASK_TAG == 1 )
pdTASK_HOOK_CODE pxTaskTag;
#endif
#if ( configGENERATE_RUN_TIME_STATS == 1 )
unsigned long ulRunTimeCounter; /*< Used for calculating how much CPU time each task is utilising. */
#endif
} tskTCB;
tskTCB* debug_task_handle;
tskTCB* prvGetTaskHandle( pthread_t hThread )
{
portLONG lIndex;
if (pxThreads==NULL) return NULL;
for ( lIndex = 0; lIndex < MAX_NUMBER_OF_TASKS; lIndex++ )
{
if ( pxThreads[ lIndex ].hThread == hThread )
{
return pxThreads[ lIndex ].hTask;
}
}
return NULL;
}
#define debug_printf(...) ( (real_pthread_mutex_lock( &xPrintfMutex )|1)?( \
( \
(NULL != (debug_task_handle = prvGetTaskHandle(pthread_self())) )? \
(fprintf( stderr, "%s(%li)\t%s\t%i:",debug_task_handle->pcTaskName,(long)pthread_self(),__func__,__LINE__)): \
(fprintf( stderr, "__unknown__(%li)\t%s\t%i:",(long)pthread_self(),__func__,__LINE__)) \
|1)?( \
((fprintf( stderr, __VA_ARGS__ )|1)?real_pthread_mutex_unlock( &xPrintfMutex ):0) \
):0 ):0 )
//int xbla;
//#define debug_printf(...) xbla=0
int real_pthread_mutex_lock(pthread_mutex_t* mutex) {
return pthread_mutex_lock(mutex);
}
int real_pthread_mutex_unlock(pthread_mutex_t* mutex) {
return pthread_mutex_unlock(mutex);
}
#define pthread_mutex_lock(...) ( (debug_printf(" -!- pthread_mutex_lock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_lock(__VA_ARGS__):0 )
#define pthread_mutex_unlock(...) ( (debug_printf(" -=- pthread_mutex_unlock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_unlock(__VA_ARGS__):0 )
#define pthread_mutex_trylock(...) ( pthread_mutex_trylock(__VA_ARGS__)==0?((debug_printf(" -:)- pthread_mutex_trylock(%s) success\n",#__VA_ARGS__)|1)?0:0):-1)
#define pthread_kill(thread,signal) ( (debug_printf(" sending signal %i to thread %li!\n",(int)signal,(long)thread)|1)?pthread_kill(thread,signal):0 )
#define vTaskSwitchContext() ( (debug_printf("SWITCHCONTEXT!\n")|1)?vTaskSwitchContext():vTaskSwitchContext() )
/*-----------------------------------------------------------*/
void prvSuspendThread( pthread_t xThreadId )
{
portBASE_TYPE xResult;
// xResult = pthread_mutex_lock( &xSuspendResumeThreadMutex );
// if ( 0 == xResult )
// {
/* Set-up for the Suspend Signal handler? */
//xSentinel = 0;
//portBASE_TYPE aSentinel=xSentinel;
xResult = pthread_kill( xThreadId, SIG_SUSPEND );
// xResult = pthread_mutex_unlock( &xSuspendResumeThreadMutex );
// while ( ( aSentinel == xSentinel ) && ( pdTRUE != xServicingTick ) )
// {
// sched_yield();
// }
// }
}
/*-----------------------------------------------------------*/
void prvResumeThread( pthread_t xThreadId )
{
portBASE_TYPE xResult;
// if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) )
// {
if ( pthread_self() != xThreadId )
{
xResult = pthread_kill( xThreadId, SIG_RESUME );
}
// xResult = pthread_mutex_unlock( &xSuspendResumeThreadMutex );
// }
}
#define prvSuspendThread(thread) debug_printf("calling SuspendThread(%li)\n",(long)thread); prvSuspendThread(thread)
#define prvResumeThread(thread) debug_printf("calling ResumeThread(%li)\n",(long)thread); prvResumeThread(thread)
/* /*
* Exception handlers. * Exception handlers.
@ -160,13 +282,32 @@ xParams *pxThisThreadParams = pvPortMalloc( sizeof( xParams ) );
pxThisThreadParams->pvParams = pvParameters; pxThisThreadParams->pvParams = pvParameters;
vPortEnterCritical(); vPortEnterCritical();
if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) ) {
while (hActiveThread!=hRequestedThread && !xVeryFirstTask) {
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
sched_yield();
(void)pthread_mutex_lock( &xSuspendResumeThreadMutex );
}
lIndexOfLastAddedTask = prvGetFreeThreadState(); lIndexOfLastAddedTask = prvGetFreeThreadState();
/* Create the new pThread. */ /* Create the new pThread. */
if ( 0 == pthread_mutex_lock( &xSingleThreadMutex ) ) /* On creation of the very first thread, RunningThreadMutex is not claimed yet
{ * by the master thread - do that! */
xSentinel = 0; if (xVeryFirstTask==1) {
debug_printf("Seting up very first task (main) - MAIN is ACTIVE TASK\n");
if (0 == pthread_mutex_lock( &xRunningThreadMutex)) {
xVeryFirstTask=0;
hActiveThread=pthread_self();
hRequestedThread=hActiveThread;
} else {
printf("Failed to acquire lock for first task");
exit(1);
}
}
if ( 0 != pthread_create( &( pxThreads[ lIndexOfLastAddedTask ].hThread ), &xThreadAttributes, prvWaitForStart, (void *)pxThisThreadParams ) ) if ( 0 != pthread_create( &( pxThreads[ lIndexOfLastAddedTask ].hThread ), &xThreadAttributes, prvWaitForStart, (void *)pxThisThreadParams ) )
{ {
/* Thread create failed, signal the failure */ /* Thread create failed, signal the failure */
@ -174,10 +315,20 @@ xParams *pxThisThreadParams = pvPortMalloc( sizeof( xParams ) );
} }
/* Wait until the task suspends. */ /* Wait until the task suspends. */
(void)pthread_mutex_unlock( &xSingleThreadMutex ); xSentinel=0;
while ( xSentinel == 0 ); (void)pthread_mutex_unlock( &xRunningThreadMutex );
vPortExitCritical(); while ( xSentinel == 0 ) {
sched_yield();
} }
(void)pthread_mutex_lock( &xRunningThreadMutex );
hActiveThread=pthread_self();
debug_printf("ACTIVE THREAD RECLAIMED!\n");
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
} else {
debug_printf("mutex locking failed\n");
exit(1);
}
vPortExitCritical();
return pxTopOfStack; return pxTopOfStack;
} }
@ -192,7 +343,10 @@ void vPortStartFirstTask( void )
vPortEnableInterrupts(); vPortEnableInterrupts();
/* Start the first task. */ /* Start the first task. */
prvResumeThread( prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) ); hRequestedThread=prvGetThreadHandle( xTaskGetCurrentTaskHandle());
prvResumeThread( hRequestedThread );
sched_yield();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -203,6 +357,7 @@ portBASE_TYPE xPortStartScheduler( void )
{ {
portBASE_TYPE xResult; portBASE_TYPE xResult;
int iSignal; int iSignal;
int fuckedUpCount=0;
sigset_t xSignals; sigset_t xSignals;
sigset_t xSignalToBlock; sigset_t xSignalToBlock;
sigset_t xSignalsBlocked; sigset_t xSignalsBlocked;
@ -229,6 +384,11 @@ portLONG lIndex;
/* This is the end signal we are looking for. */ /* This is the end signal we are looking for. */
sigemptyset( &xSignals ); sigemptyset( &xSignals );
sigaddset( &xSignals, SIG_RESUME ); sigaddset( &xSignals, SIG_RESUME );
sigaddset( &xSignals, SIG_TICK );
/* Allow other threads to run */
(void)pthread_mutex_unlock( &xRunningThreadMutex );
debug_printf( "MAIN thread is entering main signal wait loop!\n");
while ( pdTRUE != xSchedulerEnd ) while ( pdTRUE != xSchedulerEnd )
{ {
@ -236,12 +396,32 @@ portLONG lIndex;
{ {
printf( "Main thread spurious signal: %d\n", iSignal ); printf( "Main thread spurious signal: %d\n", iSignal );
} }
/**
* Tick handler is called from here - AND ONLY FROM HERE
* (needed for cygwin - but should work on all)
*/
if (iSignal==SIG_TICK) {
if (xGeneralFuckedUpIndicator!=0 && hActiveThread!=hRequestedThread) {
fuckedUpCount++;
if (fuckedUpCount>10) {
fuckedUpCount=0;
prvResolveFuckup();
}
} else {
fuckedUpCount=0;
}
vPortSystemTickHandler(iSignal);
}
if (iSignal==SIG_RESUME && pdTRUE != xSchedulerEnd) {
debug_printf( "ALERT! Main received SIG_RESUME that was supposed to go elsewhere!");
}
} }
printf( "Cleaning Up, Exiting.\n" ); printf( "Cleaning Up, Exiting.\n" );
/* Cleanup the mutexes */ /* Cleanup the mutexes */
xResult = pthread_mutex_destroy( &xSuspendResumeThreadMutex ); //xResult = pthread_mutex_destroy( &xSuspendResumeThreadMutex );
xResult = pthread_mutex_destroy( &xSingleThreadMutex ); //xResult = pthread_mutex_destroy( &xSingleThreadMutex );
xResult = pthread_mutex_destroy( &xRunningThreadMutex );
vPortFree( (void *)pxThreads ); vPortFree( (void *)pxThreads );
/* Should not get here! */ /* Should not get here! */
@ -312,8 +492,24 @@ void vPortYield( void )
pthread_t xTaskToSuspend; pthread_t xTaskToSuspend;
pthread_t xTaskToResume; pthread_t xTaskToResume;
if ( 0 == pthread_mutex_lock( &xSingleThreadMutex ) ) /**
{ * Sentinel - do not change context while the running task is not equal the task supposed to run
*/
// if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) )
while ( 0 != pthread_mutex_trylock ( &xSuspendResumeThreadMutex ) ) {
sched_yield();
}
/**
* Make sure we don't create outdated resume signals
*/
while (hActiveThread!=hRequestedThread) {
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
sched_yield();
while (0 != pthread_mutex_trylock( &xSuspendResumeThreadMutex )) {
sched_yield();
}
}
xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() ); xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
vTaskSwitchContext(); vTaskSwitchContext();
@ -325,14 +521,20 @@ pthread_t xTaskToResume;
prvSetTaskCriticalNesting( xTaskToSuspend, uxCriticalNesting ); prvSetTaskCriticalNesting( xTaskToSuspend, uxCriticalNesting );
uxCriticalNesting = prvGetTaskCriticalNesting( xTaskToResume ); uxCriticalNesting = prvGetTaskCriticalNesting( xTaskToResume );
/* Switch tasks. */ /* Switch tasks. */
hRequestedThread = xTaskToResume;
prvResumeThread( xTaskToResume ); prvResumeThread( xTaskToResume );
prvSuspendThread( xTaskToSuspend ); //prvSuspendThread( xTaskToSuspend );
if (prvGetThreadHandle(xTaskGetCurrentTaskHandle())!=xTaskToResume) {
debug_printf("\n what the fuck???? someone else did a switchcontext?!?\n");
}
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
prvSuspendSignalHandler(SIG_SUSPEND);
return;
} }
else else
{ {
/* Yielding to self */ /* Yielding to self */
(void)pthread_mutex_unlock( &xSingleThreadMutex ); (void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
}
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -372,6 +574,7 @@ void prvSetupTimerInterrupt( void )
struct itimerval itimer, oitimer; struct itimerval itimer, oitimer;
portTickType xMicroSeconds = portTICK_RATE_MICROSECONDS; portTickType xMicroSeconds = portTICK_RATE_MICROSECONDS;
debug_printf("init %li microseconds\n",(long)xMicroSeconds);
/* Initialise the structure with the current timer information. */ /* Initialise the structure with the current timer information. */
if ( 0 == getitimer( TIMER_TYPE, &itimer ) ) if ( 0 == getitimer( TIMER_TYPE, &itimer ) )
{ {
@ -400,12 +603,32 @@ void vPortSystemTickHandler( int sig )
{ {
pthread_t xTaskToSuspend; pthread_t xTaskToSuspend;
pthread_t xTaskToResume; pthread_t xTaskToResume;
struct timespec timeout;
if ( ( pdTRUE == xInterruptsEnabled ) && ( pdTRUE != xServicingTick ) ) //debug_printf("received %i\n",sig);
{ /**
if ( 0 == pthread_mutex_trylock( &xSingleThreadMutex ) ) * do not call tick handler if
* - interrupts are disabled
* - tick handler is still running
* - old task switch not yet completed (wrong task running)
*/
if ( ( pdTRUE == xInterruptsEnabled ) && ( pdTRUE != xServicingTick ) && ( hRequestedThread == hActiveThread ) )
{ {
xServicingTick = pdTRUE; xServicingTick = pdTRUE;
if ( 0 == pthread_mutex_trylock( &xSuspendResumeThreadMutex ) )
{
debug_printf("does handle tick\n");
/**
* this shouldn't ever happen - but WELL...
* Make sure we don't create outdated resume signals
*/
if (hActiveThread!=hRequestedThread) {
xServicingTick = pdFALSE;
xPendYield = pdTRUE;
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
return;
}
xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() ); xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
/* Tick Increment. */ /* Tick Increment. */
@ -416,32 +639,51 @@ pthread_t xTaskToResume;
vTaskSwitchContext(); vTaskSwitchContext();
#endif #endif
xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() ); xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
//hRequestedThread = xTaskToResume;
/* The only thread that can process this tick is the running thread. */ /* The only thread that can process this tick is the running thread. */
if ( xTaskToSuspend != xTaskToResume ) if ( xTaskToSuspend != xTaskToResume )
{ {
/* Suspend the current task. */
hRequestedThread = 0;
prvSuspendThread( xTaskToSuspend );
//timeout.tv_sec=0;
//timeout.tv_nsec=10000;
//sched_yield();
while ( 0 != pthread_mutex_lock( &xRunningThreadMutex) ) {
prvSuspendThread( xTaskToSuspend );
timeout.tv_sec=0;
timeout.tv_nsec=1;
nanosleep(&timeout,0);
}
//if ( 0 == pthread_mutex_lock( &xRunningThreadMutex) ) {
/* Remember and switch the critical nesting. */ /* Remember and switch the critical nesting. */
prvSetTaskCriticalNesting( xTaskToSuspend, uxCriticalNesting ); prvSetTaskCriticalNesting( xTaskToSuspend, uxCriticalNesting );
uxCriticalNesting = prvGetTaskCriticalNesting( xTaskToResume ); uxCriticalNesting = prvGetTaskCriticalNesting( xTaskToResume );
/* Resume next task. */ /* Resume next task. */
hRequestedThread = xTaskToResume;
prvResumeThread( xTaskToResume ); prvResumeThread( xTaskToResume );
/* Suspend the current task. */ if (prvGetThreadHandle(xTaskGetCurrentTaskHandle())!=xTaskToResume) {
prvSuspendThread( xTaskToSuspend ); debug_printf("\n what the fuck???? someone else did a switchcontext?!?\n");
}
(void)pthread_mutex_unlock( &xRunningThreadMutex );
} }
else else
{ {
/* Release the lock as we are Resuming. */ /* Release the lock as we are Resuming. */
(void)pthread_mutex_unlock( &xSingleThreadMutex ); // (void)pthread_mutex_unlock( &xSingleThreadMutex );
} }
xServicingTick = pdFALSE;
} }
else else
{ {
xPendYield = pdTRUE; xPendYield = pdTRUE;
} }
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
xServicingTick = pdFALSE;
} }
else else
{ {
debug_printf("will NOT handle tick\n");
xPendYield = pdTRUE; xPendYield = pdTRUE;
} }
} }
@ -454,16 +696,31 @@ pthread_t xTaskToDelete;
pthread_t xTaskToResume; pthread_t xTaskToResume;
portBASE_TYPE xResult; portBASE_TYPE xResult;
if ( 0 == pthread_mutex_lock( &xSingleThreadMutex ) ) // if ( 0 == pthread_mutex_lock( &xSingleThreadMutex ) )
{ // {
xTaskToDelete = prvGetThreadHandle( hTaskToDelete ); xTaskToDelete = prvGetThreadHandle( hTaskToDelete );
xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() ); xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
if ( xTaskToResume == xTaskToDelete ) if ( xTaskToResume == xTaskToDelete )
{ {
if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) ) {
/**
* Make sure we don't create outdated resume signals
*/
while (hActiveThread!=hRequestedThread) {
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
sched_yield();
(void)pthread_mutex_lock( &xSuspendResumeThreadMutex );
}
/* This is a suicidal thread, need to select a different task to run. */ /* This is a suicidal thread, need to select a different task to run. */
vTaskSwitchContext(); vTaskSwitchContext();
xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() ); xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
hRequestedThread = xTaskToResume;
(void)pthread_mutex_unlock( &xSuspendResumeThreadMutex );
} else {
debug_printf("mutex lock failed!\n");
exit(1);
}
} }
if ( pthread_self() != xTaskToDelete ) if ( pthread_self() != xTaskToDelete )
@ -476,7 +733,7 @@ portBASE_TYPE xResult;
xResult = pthread_cancel( xTaskToDelete ); xResult = pthread_cancel( xTaskToDelete );
/* Pthread Clean-up function will note the cancellation. */ /* Pthread Clean-up function will note the cancellation. */
} }
(void)pthread_mutex_unlock( &xSingleThreadMutex ); // (void)pthread_mutex_unlock( &xSingleThreadMutex );
} }
else else
{ {
@ -486,11 +743,12 @@ portBASE_TYPE xResult;
/* Release the execution. */ /* Release the execution. */
uxCriticalNesting = 0; uxCriticalNesting = 0;
vPortEnableInterrupts(); vPortEnableInterrupts();
(void)pthread_mutex_unlock( &xSingleThreadMutex ); // (void)pthread_mutex_unlock( &xSingleThreadMutex );
(void)pthread_mutex_unlock( &xRunningThreadMutex );
/* Commit suicide */ /* Commit suicide */
pthread_exit( (void *)1 ); pthread_exit( (void *)1 );
} }
} // }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -499,13 +757,27 @@ void *prvWaitForStart( void * pvParams )
xParams * pxParams = ( xParams * )pvParams; xParams * pxParams = ( xParams * )pvParams;
pdTASK_CODE pvCode = pxParams->pxCode; pdTASK_CODE pvCode = pxParams->pxCode;
void * pParams = pxParams->pvParams; void * pParams = pxParams->pvParams;
sigset_t xSignals;
vPortFree( pvParams ); vPortFree( pvParams );
pthread_cleanup_push( prvDeleteThread, (void *)pthread_self() ); pthread_cleanup_push( prvDeleteThread, (void *)pthread_self() );
if ( 0 == pthread_mutex_lock( &xSingleThreadMutex ) ) if ( 0 == pthread_mutex_lock( &xRunningThreadMutex ) )
{ {
prvSuspendThread( pthread_self() ); xSentinel=1;
hActiveThread=pthread_self();
debug_printf("temporarily made ACTIVE THREAD!\n");
sigemptyset( &xSignals );
sigaddset( &xSignals, SIG_RESUME );
/* set up proc mask */
pthread_sigmask(SIG_SETMASK,&xSignals,NULL);
prvSuspendSignalHandler(SIG_SUSPEND);
//prvSuspendThread( pthread_self() );
} else {
debug_printf("now this is just WRONG!\n");
exit(1);
} }
pvCode( pParams ); pvCode( pParams );
@ -518,23 +790,67 @@ void * pParams = pxParams->pvParams;
void prvSuspendSignalHandler(int sig) void prvSuspendSignalHandler(int sig)
{ {
sigset_t xSignals; sigset_t xSignals;
//sigset_t xPendingSignals;
/* Only interested in the resume signal. */ /* Only interested in the resume signal. */
sigemptyset( &xSignals ); sigemptyset( &xSignals );
sigaddset( &xSignals, SIG_RESUME ); sigaddset( &xSignals, SIG_RESUME );
xSentinel = 1; sigaddset( &xSignals, SIG_SUSPEND );
/* Unlock the Single thread mutex to allow the resumed task to continue. */ /* Unlock the Running thread mutex to allow the resumed task to continue. */
if ( 0 != pthread_mutex_unlock( &xSingleThreadMutex ) ) if ( 0 != pthread_mutex_unlock( &xRunningThreadMutex ) )
{ {
printf( "Releasing someone else's lock.\n" ); printf( "Releasing someone else's lock.\n" );
} }
debug_printf("SUSPENDING until SIG_RESUME received\n");
/* Wait on the resume signal. */ /* Wait on the resume signal. */
while (hRequestedThread != pthread_self()) {
if ( 0 != sigwait( &xSignals, &sig ) ) if ( 0 != sigwait( &xSignals, &sig ) )
{ {
printf( "SSH: Sw %d\n", sig ); //printf( "SSH: Sw %d\n", sig );
/* tricky one - shouldn't ever happen - trying to resolve situation as graceful as possible */
debug_printf("ALERT AAAAH PANIC! - sigwait failed.....\n\n\n");
/* Signal main thread something just went HORRIBLY wrong */
xGeneralFuckedUpIndicator = 2;
sched_yield();
//(void)pthread_mutex_lock( &xRunningThreadMutex );
//(void)pthread_kill( pthread_self(), SIG_SUSPEND );
//return;
} else if (sig == SIG_RESUME) {
//debug_printf("received signal %i\n",sig);
/* Make sure the right thread received the signal */
if (hRequestedThread != pthread_self() ) {
debug_printf( "ALERT! Received SIG_RESUME which is already outdated!\n active thread is %li\n",(long)hRequestedThread);
/* Signal main thread something just went wrong */
xGeneralFuckedUpIndicator = 1;
/*
if (0 == sigpending(&xPendingSignals)) {
if (sigismember(&xPendingSignals,SIG_SUSPEND)) {
debug_printf( "reason: we slept too long...\n");
//(void)sigwait(&xPendingSignals,&sig);
// we can safely return - signal is already pending
return;
} }
}
debug_printf( "reason: unknown! - whatever ...\n\n");
*/
//exit(1);
//(void)pthread_kill( xTaskToResume, SIG_RESUME );
//(void)pthread_mutex_lock( &xRunningThreadMutex );
//(void)pthread_kill( pthread_self(), SIG_SUSPEND );
//return;
}
}
}
/* Yield the Scheduler to ensure that the yielding thread completes. */
if ( 0 != pthread_mutex_lock( &xRunningThreadMutex ) )
{
//(void)pthread_mutex_unlock( &xSingleThreadMutex );
debug_printf("critical - mutex acquiring of active thread failed!\n");
exit(1);
}
hActiveThread = pthread_self();
/* Will resume here when the SIG_RESUME signal is received. */ /* Will resume here when the SIG_RESUME signal is received. */
/* Need to set the interrupts based on the task's critical nesting. */ /* Need to set the interrupts based on the task's critical nesting. */
@ -546,47 +862,11 @@ sigset_t xSignals;
{ {
vPortDisableInterrupts(); vPortDisableInterrupts();
} }
if (hRequestedThread==pthread_self()) {
/* doesn't look too bad, does it? */
xGeneralFuckedUpIndicator = 0;
} }
/*-----------------------------------------------------------*/ debug_printf("ACTIVE THREAD!\n");
void prvSuspendThread( pthread_t xThreadId )
{
portBASE_TYPE xResult = pthread_mutex_lock( &xSuspendResumeThreadMutex );
if ( 0 == xResult )
{
/* Set-up for the Suspend Signal handler? */
xSentinel = 0;
xResult = pthread_mutex_unlock( &xSuspendResumeThreadMutex );
xResult = pthread_kill( xThreadId, SIG_SUSPEND );
while ( ( xSentinel == 0 ) && ( pdTRUE != xServicingTick ) )
{
sched_yield();
}
}
}
/*-----------------------------------------------------------*/
void prvResumeSignalHandler(int sig)
{
/* Yield the Scheduler to ensure that the yielding thread completes. */
if ( 0 == pthread_mutex_lock( &xSingleThreadMutex ) )
{
(void)pthread_mutex_unlock( &xSingleThreadMutex );
}
}
/*-----------------------------------------------------------*/
void prvResumeThread( pthread_t xThreadId )
{
portBASE_TYPE xResult;
if ( 0 == pthread_mutex_lock( &xSuspendResumeThreadMutex ) )
{
if ( pthread_self() != xThreadId )
{
xResult = pthread_kill( xThreadId, SIG_RESUME );
}
xResult = pthread_mutex_unlock( &xSuspendResumeThreadMutex );
}
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -618,21 +898,23 @@ portLONG lIndex;
sigfillset( &sigsuspendself.sa_mask ); sigfillset( &sigsuspendself.sa_mask );
sigresume.sa_flags = 0; sigresume.sa_flags = 0;
sigresume.sa_handler = prvResumeSignalHandler; //sigresume.sa_handler = prvResumeSignalHandler;
sigresume.sa_handler = SIG_IGN;
sigfillset( &sigresume.sa_mask ); sigfillset( &sigresume.sa_mask );
sigtick.sa_flags = 0; sigtick.sa_flags = 0;
sigtick.sa_handler = vPortSystemTickHandler; //sigtick.sa_handler = vPortSystemTickHandler;
sigtick.sa_handler = SIG_IGN;
sigfillset( &sigtick.sa_mask ); sigfillset( &sigtick.sa_mask );
if ( 0 != sigaction( SIG_SUSPEND, &sigsuspendself, NULL ) ) if ( 0 != sigaction( SIG_SUSPEND, &sigsuspendself, NULL ) )
{ {
printf( "Problem installing SIG_SUSPEND_SELF\n" ); printf( "Problem installing SIG_SUSPEND_SELF\n" );
} }
if ( 0 != sigaction( SIG_RESUME, &sigresume, NULL ) ) //if ( 0 != sigaction( SIG_RESUME, &sigresume, NULL ) )
{ //{
printf( "Problem installing SIG_RESUME\n" ); // printf( "Problem installing SIG_RESUME\n" );
} //}
if ( 0 != sigaction( SIG_TICK, &sigtick, NULL ) ) if ( 0 != sigaction( SIG_TICK, &sigtick, NULL ) )
{ {
printf( "Problem installing SIG_TICK\n" ); printf( "Problem installing SIG_TICK\n" );
@ -772,3 +1054,44 @@ struct tms xTimes;
(void)ulTotalTime; (void)ulTotalTime;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/**
* Scheduler f***d up - we got to fix that
*/
void prvResolveFuckup( void )
{
struct timespec timeout;
pthread_t xTaskToResume;
(void)pthread_mutex_lock ( &xSuspendResumeThreadMutex);
if (hActiveThread == hRequestedThread) {
debug_printf("emergency handler started - but not needed - returning\n");
return;
}
printf("\nScheduler fucked up again - lets try to fix it...\n");
if (hRequestedThread==0) {
printf("\nno supposedly active thread - fixing\n");
xTaskToResume = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
} else {
xTaskToResume = hRequestedThread;
}
printf("\nsending sig_suspend to thread that is supposed to be dead...\n");
prvSuspendThread(hActiveThread);
printf("\nacquire running lock...\n");
//timeout.tv_sec=0;
//timeout.tv_nsec=100;
sched_yield();
while ( 0 != pthread_mutex_trylock( &xRunningThreadMutex) ) {
prvSuspendThread(hActiveThread);
timeout.tv_sec=0;
timeout.tv_nsec=1;
nanosleep(&timeout,NULL);
}
printf("\nsending sig_resume to thread that is supposed to be running...\n");
prvResumeThread(xTaskToResume);
printf("\ngiving up mutex...\n");
(void)pthread_mutex_unlock(&xRunningThreadMutex);
(void)pthread_mutex_unlock ( &xSuspendResumeThreadMutex);
}
/*-----------------------------------------------------------*/