/* * callout.c * * Callout.c implements callout.h. * * Written by Manu Thambi * */ #include #include #include "callout.h" int done = FALSE; #define MAX_CALLOUT_HANDLERS 1000 /* * Simple structure for maintaining callout data. For your assignment, you should * replace this structure with an array of queues */ typedef struct callout_event_data { callout_id_t id; /* Ranges from 1 to MAX_CALLOUT_HANDLERS */ int type; callout_event_func_t f; callout_event_closure_t cl; struct callout_event_data *prev, *next; /* We implement a doubly linked list */ int ncalls; } *callout_event_t; /* All global vars are initialized to zero or NULL */ callout_event_t callout_table[CALLOUT_EVENT_LAST]; callout_event_t callout_id_table[MAX_CALLOUT_HANDLERS]; int num_callout_handlers; callout_id_t callout_register(int type, callout_event_func_t f, callout_event_closure_t c) { static unsigned next_handler = 0; /* This will be intialized the first */ /* time the function is called */ callout_event_t ce; if (f == NULL) return FALSE; if ((unsigned)type >= CALLOUT_EVENT_LAST) return CALLOUT_ID_NULL; if (num_callout_handlers == MAX_CALLOUT_HANDLERS) return CALLOUT_ID_NULL; while (callout_id_table[next_handler] != NULL) next_handler = (next_handler+1) % MAX_CALLOUT_HANDLERS; ce = (callout_event_t)malloc(sizeof(struct callout_event_data)); if (!ce) return CALLOUT_ID_NULL; ce->id = (callout_id_t)(next_handler + 1); ce->f = f; ce->cl = c; ce->type = type; ce->ncalls = 0; ce->next = callout_table[type]; if (callout_table[type] != NULL) callout_table[type]->prev = ce; ce->prev = NULL; callout_table[type] = ce; callout_id_table[next_handler] = ce; next_handler = (next_handler+1) % MAX_CALLOUT_HANDLERS; num_callout_handlers++; return ce->id; } int callout_unregister(callout_id_t h, callout_event_closure_t *c) { unsigned idx = (unsigned)h -1; callout_event_t ce; if (idx >= MAX_CALLOUT_HANDLERS) return FALSE; if (callout_id_table[idx] == NULL) return FALSE; ce = callout_id_table[idx]; if (ce->prev != NULL) ce->prev->next = ce->next; else callout_table[ce->type] = ce->next; if (ce->next != NULL) ce->next->prev = ce->prev; callout_id_table[idx] = NULL; num_callout_handlers--; if (c != NULL) *c = ce->cl; return TRUE; } int callout_getstats(callout_id_t h, int *numcalls) { unsigned idx = (unsigned)h -1; callout_event_t ce; if (idx >= MAX_CALLOUT_HANDLERS) return FALSE; if (callout_id_table[idx] == NULL) return FALSE; ce = callout_id_table[idx]; if (numcalls != NULL) *numcalls = ce->ncalls; return TRUE; } void callout_map(callout_map_func_t mapf, callout_map_closure_t cl) { int e; callout_event_t ce; if (mapf == NULL) return; for (e = 0; e < CALLOUT_EVENT_LAST; e++) for (ce = callout_table[e]; ce; ce = ce->next) (*mapf)(e, cl, ce->id, ce->cl); } void callout_boot(callout_genevent_func_t g) { unsigned e; callout_event_t ce; if (g == NULL) return; while (!done) { e = (*g)(); if (e >= CALLOUT_EVENT_LAST) continue; for (ce = callout_table[e]; ce; ce = ce->next) { ce->ncalls++; (*(ce->f))(e, ce->id, ce->cl); } } } void callout_shutdown() { done = TRUE; }