event_listener.c 3.4 KB
#include <stdio.h>
#include <limits.h>

#include <scot/scot_int.h>
#include <scot/scot_types.h>
#include <scot/event_listener.h>
#include <scot/event.h>
#include <scot/thread.h>
#include <scot/exception.h>

#define GEN_LOCAL
#include <scot/list.h>
#include <scot/stack.h>
#undef  GEN_LOCAL

#define EVENT_SOURCE_THREAD_CANCEL_WAIT_MAX INFINITE

GEN_LIST             (scot_event_cb_fptr);
GEN_STACK_FUNC_PROTO (scot_event_cb_fptr);
GEN_STACK_IMPL       (scot_event_cb_fptr);

void
scot_event_listener_init (
		struct scot_event_listener * l,
		const unsigned char          group,
		const scot_thread_entry_fptr entry_func)
{
	l->group         = group;
	l->el_entry_func = entry_func;

	SCOT_MEM_ZERO (l->cb_mappings, 
			sizeof (stack_scot_event_cb_fptr_node_t *) * UCHAR_MAX);
}

void
scot_event_listener_fini (
		struct scot_event_listener * l)
{
	int i;
   excenv_t *ee;

	TRY
	{
		if (THREAD_EQUAL (l->thread_id, THREAD_ID))
			THROW (EXC (EXC_ERROR, 102, "a event listener can't be destroyed from "
						"its main thread."));

		if (scot_event_listener_is_running (l))
			scot_event_listener_stop (l);

		for (i=0; i<UCHAR_MAX; i++)
			if (l->cb_mappings[i] != NULL)
				stack_scot_event_cb_fptr_free (l->cb_mappings[i]);
	}
	CATCH (ee)
	{
		printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__);
		forward_all_exceptions (ee);
	}
}

void
scot_event_listener_start (struct scot_event_listener * l)
{
	l->thread_handle = NEW_THREAD (l->el_entry_func, l);
}

void
scot_event_listener_stop (struct scot_event_listener * l)
{
	if (! scot_event_listener_is_running (l))
		return;
	
	if (l->thread_run_flg != 0)
	{
		END_THREAD (l->thread_handle, SCOT_EL_WAIT_THREAD_MAX);
		l->thread_run_flg = 0;
	}
}

void
scot_event_listener_restart (struct scot_event_listener * l)
{
	scot_event_listener_stop (l);
	scot_event_listener_start (l);
}

int  
scot_event_listener_is_running  (struct scot_event_listener * l)
{
	return l->thread_run_flg;
}

void
scot_event_listener_register_cb (
		struct scot_event_listener * l,
		SCOT_EVENT_NO                e,
		scot_event_cb_fptr           cb,
		void *                       extra_data)
{
   excenv_t *ee;

	TRY
	{
		if ((e >> 8) != l->group)
			THROW (EXC (EXC_ERROR, 101, 
						"[EVENT_SOURCE_REG_CB]Event not supported by listener"));

		if (l->cb_mappings[e&0x00FF] == NULL)
			l->cb_mappings[e&0x00FF] = stack_scot_event_cb_fptr_new (
					l->cb_mappings[e&0x00FF]);

		stack_scot_event_cb_fptr_push (
				l->cb_mappings[e&0x00FF], 
			(scot_event_cb_fptr *)cb);

		l->cb_extra_data[e&0x00FF] = extra_data;

		/* restart listener after adding a callback. */
		if (scot_event_listener_is_running (l) != 0)
		{
			scot_event_listener_stop (l);
			scot_event_listener_start (l);
		}
	}
	CATCH (ee)
	{
		printf ("Exception in %s (%s, %d)\n", __FUNCTION__, __FILE__, __LINE__);
		forward_all_exceptions (ee);
	}
}

void 
scot_event_listener_call_cb (
		struct scot_event_listener * l,
		struct scot_event *          e)
{
	SCOT_EVENT_NO eno = e->event;

	if (l->cb_mappings[e->event&0x00FF] != NULL)
	{
		list_scot_event_cb_fptr_node_t * anchor = 
			LIST (scot_event_cb_fptr, l->cb_mappings[e->event&0x00FF]);
		list_scot_event_cb_fptr_node_t * node   = anchor;

		while (! list_scot_event_cb_fptr_eol (anchor, node))
		{
			scot_event_cb_fptr cb;

			node = list_scot_event_cb_fptr_next (node);
			cb   = (scot_event_cb_fptr) list_scot_event_cb_fptr_retrive (node);

			if (cb (e) == SCOT_EVENT_END)
				break;
		}
	}
}