mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2024-12-01 09:24:10 +01:00
This version runs stably on all three platforms for me. Corvus, please feel free to revert these changes if you want or have a better solution. Also only Mac tested with GCS, the rest just sit there running nicely
git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1063 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
parent
dd598a75a4
commit
c6b495cdcc
@ -22,49 +22,48 @@ struct timespec timeout;
|
||||
int t;
|
||||
printf("thread %li started\n",(long)pthread_self());
|
||||
|
||||
while (1) {
|
||||
printf("getting mutex\n");
|
||||
pthread_mutex_lock(&Mutex);
|
||||
printf("got mutex\n");
|
||||
while (1) {
|
||||
printf("getting mutex\n");
|
||||
pthread_mutex_lock(&Mutex);
|
||||
printf("got mutex\n");
|
||||
|
||||
|
||||
for (t=0;t<20;t++) {
|
||||
timeout.tv_sec=1;
|
||||
timeout.tv_nsec=0;
|
||||
nanosleep(&timeout,0);
|
||||
printf("thread %li still running...\n",(long)pthread_self());
|
||||
for (t=0;t<20;t++) {
|
||||
timeout.tv_sec=1;
|
||||
timeout.tv_nsec=0;
|
||||
nanosleep(&timeout,0);
|
||||
printf("thread %li still running...\n",(long)pthread_self());
|
||||
}
|
||||
pthread_mutex_unlock(&Mutex);
|
||||
sleep(1);
|
||||
}
|
||||
pthread_mutex_unlock(&Mutex);
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(char** argc, int argv) {
|
||||
|
||||
pthread_t testthread1;
|
||||
pthread_t testthread2;
|
||||
struct sigaction action;
|
||||
printf("thread test program\n");
|
||||
pthread_t testthread1;
|
||||
pthread_t testthread2;
|
||||
struct sigaction action;
|
||||
printf("thread test program\n");
|
||||
printf("installing signal handler\n");
|
||||
action.sa_handler=sighandler;
|
||||
action.sa_flags=0;
|
||||
sigfillset( &action.sa_mask );
|
||||
sigaction(SIGUSR1,&action,NULL);
|
||||
|
||||
sleep(5);
|
||||
printf("starting thread 1\n");
|
||||
pthread_create(&testthread1,NULL,threadstart,NULL);
|
||||
sleep(5);
|
||||
printf("starting thread 2\n");
|
||||
pthread_create(&testthread2,NULL,threadstart,NULL);
|
||||
while (1) {
|
||||
sleep(5);
|
||||
printf("sending SIG_USR1 to thread 1\n");
|
||||
pthread_kill(testthread1,SIGUSR1);
|
||||
printf("starting thread 1\n");
|
||||
pthread_create(&testthread1,NULL,threadstart,NULL);
|
||||
sleep(5);
|
||||
printf("sending SIG_USR1 to thread 2\n");
|
||||
pthread_kill(testthread2,SIGUSR1);
|
||||
}
|
||||
printf("starting thread 2\n");
|
||||
pthread_create(&testthread2,NULL,threadstart,NULL);
|
||||
while (1) {
|
||||
sleep(5);
|
||||
printf("sending SIG_USR1 to thread 1\n");
|
||||
pthread_kill(testthread1,SIGUSR1);
|
||||
sleep(5);
|
||||
printf("sending SIG_USR1 to thread 2\n");
|
||||
pthread_kill(testthread2,SIGUSR1);
|
||||
}
|
||||
}
|
||||
|
@ -76,10 +76,15 @@
|
||||
#define MAX_NUMBER_OF_TASKS ( _POSIX_THREAD_THREADS_MAX )
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
#define COND_SIGNALING
|
||||
#ifndef __DARWIN__
|
||||
#define COND_SIGNALING
|
||||
#define CHECK_TASK_RESUMES
|
||||
#define RUNNING_THREAD_MUTEX
|
||||
#define TICK_SIGNAL
|
||||
#endif
|
||||
#ifdef __CYGWIN__
|
||||
#define COND_SIGNALING
|
||||
#define CHECK_TASK_RESUMES
|
||||
#endif
|
||||
|
||||
/* Parameters to pass to the newly created pthread. */
|
||||
@ -177,6 +182,7 @@ void vPortSystemTickHandler( int sig );
|
||||
int real_pthread_mutex_unlock(pthread_mutex_t* mutex) {
|
||||
return pthread_mutex_unlock(mutex);
|
||||
}
|
||||
#define pthread_mutex_trylock(...) ( (debug_printf(" -!- pthread_mutex_trylock(%s)\n",#__VA_ARGS__)|1)?pthread_mutex_trylock(__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_kill(thread,signal) ( (debug_printf("Sending signal %i to thread %li!\n",(int)signal,(long)thread)|1)?pthread_kill(thread,signal):0 )
|
||||
@ -344,10 +350,8 @@ portLONG lIndex;
|
||||
debug_printf( "xPortStartScheduler\r\n" );
|
||||
|
||||
/* Establish the signals to block before they are needed. */
|
||||
sigfillset( &xSignalToBlock );
|
||||
sigemptyset( &xSignalToBlock );
|
||||
sigaddset( &xSignalToBlock, SIG_SUSPEND );
|
||||
|
||||
/* Block until the end */
|
||||
(void)pthread_sigmask( SIG_SETMASK, &xSignalToBlock, NULL );
|
||||
|
||||
for ( lIndex = 0; lIndex < MAX_NUMBER_OF_TASKS; lIndex++ )
|
||||
@ -358,16 +362,57 @@ portLONG lIndex;
|
||||
/* Start the first task. Will not return unless all threads are killed. */
|
||||
vPortStartFirstTask();
|
||||
|
||||
struct timespec x;
|
||||
/* Unfortunately things are stable if we start ticking during setup. This need to be */
|
||||
/* checked careful in startup on hardware */
|
||||
usleep(1000000);
|
||||
|
||||
#ifdef TICK_SIGNAL
|
||||
struct itimerval itimer;
|
||||
portTickType xMicroSeconds = portTICK_RATE_MICROSECONDS;
|
||||
|
||||
debug_printf("init %li microseconds\n",(long)xMicroSeconds);
|
||||
/* Initialise the structure with the current timer information. */
|
||||
assert ( 0 == getitimer( TIMER_TYPE, &itimer ) );
|
||||
|
||||
/* Set the interval between timer events. */
|
||||
itimer.it_interval.tv_sec = 0;
|
||||
itimer.it_interval.tv_usec = xMicroSeconds;
|
||||
|
||||
/* Set the current count-down. */
|
||||
itimer.it_value.tv_sec = 0;
|
||||
itimer.it_value.tv_usec = xMicroSeconds;
|
||||
|
||||
struct sigaction sigtick;
|
||||
sigtick.sa_flags = 0;
|
||||
sigtick.sa_handler = vPortSystemTickHandler;
|
||||
sigemptyset( &sigtick.sa_mask );
|
||||
assert ( 0 == sigaction( SIG_TICK, &sigtick, NULL ) );
|
||||
|
||||
/* Set-up the timer interrupt. */
|
||||
assert ( 0 == setitimer( TIMER_TYPE, &itimer, NULL ) );
|
||||
|
||||
sigemptyset( &xSignalToBlock );
|
||||
sigaddset( &xSignalToBlock, SIG_SUSPEND );
|
||||
(void)pthread_sigmask( SIG_SETMASK, &xSignalToBlock, NULL );
|
||||
|
||||
while(1)
|
||||
{
|
||||
usleep(1000);
|
||||
sched_yield();
|
||||
}
|
||||
#else
|
||||
|
||||
struct timespec x;
|
||||
while( pdTRUE != xSchedulerEnd ) {
|
||||
x.tv_sec=0;
|
||||
x.tv_nsec=portTICK_RATE_MICROSECONDS * 1000;
|
||||
nanosleep(&x,NULL);
|
||||
//printf("."); fflush(stdout);
|
||||
// printf("."); fflush(stdout);
|
||||
vPortSystemTickHandler(SIG_TICK);
|
||||
// printf("*"); fflush(stdout);
|
||||
}
|
||||
|
||||
#endif
|
||||
debug_printf( "Cleaning Up, Exiting.\n" );
|
||||
/* Cleanup the mutexes */
|
||||
xResult = pthread_mutex_destroy( &xSuspendResumeThreadMutex );
|
||||
@ -445,6 +490,7 @@ void vPortYield( void )
|
||||
pthread_t xTaskToSuspend;
|
||||
pthread_t xTaskToResume;
|
||||
sigset_t xSignals;
|
||||
int retVal;
|
||||
tskTCB * oldTask, * newTask;
|
||||
|
||||
/* We must mask the suspend signal here, because otherwise there can be an */
|
||||
@ -455,24 +501,53 @@ tskTCB * oldTask, * newTask;
|
||||
|
||||
sigemptyset( &xSignals );
|
||||
sigaddset( &xSignals, SIG_SUSPEND );
|
||||
sigaddset( &xSignals, SIG_TICK );
|
||||
pthread_sigmask( SIG_SETMASK, &xSignals, NULL );
|
||||
|
||||
assert( pthread_mutex_lock( &xSwappingThreadMutex ) == 0);
|
||||
|
||||
oldTask = xTaskGetCurrentTaskHandle();
|
||||
xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
|
||||
if(xTaskToSuspend != pthread_self() ) {
|
||||
/* This means between masking the interrupt and getting the lock, there was an interrupt */
|
||||
/* and this task should suspend. Release the lock, then unmask interrupts to go ahead and */
|
||||
/* service the signal */
|
||||
|
||||
assert( 0 == pthread_mutex_unlock( &xSwappingThreadMutex ) );
|
||||
retVal = pthread_mutex_trylock( &xSwappingThreadMutex );
|
||||
while( retVal != 0 ) {
|
||||
|
||||
assert( retVal == EBUSY );
|
||||
|
||||
/* If we can't get the mutex, that means an interrupt is running and we */
|
||||
/* should keep an eye out if this task should suspend so the interrupt */
|
||||
/* routine doesn't stall waiting for this task to pause */
|
||||
debug_printf( "Waiting to get swapping mutex from ISR\r\n" );
|
||||
|
||||
xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
|
||||
|
||||
if( prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) != pthread_self() ) {
|
||||
debug_printf( "The current task isn't even us. Pausing now, deal with possible interrupt later.\r\n" );
|
||||
pauseThread( THREAD_PAUSE_YIELD );
|
||||
|
||||
/* Now we are resuming, want to be able to catch this interrupt again */
|
||||
sigemptyset( &xSignals );
|
||||
sigaddset( &xSignals, SIG_TICK );
|
||||
pthread_sigmask( SIG_SETMASK, &xSignals, NULL);
|
||||
return;
|
||||
}
|
||||
retVal = pthread_mutex_trylock( &xSwappingThreadMutex );
|
||||
}
|
||||
|
||||
/* At this point we have the lock, active task shouldn't change */
|
||||
if(xTaskToSuspend != pthread_self() ) {
|
||||
debug_printf( "The current task isn't even us, letting interrupt happen. Watch for swap.\r\n" );
|
||||
|
||||
assert( pthread_mutex_unlock( &xSwappingThreadMutex ) == 0);
|
||||
|
||||
pauseThread( THREAD_PAUSE_YIELD );
|
||||
|
||||
/* Now we are resuming, want to be able to catch this interrupt again */
|
||||
sigemptyset( &xSignals );
|
||||
sigaddset( &xSignals, SIG_TICK );
|
||||
pthread_sigmask( SIG_SETMASK, &xSignals, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
assert( xTaskToSuspend == pthread_self() ); // race condition I didn't account for
|
||||
|
||||
xStarted = pdFALSE;
|
||||
|
||||
@ -511,6 +586,7 @@ tskTCB * oldTask, * newTask;
|
||||
|
||||
/* Now we are resuming, want to be able to catch this interrupt again */
|
||||
sigemptyset( &xSignals );
|
||||
sigaddset( &xSignals, SIG_TICK );
|
||||
pthread_sigmask( SIG_SETMASK, &xSignals, NULL);
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
@ -564,7 +640,12 @@ tskTCB * oldTask, * newTask;
|
||||
|
||||
oldTask = xTaskGetCurrentTaskHandle();
|
||||
xTaskToSuspend = prvGetThreadHandle( xTaskGetCurrentTaskHandle() );
|
||||
|
||||
|
||||
/* Need to set this before updating the task in case it notices before the */
|
||||
/* interrupt is set */
|
||||
xSuspended = pdFALSE;
|
||||
xStarted = pdFALSE;
|
||||
|
||||
/* Tick Increment. */
|
||||
vTaskIncrementTick();
|
||||
|
||||
@ -580,36 +661,36 @@ tskTCB * oldTask, * newTask;
|
||||
/* The only thread that can process this tick is the running thread. */
|
||||
if ( xTaskToSuspend != xTaskToResume )
|
||||
{
|
||||
xSuspended = pdFALSE;
|
||||
xStarted = pdFALSE;
|
||||
|
||||
/* Remember and switch the critical nesting. */
|
||||
prvSetTaskCriticalNesting( xTaskToSuspend, uxCriticalNesting );
|
||||
uxCriticalNesting = prvGetTaskCriticalNesting( xTaskToResume );
|
||||
|
||||
debug_printf( "Swapping From %li(%s) to %li(%s)\r\n", (long int) xTaskToSuspend, oldTask->pcTaskName, (long int) xTaskToResume, newTask->pcTaskName);
|
||||
|
||||
assert( pthread_kill( xTaskToSuspend, SIG_SUSPEND ) == 0);
|
||||
|
||||
#ifdef CHECK_TASK_RESUMES
|
||||
/* It shouldn't be possible for a second task swap to happen while waiting for this because */
|
||||
/* they can't get the xSwappingThreadMutex */
|
||||
while( xSuspended == pdFALSE )
|
||||
#endif
|
||||
{
|
||||
assert( pthread_kill( xTaskToSuspend, SIG_SUSPEND ) == 0);
|
||||
debug_printf( "Waiting for old task to suspend\r\n" );
|
||||
debug_printf( "Sent signal\r\n" );
|
||||
sched_yield();
|
||||
}
|
||||
debug_printf( "Suspended\r\n" );
|
||||
|
||||
#ifdef CHECK_TASK_RESUMES
|
||||
while( xStarted == pdFALSE)
|
||||
#endif
|
||||
{
|
||||
|
||||
debug_printf( "Waiting for new task to resume\r\n" );
|
||||
#ifdef COND_SIGNALING
|
||||
// Set resume condition for specific thread
|
||||
pthread_cond_t * hCond = prvGetConditionHandle( xTaskGetCurrentTaskHandle() );
|
||||
assert( pthread_cond_signal( hCond ) == 0 );
|
||||
#endif
|
||||
assert( pthread_kill( xTaskToSuspend, SIG_SUSPEND ) == 0);
|
||||
|
||||
sched_yield();
|
||||
}
|
||||
@ -634,6 +715,7 @@ tskTCB * oldTask, * newTask;
|
||||
debug_printf( "Pending yield or here\r\n");
|
||||
xPendYield = pdTRUE;
|
||||
}
|
||||
debug_printf("Exiting\r\n");
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
@ -701,7 +783,8 @@ void * pParams = pxParams->pvParams;
|
||||
sigset_t xSignals;
|
||||
sigemptyset( &xSignals );
|
||||
sigaddset( &xSignals, SIG_SUSPEND );
|
||||
assert( pthread_sigmask( SIG_BLOCK, &xSignals, NULL ) == 0);
|
||||
sigaddset( &xSignals, SIG_TICK );
|
||||
assert( pthread_sigmask( SIG_SETMASK, &xSignals, NULL ) == 0);
|
||||
|
||||
/* Because the FreeRTOS creates the TCB stack, which in this implementation */
|
||||
/* creates a thread, we need to wait until the task handle is added before */
|
||||
@ -724,6 +807,7 @@ void * pParams = pxParams->pvParams;
|
||||
debug_printf("Starting first run\r\n");
|
||||
|
||||
sigemptyset( &xSignals );
|
||||
sigaddset( &xSignals, SIG_TICK );
|
||||
assert( pthread_sigmask( SIG_SETMASK, &xSignals, NULL ) == 0);
|
||||
|
||||
pvCode( pParams );
|
||||
@ -735,7 +819,8 @@ void * pParams = pxParams->pvParams;
|
||||
|
||||
void pauseThread( portBASE_TYPE pauseMode )
|
||||
{
|
||||
debug_printf( "Pausing thread %li. Set xSuspended false\r\n", (long int) pthread_self() );
|
||||
debug_printf( "Pausing thread %li. Set xSuspended true\r\n", (long int) pthread_self() );
|
||||
xSuspended = pdTRUE;
|
||||
|
||||
#ifdef RUNNING_THREAD_MUTEX
|
||||
if( pauseMode != THREAD_PAUSE_CREATED )
|
||||
@ -756,8 +841,6 @@ void pauseThread( portBASE_TYPE pauseMode )
|
||||
ts.tv_sec = tv.tv_sec + 0;
|
||||
#endif
|
||||
|
||||
xSuspended = pdTRUE;
|
||||
|
||||
while (1) {
|
||||
if( pthread_self() == prvGetThreadHandle(xTaskGetCurrentTaskHandle() ) && xRunning )
|
||||
{
|
||||
@ -783,7 +866,7 @@ void pauseThread( portBASE_TYPE pauseMode )
|
||||
/* and there may be a sleep in the main code (this can be called from an ISR) we must */
|
||||
/* check this */
|
||||
if( pauseMode != THREAD_PAUSE_INTERRUPT )
|
||||
usleep(100);
|
||||
usleep(1000);
|
||||
sched_yield();
|
||||
|
||||
#endif
|
||||
@ -801,30 +884,32 @@ sigset_t xBlockSignals;
|
||||
/* which means if there were a swap it should result in a suspend interrupt */
|
||||
|
||||
debug_error( "Caught signal %i\r\n", sig );
|
||||
/* Check that we aren't suspending when we should be running. This bug would need tracking down */
|
||||
//assert( pthread_self() != prvGetThreadHandle(xTaskGetCurrentTaskHandle() ) );
|
||||
if( pthread_self() == prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) )
|
||||
{
|
||||
debug_printf( "Suspend ISR called while this thread still marked active. Reflects buggy behavior in scheduler\r\n" );
|
||||
|
||||
#ifdef CHECK_TASK_RESUMES
|
||||
/* This would seem like a major bug, but can happen because now we send extra suspend signals */
|
||||
/* if they aren't caught */
|
||||
if( pthread_self() == prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) ) {
|
||||
debug_printf( "Marked as current task, resuming\r\n" );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Check that we aren't suspending when we should be running. This bug would need tracking down */
|
||||
// assert( pthread_self() != prvGetThreadHandle(xTaskGetCurrentTaskHandle() ) );
|
||||
|
||||
/* Block further suspend signals. They need to go to their thread */
|
||||
sigemptyset( &xBlockSignals );
|
||||
sigaddset( &xBlockSignals, SIG_SUSPEND );
|
||||
assert( pthread_sigmask( SIG_BLOCK, &xBlockSignals, NULL ) == 0);
|
||||
sigaddset( &xBlockSignals, SIG_TICK );
|
||||
assert( pthread_sigmask( SIG_SETMASK, &xBlockSignals, NULL ) == 0);
|
||||
|
||||
pauseThread( THREAD_PAUSE_INTERRUPT );
|
||||
|
||||
// assert( pthread_self() == prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) );
|
||||
while( pthread_self() != prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) )
|
||||
{
|
||||
debug_printf( "Incorrectly woke up. Repausing\r\n" );
|
||||
pauseThread( THREAD_PAUSE_INTERRUPT );
|
||||
}
|
||||
|
||||
/* Make sure the right thread is resuming */
|
||||
assert( pthread_self() == prvGetThreadHandle(xTaskGetCurrentTaskHandle() ) );
|
||||
|
||||
assert( pthread_self() == prvGetThreadHandle( xTaskGetCurrentTaskHandle() ) );
|
||||
|
||||
/* Old synchronization code, may still be required
|
||||
while( !xHandover );
|
||||
@ -832,7 +917,8 @@ sigset_t xBlockSignals;
|
||||
|
||||
/* Respond to signals again */
|
||||
sigemptyset( &xBlockSignals );
|
||||
pthread_sigmask( SIG_SETMASK, &xBlockSignals, NULL );
|
||||
sigaddset( &xBlockSignals, SIG_TICK );
|
||||
assert( 0 == pthread_sigmask( SIG_SETMASK, &xBlockSignals, NULL ) );
|
||||
|
||||
debug_printf( "Resuming %li from signal %i\r\n", (long int) pthread_self(), sig );
|
||||
|
||||
@ -878,7 +964,7 @@ portLONG lIndex;
|
||||
|
||||
sigsuspendself.sa_flags = 0;
|
||||
sigsuspendself.sa_handler = prvSuspendSignalHandler;
|
||||
sigfillset( &sigsuspendself.sa_mask );
|
||||
sigemptyset( &sigsuspendself.sa_mask );
|
||||
|
||||
assert ( 0 == sigaction( SIG_SUSPEND, &sigsuspendself, NULL ) );
|
||||
}
|
||||
|
@ -56,6 +56,8 @@
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
@ -1830,10 +1832,17 @@ static portTASK_FUNCTION( prvIdleTask, pvParameters )
|
||||
// call nanosleep for smalles sleep time possible
|
||||
// (depending on kernel settings - around 100 microseconds)
|
||||
// decreases idle thread CPU load from 100 to practically 0
|
||||
#ifndef __CYGWIN__
|
||||
sigset_t xSignals;
|
||||
sigfillset( &xSignals );
|
||||
pthread_sigmask( SIG_SETMASK, &xSignals, NULL );
|
||||
struct timespec x;
|
||||
x.tv_sec=0;
|
||||
x.tv_nsec=0;
|
||||
x.tv_nsec=10000;
|
||||
nanosleep(&x,NULL);
|
||||
sigemptyset( &xSignals );
|
||||
pthread_sigmask( SIG_SETMASK, &xSignals, NULL );
|
||||
#endif
|
||||
}
|
||||
} /*lint !e715 pvParameters is not accessed but all task functions require the same prototype. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user