[Spread-cvs] commit: r588 - in branches/experimental-4.3-threaded: daemon examples libspread libspread-util/include libspread-util/src
jschultz at spread.org
jschultz at spread.org
Tue Sep 17 13:17:05 EDT 2013
Author: jschultz
Date: 2013-09-17 13:17:05 -0400 (Tue, 17 Sep 2013)
New Revision: 588
Modified:
branches/experimental-4.3-threaded/daemon/Makefile.in
branches/experimental-4.3-threaded/examples/Makefile.in
branches/experimental-4.3-threaded/libspread-util/include/spu_events.h
branches/experimental-4.3-threaded/libspread-util/src/Makefile.in
branches/experimental-4.3-threaded/libspread-util/src/events.c
branches/experimental-4.3-threaded/libspread/Makefile.in
Log:
Build and code changes to use new events system.
Modified: branches/experimental-4.3-threaded/daemon/Makefile.in
===================================================================
--- branches/experimental-4.3-threaded/daemon/Makefile.in 2013-09-17 16:02:02 UTC (rev 587)
+++ branches/experimental-4.3-threaded/daemon/Makefile.in 2013-09-17 17:17:05 UTC (rev 588)
@@ -83,18 +83,18 @@
$(LD) -o $@ $(LDFLAGS) $(SPREADOBJS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a ../stdutil/lib/libstdutil-threaded-release.a $(LIBS)
spmonitor$(EXEEXT): $(MONITOR_OBJS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a
- $(LD) -o $@ $(LDFLAGS) $(MONITOR_OBJS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a $(LIBS)
+ $(LD) -o $@ $(LDFLAGS) $(MONITOR_OBJS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a ../stdutil/lib/libstdutil-threaded-release.a $(LIBS)
sptmonitor$(EXEEXT): $(TMONITOR_OBJS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a
- $(LD) $(THLDFLAGS) -o $@ $(TMONITOR_OBJS) $(THLIBS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a
+ $(LD) $(THLDFLAGS) -o $@ $(TMONITOR_OBJS) $(THLIBS) $(LIBSPREADUTIL_DIR)/lib/libspread-util.a ../stdutil/lib/libstdutil-threaded-release.a
testprog: spsend$(EXEEXT) sprecv$(EXEEXT)
spsend$(EXEEXT): s.o $(LIBSPREADUTIL_DIR)/lib/libspread-util.a
- $(LD) -o $@ $(LDFLAGS) s.o $(LIBSPREADUTIL_DIR)/lib/libspread-util.a $(LIBS)
+ $(LD) -o $@ $(LDFLAGS) s.o $(LIBSPREADUTIL_DIR)/lib/libspread-util.a ../stdutil/lib/libstdutil-threaded-release.a $(LIBS)
sprecv$(EXEEXT): r.o $(LIBSPREADUTIL_DIR)/lib/libspread-util.a
- $(LD) -o $@ $(LDFLAGS) r.o $(LIBSPREADUTIL_DIR)/lib/libspread-util.a $(LIBS)
+ $(LD) -o $@ $(LDFLAGS) r.o $(LIBSPREADUTIL_DIR)/lib/libspread-util.a ../stdutil/lib/libstdutil-threaded-release.a $(LIBS)
clean:
rm -f *.lo *.tlo *.to *.o *.a *.dylib $(TARGETS) spsimple_user
Modified: branches/experimental-4.3-threaded/examples/Makefile.in
===================================================================
--- branches/experimental-4.3-threaded/examples/Makefile.in 2013-09-17 16:02:02 UTC (rev 587)
+++ branches/experimental-4.3-threaded/examples/Makefile.in 2013-09-17 17:17:05 UTC (rev 588)
@@ -49,6 +49,7 @@
ENT=@ENT@
EXEEXT=@EXEEXT@
SP_LIBRARY_DIR=../libspread
+STD_LIBRARY_DIR=../stdutil/lib
TARGETS=spuser$(EXEEXT) spflooder$(EXEEXT) sptuser${EXEEXT} flush_user$(EXEEXT)
@@ -67,19 +68,19 @@
$(SHCC) $(SHCFLAGS) $(SHCPPFLAGS) -D_REENTRANT -c $< -o $*.tlo
spuser$(EXEEXT): $(SP_LIBRARY_DIR)/libspread-core.a user.o
- $(LD) -o $@ user.o $(LDFLAGS) $(SP_LIBRARY_DIR)/libspread-core.a $(LIBS)
+ $(LD) -o $@ user.o $(LDFLAGS) $(SP_LIBRARY_DIR)/libspread-core.a $(STD_LIBRARY_DIR)/libstdutil.a $(LIBS)
spflooder$(EXEEXT): $(SP_LIBRARY_DIR)/libspread-core.a flooder.o
- $(LD) -o $@ flooder.o $(LDFLAGS) $(SP_LIBRARY_DIR)/libspread-core.a $(LIBS)
+ $(LD) -o $@ flooder.o $(LDFLAGS) $(SP_LIBRARY_DIR)/libspread-core.a $(STD_LIBRARY_DIR)/libstdutil.a $(LIBS)
sptuser$(EXEEXT): user.to $(SP_LIBRARY_DIR)/libtspread-core.a
- $(LD) $(THLDFLAGS) -o $@ user.to $(SP_LIBRARY_DIR)/libtspread-core.a $(LDFLAGS) $(LIBS) $(THLIBS)
+ $(LD) $(THLDFLAGS) -o $@ user.to $(SP_LIBRARY_DIR)/libtspread-core.a $(STD_LIBRARY_DIR)/libstdutil.a $(LDFLAGS) $(LIBS) $(THLIBS)
spsimple_user$(EXEEXT): simple_user.o $(SP_LIBRARY_DIR)/libspread-core.a
- $(LD) -o $@ $(LDFLAGS) simple_user.o $(SP_LIBRARY_DIR)/libspread-core.a $(LIBS)
+ $(LD) -o $@ $(LDFLAGS) simple_user.o $(SP_LIBRARY_DIR)/libspread-core.a $(STD_LIBRARY_DIR)/libstdutil.a $(LIBS)
flush_user$(EXEEXT): $(SP_LIBRARY_DIR)/libspread.a fl_user.to
- $(LD) $(LDFLAGS) -o flush_user fl_user.to $(SP_LIBRARY_DIR)/libspread.a $(LIBS) $(THLIBS)
+ $(LD) $(LDFLAGS) -o flush_user fl_user.to $(SP_LIBRARY_DIR)/libspread.a $(STD_LIBRARY_DIR)/libstdutil.a $(LIBS) $(THLIBS)
sp_time_memb$(EXEEXT): $(SP_LIBRARY_DIR)/libspread.a sp_time_memb.o stats.o
$(LD) $(LDFLAGS) -o sp_time_memb sp_time_memb.o stats.o $(LIBS)
Modified: branches/experimental-4.3-threaded/libspread/Makefile.in
===================================================================
--- branches/experimental-4.3-threaded/libspread/Makefile.in 2013-09-17 16:02:02 UTC (rev 587)
+++ branches/experimental-4.3-threaded/libspread/Makefile.in 2013-09-17 17:17:05 UTC (rev 588)
@@ -75,7 +75,7 @@
SP_OBJ_DIR=../daemon
-TARGETS=libspread-core.a libtspread-core.a libspread.a @LIBSPSO@ @LIBSPCORESO@ @LIBTSPCORESO@
+TARGETS=libspread-core.a libtspread-core.a libspread.a #@LIBSPSO@ @LIBSPCORESO@ @LIBTSPCORESO@
LIBSP_OBJS= sp.o
Modified: branches/experimental-4.3-threaded/libspread-util/include/spu_events.h
===================================================================
--- branches/experimental-4.3-threaded/libspread-util/include/spu_events.h 2013-09-17 16:02:02 UTC (rev 587)
+++ branches/experimental-4.3-threaded/libspread-util/include/spu_events.h 2013-09-17 17:17:05 UTC (rev 588)
@@ -32,70 +32,70 @@
*
*/
+#ifndef INC_SP_EVENTS
+#define INC_SP_EVENTS
+/* Raise MAX_FD_EVENTS AND RECOMPILE events.c to handle more active
+ fd's. This number can limit the number of connections that can be
+ handled.
+*/
-#ifndef INC_SP_EVENTS
-#define INC_SP_EVENTS
+#define MAX_FD_EVENTS 2000
-/* Raise this number AND RECOMPILE events.c to handle more active FD's.
- * This number limits the number of connections that
- * can be handled.
- */
-#define MAX_FD_EVENTS 2000
+#define NUM_PRIORITY 3 /* NOTE: the priority levels must remain 0 based */
+#define LOW_PRIORITY 0
+#define MEDIUM_PRIORITY 1
+#define HIGH_PRIORITY 2
-#define NUM_PRIORITY 3
+#define NUM_FDTYPES 3 /* NOTE: the fd types must remain 0 based */
+#define READ_FD 0
+#define WRITE_FD 1
+#define EXCEPT_FD 2
-#define LOW_PRIORITY 0
-#define MEDIUM_PRIORITY 1
-#define HIGH_PRIORITY 2
+typedef struct
+{
+ long sec;
+ long usec;
-#define NUM_FDTYPES 3
+} sp_time;
-#define READ_FD 0
-#define WRITE_FD 1
-#define EXCEPT_FD 2
+/* Time routines */
+sp_time E_get_time( void );
+sp_time E_add_time( sp_time t, sp_time delta_t );
+sp_time E_sub_time( sp_time t, sp_time delta_t );
+int E_compare_time( sp_time t1, sp_time t2 );
+void E_delay( sp_time t );
-typedef struct dummy_time {
- long sec;
- long usec;
-} sp_time;
+/* Event routines */
-#ifndef NULL
-#define NULL (void *)0
-#endif
+int E_init( void );
+void E_fini( void );
-/* Event routines */
+int E_in_queue( void (* func)( int code, void *data ), int code, void *data );
+int E_queue( void (* func)( int code, void *data ), int code, void *data, sp_time delta );
+int E_queue_absolute( void (* func)( int code, void *data ), int code, void *data, sp_time absolute );
+int E_queue_periodic( void (* func)( int code, void *data ), int code, void *data, sp_time period );
+int E_dequeue( void (* func)( int code, void *data ), int code, void *data );
-int E_init(void);
-sp_time E_get_time(void);
-sp_time E_sub_time( sp_time t, sp_time delta_t );
-sp_time E_add_time( sp_time t, sp_time delta_t );
-/* if t1 > t2 then returns 1;
- if t1 < t2 then returns -1;
- if t1 == t2 then returns 0; */
-int E_compare_time( sp_time t1, sp_time t2 );
-int E_queue( void (* func)( int code, void *data ), int code, void *data,
- sp_time delta_time );
-int E_in_queue( void (* func)( int code, void *data ), int code,
- void *data );
-/* Note: This does not dispose/free the data pointed at by the void
- *data pointer */
-int E_dequeue( void (* func)( int code, void *data ), int code,
- void *data );
-void E_delay( sp_time t );
+int E_attach_fd( int fd, int fd_type, void (* func)( int fd, int code, void *data),
+ int code, void *data, int priority );
+int E_detach_fd( int fd, int fd_type );
+int E_detach_fd_priority( int fd, int fd_type, int priority );
-int E_attach_fd( int fd, int fd_type,
- void (* func)( int fd, int code, void *data), int code,
- void *data, int priority );
-int E_detach_fd( int fd, int fd_type );
-int E_detach_fd_priority( int fd, int fd_type, int priority );
-int E_set_active_threshold( int priority );
+int E_set_active_threshold( int priority );
+int E_num_active( int priority );
+
int E_activate_fd( int fd, int fd_type );
int E_deactivate_fd( int fd, int fd_type );
-int E_num_active( int priority );
-void E_handle_events(void);
-void E_exit_events(void);
+sp_time E_get_loop_time( void );
+sp_time E_update_loop_time( void );
-#endif /* INC_SP_EVENTS */
+int E_set_elevate_count( int priority, unsigned count );
+int E_get_elevate_count( int priority, unsigned *count );
+
+int E_handle_events( void );
+void E_exit_events( void );
+
+#endif
Modified: branches/experimental-4.3-threaded/libspread-util/src/Makefile.in
===================================================================
--- branches/experimental-4.3-threaded/libspread-util/src/Makefile.in 2013-09-17 16:02:02 UTC (rev 587)
+++ branches/experimental-4.3-threaded/libspread-util/src/Makefile.in 2013-09-17 17:17:05 UTC (rev 588)
@@ -27,7 +27,7 @@
LIBCOMPATVERSION=4.0
LIBVERSION=4
-PATHS=-I. -I$(top_srcdir)/src -I../include -I$(top_srcdir)/include
+PATHS=-I. -I$(top_srcdir)/src -I../include -I$(top_srcdir)/include -I../../stdutil/src -I$(top_srcdir)/../stdutil/src
CC=@CC@
LD=@LD@
@@ -60,7 +60,7 @@
ENT=@ENT@
EXEEXT=@EXEEXT@
-TARGETS=libspread-util.a libspread-util.sa @LIBSPSO@
+TARGETS=libspread-util.a libspread-util.sa #@LIBSPSO@
LIB_OBJS=alarm.o events.o memory.o data_link.o
Modified: branches/experimental-4.3-threaded/libspread-util/src/events.c
===================================================================
--- branches/experimental-4.3-threaded/libspread-util/src/events.c 2013-09-17 16:02:02 UTC (rev 587)
+++ branches/experimental-4.3-threaded/libspread-util/src/events.c 2013-09-17 17:17:05 UTC (rev 588)
@@ -1,1015 +1,2689 @@
-/*
- * The Spread Toolkit.
- *
- * The contents of this file are subject to the Spread Open-Source
- * License, Version 1.0 (the ``License''); you may not use
- * this file except in compliance with the License. You may obtain a
- * copy of the License at:
- *
- * http://www.spread.org/license/
- *
- * or in the file ``license.txt'' found in this distribution.
- *
- * Software distributed under the License is distributed on an AS IS basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Creators of Spread are:
- * Yair Amir, Michal Miskin-Amir, Jonathan Stanton, John Schultz.
- *
- * Copyright (C) 1993-2013 Spread Concepts LLC <info at spreadconcepts.com>
- *
- * All Rights Reserved.
- *
- * Major Contributor(s):
- * ---------------
- * Ryan Caudy rcaudy at gmail.com - contributions to process groups.
- * Claudiu Danilov claudiu at acm.org - scalable wide area support.
- * Cristina Nita-Rotaru crisn at cs.purdue.edu - group communication security.
- * Theo Schlossnagle jesus at omniti.com - Perl, autoconf, old skiplist.
- * Dan Schoenblum dansch at cnds.jhu.edu - Java interface.
- *
- */
+#include "arch.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
-/* Must come before any system headers as otherwise it is ignored */
-#define _GNU_SOURCE
+#ifdef ARCH_PC_WIN95
-#include "arch.h"
+# include <winsock.h>
+# include <sys/timeb.h>
-/* undef redefined variables under windows */
-#ifdef ARCH_PC_WIN95
-#undef EINTR
-#undef EAGAIN
-#undef EWOULDBLOCK
-#undef EINPROGRESS
-#undef EALREADY
-#endif
+#else
-#include <errno.h>
+# include <sys/time.h>
+# include <sys/types.h>
+# include <unistd.h>
-#ifndef ARCH_PC_WIN95
+# ifdef HAVE_LINUX
+# include <sys/epoll.h>
+# endif
-#include <time.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <dlfcn.h>
-#else /* ARCH_PC_WIN95 */
+#endif
-#include <winsock.h>
-#include <sys/timeb.h>
+#include <stdutil/stddefines.h>
+#include <stdutil/stddll.h>
+#include <stdutil/stdskl.h>
-#endif /* ARCH_PC_WIN95 */
-
-#include <string.h>
#include "spu_events.h"
-#include "spu_objects.h" /* For memory */
-#include "spu_memory.h" /* for memory */
-#include "spu_alarm.h"
-typedef struct dummy_t_event {
- sp_time t;
- void (* func)( int code, void *data );
- int code;
- void *data;
- struct dummy_t_event *next;
-} time_event;
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-typedef struct dummy_fd_event {
- int fd;
- int fd_type;
- void (* func)( mailbox mbox, int code, void *data );
- int code;
- void *data;
- int active; /* true if active, false if inactive */
-} fd_event;
+#define E_MIN_PRIORITY 0
-typedef struct dummy_fd_queue {
- int num_fds;
- int num_active_fds;
- fd_event events[MAX_FD_EVENTS];
-} fd_queue;
+#define E_DELTA_TIMER 3
+#define E_ABSOLUTE_TIMER 4
+#define E_PERIODIC_TIMER 5
-static sp_time E_get_time_monotonic(void);
+#define E_EPOLL_INITIAL_SIZE 32
-static time_event *Time_queue;
-static sp_time Now;
+enum
+{
+ E_BUG = INT_MIN,
+ E_NOT_IMPLEMENTED,
+ E_NO_SYS,
+ E_SYS_FAILURE,
+ E_ALLOC_FAILURE,
+ E_INTERRUPTED,
+ E_TOO_MANY_FILES,
+ E_INVALID_PARAM,
+ E_DEADEND,
-static fd_queue Fd_queue[NUM_PRIORITY];
-static fd_set Fd_mask[NUM_FDTYPES];
-static int Active_priority;
-static int Exit_events;
+ E_UNKNOWN = -1,
+ E_REPOPULATE = 1,
-enum ev_type {
- NULL_EVENT_t = 0,
- TIME_EVENT_t,
- FD_EVENT_t,
};
-#define EVENT_RECORD_NAMELEN 128
+typedef enum
+{
+ E_BACKEND_UNSPECIFIED,
+ E_BACKEND_SELECT,
+ E_BACKEND_EPOLL,
-struct event_record {
- sp_time dur;
- enum ev_type type;
- char funcname[EVENT_RECORD_NAMELEN];
- fd_event fev;
- time_event tev;
-};
+} E_backend_type;
-int Slow_events_max = 5;
-int Slow_events_active = 0;
-static struct event_record Slow_events[5];
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-int E_init(void)
+typedef stdint32 E_watch_id;
+typedef int E_watch_type;
+typedef int E_priority;
+typedef void (*E_callback_fcn)();
+typedef void (*E_fd_callback_fcn)(int fd, int code, void *data);
+typedef void (*E_time_callback_fcn)(int code, void *data);
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+typedef struct
{
- int i,ret;
-
- Time_queue = NULL;
+ E_watch_type watch_type;
+ E_priority priority;
- ret = Mem_init_object(TIME_EVENT, "time_event", sizeof(time_event), 100,0);
- if (ret < 0)
- {
- Alarm(EXIT, "E_Init: Failure to Initialize TIME_EVENT memory objects\n");
- }
+ E_callback_fcn callback_fcn;
+ int callback_code;
+ void *callback_data;
- for ( i=0; i < NUM_PRIORITY; i++ )
- {
- Fd_queue[i].num_fds = 0;
- Fd_queue[i].num_active_fds = 0;
- }
- for ( i=0; i < NUM_FDTYPES; i++ )
- {
- FD_ZERO( &Fd_mask[i] );
- }
- Active_priority = LOW_PRIORITY;
+ stdbool noticed; /* if this watch has triggered and generated a notice, then notice_it is the */
+ stdit notice_it; /* position in events->priorities[priority].notices */
- E_get_time_monotonic();
+} E_watch;
- Alarm( EVENTS, "E_init: went ok\n");
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- return( 0 );
-}
+typedef struct
+{
+ E_watch w; /* NOTE: must remain first member, so we can freely cast between E_watch* and E_time_watch* */
-sp_time E_get_time(void)
+ sp_time timeout;
+
+ stdit time_watches_it; /* position in events->time_watches */
+
+ stdbool in_timeouts; /* whether or not in events->timeouts; if so, then timeouts_it is the */
+ stdit timeouts_it; /* position in events->timeouts */
+
+} E_time_watch;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+typedef struct
{
- sp_time t;
+ E_watch w; /* NOTE: must remain first member, so we can freely cast between E_watch* and E_fd_watch* */
-#ifndef ARCH_PC_WIN95
- struct timeval read_time;
+ int fd;
+ stdbool active; /* whether or not this fd watch is currently active (i.e. - watched/queried) or not */
+ stdit fd_watches_it; /* position in events->fd_watches */
-#if HAVE_STRUCT_TIMEZONE
- struct timezone dummy_tz;
-#else
- sp_time dummy_tz;
+} E_fd_watch;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+typedef struct
+{
+ E_priority priority; /* priority associated with this lvl */
+ stddll notices; /* <E_watch*>: watches at this priority that have triggered / been noticed */
+
+ unsigned starve_thresh; /* threshold that determines if/when this priority elevates to "preempt" execution */
+ unsigned starve_cnter; /* increments once for every non-preempt notice dispatch from a different priority */
+
+ int num_active_fd_watches; /* track how many active fd watches are registered at this particular priority */
+
+ void *backend_lvl_info; /* backend specific information for this priority */
+
+} E_priority_info;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+#ifdef HAVE_LINUX
+
+typedef struct
+{
+ struct epoll_event *events; /* array into which to receive results from epoll_wait */
+ int num_events; /* size of events array */
+
+} E_epoll_info;
+
+typedef struct
+{
+ int epoll_fd; /* epoll fd that is tracking all fds with priority >= associated lvl */
+ int num_poll_fds; /* # of fds we currently have registered with epoll_fd */
+
+} E_epoll_lvl_info;
+
#endif
- int ret;
- ret = gettimeofday( &read_time, &dummy_tz );
- if ( ret < 0 ) Alarm( EXIT, "E_get_time: gettimeofday problems.\n" );
- t.sec = read_time.tv_sec;
- t.usec = read_time.tv_usec;
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-#else /* ARCH_PC_WIN95 */
+typedef struct
+{
+ fd_set tmp_fd_sets[NUM_FDTYPES]; /* select sets used as a scratch pad when calling select */
- struct _timeb timebuffer;
+} E_select_info;
- _ftime( &timebuffer );
+typedef struct
+{
+ fd_set fd_sets[NUM_FDTYPES]; /* select sets of all fds with priority >= associated lvl of the associated type */
+ stdskl fd_skls[NUM_FDTYPES]; /* <int -> E_fd_watch*>: sparse representation of same fds (ordered by E_fd_cmp) */
- t.sec = timebuffer.time;
- t.usec = timebuffer.millitm;
- t.usec *= 1000;
+} E_select_lvl_info;
-#endif /* ARCH_PC_WIN95 */
-#if 0
- Alarm( EVENTS, "E_get_time: time is (%d, %d)\n", t.sec, t.usec);
-#endif
- return ( t );
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+typedef struct
+{
+ stdbool keep_running; /* whether or not the current call to E_events_handle_events() should keep looping */
+ E_priority max_priority; /* highest priority lvl in the system */
+ E_priority active_threshold; /* minimum priority lvl that is currently being monitored */
+
+ sp_time last_clock_time; /* most recent time returned from the clock for this system */
+ sp_time last_loop_time; /* most recent time when we returned from an OS query */
+
+ stdskl time_watches; /* <E_time_watch* -> nil>: ordered by E_time_watch_ptr_cmp: [fcn, code, data] */
+ stdskl fd_watches; /* <int -> E_fd_watch*>: fds ordered by E_fd_cmp */
+
+ E_priority_info *priorities; /* array of size max_priority: notification Qs and other per priority lvl info */
+
+ /* notification generation mechanisms */
+
+ stdskl timeouts; /* <sp_time -> E_time_watch*>: absolute timeouts ordered by E_sp_time_cmp */
+
+ E_backend_type backend_type; /* method used by this sytem to query fds */
+ void *backend_info; /* backend specific info for this system */
+
+} E_events;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_fd_cmp(const void *left, const void *right);
+static int E_time_watch_ptr_cmp(const void *left, const void *right);
+static int E_sp_time_cmp(const void *left, const void *right);
+static sp_time E_get_time_low(void);
+
+static int E_events_init(E_events *events);
+static void E_events_fini(E_events *events);
+
+static stdbool E_events_is_valid(const E_events *events);
+
+static void E_events_exit_events(E_events *events);
+static E_fd_watch *E_events_get_fd_watch(E_events *events, int fd, E_watch_type fd_type, stdit *sit);
+
+static sp_time E_events_get_time(E_events *events);
+static sp_time E_events_get_loop_time(E_events *events);
+static sp_time E_events_update_loop_time(E_events *events);
+
+static int E_events_handle_events(E_events *events);
+static int E_events_populate_priority_queues(E_events *events, E_priority dispatch_lvl);
+static int E_events_handle_starvation(E_events *events);
+static int E_events_dispatch_notice(E_events *events, E_priority dispatch_lvl);
+
+static int E_events_create_timer(E_events *e, sp_time TO, E_watch_type t, E_time_callback_fcn f, int code, void *d, E_priority p);
+static int E_events_attach_fd(E_events *e, int fd, E_watch_type t, E_fd_callback_fcn f, int code, void *d, E_priority p);
+static void E_events_cancel_watch(E_events *events, E_watch *watch);
+
+static int E_events_in_queue(E_events *events, E_time_callback_fcn fcn, int code, void *data);
+static int E_events_queue(E_events *events, E_time_callback_fcn fcn, int code, void *data, sp_time delta_time);
+static int E_events_queue_absolute(E_events *events, E_time_callback_fcn fcn, int code, void *data, sp_time absolute_time);
+static int E_events_queue_periodic(E_events *events, E_time_callback_fcn fcn, int code, void *data, sp_time periodic_time);
+static int E_events_dequeue(E_events *events, E_time_callback_fcn fcn, int code, void *data);
+static int E_events_detach_fd(E_events *events, int fd, E_watch_type fd_type);
+static int E_events_detach_fd_priority(E_events *events, int fd, E_watch_type fd_type, E_priority priority);
+
+static int E_events_set_active_threshold(E_events *events, E_priority priority);
+static int E_events_num_active(E_events *events, E_priority priority);
+static int E_events_activate_fd(E_events *events, int fd, E_watch_type fd_type);
+static int E_events_deactivate_fd(E_events *events, int fd, E_watch_type fd_type);
+
+static int E_events_set_elevate_count(E_events *events, E_priority priority, unsigned count);
+static int E_events_get_elevate_count(E_events *events, E_priority priority, unsigned *count);
+
+static int E_events_select_init(E_events *events);
+static void E_events_select_fini(E_events *events);
+static int E_events_select_activate_watch(E_events *events, E_fd_watch *fd_watch);
+static int E_events_select_deactivate_watch(E_events *events, E_fd_watch *fd_watch);
+static int E_events_select_query(E_events *events, E_priority query_lvl, const sp_time *delta_timeout, E_priority *queried_lvl);
+
+static int E_events_epoll_init(E_events *events);
+static void E_events_epoll_fini(E_events *events);
+static int E_events_epoll_activate_watch(E_events *events, E_fd_watch *fd_watch);
+static int E_events_epoll_deactivate_watch(E_events *events, E_fd_watch *fd_watch);
+static int E_events_epoll_query(E_events *events, E_priority query_lvl, const sp_time *delta_timeout, E_priority *queried_lvl);
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static E_events Events; /* implicit event system for public E_* calls */
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_fd_cmp(const void *left,
+ const void *right)
+{
+ return *(int*) left - *(int*) right;
}
-static sp_time E_get_time_monotonic(void)
-#ifdef HAVE_CLOCK_GETTIME_CLOCK_MONOTONIC
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_time_watch_ptr_cmp(const void *left,
+ const void *right)
{
- struct timespec t;
+ E_time_watch *left_watch = *(E_time_watch**) left;
+ E_time_watch *right_watch = *(E_time_watch**) right;
+ int ret = 0;
- if (clock_gettime(CLOCK_MONOTONIC, &t) != 0) {
- Alarm( EXIT, "E_get_time_monotonic: clock_gettime problems: %d '%s'\n", errno, strerror(errno) );
+ if (left_watch->w.callback_fcn < right_watch->w.callback_fcn) { ret = -1;
+ } else if (left_watch->w.callback_fcn > right_watch->w.callback_fcn) { ret = 1;
+ } else if (left_watch->w.callback_code < right_watch->w.callback_code) { ret = -1;
+ } else if (left_watch->w.callback_code > right_watch->w.callback_code) { ret = 1;
+ } else if (left_watch->w.callback_data < right_watch->w.callback_data) { ret = -1;
+ } else if (left_watch->w.callback_data > right_watch->w.callback_data) { ret = 1;
}
- Now.sec = t.tv_sec;
- Now.usec = (t.tv_nsec + 500) / 1000;
+ return ret;
+}
- return Now;
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_sp_time_cmp(const void *left,
+ const void *right)
+{
+ return E_compare_time(*(const sp_time*) left, *(const sp_time*) right);
}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static sp_time E_get_time_low(void)
+#ifdef ARCH_PC_WIN95
+{
+ sp_time ret;
+ struct _timeb t;
+
+ _ftime(&t);
+
+ ret.sec = t.time;
+ ret.usec = (long) t.millitm * 1000;
+
+ return ret;
+}
#else
{
- Now = E_get_time();
+ sp_time ret;
+ struct timeval t;
- return Now;
+ gettimeofday(&t, NULL);
+
+ ret.sec = t.tv_sec;
+ ret.usec = t.tv_usec;
+
+ return ret;
}
#endif
-sp_time E_sub_time( sp_time t, sp_time delta_t )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_init(E_events *events)
{
- sp_time res;
+ E_priority_info *info;
+ E_priority priority;
+ E_backend_type backend_type;
+ int ret = 0;
- res.sec = t.sec - delta_t.sec;
- res.usec = t.usec - delta_t.usec;
- if ( res.usec < 0 )
- {
- res.usec = res.usec + 1000000;
- res.sec--;
- }
- if ( res.sec < 0 ) Alarm( EVENTS, "E_sub_time: negative time result.\n");
- return ( res );
+ memset(events, 0, sizeof(*events));
+
+ events->keep_running = STDFALSE; /* NOTE: only set in E_events_handle_events; indicates loop is running */
+ events->max_priority = HIGH_PRIORITY;
+ events->active_threshold = LOW_PRIORITY;
+
+ events->last_loop_time = events->last_clock_time = E_get_time_low();
+
+ if (stdskl_construct(&events->time_watches, sizeof(E_time_watch*), 0, E_time_watch_ptr_cmp) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ if (stdskl_construct(&events->fd_watches, sizeof(int), sizeof(E_fd_watch*), E_fd_cmp) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_TIME_WATCHES;
+ }
+
+ if ((events->priorities = (E_priority_info*) calloc(events->max_priority + 1, sizeof(E_priority_info))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_FD_WATCHES;
+ }
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+
+ info = &events->priorities[priority];
+ info->priority = priority;
+
+ if (stddll_construct(&info->notices, sizeof(E_watch*)) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_PRIORITIES;
+ }
+
+ info->starve_thresh = 0;
+ info->starve_cnter = 0;
+ info->num_active_fd_watches = 0;
+ info->backend_lvl_info = NULL;
+ }
+
+ if (stdskl_construct(&events->timeouts, sizeof(sp_time), sizeof(E_time_watch*), E_sp_time_cmp) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_PRIORITIES;
+ }
+
+ events->backend_type = E_BACKEND_UNSPECIFIED;
+
+#ifdef HAVE_LINUX
+ backend_type = E_BACKEND_EPOLL;
+#else
+ backend_type = E_BACKEND_SELECT;
+#endif
+
+ switch (backend_type) {
+
+ case E_BACKEND_SELECT:
+ ret = E_events_select_init(events);
+ break;
+
+ case E_BACKEND_EPOLL:
+ ret = E_events_epoll_init(events);
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ break;
+ }
+
+ if (ret != 0) {
+ goto FAIL_TIMEOUTS;
+ }
+
+ if (!E_events_is_valid(events)) {
+ assert(0);
+ }
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL_TIMEOUTS:
+ stdskl_destruct(&events->timeouts);
+
+ FAIL_PRIORITIES:
+ while (priority-- != E_MIN_PRIORITY) {
+ stddll_destruct(&events->priorities[priority].notices);
+ }
+
+ free(events->priorities);
+
+ FAIL_FD_WATCHES:
+ stdskl_destruct(&events->fd_watches);
+
+ FAIL_TIME_WATCHES:
+ stdskl_destruct(&events->time_watches);
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ return ret;
}
-sp_time E_add_time( sp_time t, sp_time delta_t )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static void E_events_fini(E_events *events)
{
- sp_time res;
+ E_priority priority;
+ stdit sit;
+
+ switch (events->backend_type) {
- res.sec = t.sec + delta_t.sec;
- res.usec = t.usec + delta_t.usec;
- if ( res.usec > 1000000 )
- {
- res.usec = res.usec - 1000000;
- res.sec++;
- }
- return ( res );
+ case E_BACKEND_SELECT:
+ E_events_select_fini(events);
+ break;
+
+ case E_BACKEND_EPOLL:
+ E_events_epoll_fini(events);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ stdskl_destruct(&events->timeouts);
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+ stddll_destruct(&events->priorities[priority].notices);
+ }
+
+ free(events->priorities);
+
+ for (stdskl_begin(&events->fd_watches, &sit); !stdskl_is_end(&events->fd_watches, &sit); stdskl_it_next(&sit)) {
+ free(*(E_fd_watch**) stdskl_it_val(&sit));
+ }
+
+ stdskl_destruct(&events->fd_watches);
+
+ for (stdskl_begin(&events->time_watches, &sit); !stdskl_is_end(&events->time_watches, &sit); stdskl_it_next(&sit)) {
+ free(*(E_time_watch**) stdskl_it_key(&sit));
+ }
+
+ stdskl_destruct(&events->time_watches);
+ memset(events, 0, sizeof(*events));
}
-int E_compare_time( sp_time t1, sp_time t2 )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static stdbool E_events_is_valid(const E_events *events)
{
- if ( t1.sec > t2.sec ) return ( 1 );
- else if ( t1.sec < t2.sec ) return ( -1 );
- else if ( t1.usec > t2.usec ) return ( 1 );
- else if ( t1.usec < t2.usec ) return ( -1 );
- else return ( 0 );
+ return STDTRUE;
}
-int E_queue( void (* func)( int code, void *data ), int code, void *data,
- sp_time delta_time )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static void E_events_exit_events(E_events *events)
{
- time_event *t_pre;
- time_event *t_post;
- time_event *t_e;
- int inserted;
- int deleted;
- int compare;
+ events->keep_running = STDFALSE;
+}
- t_e = new( TIME_EVENT );
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- t_e->t = E_add_time( E_get_time_monotonic(), delta_time );
- t_e->func = func;
- t_e->code = code;
- t_e->data = data;
- deleted = 0;
- inserted = 0;
+static E_fd_watch *E_events_get_fd_watch(E_events *events,
+ int fd,
+ E_watch_type fd_type,
+ stdit *sit)
+{
+ E_fd_watch *fd_watch;
- if( Time_queue != NULL )
- {
- if( Time_queue->func == t_e->func &&
- Time_queue->data == t_e->data &&
- Time_queue->code == t_e->code )
- {
- t_pre = Time_queue;
- Time_queue = Time_queue->next;
- dispose( t_pre );
- deleted = 1;
- Alarm( EVENTS, "E_queue: dequeued a (first) simillar event\n" );
- }
- }
- if( Time_queue == NULL )
- {
- t_e->next = NULL;
- Time_queue = t_e;
- Alarm( EVENTS, "E_queue: (only) event queued func 0x%x code %d data 0x%x in future (%u:%u)\n",t_e->func,t_e->code, t_e->data, delta_time.sec, delta_time.usec );
- return( 0 );
- }else{
- compare = E_compare_time ( t_e->t, Time_queue->t );
- if( compare < 0 )
- {
- t_e->next = Time_queue;
- Time_queue = t_e;
- inserted = 1;
- Alarm( EVENTS, "E_queue: (first) event queued func 0x%x code %d data 0x%x in future (%u:%u)\n",t_e->func,t_e->code, t_e->data, delta_time.sec,delta_time.usec );
- }
- }
- t_pre = Time_queue ;
- t_post = Time_queue->next;
- while ( t_post != NULL && ( !inserted || !deleted ) )
- {
- if( t_post->func == t_e->func &&
- t_post->data == t_e->data &&
- t_post->code == t_e->code )
- {
- t_pre->next = t_post->next;
- dispose( t_post );
- t_post = t_pre->next;
- deleted = 1;
- Alarm( EVENTS, "E_queue: dequeued a simillar event\n" );
- continue;
- }
+ for (stdskl_lowerb(&events->fd_watches, sit, &fd); !stdskl_is_end(&events->fd_watches, sit); stdskl_it_next(sit)) {
- if ( !inserted )
- {
- compare = E_compare_time ( t_e->t, t_post->t );
- if( compare < 0 )
- {
- t_pre->next = t_e;
- t_e->next = t_post;
- inserted = 1;
- Alarm( EVENTS, "E_queue: event queued for func 0x%x code %d data 0x%x in future (%u:%u)\n",t_e->func,t_e->code, t_e->data, delta_time.sec, delta_time.usec );
- }
- }
+ fd_watch = *(E_fd_watch**) stdskl_it_val(sit);
- t_pre = t_post;
- t_post = t_post->next;
- }
+ if (fd_watch->fd != fd) { /* no such watch */
+ break;
+ }
- if( !inserted )
- {
- t_pre->next = t_e;
- t_e->next = NULL;
- Alarm( EVENTS, "E_queue: (last) event queued func 0x%x code %d data 0x%x in future (%u:%u)\n",t_e->func,t_e->code, t_e->data, delta_time.sec,delta_time.usec );
- }
+ if (fd_watch->w.watch_type == fd_type) { /* exact match */
+ return fd_watch;
+ }
+ }
- return( 0 );
+ return NULL;
}
-int E_dequeue( void (* func)( int code, void *data ), int code,
- void *data )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static sp_time E_events_get_time(E_events *events)
{
- time_event *t_pre;
- time_event *t_ptr;
+ return events->last_clock_time = E_get_time_low();
+}
- if( Time_queue == NULL )
- {
- Alarm( EVENTS, "E_dequeue: no such event\n" );
- return( -1 );
- }
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- if( Time_queue->func == func &&
- Time_queue->data == data &&
- Time_queue->code == code )
- {
- t_ptr = Time_queue;
- Time_queue = Time_queue->next;
- dispose( t_ptr );
- Alarm( EVENTS, "E_dequeue: first event dequeued func 0x%x code %d data 0x%x\n",func,code, data);
- return( 0 );
- }
+static sp_time E_events_get_loop_time(E_events *events)
+{
+ return events->last_loop_time;
+}
- t_pre = Time_queue;
- while ( t_pre->next != NULL )
- {
- t_ptr = t_pre->next;
- if( t_ptr->func == func &&
- t_ptr->data == data &&
- t_ptr->code == code )
- {
- t_pre->next = t_ptr->next;
- dispose( t_ptr );
- Alarm( EVENTS, "E_dequeue: event dequeued func 0x%x code %d data 0x%x\n",func,code, data);
- return( 0 );
- }
- t_pre = t_ptr;
- }
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- Alarm( EVENTS, "E_dequeue: no such event\n" );
- return( -1 );
+static sp_time E_events_update_loop_time(E_events *events)
+{
+ return events->last_loop_time = E_events_get_time(events);
}
-int E_in_queue( void (* func)( int code, void *data ), int code,
- void *data )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_handle_events(E_events *events)
{
- time_event *t_pre;
- time_event *t_ptr;
+ int ret = 0;
+ E_priority dispatch_lvl = events->max_priority;
+ E_priority starve_lvl;
- if( Time_queue == NULL )
- {
- Alarm( EVENTS, "E_in_queue: no such event\n" );
- return( 0 );
- }
+ events->keep_running = STDTRUE;
- if( Time_queue->func == func &&
- Time_queue->data == data &&
- Time_queue->code == code )
- {
- Alarm( EVENTS, "E_in_queue: found event in queue func 0x%x code %d data 0x%x\n",func,code, data);
- return( 1 );
- }
+ do {
- t_pre = Time_queue;
- while ( t_pre->next != NULL )
- {
- t_ptr = t_pre->next;
- if( t_ptr->func == func &&
- t_ptr->data == data &&
- t_ptr->code == code )
- {
- Alarm( EVENTS, "E_in_queue: found event in queue func 0x%x code %d data 0x%x\n",func,code, data);
- return(1);
- }
- t_pre = t_ptr;
- }
+ /* efficiently query watches for new notices */
- Alarm( EVENTS, "E_in_queue: no such event\n" );
- return( 0 );
+ if ((ret = E_events_populate_priority_queues(events, dispatch_lvl)) != 0) {
+ goto FAIL;
+ }
+
+ /* handle any "left over" starvation from previous iterations */
+
+ if ((ret = E_events_handle_starvation(events)) != 0) {
+
+ if (ret == E_REPOPULATE) { /* need to repopulate priority queues to ensure we aren't starving empty levels */
+ ret = 0;
+ continue; /* NOTE: should only happen here if in a starved callback the user lowered active_threshold */
+ }
+
+ goto FAIL;
+ }
+
+ /* find the highest non-empty priority */
+
+ for (dispatch_lvl = events->max_priority;
+ dispatch_lvl >= events->active_threshold && stddll_empty(&events->priorities[dispatch_lvl].notices);
+ --dispatch_lvl);
+
+ /* dispatch some notices from dispatch_lvl */
+
+ while (events->keep_running && dispatch_lvl >= events->active_threshold && !stddll_empty(&events->priorities[dispatch_lvl].notices)) {
+
+ if ((ret = E_events_dispatch_notice(events, dispatch_lvl)) != 0) {
+ goto FAIL;
+ }
+
+ /* increment starvation counts for other priorities */
+
+ for (starve_lvl = events->max_priority; starve_lvl >= events->active_threshold; --starve_lvl) {
+
+ if (starve_lvl != dispatch_lvl &&
+ events->priorities[starve_lvl].starve_thresh != 0 &&
+ events->priorities[starve_lvl].num_active_fd_watches != 0) {
+ ++events->priorities[starve_lvl].starve_cnter;
+ }
+ }
+
+ /* handle any starvation */
+
+ if ((ret = E_events_handle_starvation(events)) != 0) {
+
+ if (ret == E_REPOPULATE) { /* need to repopulate priority queues to ensure we aren't starving empty levels */
+ ret = 0;
+ continue;
+ }
+
+ goto FAIL;
+ }
+ }
+
+ } while (events->keep_running);
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ assert(ret != 0 && ret != E_REPOPULATE);
+
+ END:
+ return ret;
}
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-void E_delay( sp_time t )
+static int E_events_populate_priority_queues(E_events *events,
+ E_priority dispatch_lvl)
{
- struct timeval tmp_t;
+ E_priority starve_lvl;
+ E_priority query_lvl;
+ E_priority queried_lvl = events->max_priority;
+ E_watch *watch;
+ sp_time timeout_dmy;
+ sp_time *timeout = &timeout_dmy;
+ const sp_time *abs_timeout;
+ E_priority tmp_lvl;
+ stdit sit;
+ stdit qit;
+ int ret;
- tmp_t.tv_sec = t.sec;
- tmp_t.tv_usec = t.usec;
+ /* We postpone querying a non-empty priority level's (and all lower
+ levels too) fds until its notification queue is completely
+ drained. This approach also allows us to use the smallest query
+ sets possible, which often speeds up queries and processing their
+ results.
-#ifndef ARCH_PC_WIN95
- if (select(0, NULL, NULL, NULL, &tmp_t ) < 0)
- {
- Alarm( EVENTS, "E_delay: select delay returned error: %s\n", strerror(errno));
+ However, we may lower the level to which we query in order to
+ check for potentially starving notices at those lower levels. We
+ may also lower the level to which we query for performance
+ reasons. For example, select()ing on 10 fds is only 30% more
+ expensive than selecting on 1 fd. So, it may make sense for
+ certain backend implementations to further lower the query level
+ in certain cases.
+ */
+
+ /* find the lowest priority lvl that we must query due to potential starvation */
+
+ for (starve_lvl = tmp_lvl = events->max_priority; tmp_lvl >= events->active_threshold; --tmp_lvl) {
+
+ if (events->priorities[tmp_lvl].starve_thresh != 0 && /* starvation protection enabled */
+ events->priorities[tmp_lvl].starve_cnter >= events->priorities[tmp_lvl].starve_thresh && /* starvation threshold reached */
+ stddll_empty(&events->priorities[tmp_lvl].notices)) { /* empty -> potential starvation */
+
+ starve_lvl = tmp_lvl;
+ }
+ }
+
+ /* dispatch_lvl was the highest non-empty priority the last time we dispatched notices */
+ /* if we didn't fully drain dispatch_lvl then just query higher priorities */
+
+ /* NOTE: dispatch_lvl can go below active_threshold if user raises
+ the threshold in a callback or if there are no notices left
+ */
+
+ assert(dispatch_lvl <= events->max_priority && dispatch_lvl >= E_MIN_PRIORITY - 1);
+
+ if (dispatch_lvl < events->active_threshold) {
+ query_lvl = events->active_threshold;
+
+ } else {
+ query_lvl = (!stddll_empty(&events->priorities[dispatch_lvl].notices) ? dispatch_lvl + 1 : dispatch_lvl);
+ }
+
+ /* query the minimum between what dispatch_lvl indicates and what starvation requires */
+
+ query_lvl = STDMIN(query_lvl, starve_lvl);
+ assert(query_lvl <= events->max_priority && query_lvl >= events->active_threshold && query_lvl >= E_MIN_PRIORITY);
+
+ /* figure out an appropriate (delta) timeout and query backend implementation */
+
+ do {
+
+ /* if we are querying a priority lvl higher than the lowest possible -> use a zero timeout */
+
+ if (query_lvl != events->active_threshold) {
+
+ timeout->sec = 0;
+ timeout->usec = 0;
+
+ } else { /* else calculate an appropriate timeout */
+
+ abs_timeout = NULL;
+
+ for (stdskl_begin(&events->timeouts, &sit); !stdskl_is_end(&events->timeouts, &sit); stdskl_it_next(&sit)) {
+
+ watch = *(E_watch**) stdskl_it_val(&sit);
+
+ if (watch->priority < events->active_threshold) {
+ continue; /* NOTE: don't allow watches that we will ignore anyway to wake us early */
}
-#else /* ARCH_PC_WIN95 */
- SleepEx( tmp_t.tv_sec*1000+tmp_t.tv_usec/1000, 0 );
-#endif /* ARCH_PC_WIN95 */
+ abs_timeout = (const sp_time*) stdskl_it_key(&sit);
+ break;
+ }
+
+ if (abs_timeout != NULL) {
+ E_events_update_loop_time(events);
+
+ timeout->sec = abs_timeout->sec - events->last_loop_time.sec;
+ timeout->usec = abs_timeout->usec - events->last_loop_time.usec;
+
+ if (timeout->usec < 0) {
+ timeout->usec += 1000000;
+ --timeout->sec;
+ }
+
+ assert(timeout->usec >= 0 && timeout->usec < 1000000);
+
+ if (timeout->sec < 0) { /* earliest timeout has already expired */
+ timeout->sec = 0;
+ timeout->usec = 0;
+ }
+
+ } else {
+ /* NOTE: backend query mechanism must return an error if not watching any fds to avoid sleeping forever */
+ timeout = NULL;
+ }
+ }
+
+ switch (events->backend_type) {
+
+ case E_BACKEND_SELECT:
+ ret = E_events_select_query(events, query_lvl, timeout, &queried_lvl);
+ break;
+
+ case E_BACKEND_EPOLL:
+ ret = E_events_epoll_query(events, query_lvl, timeout, &queried_lvl);
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ break;
+ }
+
+ } while (ret == E_INTERRUPTED); /* loop while interrupted */
+
+ if (ret != 0) {
+ goto FAIL;
+ }
+
+ assert(queried_lvl <= events->max_priority && queried_lvl >= events->active_threshold && queried_lvl <= query_lvl);
+
+ /* generate timeout notices and trim timeouts queue */
+
+ E_events_update_loop_time(events); /* update events->last_loop_time */
+ stdskl_upperb(&events->timeouts, &qit, &events->last_loop_time); /* search for end of tripped timeouts */
+
+ for (stdskl_begin(&events->timeouts, &sit); !stdskl_it_eq(&sit, &qit); stdskl_it_next(&sit)) {
+
+ watch = *(E_watch**) stdskl_it_val(&sit);
+ assert(!watch->noticed);
+
+ if (stddll_push_back(&events->priorities[watch->priority].notices, &watch)) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ watch->noticed = STDTRUE;
+ stddll_last(&events->priorities[watch->priority].notices, &watch->notice_it);
+
+ ((E_time_watch*) watch)->in_timeouts = STDFALSE; /* removed from timeouts immediately below */
+ }
+
+ stdskl_erase_seq(&events->timeouts, stdskl_begin(&events->timeouts, &sit), &qit);
+
+ /* reset starvation counters on all queried levels that are still empty after the query */
+
+ for (tmp_lvl = events->max_priority; tmp_lvl >= queried_lvl; --tmp_lvl) {
+
+ if (events->priorities[tmp_lvl].starve_thresh != 0 && /* starvation protection enabled */
+ events->priorities[tmp_lvl].starve_cnter >= events->priorities[tmp_lvl].starve_thresh && /* starvation threshold reached */
+ stddll_empty(&events->priorities[tmp_lvl].notices)) { /* no new notices from query */
+
+ events->priorities[tmp_lvl].starve_cnter = 0; /* reset the starvation counter */
+ }
+ }
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ return ret;
}
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-void E_print_slow_event( struct event_record *ev )
+static int E_events_handle_starvation(E_events *events)
{
+ E_priority starve_lvl;
+ int ret = 0;
- if (ev->type == NULL_EVENT_t)
- return;
+ /* iterate over all active events->priorities */
- Alarmp( SPLOG_PRINT, SYSTEM, "Slow Event: %s \ttook %d.%06d sec:", &ev->funcname[0], ev->dur.sec, ev->dur.usec);
- if (ev->type == FD_EVENT_t)
- Alarmp( SPLOG_PRINT | SPLOG_NODATE, SYSTEM, "fd event: fd (%d) type (%d) funcptr (0x%x) code (%d) data ptr (0x%x) active (%d)\n", ev->fev.fd, ev->fev.fd_type, ev->fev.func, ev->fev.code, ev->fev.data, ev->fev.active);
- if (ev->type == TIME_EVENT_t)
- Alarmp( SPLOG_PRINT | SPLOG_NODATE, SYSTEM, "time event: funcptr (0x%x) code (%d) data ptr (0x%x)\n", ev->tev.func, ev->tev.code, ev->tev.data);
+ for (starve_lvl = events->max_priority; events->keep_running && starve_lvl >= events->active_threshold; --starve_lvl) {
+
+ if (events->priorities[starve_lvl].starve_thresh != 0 && /* starvation protection enabled */
+ events->priorities[starve_lvl].starve_cnter >= events->priorities[starve_lvl].starve_thresh) { /* starvation threshold reached */
+
+ if (!stddll_empty(&events->priorities[starve_lvl].notices)) { /* dispatch starving priority */
+
+ if ((ret = E_events_dispatch_notice(events, starve_lvl)) != 0) { /* resets starvation counter */
+ break;
+ }
+
+ } else {
+ ret = E_REPOPULATE; /* this notice queue is empty: we need to try to populate this priority */
+ break;
+ }
+ }
+ }
- return;
+ return ret;
}
-void E_print_slow_events(void)
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_dispatch_notice(E_events *events,
+ E_priority dispatch_lvl)
{
- int i;
+ int ret = 0;
+ E_watch *watch;
+ stdit dit;
- for ( i = 0; i < Slow_events_active; i++ ) {
- E_print_slow_event( &Slow_events[i] );
+ assert(dispatch_lvl <= events->max_priority && dispatch_lvl >= events->active_threshold && events->active_threshold >= E_MIN_PRIORITY);
+ assert(!stddll_empty(&events->priorities[dispatch_lvl].notices));
+
+ /* pop the head notice off of dispatch_lvl */
+
+ watch = *(E_watch**) stddll_it_val(stddll_begin(&events->priorities[dispatch_lvl].notices, &dit));
+ assert(watch->priority == dispatch_lvl && watch->noticed && stddll_it_eq(&dit, &watch->notice_it));
+
+ stddll_erase(&events->priorities[dispatch_lvl].notices, &dit);
+ watch->noticed = STDFALSE;
+
+ events->priorities[dispatch_lvl].starve_cnter = 0; /* reset starvation counter on this level as we are about to "feed" it */
+
+ /* execute the callback depending on watch type */
+
+ switch (watch->watch_type) {
+
+ case READ_FD:
+ case WRITE_FD:
+ case EXCEPT_FD:
+ ((E_fd_callback_fcn) watch->callback_fcn)(((E_fd_watch*) watch)->fd, watch->callback_code, watch->callback_data);
+ break;
+
+ case E_DELTA_TIMER:
+ case E_PERIODIC_TIMER:
+ case E_ABSOLUTE_TIMER: {
+ E_time_watch *t_watch = (E_time_watch*) watch;
+ E_watch watch_cpy;
+
+ assert(!t_watch->in_timeouts);
+
+ if (watch->watch_type != E_PERIODIC_TIMER) {
+
+ watch_cpy = *watch; /* copy cb params */
+ E_events_cancel_watch(events, watch); /* one shot watch: remove it */
+ watch = &watch_cpy; /* watch no longer valid -> cpy is valid */
+
+ } else {
+ /* TODO: should we use E_events_get_time(),
+ events->last_clock_time or events->last_loop_time or
+ something even more complicated that keeps the periodic timer
+ on schedule according to its periodicity (i.e. - when the
+ next picket should fall based on initial time of scheduling)?
+ */
+
+ sp_time wake_time = E_add_time(E_events_get_time(events), t_watch->timeout);
+
+ if (stdskl_insert(&events->timeouts, &t_watch->timeouts_it, &wake_time, &watch, STDFALSE)) { /* periodic watch: reschedule it */
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ t_watch->in_timeouts = STDTRUE;
}
+ ((E_time_callback_fcn) watch->callback_fcn)(watch->callback_code, watch->callback_data);
+ break;
+ }
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+ }
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ return ret;
}
-#ifdef DISABLE_FUNCTION_NAME_LOOKUP
-void E_lookup_function_name( void* fptr, char *fname, int fname_len )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_create_timer(E_events * events,
+ sp_time timeout,
+ E_watch_type timer_type,
+ E_time_callback_fcn fcn,
+ int code,
+ void * data,
+ E_priority priority)
{
- snprintf( fname, fname_len -1, "LOOKUP_FAIL_0x%p", fptr);
- /* NOTE: snprintf is safe if fname is too short, the string will be truncated and null terminated */
- return;
+ E_time_watch *time_watch = NULL;
+ E_time_watch *tmp_watch = NULL;
+ sp_time next_timeout = { 0, 0 };
+ int ret = 0;
+
+ /* validate input */
+
+ if (E_compare_time(next_timeout, timeout) > 0 || /* negative timeouts are illegal for all timer types */
+ priority > events->max_priority ||
+ priority < E_MIN_PRIORITY) {
+ ret = E_INVALID_PARAM;
+ goto FAIL;
+ }
+
+ /* figure out first expiration for this timer */
+
+ switch (timer_type) {
+
+ case E_DELTA_TIMER:
+ case E_PERIODIC_TIMER:
+ /* TODO: should we use E_events_get_time(), events->last_clock_time or events->last_loop_time?
+ Remember about !events->keep_running case: before or not during an event loop who knows how old those last two are?
+ */
+ next_timeout = E_add_time(E_events_get_time(events), timeout);
+ break;
+
+ case E_ABSOLUTE_TIMER:
+ /* TODO: if we start using a monotonic timer how does that relate to the wall clock? */
+ next_timeout = timeout;
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG; /* NOTE: currently only internal code calls this fcn and it should call with a valid timer type */
+ goto FAIL;
+ }
+
+ /* allocate and initialize timer */
+
+ if ((time_watch = (E_time_watch*) calloc(1, sizeof(E_time_watch))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ time_watch->w.watch_type = timer_type;
+ time_watch->w.priority = priority;
+ time_watch->w.callback_fcn = fcn;
+ time_watch->w.callback_code = code;
+ time_watch->w.callback_data = data;
+ time_watch->w.noticed = STDFALSE;
+ time_watch->timeout = timeout;
+ time_watch->in_timeouts = STDFALSE; /* updated below */
+
+ /* look up any pre-existing timer with same parameters and insertion spot for new timer */
+
+ if (!stdskl_is_end(&events->time_watches, stdskl_lowerb(&events->time_watches, &time_watch->time_watches_it, &time_watch))) {
+
+ tmp_watch = *(E_time_watch**) stdskl_it_key(&time_watch->time_watches_it);
+
+ /* if a pre-existing watch exists: cancel old watch */
+
+ if (E_time_watch_ptr_cmp(&time_watch, &tmp_watch) == 0) {
+ stdskl_it_next(&time_watch->time_watches_it); /* NOTE: advance so iterator remains valid after cancellation */
+ E_events_cancel_watch(events, (E_watch*) tmp_watch);
+ }
+ }
+
+ /* insert into main timer lookup table using events->time_watches_it as a hint */
+
+ if (stdskl_insert(&events->time_watches, &time_watch->time_watches_it, &time_watch, NULL, STDTRUE)) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_TIME_WATCH;
+ }
+
+ /* insert into events->timeouts */
+
+ if (stdskl_insert(&events->timeouts, &time_watch->timeouts_it, &next_timeout, &time_watch, STDFALSE)) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_TIME_WATCHES;
+ }
+
+ time_watch->in_timeouts = STDTRUE;
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL_TIME_WATCHES:
+ stdskl_erase(&events->time_watches, &time_watch->time_watches_it);
+
+ FAIL_TIME_WATCH:
+ free(time_watch);
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ return ret;
}
-#else
-void E_lookup_function_name( void* fptr, char *fname, int fname_len )
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_attach_fd(E_events * events,
+ int fd,
+ E_watch_type fd_type,
+ E_fd_callback_fcn fcn,
+ int code,
+ void * data,
+ int priority)
{
- Dl_info dli;
- int ret, len;
+ E_fd_watch *fd_watch;
+ E_fd_watch *tmp_watch;
+ int ret = 0;
- ret = dladdr(fptr, &dli);
+ /* validate input */
- if (ret == 0) {
- /* Failed call */
- len = snprintf( fname, fname_len -1, "LOOKUP_FAIL_0x%p", fptr);
- /* NOTE: snprintf is safe if fname is too short, the string will be truncated and null terminated */
- } else {
- if (dli.dli_sname == NULL) {
- len = snprintf( fname, fname_len -1, "NO_NAME");
- } else {
- len = strlen(dli.dli_sname);
- strncpy( fname, dli.dli_sname, fname_len - 1);
- if (len >= fname_len) {
- /* function name too long to store, so truncate it */
- fname[fname_len -1] = '\0';
- }
- }
- }
- return;
+ if (fd < 0 ||
+ priority > events->max_priority ||
+ priority < E_MIN_PRIORITY ||
+ fd < 0) {
+ ret = E_INVALID_PARAM;
+ goto FAIL;
+ }
+
+ switch (fd_type) {
+
+ case READ_FD:
+ case WRITE_FD:
+ case EXCEPT_FD:
+ break;
+
+ default:
+ ret = E_INVALID_PARAM;
+ goto FAIL;
+ }
+
+ /* allocate and initialize new fd_watch */
+
+ if ((fd_watch = (E_fd_watch*) calloc(1, sizeof(E_fd_watch))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ fd_watch->w.watch_type = fd_type;
+ fd_watch->w.priority = priority;
+ fd_watch->w.callback_fcn = fcn;
+ fd_watch->w.callback_code = code;
+ fd_watch->w.callback_data = data;
+ fd_watch->w.noticed = STDFALSE;
+ fd_watch->fd = fd;
+ fd_watch->active = STDFALSE; /* updated below */
+
+ /* find insertion point and cancel any previously existing watch with same parameters */
+
+ if ((tmp_watch = E_events_get_fd_watch(events, fd, fd_type, &fd_watch->fd_watches_it)) != NULL) {
+ stdskl_it_next(&fd_watch->fd_watches_it); /* NOTE: advance iterator here so it remains valid after cancellation */
+ E_events_cancel_watch(events, (E_watch*) tmp_watch);
+ }
+
+ /* insert into events->fd_watches using events->fd_watches_it as a hint */
+
+ if (stdskl_insert(&events->fd_watches, &fd_watch->fd_watches_it, &fd, &fd_watch, STDTRUE) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_FD_WATCH;
+ }
+
+ /* insert into backend specific monitoring mechanism */
+
+ switch (events->backend_type) {
+
+ case E_BACKEND_SELECT:
+ ret = E_events_select_activate_watch(events, fd_watch);
+ break;
+
+ case E_BACKEND_EPOLL:
+ ret = E_events_epoll_activate_watch(events, fd_watch);
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ break;
+ }
+
+ if (ret != 0) {
+ goto FAIL_FD_WATCHES;
+ }
+
+ fd_watch->active = STDTRUE;
+ ++events->priorities[priority].num_active_fd_watches;
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL_FD_WATCHES:
+ stdskl_erase(&events->fd_watches, &fd_watch->fd_watches_it);
+
+ FAIL_FD_WATCH:
+ free(fd_watch);
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ return ret;
}
-#endif
-void E_time_events( sp_time start, sp_time stop, fd_event *fev, time_event *tev)
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static void E_events_cancel_watch(E_events *events,
+ E_watch * watch)
{
- sp_time ev_dur;
- int slot,i;
+ /* remove any notice on this watch */
+ if (watch->noticed) {
+ stddll_erase(&events->priorities[watch->priority].notices, &watch->notice_it);
+ watch->noticed = STDFALSE;
+ }
- if ( (fev != NULL && tev != NULL) || (fev == NULL && tev == NULL) ) {
- Alarm( EXIT, "E_time_events: Bug! called with invalid fev (0x%x) and tev (0x%x) pointers. Exactly one must be non NULL\n", fev, tev);
+ /* remove the watch from its containers based on its type */
+
+ switch (watch->watch_type) {
+
+ case READ_FD:
+ case WRITE_FD:
+ case EXCEPT_FD: {
+ E_fd_watch *fd_watch = (E_fd_watch*) watch;
+
+ stdskl_erase(&events->fd_watches, &fd_watch->fd_watches_it);
+
+ if (fd_watch->active) {
+
+ switch (events->backend_type) {
+
+ case E_BACKEND_SELECT:
+ E_events_select_deactivate_watch(events, fd_watch); /* TODO: should we look at return value or not? */
+ break;
+
+ case E_BACKEND_EPOLL:
+ E_events_epoll_deactivate_watch(events, fd_watch); /* TODO: should we look at return value or not? */
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ fd_watch->active = STDFALSE;
+ --events->priorities[watch->priority].num_active_fd_watches;
}
- ev_dur = E_sub_time( stop, start );
- if ( Slow_events_active != 0 && E_compare_time( ev_dur, Slow_events[Slow_events_active-1].dur) <= 0 ) {
- /* Fast event so skip */
- return;
- } else {
- if ( Slow_events_active == 0 ) {
- slot = 0;
- } else {
- /* this event is slower then at least one current slow_events so it gets added */
- slot = Slow_events_active -1;
- i = slot -1;
- while (i >= 0 && E_compare_time( ev_dur, Slow_events[i].dur) > 0) {
- slot=i;
- i--;
- }
- }
- /* slot is now the slot holding the new location of this slow event. */
- Alarmp( SPLOG_DEBUG, EVENTS, "DEBUG: Currently %d events stored -- Insert slow event (dur %d.%06d) into slot %d. Prev duration %d.%06d\n", Slow_events_active, ev_dur.sec, ev_dur.usec, slot, Slow_events[slot].dur.sec, Slow_events[slot].dur.usec);
+ break;
+ }
- if (slot < Slow_events_max -1)
- memmove( &Slow_events[slot+1], &Slow_events[slot], (Slow_events_max - slot - 1) * sizeof(struct event_record));
- Slow_events[slot].dur = ev_dur;
- if (fev == NULL) {
- Slow_events[slot].type = TIME_EVENT_t;
- E_lookup_function_name( tev->func, &Slow_events[slot].funcname[0], EVENT_RECORD_NAMELEN);
- Slow_events[slot].tev = *tev;
- } else if (tev == NULL) {
- Slow_events[slot].type = FD_EVENT_t;
- E_lookup_function_name( fev->func, &Slow_events[slot].funcname[0], EVENT_RECORD_NAMELEN);
- Slow_events[slot].fev = *fev;
- }
+ case E_DELTA_TIMER:
+ case E_ABSOLUTE_TIMER:
+ case E_PERIODIC_TIMER: {
+ E_time_watch *time_watch = (E_time_watch*) watch;
-
- if (Slow_events_active < Slow_events_max)
- Slow_events_active++;
+ stdskl_erase(&events->time_watches, &time_watch->time_watches_it);
+ if (time_watch->in_timeouts) {
+ stdskl_erase(&events->timeouts, &time_watch->timeouts_it);
+ time_watch->in_timeouts = STDFALSE;
}
- return;
+ break;
+ }
+
+ default:
+ assert(0);
+ break;
+ }
+
+ /* deallocate the watch */
+
+ free(watch);
}
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-int E_attach_fd( int fd, int fd_type,
- void (* func)( mailbox mbox, int code, void *data ),
- int code, void *data, int priority )
+static int E_events_in_queue(E_events *events,
+ E_time_callback_fcn fcn,
+ int code,
+ void *data)
{
- int num_fds;
- int j;
+ E_time_watch time_watch_impl;
+ E_time_watch *time_watch = &time_watch_impl;
+ stdit sit;
- if( priority < 0 || priority > NUM_PRIORITY )
- {
- Alarm( PRINT, "E_attach_fd: invalid priority %d for fd %d with fd_type %d\n", priority, fd, fd_type );
- return( -1 );
- }
- if( fd_type < 0 || fd_type > NUM_FDTYPES )
- {
- Alarm( PRINT, "E_attach_fd: invalid fd_type %d for fd %d with priority %d\n", fd_type, fd, priority );
- return( -1 );
- }
-#ifndef ARCH_PC_WIN95
- /* Windows bug: Reports FD_SETSIZE of 64 but select works on all
- * fd's even ones with numbers greater then 64.
- */
- if( fd < 0 || fd > FD_SETSIZE )
- {
- Alarm( PRINT, "E_attach_fd: invalid fd %d (max %d) with fd_type %d with priority %d\n", fd, FD_SETSIZE, fd_type, priority );
- return( -1 );
- }
-#endif
- for( j=0; j < Fd_queue[priority].num_fds; j++ )
- {
- if( ( Fd_queue[priority].events[j].fd == fd ) && ( Fd_queue[priority].events[j].fd_type == fd_type ) )
- {
- Fd_queue[priority].events[j].func = func;
- Fd_queue[priority].events[j].code = code;
- Fd_queue[priority].events[j].data = data;
- if ( !(Fd_queue[priority].events[j].active) )
- Fd_queue[priority].num_active_fds++;
- Fd_queue[priority].events[j].active = TRUE;
- Alarm( EVENTS,
- "E_attach_fd: fd %d with type %d exists & replaced & activated\n", fd, fd_type );
- return( 1 );
- }
- }
- num_fds = Fd_queue[priority].num_fds;
+ /* look up any existing time watch and cancel it */
- if ( num_fds == MAX_FD_EVENTS ) {
- Alarm( PRINT, "E_attach_fd: Reached Maximum number of events. Recompile with larger MAX_FD_EVENTS\n");
- return( -1 );
- }
- Fd_queue[priority].events[num_fds].fd = fd;
- Fd_queue[priority].events[num_fds].fd_type = fd_type;
- Fd_queue[priority].events[num_fds].func = func;
- Fd_queue[priority].events[num_fds].code = code;
- Fd_queue[priority].events[num_fds].data = data;
- Fd_queue[priority].events[num_fds].active = TRUE;
- Fd_queue[priority].num_fds++;
- Fd_queue[priority].num_active_fds++;
- if( Active_priority <= priority ) FD_SET( fd, &Fd_mask[fd_type] );
+ time_watch->w.callback_fcn = fcn;
+ time_watch->w.callback_code = code;
+ time_watch->w.callback_data = data;
- Alarm( EVENTS, "E_attach_fd: fd %d, fd_type %d, code %d, data 0x%x, priority %d Active_priority %d\n",
- fd, fd_type, code, data, priority, Active_priority );
+ return !stdskl_is_end(&events->time_watches, stdskl_find(&events->time_watches, &sit, &time_watch));
+}
- return( 0 );
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_queue(E_events *events,
+ E_time_callback_fcn fcn,
+ int code,
+ void *data,
+ sp_time delta_time)
+{
+ return E_events_create_timer(events, delta_time, E_DELTA_TIMER, fcn, code, data, LOW_PRIORITY);
}
-int E_detach_fd( int fd, int fd_type )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_queue_absolute(E_events *events,
+ E_time_callback_fcn fcn,
+ int code,
+ void *data,
+ sp_time absolute_time)
{
- int i;
- int found;
+ return E_events_create_timer(events, absolute_time, E_ABSOLUTE_TIMER, fcn, code, data, LOW_PRIORITY);
+}
- if( fd_type < 0 || fd_type > NUM_FDTYPES )
- {
- Alarm( PRINT, "E_detach_fd: invalid fd_type %d for fd %d\n", fd_type, fd );
- return( -1 );
- }
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- found = 0;
- for( i=0; i < NUM_PRIORITY; i++ )
- {
- if( E_detach_fd_priority( fd, fd_type, i ) == 0 )
- {
- found = 1;
- }
- }
+static int E_events_queue_periodic(E_events *events,
+ E_time_callback_fcn fcn,
+ int code,
+ void *data,
+ sp_time periodic_time)
+{
+ return E_events_create_timer(events, periodic_time, E_PERIODIC_TIMER, fcn, code, data, LOW_PRIORITY);
+}
- if( ! found ) return( -1 );
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- return( 0 );
+static int E_events_dequeue(E_events *events,
+ E_time_callback_fcn fcn,
+ int code,
+ void *data)
+{
+ int ret = -1; /* NOTE: backwards compatability */
+ E_time_watch time_watch_impl;
+ E_time_watch *time_watch = &time_watch_impl;
+ stdit sit;
+
+ /* look up any existing time watch and cancel it */
+
+ time_watch->w.callback_fcn = fcn;
+ time_watch->w.callback_code = code;
+ time_watch->w.callback_data = data;
+
+ if (!stdskl_is_end(&events->time_watches, stdskl_find(&events->time_watches, &sit, &time_watch))) {
+ E_events_cancel_watch(events, *(E_watch**) stdskl_it_key(&sit));
+ ret = 0;
+ }
+
+ return ret;
}
-int E_detach_fd_priority( int fd, int fd_type, int priority )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_detach_fd(E_events * events,
+ int fd,
+ E_watch_type fd_type)
{
- int i;
- int found;
+ int ret = -1; /* NOTE: backwards compatability */
+ E_fd_watch *fd_watch;
+ stdit sit;
- if( fd_type < 0 || fd_type > NUM_FDTYPES )
- {
- Alarm( PRINT, "E_detach_fd: invalid fd_type %d for fd %d\n", fd_type, fd );
- return( -1 );
- }
+ /* cancel any previously existing watch */
- found = 0;
- for( i=0; i < Fd_queue[priority].num_fds; i++ )
- {
- if( ( Fd_queue[priority].events[i].fd == fd ) && ( Fd_queue[priority].events[i].fd_type == fd_type ) )
- {
- if (Fd_queue[priority].events[i].active)
- Fd_queue[priority].num_active_fds--;
- Fd_queue[priority].num_fds--;
- Fd_queue[priority].events[i] = Fd_queue[priority].events[Fd_queue[priority].num_fds];
+ if ((fd_watch = E_events_get_fd_watch(events, fd, fd_type, &sit)) != NULL) {
+ E_events_cancel_watch(events, (E_watch*) fd_watch);
+ ret = 0;
+ }
- FD_CLR( fd, &Fd_mask[fd_type] );
- found = 1;
+ return ret;
- break;
- }
- }
+#if 0
+ /* TODO: implement specific priority levels? */
- if( ! found ) return( -1 );
+ int ret = -1; /* NOTE: backwards compatability */
+ E_priority priority;
- return( 0 );
+ /* cancel any previously existing watch */
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+
+ if (E_events_detach_fd(events, fd, fd_type, priority) == 0) {
+ ret = 0;
+ }
+ }
+
+ return ret;
+#endif
}
-int E_deactivate_fd( int fd, int fd_type )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_detach_fd_priority(E_events *events,
+ int fd,
+ E_watch_type fd_type,
+ E_priority priority)
{
- int i,j;
- int found;
+ return E_events_detach_fd(events, fd, fd_type); /* TODO: implement specific priority lvls? */
+}
- if( fd_type < 0 || fd_type > NUM_FDTYPES )
- {
- Alarm( PRINT, "E_deactivate_fd: invalid fd_type %d for fd %d\n", fd_type, fd );
- return( -1 );
- }
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- found = 0;
+static int E_events_set_active_threshold(E_events *events,
+ E_priority priority)
+{
+ if (priority < E_MIN_PRIORITY || priority > events->max_priority) {
+ return -1; /* backwards compatability */
+ }
- for( i=0; i < NUM_PRIORITY; i++ )
- for( j=0; j < Fd_queue[i].num_fds; j++ )
- {
- if( ( Fd_queue[i].events[j].fd == fd ) && ( Fd_queue[i].events[j].fd_type == fd_type ) )
- {
- if (Fd_queue[i].events[j].active)
- Fd_queue[i].num_active_fds--;
- Fd_queue[i].events[j].active = FALSE;
- FD_CLR( fd, &Fd_mask[fd_type] );
- found = 1;
+ events->active_threshold = priority;
- break; /* from the j for only */
- }
- }
+ return priority; /* backwards compatability */
+}
- if( ! found ) return( -1 );
- return( 0 );
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_num_active(E_events *events,
+ E_priority priority)
+{
+ if (priority < E_MIN_PRIORITY || priority > events->max_priority) {
+ return -1; /* backwards compatability */
+ }
+
+ return events->priorities[priority].num_active_fd_watches;
}
-int E_activate_fd( int fd, int fd_type )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_activate_fd(E_events * events,
+ int fd,
+ E_watch_type fd_type)
{
- int i,j;
- int found;
+ E_fd_watch *fd_watch;
+ stdit sit;
+ int ret = -1; /* backwards compatability */
- if( fd_type < 0 || fd_type > NUM_FDTYPES )
- {
- Alarm( PRINT, "E_activate_fd: invalid fd_type %d for fd %d\n", fd_type, fd );
- return( -1 );
- }
+ if ((fd_watch = E_events_get_fd_watch(events, fd, fd_type, &sit)) != NULL) {
- found = 0;
+ ret = 0;
- for( i=0; i < NUM_PRIORITY; i++ )
- for( j=0; j < Fd_queue[i].num_fds; j++ )
- {
- if( ( Fd_queue[i].events[j].fd == fd ) && ( Fd_queue[i].events[j].fd_type == fd_type ) )
- {
- if ( !(Fd_queue[i].events[j].active) )
- Fd_queue[i].num_active_fds++;
- Fd_queue[i].events[j].active = TRUE;
- if( i >= Active_priority ) FD_SET( fd, &Fd_mask[ fd_type ] );
- found = 1;
+ if (!fd_watch->active) {
+
+ switch (events->backend_type) {
+
+ case E_BACKEND_SELECT:
+ ret = E_events_select_activate_watch(events, fd_watch);
+ break;
+
+ case E_BACKEND_EPOLL:
+ ret = E_events_epoll_activate_watch(events, fd_watch);
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ break;
+ }
- break; /* from the j for only */
- }
- }
+ if (ret == 0) {
+ fd_watch->active = STDTRUE;
+ ++events->priorities[fd_watch->w.priority].num_active_fd_watches;
+ }
+ }
+ }
- if( ! found ) return( -1 );
- return( 0 );
+ return ret;
}
-int E_set_active_threshold( int priority )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_deactivate_fd(E_events * events,
+ int fd,
+ E_watch_type fd_type)
{
- int fd_type;
- int i,j;
+ E_fd_watch *fd_watch;
+ stdit sit;
+ int ret = -1; /* backwards compatability */
- if( priority < 0 || priority > NUM_PRIORITY )
- {
- Alarm( PRINT, "E_set_active_threshold: invalid priority %d\n", priority );
- return( -1 );
- }
+ if ((fd_watch = E_events_get_fd_watch(events, fd, fd_type, &sit)) != NULL) {
- if( priority == Active_priority ) return( priority );
+ ret = 0;
- Active_priority = priority;
- for ( i=0; i < NUM_FDTYPES; i++ )
- {
- FD_ZERO( &Fd_mask[i] );
- }
+ if (fd_watch->active) {
+
+ switch (events->backend_type) {
+
+ case E_BACKEND_SELECT:
+ E_events_select_deactivate_watch(events, fd_watch); /* TODO: should we look at return value or not? */
+ break;
+
+ case E_BACKEND_EPOLL:
+ E_events_epoll_deactivate_watch(events, fd_watch); /* TODO: should we look at return value or not? */
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ break;
+ }
- for( i = priority; i < NUM_PRIORITY; i++ )
- for( j=0; j < Fd_queue[i].num_fds; j++ )
- {
- fd_type = Fd_queue[i].events[j].fd_type;
- if (Fd_queue[i].events[j].active)
- FD_SET( Fd_queue[i].events[j].fd, &Fd_mask[fd_type] );
- }
+ --events->priorities[fd_watch->w.priority].num_active_fd_watches;
+ fd_watch->active = STDFALSE;
+ }
+ }
- Alarm( EVENTS, "E_set_active_threshold: changed to %d\n",Active_priority);
+ return ret;
+}
- return( priority );
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_set_elevate_count(E_events *events,
+ E_priority priority,
+ unsigned count)
+{
+ if (priority < E_MIN_PRIORITY || priority > events->max_priority) {
+ return E_INVALID_PARAM;
+ }
+
+ if ((events->priorities[priority].starve_thresh = count) == 0) {
+ events->priorities[priority].starve_cnter = 0;
+ }
+
+ return 0;
}
-int E_num_active( int priority )
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_get_elevate_count(E_events *events,
+ E_priority priority,
+ unsigned *count)
{
- if( priority < 0 || priority > NUM_PRIORITY )
- {
- Alarm( PRINT, "E_num_active: invalid priority %d\n", priority );
- return( -1 );
- }
- return( Fd_queue[priority].num_active_fds );
+ if (priority < E_MIN_PRIORITY || priority > events->max_priority) {
+ return E_INVALID_PARAM;
+ }
+
+ *count = events->priorities[priority].starve_thresh;
+
+ return 0;
}
-void E_handle_events(void)
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_select_init(E_events *events)
{
-static int Round_robin = 0;
-static const sp_time long_timeout = { 10000, 0};
-static const sp_time zero_sec = { 0, 0};
-#ifdef BADCLOCK
-static const sp_time mili_sec = { 0, 1000};
- int clock_sync;
+ int priority;
+ E_select_info * info;
+ E_select_lvl_info *lvl_info;
+ E_watch_type fd_type;
+ int ret = 0;
+
+ assert(events->backend_type == E_BACKEND_UNSPECIFIED);
+
+ if ((info = (E_select_info*) calloc(1, sizeof(E_select_info))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+
+ if ((lvl_info = (E_select_lvl_info*) calloc(1, sizeof(E_select_lvl_info))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_PRIORITY;
+ }
+
+ for (fd_type = 0; fd_type != NUM_FDTYPES; ++fd_type) {
+
+ FD_ZERO(&lvl_info->fd_sets[fd_type]);
+
+ if (stdskl_construct(&lvl_info->fd_skls[fd_type], sizeof(int), sizeof(E_fd_watch*), E_fd_cmp) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_LVL_INFO;
+ }
+ }
+
+ events->priorities[priority].backend_lvl_info = lvl_info;
+ }
+
+ events->backend_type = E_BACKEND_SELECT;
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL_LVL_INFO:
+ while (fd_type-- != 0) {
+ stdskl_destruct(&lvl_info->fd_skls[fd_type]);
+ }
+
+ free(lvl_info);
+
+ FAIL_PRIORITY:
+ while (priority-- != E_MIN_PRIORITY) {
+
+ lvl_info = (E_select_lvl_info*) events->priorities[priority].backend_lvl_info;
+
+ for (fd_type = 0; fd_type != NUM_FDTYPES; ++fd_type) {
+ stdskl_destruct(&lvl_info->fd_skls[fd_type]);
+ }
+
+ free(lvl_info);
+ events->priorities[priority].backend_lvl_info = NULL;
+ }
+
+ free(info);
+
+ FAIL:
+ info = NULL;
+ assert(ret != 0);
+
+ END:
+ events->backend_info = info;
+
+ return ret;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static void E_events_select_fini(E_events *events)
+{
+ E_priority priority;
+ E_select_info * info;
+ E_select_lvl_info *lvl_info;
+ E_watch_type fd_type;
+
+ assert(events->backend_type == E_BACKEND_SELECT && events->backend_info != NULL);
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+
+ lvl_info = (E_select_lvl_info*) events->priorities[priority].backend_lvl_info;
+ assert(lvl_info != NULL);
+
+ for (fd_type = 0; fd_type != NUM_FDTYPES; ++fd_type) {
+ stdskl_destruct(&lvl_info->fd_skls[fd_type]);
+ }
+
+ free(lvl_info);
+ events->priorities[priority].backend_lvl_info = NULL;
+ }
+
+ info = (E_select_info*) events->backend_info;
+ free(info);
+
+ events->backend_info = NULL;
+ events->backend_type = E_BACKEND_UNSPECIFIED;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_select_activate_watch(E_events * events,
+ E_fd_watch *fd_watch)
+{
+ E_priority lvl;
+ E_select_lvl_info *lvl_info;
+ stdit sit;
+ int ret = 0;
+
+ assert(fd_watch == E_events_get_fd_watch(events, fd_watch->fd, fd_watch->w.watch_type, &sit));
+ assert(fd_watch->w.priority >= E_MIN_PRIORITY && fd_watch->w.priority <= events->max_priority);
+ assert(fd_watch->w.watch_type >= 0 && fd_watch->w.watch_type <= NUM_FDTYPES);
+ assert(!fd_watch->active);
+
+ /* add the new watch to each priority's fd sets up to its priority lvl */
+
+ for (lvl = E_MIN_PRIORITY; lvl <= fd_watch->w.priority; ++lvl) {
+
+ lvl_info = (E_select_lvl_info*) events->priorities[lvl].backend_lvl_info;
+
+ assert(!FD_ISSET(fd_watch->fd, &lvl_info->fd_sets[fd_watch->w.watch_type]));
+ assert(!stdskl_contains(&lvl_info->fd_skls[fd_watch->w.watch_type], &fd_watch->fd));
+
+ if (stdskl_put(&lvl_info->fd_skls[fd_watch->w.watch_type], &sit, &fd_watch->fd, &fd_watch, STDFALSE) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ FD_SET(fd_watch->fd, &lvl_info->fd_sets[fd_watch->w.watch_type]);
+ }
+
+ fd_watch->active = STDTRUE;
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ E_events_select_deactivate_watch(events, fd_watch);
+ assert(ret != 0);
+
+ END:
+ return ret;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_select_deactivate_watch(E_events * events,
+ E_fd_watch *fd_watch)
+{
+ E_priority lvl;
+ E_select_lvl_info *lvl_info;
+#ifndef NDEBUG
+ stdit sit;
#endif
- int num_set;
- int treated;
- int fd;
- int fd_type;
- int i,j;
- sp_time timeout;
- struct timeval sel_timeout, wait_timeout;
- fd_set current_mask[NUM_FDTYPES];
- time_event *temp_ptr;
- int first=1;
- sp_time ev_start;
-#ifdef TESTTIME
- sp_time tmp_late,start,stop,req_time; /* DEBUGGING */
-#endif
-#ifdef BADCLOCK
- clock_sync = 0;
-#endif
- for( Exit_events = 0 ; !Exit_events ; )
- {
- Alarm( EVENTS, "E_handle_events: next event \n");
- /* Handle time events */
- timeout = long_timeout;
-#ifdef TESTTIME
- start = E_get_time_monotonic();
-#endif
- while( Time_queue != NULL )
- {
-#ifdef BADCLOCK
- if ( clock_sync >= 0 )
- {
- E_get_time_monotonic();
- clock_sync = -20;
- }
+ assert(fd_watch == E_events_get_fd_watch(events, fd_watch->fd, fd_watch->w.watch_type, &sit));
+ assert(fd_watch->w.priority >= E_MIN_PRIORITY && fd_watch->w.priority <= events->max_priority);
+ assert(fd_watch->w.watch_type >= 0 && fd_watch->w.watch_type <= NUM_FDTYPES);
+
+ /* NOTE: we can't assert(fd_watch->active) bc we use this fcn to
+ clean up errors in activate_watch(). That's also the reason why
+ our logic must be conditional within the loop.
+ */
+
+ /* remove the watch from each priority's fd sets up to its priority lvl */
+
+ for (lvl = E_MIN_PRIORITY; lvl <= fd_watch->w.priority; ++lvl) {
+
+ lvl_info = (E_select_lvl_info*) events->priorities[lvl].backend_lvl_info;
+
+ if (FD_ISSET(fd_watch->fd, &lvl_info->fd_sets[fd_watch->w.watch_type])) {
+
+ assert(stdskl_contains(&lvl_info->fd_skls[fd_watch->w.watch_type], &fd_watch->fd));
+ stdskl_erase_key(&lvl_info->fd_skls[fd_watch->w.watch_type], &fd_watch->fd);
+ FD_CLR(fd_watch->fd, &lvl_info->fd_sets[fd_watch->w.watch_type]);
+
+ } else {
+ assert(!stdskl_contains(&lvl_info->fd_skls[fd_watch->w.watch_type], &fd_watch->fd));
+ }
+ }
+
+ fd_watch->active = STDFALSE;
+
+ return 0;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_select_query(E_events * events,
+ E_priority query_lvl,
+ const sp_time *delta_timeout,
+ E_priority * queried_lvl)
+{
+ int ret = 0;
+ E_select_info * info = (E_select_info*) events->backend_info;
+ E_select_lvl_info *lvl_info = (E_select_lvl_info*) events->priorities[query_lvl].backend_lvl_info;
+ int nfds = 0;
+ fd_set * fd_sets[3] = { NULL, NULL, NULL };
+ struct timeval timeout_dmy = { 0, 0 };
+ struct timeval * timeout = &timeout_dmy;
+ E_watch_type fd_type;
+ E_fd_watch * fd_watch;
+ int tmp_fd;
+ stdit sit;
+
+ /* set up select's inputs: nfds, fd_sets, timeout */
+
+ for (fd_type = 0; fd_type != NUM_FDTYPES; ++fd_type) {
+
+ if (!stdskl_empty(&lvl_info->fd_skls[fd_type])) { /* make a tmp copy of lvl_info's fd set in info */
+
+ fd_sets[fd_type] = &info->tmp_fd_sets[fd_type];
+ info->tmp_fd_sets[fd_type] = lvl_info->fd_sets[fd_type];
+ tmp_fd = 1 + *(int*) stdskl_it_key(stdskl_last(&lvl_info->fd_skls[fd_type], &sit));
+ nfds = STDMAX(nfds, tmp_fd);
+ assert(tmp_fd >= 1);
+ }
+ }
+
+ if (delta_timeout != NULL) {
+ timeout->tv_sec = delta_timeout->sec;
+ timeout->tv_usec = delta_timeout->usec;
+
+ } else if (nfds != 0) {
+ timeout = NULL;
+
+ } else {
+ ret = E_DEADEND; /* error on infinite timeout and no fds to watch */
+ goto FAIL;
+ }
+
+ /* query select */
+
+ if ((ret = select(nfds, fd_sets[READ_FD], fd_sets[WRITE_FD], fd_sets[EXCEPT_FD], timeout)) < 0) {
+
+ ret = errno;
+ assert(ret != 0);
+
+ switch (ret) {
+
+ case EINTR:
+ ret = E_INTERRUPTED; /* will cause this fcn to be called again */
+ goto FAIL;
+
+ case EBADF:
+ ret = E_INVALID_PARAM; /* bad fd or fd w/ an error in a set */
+ goto FAIL;
+
+ case EINVAL:
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+
+ default:
+ ret = E_SYS_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ /* process the result sets */
+
+ /* TODO: this always processes in order by fd #, which ever so
+ slightly favors the lower # fds (remember we use fifo queues for
+ storing notifications across queries) -- should we randomize
+ where we start to make it more fair here somehow?
+ */
+
+ for (fd_type = 0; ret != 0 && fd_type != NUM_FDTYPES; ++fd_type) {
+
+ for (stdskl_begin(&lvl_info->fd_skls[fd_type], &sit);
+ ret != 0 && !stdskl_is_end(&lvl_info->fd_skls[fd_type], &sit);
+ stdskl_it_next(&sit)) {
+
+ tmp_fd = *(int*) stdskl_it_key(&sit);
+
+ if (!FD_ISSET(tmp_fd, fd_sets[fd_type])) {
+ continue;
+ }
+
+ --ret; /* decrement count of fd bits set */
+
+ fd_watch = *(E_fd_watch**) stdskl_it_val(&sit);
+ assert(tmp_fd == fd_watch->fd && fd_type == fd_watch->w.watch_type);
+
+ if (fd_watch->w.noticed) { /* already noticed and in notification queue */
+ continue;
+ }
+
+ if (stddll_insert(&events->priorities[fd_watch->w.priority].notices,
+ stddll_end(&events->priorities[fd_watch->w.priority].notices, &fd_watch->w.notice_it),
+ &fd_watch) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ fd_watch->w.noticed = STDTRUE;
+ }
+ }
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ *queried_lvl = query_lvl;
+
+ return ret;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_epoll_init(E_events *events)
+#ifdef HAVE_LINUX
+{
+ int priority;
+ E_epoll_info * info;
+ E_epoll_lvl_info *lvl_info;
+ int ret = 0;
+
+ assert(events->backend_type == E_BACKEND_UNSPECIFIED);
+ assert(E_EPOLL_INITIAL_SIZE > 0);
+
+ /*fprintf(stdout, "EPOLLIN = 0x%x; EPOLLOUT = 0x%x; EPOLLPRI = 0x%x\r\n", EPOLLIN, EPOLLOUT, EPOLLPRI);*/
+
+ if ((info = (E_epoll_info*) calloc(1, sizeof(E_epoll_info))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ if ((info->events = (struct epoll_event*) calloc(E_EPOLL_INITIAL_SIZE, sizeof(struct epoll_event))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_INFO;
+ }
+
+ info->num_events = E_EPOLL_INITIAL_SIZE;
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+
+ if ((lvl_info = (E_epoll_lvl_info*) calloc(1, sizeof(E_epoll_lvl_info))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL_PRIORITY;
+ }
+
+ if ((lvl_info->epoll_fd = epoll_create(E_EPOLL_INITIAL_SIZE)) < 0) {
+
+ ret = errno;
+ assert(ret != 0);
+
+ switch (ret) {
+
+ case EINVAL:
+ assert(0);
+ ret = E_BUG;
+ break;
+
+ case ENFILE:
+ ret = E_TOO_MANY_FILES;
+ break;
+
+ case ENOMEM:
+ ret = E_ALLOC_FAILURE;
+ break;
+
+ default:
+ ret = E_SYS_FAILURE;
+ break;
+ }
+
+ goto FAIL_LVL_INFO;
+ }
+
+ lvl_info->num_poll_fds = 0;
+ events->priorities[priority].backend_lvl_info = lvl_info;
+ }
+
+ events->backend_type = E_BACKEND_EPOLL;
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL_LVL_INFO:
+ free(lvl_info);
+
+ FAIL_PRIORITY:
+ while (priority-- != E_MIN_PRIORITY) {
+ lvl_info = (E_epoll_lvl_info*) events->priorities[priority].backend_lvl_info;
+
+ close(lvl_info->epoll_fd);
+ free(lvl_info);
+
+ events->priorities[priority].backend_lvl_info = NULL;
+ }
+
+ free(info->events);
+
+ FAIL_INFO:
+ free(info);
+
+ FAIL:
+ info = NULL;
+ assert(ret != 0);
+
+ END:
+ events->backend_info = info;
+
+ return ret;
+}
#else
- E_get_time_monotonic();
+{
+ return E_NO_SYS;
+}
#endif
- if ( !first && E_compare_time( Now, Time_queue->t ) >= 0 )
- {
-#ifdef TESTTIME
- tmp_late = E_sub_time( Now, Time_queue->t );
-#endif
- temp_ptr = Time_queue;
- Time_queue = Time_queue->next;
- Alarm( EVENTS, "E_handle_events: exec time event \n");
-#ifdef TESTTIME
- Alarm( DEBUG, "Events: TimeEv is %d %d late\n",tmp_late.sec, tmp_late.usec);
-#endif
- ev_start = Now;
- temp_ptr->func( temp_ptr->code, temp_ptr->data );
- dispose( temp_ptr );
-#ifdef BADCLOCK
- Now = E_add_time( Now, mili_sec );
- clock_sync++;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static void E_events_epoll_fini(E_events *events)
+#ifdef HAVE_LINUX
+{
+ E_priority priority;
+ E_epoll_info * info;
+ E_epoll_lvl_info *lvl_info;
+
+ assert(events->backend_type == E_BACKEND_EPOLL && events->backend_info != NULL);
+
+ for (priority = E_MIN_PRIORITY; priority <= events->max_priority; ++priority) {
+
+ lvl_info = (E_epoll_lvl_info*) events->priorities[priority].backend_lvl_info;
+ assert(lvl_info != NULL);
+
+ close(lvl_info->epoll_fd);
+ free(lvl_info);
+
+ events->priorities[priority].backend_lvl_info = NULL;
+ }
+
+ info = (E_epoll_info*) events->backend_info;
+ free(info->events);
+ free(info);
+
+ events->backend_info = NULL;
+ events->backend_type = E_BACKEND_UNSPECIFIED;
+}
#else
- E_get_time_monotonic();
+{
+}
#endif
- E_time_events( ev_start, Now, NULL, temp_ptr );
- if (Exit_events) goto end_handler;
- }else{
- timeout = E_sub_time( Time_queue->t, Now );
- break;
- }
- }
- if (timeout.sec < 0 )
- timeout.sec = timeout.usec = 0; /* this can happen until first is unset */
-#ifdef TESTTIME
- stop = E_get_time_monotonic();
- tmp_late = E_sub_time(stop, start);
- Alarm(DEBUG, "Events: TimeEv's took %d %d to handle\n", tmp_late.sec, tmp_late.usec);
-#endif
- /* Handle fd events */
- for( i=0; i < NUM_FDTYPES; i++ )
- {
- current_mask[i] = Fd_mask[i];
- }
- Alarm( EVENTS, "E_handle_events: poll select\n");
-#ifdef TESTTIME
- req_time = zero_sec;
-#endif
- wait_timeout.tv_sec = zero_sec.sec;
- wait_timeout.tv_usec = zero_sec.usec;
- num_set = select( FD_SETSIZE, ¤t_mask[READ_FD], ¤t_mask[WRITE_FD], ¤t_mask[EXCEPT_FD],
- &wait_timeout );
- if (num_set == 0 && !Exit_events)
- {
-#ifdef BADCLOCK
- clock_sync = 0;
-#endif
- for( i=0; i < NUM_FDTYPES; i++ )
- {
- current_mask[i] = Fd_mask[i];
- }
- Alarm( EVENTS, "E_handle_events: select with timeout (%d, %d)\n",
- timeout.sec,timeout.usec );
-#ifdef TESTTIME
- req_time = E_add_time(req_time, timeout);
-#endif
- sel_timeout.tv_sec = timeout.sec;
- sel_timeout.tv_usec = timeout.usec;
- num_set = select( FD_SETSIZE, ¤t_mask[READ_FD], ¤t_mask[WRITE_FD],
- ¤t_mask[EXCEPT_FD], &sel_timeout );
- }
-#ifdef TESTTIME
- start = E_get_time_monotonic();
- tmp_late = E_sub_time(start, stop);
- Alarm( DEBUG, "Events: Waiting for fd or timout took %d %d asked for %d %d\n", tmp_late.sec, tmp_late.usec, req_time.sec, req_time.usec);
-#endif
- /* Handle all high and medium priority fd events */
- for( i=NUM_PRIORITY-1,treated=0;
- i > LOW_PRIORITY && num_set > 0 && !treated;
- i-- )
- {
- for( j=0; j < Fd_queue[i].num_fds && num_set > 0; j++ )
- {
- fd = Fd_queue[i].events[j].fd;
- fd_type = Fd_queue[i].events[j].fd_type;
- if( FD_ISSET( fd, ¤t_mask[fd_type] ) )
- {
- Alarm( EVENTS, "E_handle_events: exec handler for fd %d, fd_type %d, priority %d\n",
- fd, fd_type, i );
-#ifdef BADCLOCK
- Now = E_add_time( Now, mili_sec );
- clock_sync++;
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_epoll_activate_watch(E_events * events,
+ E_fd_watch *fd_watch)
+#ifdef HAVE_LINUX
+{
+ E_priority lvl;
+ E_epoll_lvl_info *lvl_info;
+ E_fd_watch * tmp_watch;
+ int num_events;
+ struct epoll_event epoll_evnt;
+ struct epoll_event epoll_evnt_cpy;
+ int epoll_op;
+ stdit fd_it;
+ stdit sit;
+ int ret = 0;
+
+ assert(fd_watch == E_events_get_fd_watch(events, fd_watch->fd, fd_watch->w.watch_type, &sit));
+ assert(fd_watch->w.priority >= E_MIN_PRIORITY && fd_watch->w.priority <= events->max_priority);
+ assert(fd_watch->w.watch_type >= 0 && fd_watch->w.watch_type <= NUM_FDTYPES);
+ assert(!fd_watch->active);
+
+ memset(&epoll_evnt, 0, sizeof(epoll_evnt));
+ epoll_evnt.data.fd = fd_watch->fd;
+ stdskl_lowerb(&events->fd_watches, &fd_it, &fd_watch->fd); /* find the beginning of all the watches on the fd */
+
+ /* go down to the watch's priority lvl adding the new watch to each priority's epoll fd sets */
+
+ for (lvl = E_MIN_PRIORITY; lvl <= fd_watch->w.priority; ++lvl) {
+
+ lvl_info = (E_epoll_lvl_info*) events->priorities[lvl].backend_lvl_info;
+
+ /* calculate what events we should query for at this priority lvl for all the other watches on this fd */
+
+ epoll_evnt.events = 0;
+ num_events = 0;
+
+ for (sit = fd_it; !stdskl_is_end(&events->fd_watches, &sit); stdskl_it_next(&sit)) { /* go over all the watches on this fd */
+
+ tmp_watch = *(E_fd_watch**) stdskl_it_val(&sit);
+
+ if (tmp_watch->fd != fd_watch->fd) { /* end of watches on this fd */
+ break;
+ }
+
+ if (!tmp_watch->active || tmp_watch == fd_watch) { /* skip inactive watches (we handle fd_watch after this loop) */
+ continue;
+ }
+
+ if (tmp_watch->w.priority >= lvl) { /* is this watch participating in this lvl? */
+
+ switch (tmp_watch->w.watch_type) { /* how is this watch participating? */
+
+ case READ_FD:
+ epoll_evnt.events |= EPOLLIN;
+ break;
+
+ case WRITE_FD:
+ epoll_evnt.events |= EPOLLOUT;
+ break;
+
+ case EXCEPT_FD:
+ epoll_evnt.events |= EPOLLPRI;
+ break;
+
+ default:
+ ret = E_BUG;
+ assert(0);
+ goto FAIL;
+ }
+
+ ++num_events;
+ }
+ }
+
+ /* now include fd_watch */
+
+ switch (fd_watch->w.watch_type) { /* how is this watch participating? */
+
+ case READ_FD:
+ epoll_evnt.events |= EPOLLIN;
+ break;
+
+ case WRITE_FD:
+ epoll_evnt.events |= EPOLLOUT;
+ break;
+
+ case EXCEPT_FD:
+ epoll_evnt.events |= EPOLLPRI;
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+ }
+
+ ++num_events;
+
+ /* now actually modify the epoll set with the calculated events */
+
+ epoll_op = (num_events == 1 ? EPOLL_CTL_ADD : EPOLL_CTL_MOD);
+
+ RETRY: /* allow a single retry w/ a different epoll_op in the case of ENOENT (see below) */
+ epoll_evnt_cpy = epoll_evnt; /* epoll_ctl's interface isn't const so make a copy in case they trash our input */
+
+ /*fprintf(stdout, "Adding fd(%d) to epoll_fd(%d) for priority(%d) w/ op(%s) and events(0x%x)\r\n",
+ fd_watch->fd, lvl_info->epoll_fd, lvl, (epoll_op == EPOLL_CTL_ADD ? "EPOLL_CTL_ADD" : "EPOLL_CTL_MOD"), epoll_evnt.events);
+ */
+
+ if ((ret = epoll_ctl(lvl_info->epoll_fd, epoll_op, fd_watch->fd, &epoll_evnt_cpy)) != 0) {
+
+ ret = errno;
+ assert(ret != 0);
+
+ switch (ret) {
+
+ case ENOENT: /* can happen if watched fd's were close()'d, which epoll notices, without the user calling E_detach_fd() */
+ assert(epoll_op == EPOLL_CTL_MOD);
+ epoll_op = EPOLL_CTL_ADD; /* call again with ADD instead of MOD */ /* TODO: user error -- should we just error out instead? */
+ goto RETRY;
+
+ case EEXIST: /* bug either in epoll_ctl or in our code: shouldn't happen */
+ assert(epoll_op == EPOLL_CTL_ADD);
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+
+ case EBADF: /* bad fd from user */
+ case EPERM:
+ ret = E_INVALID_PARAM;
+ goto FAIL;
+
+ case EINVAL:
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+
+ case ENOMEM:
+ default:
+ ret = E_SYS_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ if (num_events == 1) {
+ assert(lvl_info->num_poll_fds >= 0);
+ ++lvl_info->num_poll_fds;
+ assert(lvl_info->num_poll_fds >= 0);
+ }
+ }
+
+ fd_watch->active = STDTRUE;
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ E_events_epoll_deactivate_watch(events, fd_watch);
+ assert(ret != 0);
+
+ END:
+ return ret;
+}
#else
- E_get_time_monotonic();
+{
+ return E_NO_SYS;
+}
#endif
- ev_start = Now;
- Fd_queue[i].events[j].func(
- Fd_queue[i].events[j].fd,
- Fd_queue[i].events[j].code,
- Fd_queue[i].events[j].data );
- treated = 1;
- num_set--;
-#ifdef BADCLOCK
- Now = E_add_time( Now, mili_sec );
- clock_sync++;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+static int E_events_epoll_deactivate_watch(E_events * events,
+ E_fd_watch *fd_watch)
+#ifdef HAVE_LINUX
+{
+ E_priority lvl;
+ E_epoll_lvl_info *lvl_info;
+ E_fd_watch * tmp_watch;
+ int num_events;
+ struct epoll_event epoll_evnt;
+ int epoll_op;
+ stdit fd_it;
+ stdit sit;
+ int ret = 0;
+
+ assert(fd_watch == E_events_get_fd_watch(events, fd_watch->fd, fd_watch->w.watch_type, &sit));
+ assert(fd_watch->w.priority >= E_MIN_PRIORITY && fd_watch->w.priority <= events->max_priority);
+ assert(fd_watch->w.watch_type >= 0 && fd_watch->w.watch_type <= NUM_FDTYPES);
+
+ /* NOTE: we can't assert(fd_watch->active) bc we use this fcn to
+ clean up errors in activate_watch()
+ */
+
+ epoll_evnt.data.fd = fd_watch->fd;
+ stdskl_lowerb(&events->fd_watches, &fd_it, &fd_watch->fd); /* find the beginning of all the watches on the fd */
+
+ /* go down to the watch's priority lvl removing the watch from each priority's epoll fd sets */
+
+ for (lvl = E_MIN_PRIORITY; lvl <= fd_watch->w.priority; ++lvl) {
+
+ lvl_info = (E_epoll_lvl_info*) events->priorities[lvl].backend_lvl_info;
+
+ /* calculate what events we should query for at this priority lvl for all the other watches on this fd */
+
+ epoll_evnt.events = 0;
+ num_events = 0;
+
+ for (sit = fd_it; !stdskl_is_end(&events->fd_watches, &sit); stdskl_it_next(&sit)) { /* go over all the watches on this fd */
+
+ tmp_watch = *(E_fd_watch**) stdskl_it_val(&sit);
+
+ if (tmp_watch->fd != fd_watch->fd) { /* end of watches on this fd */
+ break;
+ }
+
+ if (!tmp_watch->active || tmp_watch == fd_watch) { /* skip inactive watches and fd_watch */
+ continue;
+ }
+
+ if (tmp_watch->w.priority >= lvl) { /* is this watch participating in this lvl? */
+
+ switch (tmp_watch->w.watch_type) { /* how is this watch participating? */
+
+ case READ_FD:
+ epoll_evnt.events |= EPOLLIN;
+ break;
+
+ case WRITE_FD:
+ epoll_evnt.events |= EPOLLOUT;
+ break;
+
+ case EXCEPT_FD:
+ epoll_evnt.events |= EPOLLPRI;
+ break;
+
+ default:
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+ }
+
+ ++num_events;
+ }
+ }
+
+ /* now actually modify the epoll set with the calculated events */
+
+ epoll_op = (num_events == 0 ? EPOLL_CTL_DEL : EPOLL_CTL_MOD);
+
+ if ((ret = epoll_ctl(lvl_info->epoll_fd, epoll_op, fd_watch->fd, &epoll_evnt)) != 0) {
+
+ ret = errno;
+ assert(ret != 0);
+
+ switch (ret) {
+
+ case ENOENT: /* can happen if watched fd's were close()'d, which epoll notices, without the user calling E_detach_fd() */
+ case EPERM: /* same as above, but user opened a new fd (w/ same fd number) that can't be polled */
+ case EBADF: /* can happen if user closed fd or if somehow closed our epoll fd (which would be a big no-no) */
+ case EINVAL: /* shouldn't happen (might happen if user somehow closed our epoll fd, which would be a big no-no, or tried to watch it) */
+ case EEXIST: /* bug either in epoll_ctl or in our code: shouldn't happen */
+ case ENOMEM: /* shouldn't happen if Linux has any brains */
+ default:
+ ret = 0; /* ignore errors */ /* TODO: should we really swallow all errors? */
+ break;
+ }
+ }
+
+ if (num_events == 0) {
+ assert(lvl_info->num_poll_fds >= 0);
+ --lvl_info->num_poll_fds;
+ assert(lvl_info->num_poll_fds >= 0);
+ }
+ }
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ return ret;
+}
#else
- E_get_time_monotonic();
+{
+ return E_NO_SYS;
+}
#endif
- E_time_events(ev_start, Now, &(Fd_queue[i].events[j]), NULL);
- if (Exit_events) goto end_handler;
- }
- }
- }
- /* Don't handle timed events until all non-low-priority fd events have been handled
- * FIXME: This may or may not be right. If continual high priority events occur, then
- * timed events will starve, I'm not sure if that is better then what we have. We
- * could also set first=0 no matter what after trying the high events once, then
- * they will get a shot first, but after that timed events will also be handled.
- */
- if (!treated)
- first = 0;
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
-#ifdef TESTTIME
- stop = E_get_time_monotonic();
- tmp_late = E_sub_time(stop, start);
- Alarm(DEBUG, "Events: High & Med took %d %d time to handle\n", tmp_late.sec, tmp_late.usec);
-#endif
- /* Handle one low priority fd event.
- However, verify that Active_priority still allows LOW_PRIORITY events.
- Active_priority can change because of calls to E_set_threshold() during the current select loop.
- */
- for( i=0; i < Fd_queue[LOW_PRIORITY].num_fds
- && num_set > 0
- && Active_priority == LOW_PRIORITY;
- i++ )
- {
- j = ( i + Round_robin ) % Fd_queue[LOW_PRIORITY].num_fds;
- fd = Fd_queue[LOW_PRIORITY].events[j].fd;
- fd_type = Fd_queue[LOW_PRIORITY].events[j].fd_type;
- if( FD_ISSET( fd, ¤t_mask[fd_type] ) )
- {
- Round_robin = ( j + 1 ) % Fd_queue[LOW_PRIORITY].num_fds;
+static int E_events_epoll_query(E_events * events,
+ E_priority query_lvl,
+ const sp_time *delta_timeout,
+ E_priority * queried_lvl)
+#ifdef HAVE_LINUX
+{
+ E_epoll_info * info = (E_epoll_info*) events->backend_info;
+ E_epoll_lvl_info * lvl_info = (E_epoll_lvl_info*) events->priorities[query_lvl].backend_lvl_info;
+ double tmp_timeout;
+ int timeout;
+ struct epoll_event *evnt;
+ struct epoll_event *evnts_end;
+ E_fd_watch * fd_watch;
+ stdit sit;
+ int ret = 0;
- Alarm( EVENTS , "E_handle_events: exec ext fd event \n");
-#ifdef BADCLOCK
- Now = E_add_time( Now, mili_sec );
- clock_sync++;
+ /* convert the timeout to epoll's input */
+
+ if (delta_timeout != NULL) {
+
+ if (delta_timeout->sec == 0 && delta_timeout->usec == 0) {
+ timeout = 0;
+
+ } else {
+ tmp_timeout = delta_timeout->sec * 1000.0 + (999 + delta_timeout->usec) / 1000.0; /* [1, 1000] usec -> round up to 1 ms */
+ assert(tmp_timeout >= 0.0);
+
+ if (tmp_timeout <= INT_MAX) {
+ timeout = (int) tmp_timeout; /* round off excess usec */
+
+ } else {
+ timeout = INT_MAX;
+ }
+ }
+
+ } else if (lvl_info->num_poll_fds != 0) {
+ timeout = -1; /* infinite timeout */
+
+ } else {
+ ret = E_DEADEND; /* error on infinite timeout and no fds to watch */
+ goto FAIL;
+ }
+
+ /* ensure our query array is still large enough */
+
+ if (lvl_info->num_poll_fds > info->num_events) {
+
+ if ((evnt = (struct epoll_event*) calloc(2 * lvl_info->num_poll_fds, sizeof(struct epoll_event))) == NULL) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ free(info->events);
+ info->events = evnt;
+ info->num_events = 2 * lvl_info->num_poll_fds;
+ assert(info->num_events >= lvl_info->num_poll_fds);
+ }
+
+ /* query epoll */
+
+ if ((ret = epoll_wait(lvl_info->epoll_fd, info->events, info->num_events, timeout)) < 0) {
+
+ ret = errno;
+ assert(ret != 0);
+
+ switch (ret) {
+
+ case EINTR:
+ ret = E_INTERRUPTED; /* will cause this fcn to be called again */
+ goto FAIL;
+
+ case EBADF:
+ case EINVAL:
+ case EFAULT:
+ assert(0);
+ ret = E_BUG;
+ goto FAIL;
+
+ default:
+ ret = E_SYS_FAILURE;
+ goto FAIL;
+ }
+ }
+
+ /* process the result set */
+
+ evnts_end = info->events + ret;
+ ret = 0;
+
+ for (evnt = info->events; evnt != evnts_end; ++evnt) {
+
+ /* look up the fd and process all watches on it */
+
+ for (stdskl_lowerb(&events->fd_watches, &sit, &evnt->data.fd); !stdskl_is_end(&events->fd_watches, &sit); stdskl_it_next(&sit)) {
+
+ stdbool generate_notice = STDFALSE;
+
+ fd_watch = *(E_fd_watch**) stdskl_it_val(&sit);
+
+ if (fd_watch->fd != evnt->data.fd) { /* we've moved onto the next fd */
+ break;
+ }
+
+ if (fd_watch->w.noticed) { /* this watch is already noticed */
+ continue;
+ }
+
+ switch (fd_watch->w.watch_type) {
+
+ case READ_FD:
+ generate_notice = ((evnt->events & (EPOLLIN | EPOLLERR | EPOLLHUP)) != 0);
+ break;
+
+ case WRITE_FD:
+ generate_notice = ((evnt->events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) != 0);
+ break;
+
+ case EXCEPT_FD:
+ generate_notice = ((evnt->events & (EPOLLPRI | EPOLLERR | EPOLLHUP)) != 0);
+ break;
+ }
+
+ /* push a new notice onto the associated priority's notice queue and record where it is */
+
+ if (generate_notice &&
+ stddll_insert(&events->priorities[fd_watch->w.priority].notices,
+ stddll_end(&events->priorities[fd_watch->w.priority].notices, &fd_watch->w.notice_it),
+ &fd_watch) != 0) {
+ ret = E_ALLOC_FAILURE;
+ goto FAIL;
+ }
+
+ fd_watch->w.noticed = STDTRUE;
+ }
+ }
+
+ assert(ret == 0);
+ goto END;
+
+ /* error handling and return */
+
+ FAIL:
+ assert(ret != 0);
+
+ END:
+ *queried_lvl = query_lvl;
+
+ return ret;
+}
#else
- E_get_time_monotonic();
+{
+ return E_NO_SYS;
+}
#endif
- ev_start = Now;
- Fd_queue[LOW_PRIORITY].events[j].func(
- Fd_queue[LOW_PRIORITY].events[j].fd,
- Fd_queue[LOW_PRIORITY].events[j].code,
- Fd_queue[LOW_PRIORITY].events[j].data );
- num_set--;
-#ifdef BADCLOCK
- Now = E_add_time( Now, mili_sec );
- clock_sync++;
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+sp_time E_get_time(void)
+{
+ return E_events_get_time(&Events);
+}
+
+/***************************************************************************************************************************
+ * NOTE: Bad implementation kept for backwards compatability -- should allow for negative times
+ ***************************************************************************************************************************/
+
+sp_time E_sub_time(sp_time t,
+ sp_time delta_t)
+{
+ t.sec -= delta_t.sec;
+ t.usec -= delta_t.usec;
+
+ if (t.usec < 0) {
+ t.usec += 1000000;
+ --t.sec;
+ }
+
+ return t;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+sp_time E_add_time(sp_time t,
+ sp_time delta_t)
+{
+ t.sec += delta_t.sec;
+ t.usec += delta_t.usec;
+
+ if (t.usec > 1000000) {
+ t.usec -= 1000000;
+ ++t.sec;
+ }
+
+ return t;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_compare_time(sp_time t1,
+ sp_time t2)
+{
+ int ret = 0;
+
+ if (t1.sec > t2.sec) ret = 1;
+ else if (t1.sec < t2.sec) ret = -1;
+ else if (t1.usec > t2.usec) ret = 1;
+ else if (t1.usec < t2.usec) ret = -1;
+
+ return ret;
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+void E_delay(sp_time t)
+#ifdef ARCH_PC_WIN95
+{
+ SleepEx(t.sec * 1000 + t.usec / 1000, 0);
+}
#else
- E_get_time_monotonic();
+{
+ struct timeval tmp_t;
+
+ tmp_t.tv_sec = t.sec;
+ tmp_t.tv_usec = t.usec;
+
+ select(0, NULL, NULL, NULL, &tmp_t);
+}
#endif
- E_time_events(ev_start, Now, &(Fd_queue[LOW_PRIORITY].events[j]), NULL);
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
- if (Exit_events) goto end_handler;
- break;
- }
- }
-#ifdef TESTTIME
- start = E_get_time_monotonic();
- tmp_late = E_sub_time(start, stop);
- Alarm(DEBUG, "Events: Low priority took %d %d to handle\n", tmp_late.sec, tmp_late.usec);
-#endif
- }
- end_handler:
- /* Clean up data structures for exit OR restart of handler loop */
- /* Actually nothing needs to be cleaned up to allow E_handle_events()
- * to be called again. The events are still registered (or not registered)
- * and the only state for the actual events loop is Exit_events which is reset
- * in the for loop.
- */
+int E_init(void)
+{
+ return E_events_init(&Events);
+}
- return;
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+void E_fini(void)
+{
+ E_events_fini(&Events);
}
-void E_exit_events(void)
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+sp_time E_get_loop_time(void)
{
- Alarm( EVENTS, "E_exit_events:\n");
- Exit_events = 1;
+ return E_events_get_loop_time(&Events);
}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+sp_time E_update_loop_time(void)
+{
+ return E_events_update_loop_time(&Events);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_in_queue(E_time_callback_fcn fcn, int code, void *data)
+{
+ return E_events_in_queue(&Events, fcn, code, data);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_queue(E_time_callback_fcn fcn, int code, void *data, sp_time delta_time)
+{
+ return E_events_queue(&Events, fcn, code, data, delta_time);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_queue_absolute(E_time_callback_fcn fcn, int code, void *data, sp_time absolute_time)
+{
+ return E_events_queue_absolute(&Events, fcn, code, data, absolute_time);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_queue_periodic(E_time_callback_fcn fcn, int code, void *data, sp_time periodic_time)
+{
+ return E_events_queue_periodic(&Events, fcn, code, data, periodic_time);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_dequeue(E_time_callback_fcn fcn, int code, void *data)
+{
+ return E_events_dequeue(&Events, fcn, code, data);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_attach_fd(int fd, E_watch_type fd_type, E_fd_callback_fcn fcn, int code, void *data, E_priority priority)
+{
+ return E_events_attach_fd(&Events, fd, fd_type, fcn, code, data, priority);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_detach_fd(int fd, E_watch_type fd_type)
+{
+ return E_events_detach_fd(&Events, fd, fd_type);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_detach_fd_priority(int fd, E_watch_type fd_type, int priority)
+{
+ return E_events_detach_fd_priority(&Events, fd, fd_type, priority);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_set_active_threshold(E_priority priority)
+{
+ return E_events_set_active_threshold(&Events, priority);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_num_active(E_priority priority)
+{
+ return E_events_num_active(&Events, priority);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_activate_fd(int fd, E_watch_type fd_type)
+{
+ return E_events_activate_fd(&Events, fd, fd_type);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_deactivate_fd(int fd, E_watch_type fd_type)
+{
+ return E_events_deactivate_fd(&Events, fd, fd_type);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_set_elevate_count(E_priority priority, unsigned count)
+{
+ return E_events_set_elevate_count(&Events, priority, count);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_get_elevate_count(E_priority priority, unsigned *count)
+{
+ return E_events_get_elevate_count(&Events, priority, count);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+int E_handle_events(void)
+{
+ return E_events_handle_events(&Events);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
+
+void E_exit_events(void)
+{
+ E_events_exit_events(&Events);
+}
+
+/***************************************************************************************************************************
+ ***************************************************************************************************************************/
More information about the Spread-cvs
mailing list