Event driven design in c

A system I can think about is a subscriber-notifier model. You may have something that handles your sensors (for example, a thread that polls on it to see if something happened). When it detects something, the task should raise a mechanism in order to let the outer world be aware : this is the notification process.
On the other side, only the people who are interested in your sensor should be notified, thus, a subscription method should be here to take care of this.

Now, the hard part comes in. When the sensor handler notifies the world, it must NOT spend too much time doing so otherwise it might miss other events. Thus, it is compulsory to have a task (or thread) dedicated to the notifying process. On the other hand, the subscribers wish to have some of their data updated when such a notified event is received. This is obviously an asynchronous process and thus the subscribers will have to supply the notifier thread with a callback.
Finally, you should mark your events with timestamps, this way the receivers will know if the event they get is outdated and wether or not they should discard it.
The final thing may look like the piece of code below :


Data structures

/*
 * Some data structures to begin with
 */
struct event;
struct notifier;
struct subscription;
struct notify_sched;


typedef int (*notify_cbck)(struct event *evt, void *private);
/*
 *@type : a value to show the type of event
 *@t : the timestamp of the event
 *@value : a pointer towards the event data
 */
struct event {
    int type;
    struct timeval t; // the timestamp
    void *value;
};

/*
 * @type : the type in which the subscriber is interested
 * @cb : the callback that should be run when an event occur
 * @cb_data : the data to provide to the callback
 * @next,prev : doubly-linked list
 */
struct subscription {
    int type;
    notify_cbck cb;
    void *cb_data;
    struct subscription *next, *prev;
};

/*
 * This structure gathers the subscriptions of a given type.
 * @type : the event type
 * @subs : the subscription list
 * @mutex : a mutex to protect the list while inserting/removing subscriptions
 * @next,prev : link to other typed subscriptions
 */

struct typed_subscription {
    int type;
    struct subscription *subs;
    mutex_t mutex;
    struct typed_subscription *next, *prev;
};

/*
 * @magic : the ID of the event producer
 * @t_subs : the typed_subscription list
 * @mutex : a mutex to protect data when (un)registering new types to the producer
 * @next, prev : doubly-linked list ...
 */
struct notifier {
    int magic;
    struct typed_subscription *t_subs;
    mutex_t mutex;
    struct notifier *next, *prev;
};

/*
 * @ntf : the notifiers list
 * @mutex : a mutex to protect the ntf list
 * @th : something to identify the task that hosts the scheduler
 */
struct notify_sched {
    struct notifier *ntf;
    mutex_t mutex;
    pthread_t th; // I assume it's a classic pthread in this example.
};

    

I would assume you're owning an embedded system with access to interrupts or a major event loop in a separate thread, otherwise this isn't possible..

A basic model for event handling is here:

#define NOEVENT 0

typedef void *(*EventHandler)(void *);

void *doNothing(void *p){/*do nothing absolutely*/ return NULL; }
typedef struct _event{
  EventHandler handler;
}Event, *PEvent;

Event AllEvents[1000];
unsigned short counter = 0;
void InitEvents()
{
    LOCK(AllEvents);
    for(int i = 0; i < 1000; i++){ 
        AllEvents[i].handler = doNothing;
    }
    UNLOCK(AllEvents);
}
void AddEvent(int EventType, EventHandler ev_handler)
{
    LOCK(AllEvents);
    AllEvents[EventType].handler = ev_handler;
    UNLOCK(AllEvents);
}

void RemoveEvent(int EventType, EventHandler ev_handler)
{
   LOCK(AllEvents);
   AllEvents[EventType] = doNothing;
   UNLOCK(AllEvents); /*to safeguard the event loop*/
}

/*to be run in separate thread*/
void EventLoop()
{
   int event = NOEVENT;
   EventHandler handler;
   while(1){
       while(event == NOEVENT)event=GetEvents();
       handler = AllEvents[event].handler;
       handler();/*perform on an event*/
  }
}