Multiple threads with timer interrupts(every 10ms,20ms,50ms)

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, &params);
    params.sched_priority = 160;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &params);
#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, &params);
    params.sched_priority = 140;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &params);
#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, &params);
    params.sched_priority = 120;
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &params);
#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

I’m not sure what you thing is wrong. CPU READY means a thread want the CPU but isn’t getting it, hence it normal that the 20 and 50 ms thread don’t have the CPU since the 10ms thread can steal it from them.

Also note that in the threads:

InterruptWait( 0, NULL );
if (counter10ms == 0) {
bubblesort10ms(NUM_EVENTS10ms*40);
}

There is no guaranty that counter10ms is at 0 when the thread runs after the InterruptWait.
If for some reason a higher priority thread prevents the thread from running for one interrupt time or that bubblesort takes more then 10ms.

Hi! Thanks for your fast reply.

In order to give you an example how the threads are executed I attached a screenshot of the timeline.

At marker “1” Thread 2 and 3 execute how it’s supposed to be. Thread 2 has higher priority than 3 hence Thread 3 is continued after Thread 2 is finished BUT Thread 4 does not continue.

At marker “2” theres no Thread 3 but Thread 4 works now.

I think you are right…I drew the same conclusion 5 minutes ago :slight_smile: Removed the
if (counterXXms == 0) {
after InterruptWait()

Stupid mistake :slight_smile: But now (see 2nd screenshot) some deadlines are missed, but as far as i can see no other processes use the cpu there. So whats the problem now? Are the events too late? How can i increase the priority?