Here's an example that includes relevant portions of the interrupt service routine and the handling thread:
#define INTNUM 0 #include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <string.h> #include <sys/iofunc.h> #include <sys/dispatch.h> #include <sys/neutrino.h> static resmgr_connect_funcs_t connect_funcs; static resmgr_io_funcs_t io_funcs; static iofunc_attr_t attr; void * interrupt_thread (void * data) { struct sigevent event; int id; /* fill in "event" structure */ memset(&event, 0, sizeof(event)); event.sigev_notify = SIGEV_INTR; /* Enable the INTERRUPTEVENT ability */ procmgr_ability(0, PROCMGR_ADN_ROOT|PROCMGR_AOP_ALLOW|PROCMGR_AID_INTERRUPTEVENT, PROCMGR_AID_EOL); /* intNum is the desired interrupt level */ id = InterruptAttachEvent (INTNUM, &event, 0); /*... insert your code here ... */ while (1) { InterruptWait (NULL, NULL); /* do something about the interrupt, * perhaps updating some shared * structures in the resource manager * * unmask the interrupt when done */ InterruptUnmask(INTNUM, id); } } int main(int argc, char **argv) { thread_pool_attr_t pool_attr; resmgr_attr_t resmgr_attr; dispatch_t *dpp; thread_pool_t *tpp; int id; if((dpp = dispatch_create()) == NULL) { fprintf(stderr, "%s: Unable to allocate dispatch handle.\n", argv[0]); return EXIT_FAILURE; } memset(&pool_attr, 0, sizeof pool_attr); pool_attr.handle = dpp; pool_attr.context_alloc = (void *) dispatch_context_alloc; pool_attr.block_func = (void *) dispatch_block; pool_attr.unblock_func = (void *) dispatch_unblock; pool_attr.handler_func = (void *) dispatch_handler; pool_attr.context_free = (void *) dispatch_context_free; pool_attr.lo_water = 2; pool_attr.hi_water = 4; pool_attr.increment = 1; pool_attr.maximum = 50; if((tpp = thread_pool_create(&pool_attr, POOL_FLAG_EXIT_SELF)) == NULL) { fprintf(stderr, "%s: Unable to initialize thread pool.\n", argv[0]); return EXIT_FAILURE; } iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs, _RESMGR_IO_NFUNCS, &io_funcs); iofunc_attr_init(&attr, S_IFNAM | 0666, 0, 0); memset(&resmgr_attr, 0, sizeof resmgr_attr); resmgr_attr.nparts_max = 1; resmgr_attr.msg_max_size = 2048; if((id = resmgr_attach(dpp, &resmgr_attr, "/dev/sample", _FTYPE_ANY, 0, &connect_funcs, &io_funcs, &attr)) == -1) { fprintf(stderr, "%s: Unable to attach name.\n", argv[0]); return EXIT_FAILURE; } /* Start the thread that will handle interrupt events. */ pthread_create (NULL, NULL, interrupt_thread, NULL); /* Never returns */ thread_pool_start(tpp); return EXIT_SUCCESS; }
Here the interrupt_thread() function uses InterruptAttachEvent() to bind the interrupt source (intNum) to the event (passed in event), and then waits for the event to occur.
This approach has a major advantage over using a pulse. A pulse is delivered as a message to the resource manager, which means that if the resource manager's message-handling threads are busy processing requests, the pulse will be queued until a thread does a MsgReceive().
With the InterruptWait() approach, if the thread that's executing the InterruptWait() is of sufficient priority, it unblocks and runs immediately after the SIGEV_INTR is generated.