384 lines
8.7 KiB
C
Executable File
384 lines
8.7 KiB
C
Executable File
/*
|
|
* Event handler
|
|
*
|
|
* $Id: //BBN_Linux/Branch/Branch_for_Rel_TP_ASEAN_20161216/tclinux_phoenix/apps/public/linux-atm/lane/events.c#1 $
|
|
*
|
|
*/
|
|
|
|
|
|
/* System includes */
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
|
|
/* Local includes */
|
|
#include "events.h"
|
|
#include "load.h"
|
|
#include "dump.h"
|
|
#include "mem.h"
|
|
#include "timers.h"
|
|
#include "connect.h"
|
|
|
|
/* Type definitions */
|
|
typedef struct _EventList_t {
|
|
const Event_t *event;
|
|
struct _EventList_t *next;
|
|
struct _EventList_t *prev;
|
|
} EventList_t;
|
|
|
|
typedef struct _HFList_t {
|
|
const char *name;
|
|
HandlerFunc_t h;
|
|
void *funcdata;
|
|
struct _HFList_t *next;
|
|
} HFList_t;
|
|
|
|
typedef struct _FDList_t {
|
|
int fd;
|
|
void *data;
|
|
struct _FDList_t *next;
|
|
} FDList_t;
|
|
|
|
/* Local function prototypes */
|
|
static void events_init0(void);
|
|
static void events_init1(void);
|
|
static void events_dump(void);
|
|
static void events_release(void);
|
|
static void event_get_fds(fd_set *dest);
|
|
|
|
/* Data */
|
|
static const char *rcsid="$Id: //BBN_Linux/Branch/Branch_for_Rel_TP_ASEAN_20161216/tclinux_phoenix/apps/public/linux-atm/lane/events.c#1 $";
|
|
|
|
const Unit_t events_unit = {
|
|
"events",
|
|
&events_init0,
|
|
&events_init1,
|
|
&events_dump,
|
|
&events_release
|
|
};
|
|
|
|
/*static mutex_t event_mutex;*/
|
|
static EventList_t *eventhead, *eventtail;
|
|
static HFList_t *handlers[CE_MAX + 1];
|
|
static FDList_t *fdlist;
|
|
|
|
/* Functions */
|
|
|
|
/* Initialize local data */
|
|
static void
|
|
events_init0(void)
|
|
{
|
|
unsigned int i;
|
|
|
|
eventhead = NULL;
|
|
eventtail = NULL;
|
|
for (i = 0; i <= CE_MAX; i++) {
|
|
handlers[i] = NULL;
|
|
}
|
|
fdlist = NULL;
|
|
}
|
|
|
|
/* Initialization for data that needs other units */
|
|
static void
|
|
events_init1(void)
|
|
{
|
|
set_var_str(&events_unit, "version", rcsid);
|
|
Debug_unit(&events_unit, "Initialized.");
|
|
}
|
|
|
|
/* Dump status, local data etc. */
|
|
static void
|
|
events_dump(void)
|
|
{
|
|
const EventList_t *tmp;
|
|
const HFList_t *htmp;
|
|
const FDList_t *ftmp;
|
|
unsigned int i;
|
|
|
|
for (tmp = eventhead; tmp != NULL; tmp = tmp->next) {
|
|
assert(tmp->event != NULL);
|
|
assert(tmp->event->unit != NULL);
|
|
assert(tmp->event->unit->name != NULL);
|
|
Debug_unit(&events_unit, "unit %s type %s data 0x%x", tmp->event->unit->name, dump_event_type(tmp->event->type), tmp->event->data);
|
|
}
|
|
for (i = 0; i <= CE_MAX; i++) {
|
|
for (htmp = handlers[i]; htmp != NULL; htmp = htmp->next) {
|
|
Debug_unit(&events_unit, "type %s func 0x%x name %s data 0x%x", dump_event_type(i), htmp->h, htmp->name, htmp->funcdata);
|
|
}
|
|
}
|
|
for (ftmp = fdlist; ftmp != NULL; ftmp = ftmp->next) {
|
|
Debug_unit(&events_unit, "polled fd %d", ftmp->fd);
|
|
}
|
|
}
|
|
|
|
/* Release allocated memory, close files etc. */
|
|
static void
|
|
events_release(void)
|
|
{
|
|
unsigned int i;
|
|
HFList_t *htmp;
|
|
FDList_t *ftmp;
|
|
EventList_t *tmp;
|
|
|
|
/* Lock list */
|
|
for (tmp = eventhead; tmp != NULL; ) {
|
|
assert(eventhead->event != NULL);
|
|
assert(eventhead->event->unit != NULL);
|
|
assert(eventhead->event->unit->name != NULL);
|
|
Debug_unit(&events_unit, "discarding unread event, unit %s type %s data 0x%x", eventhead->event->unit->name, dump_event_type(eventhead->event->type), eventhead->event->data);
|
|
tmp = eventhead->next;
|
|
mem_free(&events_unit, eventhead->event);
|
|
mem_free(&events_unit, eventhead);
|
|
eventhead = tmp;
|
|
}
|
|
eventtail = NULL;
|
|
/* Unlock list */
|
|
for (i = 0; i <= CE_MAX; i++) {
|
|
for (htmp = handlers[i]; htmp != NULL; htmp = htmp->next) {
|
|
handlers[i] = htmp->next;
|
|
mem_free(&events_unit, htmp);
|
|
}
|
|
}
|
|
for (ftmp = fdlist; ftmp != NULL; ftmp = ftmp->next) {
|
|
printf("Closing:%d\n",ftmp->fd);
|
|
close(ftmp->fd);
|
|
fdlist = ftmp->next;
|
|
mem_free(&events_unit, ftmp);
|
|
}
|
|
}
|
|
|
|
void
|
|
add_event_handler(EventType_t type, HandlerFunc_t func, const char *name, void *funcdata)
|
|
{
|
|
HFList_t *tmp;
|
|
|
|
tmp = (HFList_t *)mem_alloc(&events_unit, sizeof(HFList_t));
|
|
tmp->name = name;
|
|
tmp->h = func;
|
|
tmp->funcdata = funcdata;
|
|
assert(type <= CE_MAX);
|
|
tmp->next = handlers[type];
|
|
|
|
handlers[type] = tmp;
|
|
}
|
|
|
|
static const char *typetable[CE_MAX + 1] = {
|
|
"New SVC",
|
|
"SVC closed",
|
|
"Data arrived",
|
|
"Timer expired",
|
|
"Dump",
|
|
"Restart",
|
|
"Termination"
|
|
};
|
|
|
|
/* Return event type as string */
|
|
const char *
|
|
dump_event_type(EventType_t type)
|
|
{
|
|
assert(type >= CE_SVC_CLOSE && type <= CE_MAX);
|
|
return typetable[type];
|
|
}
|
|
|
|
/* Get next event from queue */
|
|
const Event_t *
|
|
event_get_next(void)
|
|
{
|
|
const Event_t *event = NULL;
|
|
EventList_t *tmplist;
|
|
const FDList_t *tmp;
|
|
int poll_ret;
|
|
Timer_t *soonest;
|
|
fd_set to_select;
|
|
struct timeval *rolex;
|
|
|
|
while (eventtail == NULL && sig_hup == 0 &&
|
|
sig_usr1 == 0 && sig_alarm == 0 &&
|
|
sig_usr2 == 0) {
|
|
/* No events waiting, sleep on select() or poll() */
|
|
if (fdlist != NULL) {
|
|
soonest = timer_find_soonest(&events_unit);
|
|
if (soonest != NULL) {
|
|
rolex = (struct timeval *)mem_alloc(&events_unit,
|
|
sizeof(struct timeval));
|
|
rolex->tv_sec = soonest->alarm_time - time(NULL);
|
|
rolex->tv_usec = 0;
|
|
Debug_unit(&events_unit, "Sleeping %d s...", rolex->tv_sec);
|
|
}
|
|
else {
|
|
rolex = NULL;
|
|
Debug_unit(&events_unit, "Sleeping forever...");
|
|
}
|
|
event_get_fds(&to_select);
|
|
poll_ret = select(FD_SETSIZE, &to_select, NULL, NULL, rolex);
|
|
if (rolex)
|
|
mem_free(&events_unit,rolex);
|
|
Debug_unit(&events_unit, "Select: %d", poll_ret);
|
|
switch (poll_ret) {
|
|
case -1:
|
|
/* Error occurred */
|
|
dump_error(&events_unit, "select");
|
|
break;
|
|
case 0:
|
|
/* Timeout */
|
|
timer_ack(&events_unit, soonest);
|
|
event_put(&events_unit, CE_TIMER, (void*)soonest->data);
|
|
break;
|
|
default:
|
|
/* Data arrival / SVC creation */
|
|
Debug_unit(&events_unit,"fdlist:%d",fdlist);
|
|
for (tmp = fdlist; tmp != NULL; tmp = tmp->next) {
|
|
dump_printf(EL_DEBUG,"FD:%d",tmp->fd);
|
|
if (FD_ISSET(tmp->fd, &to_select)) {
|
|
Debug_unit(&events_unit, "Event on fd %d", tmp->fd);
|
|
conn_set_active(tmp->data, tmp->fd);
|
|
event_put(&events_unit, CE_DATA, tmp->data);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
Debug_unit(&events_unit, "No fds, restarting after 10 s");
|
|
sleep(10);
|
|
event_put(&events_unit, CE_RESTART, NULL);
|
|
}
|
|
}
|
|
if (sig_hup != 0) {
|
|
event_put(&events_unit, CE_RESTART, NULL);
|
|
sig_hup = 0;
|
|
}
|
|
if (sig_usr1 != 0) {
|
|
event_put(&events_unit, CE_DUMP, NULL);
|
|
sig_usr1 = 0;
|
|
}
|
|
if (sig_usr2 != 0) {
|
|
event_put(&events_unit, CE_EXIT, NULL);
|
|
sig_usr2 = 0;
|
|
}
|
|
if (sig_alarm != 0) {
|
|
event_put(&events_unit, CE_TIMER, NULL);
|
|
sig_alarm = 0;
|
|
}
|
|
Debug_unit(&events_unit, "get event %s", dump_event_type(eventtail->event->type));
|
|
/* Lock list */
|
|
event = eventhead->event;
|
|
if (eventhead->next != NULL) {
|
|
eventhead->next->prev = NULL;
|
|
}
|
|
else {
|
|
/* This was the last */
|
|
eventtail = NULL;
|
|
}
|
|
tmplist = eventhead;
|
|
eventhead = eventhead->next;
|
|
/* Unlock list */
|
|
mem_free(&events_unit, tmplist);
|
|
return event;
|
|
}
|
|
|
|
/* Add event to queue */
|
|
void
|
|
event_put(const Unit_t *unit, EventType_t type, void *data)
|
|
{
|
|
Event_t *event;
|
|
EventList_t *tmplist;
|
|
|
|
Debug_unit(&events_unit, "unit %s puts event %s", unit->name, dump_event_type(type));
|
|
event = (Event_t *)mem_alloc(&events_unit, sizeof(Event_t));
|
|
event->unit = unit;
|
|
event->type = type;
|
|
event->data = data;
|
|
|
|
tmplist = (EventList_t *)mem_alloc(&events_unit, sizeof(EventList_t));
|
|
tmplist->event = event;
|
|
tmplist->next = NULL;
|
|
/* Lock list */
|
|
tmplist->prev = eventtail;
|
|
|
|
if (eventtail != NULL) {
|
|
eventtail->next = tmplist;
|
|
}
|
|
else {
|
|
/* This is the first one */
|
|
eventhead = tmplist;
|
|
}
|
|
eventtail = tmplist;
|
|
/* Unlock list */
|
|
}
|
|
|
|
/* Call handlers until one returns nonzero */
|
|
int
|
|
dispatch_handlers(const Event_t *event)
|
|
{
|
|
int handled = 0;
|
|
const HFList_t *htmp;
|
|
|
|
assert(event != NULL);
|
|
for (htmp = handlers[event->type]; htmp != NULL; htmp = htmp->next) {
|
|
Debug_unit(&events_unit, "trying handler %s", htmp->name);
|
|
handled = (htmp->h(event, htmp->funcdata));
|
|
if (handled != 0) {
|
|
Debug_unit(&events_unit, "success.");
|
|
break;
|
|
}
|
|
else {
|
|
Debug_unit(&events_unit, "failed.");
|
|
}
|
|
}
|
|
return handled;
|
|
}
|
|
|
|
static void
|
|
event_get_fds(fd_set *dest)
|
|
{
|
|
FDList_t *tmp;
|
|
|
|
FD_ZERO(dest);
|
|
|
|
for(tmp = fdlist; tmp != NULL; tmp = tmp->next)
|
|
FD_SET(tmp->fd, dest);
|
|
}
|
|
|
|
void
|
|
event_add_fd(int fd, void *data)
|
|
{
|
|
FDList_t *tmp;
|
|
|
|
tmp = mem_alloc(&events_unit, sizeof(FDList_t));
|
|
tmp->fd = fd;
|
|
tmp->data = data;
|
|
tmp->next = fdlist;
|
|
fdlist = tmp;
|
|
}
|
|
|
|
void
|
|
event_remove_fd(int fd)
|
|
{
|
|
FDList_t *tmp, *prev = NULL;
|
|
|
|
for (tmp = fdlist; tmp != NULL; prev = tmp, tmp = tmp->next) {
|
|
if (tmp->fd == fd) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (tmp == NULL) {
|
|
Debug_unit(&events_unit, "Could not find fd %d for removal", fd);
|
|
return;
|
|
}
|
|
else {
|
|
if (prev != NULL) {
|
|
prev->next = tmp->next;
|
|
}
|
|
else {
|
|
fdlist = tmp->next;
|
|
}
|
|
mem_free(&events_unit, tmp);
|
|
}
|
|
}
|