/* * $Id: event.c,v 1.3 2005/06/23 22:02:10 av1-op Exp $ * * Author: Markus Stenberg <fingon@iki.fi> * * Copyright (c) 1996 Markus Stenberg * Copyright (c) 1999-2005 Kevin Stevens * All rights reserved * * Created: Tue Aug 27 19:01:55 1996 fingon * Last modified: Tue Nov 10 16:21:43 1998 fingon * */ /* Interface for creating pretty damn nasty timed events, with additional load balancing in the works. Description of the interface: void muxevent_add() Adds a new event to occur <time> ticks from now on, which calls function func with the present event as parameter, and with data as the data (also optional type can be supplied ; just makes deletion of stuff of particular type far faster, and allows nice statistics) void muxevent_initialize() Initializes the event system void muxevent_run() Runs one 'tick' of events (second, 1/10sec, whatever) int muxevent_count_type(int type) int muxevent_count_type_data(int type, void *data) int muxevent_count_data(void *data) Counts pending events (count_type is fast ; count_type_data relatively slow and count_data a dog) int muxevent_last_type() Returns # of the last type that has been used int muxevent_last_type_data(int type, void *data) Finds the event furthest in the future and returns the difference in seconds to present time (or actually in event ticks) void muxevent_gothru_type_data(int type, void *data, void (*func)(MUXEVENT *)) Executes the function func for every object in tye first_in_type queue matching type, and/or data. */ /* NOTE: This approach turns _very_ costly, if you have regularly events further than LOOKAHEAD_STACK_SIZE in the future */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <sys/types.h> #include <time.h> #include <event.h> #include "muxevent.h" #include "create.h" #include "debug.h" int muxevent_tick = 0; /* Stack of the events according to date */ static MUXEVENT **muxevent_first_in_type = NULL; /* Whole list (dual linked) */ static MUXEVENT *muxevent_list = NULL; /* List of 'free' events */ static MUXEVENT *muxevent_free_list = NULL; static int last_muxevent_type = -1; /* The main add-to-lists event handling function */ extern void prerun_event(MUXEVENT * e); extern void postrun_event(MUXEVENT * e); static void muxevent_delete(MUXEVENT *); #define Zombie(e) (e->flags & FLAG_ZOMBIE) #define LoopType(type,var) \ for (var = muxevent_first_in_type[type] ; var ; var = var->next_in_type) \ if (!Zombie(var)) #define LoopEvent(var) \ for (var = muxevent_list ; var ; var = var->next_in_main) \ if (!Zombie(var)) static void muxevent_wakeup(int fd, short event, void *arg) { MUXEVENT *e = (MUXEVENT *)arg; if(Zombie(e)) { muxevent_delete(e); return; } prerun_event(e); e->function(e); postrun_event(e); muxevent_delete(e); } void muxevent_add(int time, int flags, int type, void (*func) (MUXEVENT *), void *data, void *data2) { MUXEVENT *e; struct timeval tv; int i, spot; if (time < 1) time = 1; /* Nasty thing about the new system : we _do_ have to allocate muxevent_first_in_type dynamically. */ if (type > last_muxevent_type) { muxevent_first_in_type = realloc(muxevent_first_in_type, sizeof(MUXEVENT *) * (type + 1)); for (i = last_muxevent_type + 1; i <= type; i++) muxevent_first_in_type[i] = NULL; last_muxevent_type = type; } if (muxevent_free_list) { e = muxevent_free_list; muxevent_free_list = muxevent_free_list->next; } else Create(e, MUXEVENT, 1); e->flags = flags; e->function = func; e->data = data; e->data2 = data2; e->type = type; e->tick = muxevent_tick + time; e->next = NULL; tv.tv_sec = time; tv.tv_usec = 0; evtimer_set(&e->ev, muxevent_wakeup, e); evtimer_add(&e->ev, &tv); ADD_TO_BIDIR_LIST_HEAD(muxevent_list, prev_in_main, next_in_main, e); ADD_TO_BIDIR_LIST_HEAD(muxevent_first_in_type[type], prev_in_type, next_in_type, e); } /* Remove event */ static void muxevent_delete(MUXEVENT * e) { if(evtimer_pending(&e->ev, NULL)) { evtimer_del(&e->ev); } if (e->flags & FLAG_FREE_DATA) free((void *) e->data); if (e->flags & FLAG_FREE_DATA2) free((void *) e->data2); REMOVE_FROM_BIDIR_LIST(muxevent_list, prev_in_main, next_in_main, e); REMOVE_FROM_BIDIR_LIST(muxevent_first_in_type[(int) e->type], prev_in_type, next_in_type, e); ADD_TO_LIST_HEAD(muxevent_free_list, next, e); } /* Run the thingy */ void muxevent_run() { muxevent_tick += 1; } int muxevent_run_by_type(int type) { MUXEVENT *e; int ran = 0; if (type <= last_muxevent_type) { for (e = muxevent_first_in_type[type]; e; e = e->next_in_type) { if (!Zombie(e)) { prerun_event(e); e->function(e); postrun_event(e); e->flags |= FLAG_ZOMBIE; ran++; } } } return ran; } int muxevent_last_type() { return last_muxevent_type; } /* Initialize the events */ void muxevent_initialize() { dprintk("muxevent initializing"); } /* Event removal functions */ void muxevent_remove_data(void *data) { MUXEVENT *e; for (e = muxevent_list; e; e = e->next_in_main) if (e->data == data) e->flags |= FLAG_ZOMBIE; } void muxevent_remove_type_data(int type, void *data) { MUXEVENT *e; if (type > last_muxevent_type) return; for (e = muxevent_first_in_type[type]; e; e = e->next_in_type) if (e->data == data) e->flags |= FLAG_ZOMBIE; } void muxevent_remove_type_data2(int type, void *data) { MUXEVENT *e; if (type > last_muxevent_type) return; for (e = muxevent_first_in_type[type]; e; e = e->next_in_type) if (e->data2 == data) e->flags |= FLAG_ZOMBIE; } void muxevent_remove_type_data_data(int type, void *data, void *data2) { MUXEVENT *e; if (type > last_muxevent_type) return; for (e = muxevent_first_in_type[type]; e; e = e->next_in_type) if (e->data == data && e->data2 == data2) e->flags |= FLAG_ZOMBIE; } /* return the args of the event */ void muxevent_get_type_data(int type, void *data, int *data2) { MUXEVENT *e; LoopType(type, e) if (e->data == data) *data2 = (int) e->data2; } /* All the counting / other kinds of 'useless' functions */ int muxevent_count_type(int type) { MUXEVENT *e; int count = 0; if (type > last_muxevent_type) return count; LoopType(type, e) count++; return count; } int muxevent_count_type_data(int type, void *data) { MUXEVENT *e; int count = 0; if (type > last_muxevent_type) return count; LoopType(type, e) if (e->data == data) count++; return count; } int muxevent_count_type_data2(int type, void *data) { MUXEVENT *e; int count = 0; if (type > last_muxevent_type) return count; LoopType(type, e) if (e->data2 == data) count++; return count; } int muxevent_count_type_data_data(int type, void *data, void *data2) { MUXEVENT *e; int count = 0; if (type > last_muxevent_type) return count; LoopType(type, e) if (e->data == data && e->data2 == data2) count++; return count; } int muxevent_count_data(int type, void *data) { MUXEVENT *e; int count = 0; LoopEvent(e) if (e->data == data) count++; return count; } int muxevent_count_data_data(int type, void *data, void *data2) { MUXEVENT *e; int count = 0; LoopEvent(e) if (e->data == data && e->data2 == data2) count++; return count; } void muxevent_gothru_type_data(int type, void *data, void (*func) (MUXEVENT *)) { MUXEVENT *e; if (type > last_muxevent_type) return; LoopType(type, e) if (e->data == data) func(e); } void muxevent_gothru_type(int type, void (*func) (MUXEVENT *)) { MUXEVENT *e; if (type > last_muxevent_type) return; LoopType(type, e) func(e); } int muxevent_last_type_data(int type, void *data) { MUXEVENT *e; int last = 0, t; if (type > last_muxevent_type) return last; LoopType(type, e) if (e->data == data) if ((t = (e->tick - muxevent_tick)) > last) last = t; return last; } int muxevent_first_type_data(int type, void *data) { MUXEVENT *e; int last = -1, t; if (type > last_muxevent_type) return last; LoopType(type, e) if (e->data == data) if ((t = (e->tick - muxevent_tick)) < last || last < 0) if (t > 0) last = t; return last; } int muxevent_count_type_data_firstev(int type, void *data) { MUXEVENT *e; if (type > last_muxevent_type) return -1; LoopType(type, e) if (e->data == data) { return (int) (e->data2); } return -1; }