Hi guys,
I’m working on a real-time test tool. Every 10ms, 20ms and 50ms a task (in my case a bubblesort with different complex input data) is executed by an individual thread. One thread for 10ms, one for 20 ms and one for 50ms. I used different threads because the 10ms thread needs a higher priority than 20ms and 50 ms thread - 10ms is more critical than 20ms. 20ms thread priority is higher than 50ms. So I can set individual priorities for the threads.
Now my problem is that the 10ms thread is executed (via interrupt) but not the 20ms and the 50ms thread (or only sometimes). Hmmm…okay…the thread iIS executed and waiting for the interrupt, but it seems that the counter variables for 20ms and 50ms in the interrupt handlers are not increased. The timeline (kernel trace) shows dark green sections in the 20 and 50ms threads (“CPU READY”).
I thought if the 10ms thread (highest priority), the 20ms thread (medium priority) and the 50ms thread (lower priority) are called (via interrupts) the 20ms thread is queued after the 10ms and the 50ms is queued after the 20ms thread BUT after 10ms thread execution is finished (thread blocks) the 20ms is executed …and so on… but this does not happen! So whats wrong? Or how to solve this problem? Is there a better way to do such timing critical tasks?
Here is the source code I used (btw the 10ms,20ms and 50ms threads are almost the same code…looks more than it is):
//variables and defines
#define THREAD_PRIO 1
#define NUM_EVENTS10ms 10
#define NUM_EVENTS20ms 20
#define NUM_EVENTS50ms 50
struct sigevent isr_event10ms,
isr_event20ms,
isr_event50ms;
volatile unsigned counter10ms,
counter20ms,
counter50ms;
pthread_barrier_t isr_barrier;
// ISR main
//
void main() {
int rc10ms,
rc20ms,
rc50ms;
pthread_t isr_worker_thread10ms,
isr_worker_thread20ms,
isr_worker_thread50ms;
pthread_barrier_init(&isr_barrier, NULL, 4);
rc10ms = pthread_create (&isr_worker_thread10ms , NULL, &int_thread10ms , &isr_barrier);
rc20ms = pthread_create (&isr_worker_thread20ms , NULL, &int_thread20ms , &isr_barrier);
rc50ms = pthread_create (&isr_worker_thread50ms , NULL, &int_thread50ms , &isr_barrier);
pthread_barrier_wait(&isr_barrier);
pthread_barrier_destroy(&isr_barrier);
return;
}
// Interrupt event handler 10ms
//
const struct sigevent *isr_handler10ms( void *area, int id ) {
if (++counter10ms == NUM_EVENTS10ms) {
counter10ms = 0;
return( &isr_event10ms );
}
else
return( NULL );
}
// this thread is dedicated to handling and managing interrupt 10ms
void *int_thread10ms (void *arg)
{
int i;
int id;
//Scheduling and priority
struct sched_param params;
int prio;
pthread_barrier_t * isr_barrier10ms;
isr_barrier10ms = (pthread_barrier_t *) arg;
counter10ms = 0;
printf(" Now in ISR thread 10ms... \n");
// perhaps boost this thread's priority here
#if THREAD_PRIO
pthread_getschedparam(pthread_self(), &prio, ¶ms);
params.sched_priority = 160;
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶ms);
#endif
// Request I/O privileges
ThreadCtl( _NTO_TCTL_IO, 0 );
// Initialize event structure
isr_event10ms.sigev_notify = SIGEV_INTR;
// Attach ISR vector
id=InterruptAttach( SYSPAGE_ENTRY(qtime)->intr, &isr_handler10ms,
NULL, 0, 0 );
for( i = 0; i < 100; ++i ) {
// Wait for ISR to wake us up
InterruptWait( 0, NULL );
if (counter10ms == 0) {
bubblesort10ms(NUM_EVENTS10ms*40);
}
}
// Disconnect the ISR handler
InterruptDetach(id);
printf(" End of ISR thread10ms... \n");
pthread_barrier_wait(isr_barrier10ms);
return 0;
}
// Interrupt event handler 20ms
//
const struct sigevent *isr_handler20ms( void *area, int id ) {
if (++counter20ms == NUM_EVENTS20ms) {
counter20ms = 0;
return( &isr_event20ms );
}
else
return( NULL );
}
// this thread is dedicated to handling and managing interrupt 20ms
void *int_thread20ms (void *arg)
{
int i;
int id;
//Scheduling and priority
struct sched_param params;
int prio;
pthread_barrier_t * isr_barrier20ms;
isr_barrier20ms = (pthread_barrier_t *) arg;
counter20ms = 0;
printf(" Now in ISR thread 20ms... \n");
// perhaps boost this thread's priority here
#if THREAD_PRIO
pthread_getschedparam(pthread_self(), &prio, ¶ms);
params.sched_priority = 140;
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶ms);
#endif
// Request I/O privileges
ThreadCtl( _NTO_TCTL_IO, 0 );
// Initialize event structure
isr_event20ms.sigev_notify = SIGEV_INTR;
// Attach ISR vector
id=InterruptAttach( SYSPAGE_ENTRY(qtime)->intr, &isr_handler20ms,
NULL, 0, 0 );
for( i = 0; i < 50; ++i ) {
// Wait for ISR to wake us up
InterruptWait( 0, NULL );
if (counter20ms == 0) {
bubblesort20ms(NUM_EVENTS20ms*20);
}
}
// Disconnect the ISR handler
InterruptDetach(id);
printf(" End of ISR thread20ms... \n");
pthread_barrier_wait(isr_barrier20ms);
return 0;
}
// Interrupt event handler 50ms
//
const struct sigevent *isr_handler50ms( void *area, int id ) {
if (++counter50ms == NUM_EVENTS50ms) {
counter50ms = 0;
return( &isr_event50ms );
}
else
return( NULL );
}
// this thread is dedicated to handling and managing interrupt 50ms
void *int_thread50ms (void *arg)
{
int i;
int id;
//Scheduling and priority
struct sched_param params;
int prio;
pthread_barrier_t * isr_barrier50ms;
isr_barrier50ms = (pthread_barrier_t *) arg;
counter50ms = 0;
printf(" Now in ISR thread 50ms... \n");
// perhaps boost this thread's priority here
#if THREAD_PRIO
pthread_getschedparam(pthread_self(), &prio, ¶ms);
params.sched_priority = 120;
pthread_setschedparam(pthread_self(), SCHED_FIFO, ¶ms);
#endif
// Request I/O privileges
ThreadCtl( _NTO_TCTL_IO, 0 );
// Initialize event structure
isr_event50ms.sigev_notify = SIGEV_INTR;
// Attach ISR vector
id=InterruptAttach( SYSPAGE_ENTRY(qtime)->intr, &isr_handler50ms,
NULL, 0, 0 );
for( i = 0; i < 20; ++i ) {
// Wait for ISR to wake us up
InterruptWait( 0, NULL );
if (counter50ms == 0) {
bubblesort50ms(NUM_EVENTS50ms*10);
}
}
// Disconnect the ISR handler
InterruptDetach(id);
printf(" End of ISR thread50ms... \n");
pthread_barrier_wait(isr_barrier50ms);
return 0;
}
Thanks a lot
Christian