Communicating with the Kernel

Top  Previous  Next

In general, high-level interrupt handlers must not call Diamond functions, such as those found in stdio.h, chan.h, sema.h, event.h, and timer.h. Often, however, a handler needs to restart a thread that is waiting for an interrupt. Three special functions that can be called from a high-level interrupt handler (and only from a high-level interrupt handler) are provided for this:

 

i_sema_signal_n

#include <c6xint.h>

void i_sema_signal_n(SEMA *s, unsigned int n);

 stand-alone

This function signals a semaphore n times from an interrupt handler. Up to n threads waiting on the semaphore can become eligible to execute once the interrupt handler terminates.

i_sema_signal

#include <c6xint.h>

void i_sema_signal(SEMA *s);

 stand-alone

This function signals a semaphore from an interrupt handler. If a thread is waiting on the semaphore, it becomes eligible to execute once the interrupt handler terminates. i_sema_signal is implemented as a macro. It is equivalent to calling i_sema_signal_n with the parameter n set to one.

i_event_set

#include <c6xint.h>

void i_event_set(EVENT *e);

 stand-alone

This function sets an event from an interrupt handler. Any threads waiting for the event become eligible to execute once the interrupt handler terminates.

 

Dragons003Do not call plain sema_signal or event_set from an interrupt handler; this will certainly cause your application to fail.

 

Always make sure that all semaphores and events used by interrupt handlers have been initialised appropriately before attaching the handler to an interrupt.

 

When an ordinary thread needs to wait for an interrupt it can simply wait for a semaphore to be signalled or an event to be set. For example:

 

#include <sema.h>

static SEMA int_sema;         // global to handler and waiting thread

 

void interrupt my_handler(void) {

   i_sema_signal(&int_sema);

}

 

main() {

   sema_init(&int_sema, 0);  // BEFORE attaching interrupt

   . . . attach my_handler to interrupt as described above

   for (;;) {

      sema_wait(&dint_sema); // Wait for a block of data

      . . . process device data

   }

}

 

As well as optionally signalling semaphores and setting events, handler code can freely read and write the contents of memory. Just remember to declare variables that are shared with the rest of an application as volatile (this is not necessary for semaphores and events).

 

Don’t be tempted into making user threads wait for interrupts by polling flags in memory though: use semaphores or events instead. In general you should avoid polling because it starves other tasks and threads of CPU cycles. Even devices that transfer only a small amount of data per interrupt can be efficiently dealt with if the handler buffers up data in memory and only signals the user thread when a complete block of data has been processed.

 

The folder <3L>Diamond\edition\Sundance\c6000\examples\interrupts\attachfn contains sample code that handles interrupts using events and semaphores. The examples both set up timer 1 to interrupt once per second. Each second, when the hardware interrupts, the interrupt handler signals a semaphore or sets an event. This wakes the main thread, which prints a message. The message includes the current value of a counter variable updated by the handler.