/*
 * Copyright (c) 2002-2006 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 * Copyright (c) 2006 Claus Assmann
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 *
 *	$Id: evthr.h,v 1.94 2007/01/01 02:10:25 ca Exp $
 */

#ifndef SM_EVTHR_H
#define SM_EVTHR_H 1

#include "sm/generic.h"
#include "sm/magic.h"
#include "sm/types.h"
#include "sm/time.h"
#include "sm/queue.h"
#include "sm/pthread.h"
#include "sm/socket.h"
#include "sm/io.h"
#include "sm/log.h"
#include "sm/note.h"

#ifndef EVTHR_DEBUG
# define EVTHR_DEBUG 0
#endif

/* put some additional checks into place? */
#ifndef EVTHR_PARANOIA
# define EVTHR_PARANOIA 0
#endif

#ifndef SM_EVTHR_CV
/* do NOT activate this; it has not been implemented yet! */
# define SM_EVTHR_CV 0
#endif

#ifndef SM_LOCK_TASK
# define SM_LOCK_TASK 0
#endif

/* number of priorities */
#ifndef EVTHR_PRIOS
# define EVTHR_PRIOS 1
#endif

/* max. signals handled by application: USR1, USR2 */
#define EVTHR_MAX_SIGS 2

/* for debugging */
#define ERRPRINTTV(msg, tv) fprintf(stderr, msg "%ld.%06ld\n", (tv).tv_sec, (tv).tv_usec)

typedef struct sm_evthr_ctx_S  sm_evthr_ctx_T, *sm_evthr_ctx_P;
typedef struct sm_evthr_task_S sm_evthr_task_T, *sm_evthr_task_P;
typedef struct sm_evthr_req_S  sm_evthr_req_T, *sm_evthr_req_P;

#define SM_IS_EVTHR_CTX(ctx) SM_REQUIRE_ISA(ctx, SM_EVTHR_CTX_MAGIC)
#define SM_IS_EVTHR_TSK(tsk) SM_REQUIRE_ISA(tsk, SM_EVTHR_TASK_MAGIC)

/* use an rpool here?? */
struct sm_evthr_ctx_S
{
	sm_magic_T       sm_magic;

	pthread_cond_t   evthr_c_cv;

	/* for waitq */
	pthread_mutex_t  evthr_c_waitqmut;

	/* for runq and counters c_cur, c_idl etc */
	pthread_mutex_t  evthr_c_runqmut;

	uint             evthr_c_max_h; /* max. # of threads (hard limit) */
	uint             evthr_c_max_s; /* max. # of threads (soft limit) */
	uint             evthr_c_min;   /* min. number of threads */
	uint             evthr_c_cur;   /* current number of threads */
	uint             evthr_c_idl;   /* idle threads */
	uint             evthr_c_act;   /* active threads */

	uint             evthr_c_flags; /* flags, see below */
	uint             evthr_c_wflags;/* flags, see below */
	uint             evthr_c_maxfd; /* maximum number of FDs */
	timeval_T        evthr_c_time;  /* current time */
	sm_evthr_task_P *evthr_c_fd2t;  /* array to map FDs to tasks */

	/* array to map signals to tasks */
	sm_evthr_task_P  evthr_c_sg2t[EVTHR_MAX_SIGS];

	uint             evthr_c_tasks; /* number of tasks */

	sm_log_ctx_P     evthr_c_lctx;

	/* pipe between control thread and worker/signal threads */
	/* should this be fd_T?? */
	int              evthr_c_pipe[2];

	/*
	**  Simple way to let the main loop "know" about errors in
	**  the signal handler module (which must only use "signal-safe"
	**  functions).
	**  A more "sophisticated" way is to use a (fixed sized) queue
	**  in case more than one error occurs before the main loop
	**  can react.
	*/

	int              evthr_sige_where;
	int              evthr_sige_what;

	CIRCLEQ_HEAD(, sm_evthr_task_S) evthr_c_waitq;
#if EVTHR_PRIOS <= 1
	CIRCLEQ_HEAD(, sm_evthr_task_S) evthr_c_runq;
#else
	CIRCLEQ_HEAD(, sm_evthr_task_S) evthr_c_runq[EVTHR_PRIOS];
	uint             evthr_c_nprio;
#endif

	/* change requests: mutex and list of change requests */
	pthread_mutex_t  evthr_c_reqmut;
	uint             evthr_c_nreqs;
	/* total # of entries in request queue including those that aren't used */
	uint             evthr_c_tot_reqs;

	/* list of requests (free [evthr_r_task==NULL] or in use) */
	CIRCLEQ_HEAD(, sm_evthr_req_S)  evthr_c_reqs;

#if SM_EVTHR_CV
	uint             evthr_c_ncvs;
	CIRCLEQ_HEAD(, sm_evthr_req_S)  evthr_c_cvq;
#endif /* SM_EVTHR_CV */
#if EVTHR_DEBUG
	uint             evthr_c_dbglvl;
#endif
};
NOTE(LOCK_ORDER(sm_evthr_ctx_S::evthr_c_runqmut sm_evthr_ctx_S::evthr_c_waitqmut))
NOTE(MUTEX_PROTECTS_DATA(sm_evthr_ctx_S::evthr_c_waitqmut, sm_evthr_ctx_S::evthr_c_waitq))
NOTE(MUTEX_PROTECTS_DATA(sm_evthr_ctx_S::evthr_c_runqmut, sm_evthr_ctx_S::evthr_c_runq))
NOTE(MUTEX_PROTECTS_DATA(sm_evthr_ctx_S::evthr_c_reqmut, sm_evthr_ctx_S::evthr_c_reqs))
NOTE(DATA_READABLE_WITHOUT_LOCK(sm_evthr_ctx_S::sm_magic))

#define EVTHR_FL_NONE   0x0000

/* stop all threads; maybe types like shutdown, abort, ...? */
#define EVTHR_FL_STOP   0x0001
/* protected by runq mutex? */

/*
**  soft limit exceeded: if this is already set then more workers
**  (up to the hard limit) can be started.
**  Note: it might be useful to have a counter or a time limit instead
**  that must be exceeded (this is just a counter of 1).
*/

#define EVTHR_FL_SL_EXC 0x0010
/* protected by runq mutex? */

#define EVTHR_SET_FLAG(evthr_ctx, fl) (evthr_ctx)->evthr_c_flags |= (fl)
#define EVTHR_CLR_FLAG(evthr_ctx, fl) (evthr_ctx)->evthr_c_flags &= ~(fl)
#define EVTHR_IS_FLAG(evthr_ctx, fl) (((evthr_ctx)->evthr_c_flags & (fl)) != 0)

/* wflags are protected by waitq mutex */

#define EVTHR_WFL_NONE  0x0000

/* scheduler has been informed to "wake up", no need to tell it again */
#define EVTHR_WFL_WAKEUP        0x0001

#define EVTHR_SET_WFLAG(evthr_ctx, fl) (evthr_ctx)->evthr_c_wflags |= (fl)
#define EVTHR_CLR_WFLAG(evthr_ctx, fl) (evthr_ctx)->evthr_c_wflags &= ~(fl)
#define EVTHR_IS_WFLAG(evthr_ctx, fl) (((evthr_ctx)->evthr_c_wflags & (fl)) != 0)

#define EVTHR_SET_WAKEUP(evthr_ctx) EVTHR_SET_WFLAG(evthr_ctx, EVTHR_WFL_WAKEUP)
#define EVTHR_CLR_WAKEUP(evthr_ctx) EVTHR_CLR_WFLAG(evthr_ctx, EVTHR_WFL_WAKEUP)
#define EVTHR_IS_WAKEUP(evthr_ctx) EVTHR_IS_WFLAG(evthr_ctx, EVTHR_WFL_WAKEUP)

/* for listen() sockets: accepted fd */
struct sm_evthr_nc_S
{
	socklen_T        evthr_a_len;
	struct sockaddr  evthr_a_addr;
	int              evthr_a_fd;
};

typedef struct sm_evthr_nc_S    sm_evthr_nc_T, *sm_evthr_nc_P;

/*
**  requests for change of event flags (task status)
*/

struct sm_evthr_req_S
{
	CIRCLEQ_ENTRY(sm_evthr_req_S)   evthr_r_next;

	sm_evthr_task_P  evthr_r_task;  /* pointer to task for identification */
	int              evthr_r_rqevf; /* see below */
	timeval_T        evthr_r_sleep; /* when to wake up */
	int              evthr_r_chge;  /* when to change wakeup time */
};

/* must be ordered */
#define EVTHR_CHG_TIME_NO       0
#define EVTHR_CHG_TIME_YES      1
#define EVTHR_CHG_TIME_LESS     2

#define EVTHR_REQ_CLR(req)      do {    \
		(req)->evthr_r_task = NULL;     \
		(req)->evthr_r_rqevf = 0;       \
		(req)->evthr_r_chge = 0;        \
	} while (0)


#if SM_EVTHR_CV

NOT YET IMPLEMENTED!
Need to determine first whether this is really required/useful.

/*
**  Queue of tasks waiting for a condition (result)
*/

struct sm_evthr_cv_S
{
	sm_evthr_task_P                  evthr_cv_task;
	uint                             evthr_cv_id;
	pthread_mutex_t                  evthr_cv_mutex;
	CIRCLEQ_ENTRY(sm_evthr_cv_S)     evthr_cv_next;
};
sm_ret_T evthr_cv_get_id(sm_evthr_ctx_P _ctx, uint *pid);
#endif /* SM_EVTHR_CV */

/*
**  worker function prototype
**  receives task as argument; access the application context through it
*/

typedef sm_ret_T (evthr_task_F)(sm_evthr_task_P);

/*
**  Task description
**  Do we want to have a mutex per task?
**  When do we need it? Only if we manipulate the task itself.
**  However, each task is (almost) always in some queue and those
**  queues are protected by mutexes.
*/

struct sm_evthr_task_S
{
	sm_magic_T       sm_magic;

	CIRCLEQ_ENTRY(sm_evthr_task_S)  evthr_t_next;

#if SM_LOCK_TASK
	/* protects evthr_t_rqevf and evthr_t_sleep */
	pthread_mutex_t  evthr_t_mutex;
#endif

	/* types of event on which this tasks waits */
	uint32_t         evthr_t_rqevf; /* see below */
	uint32_t         evthr_t_evocc; /* events occurred; see below */
	uint32_t         evthr_t_state; /* current state; see below  */
	uint32_t         evthr_t_flags; /* flags; see below  */
	int              evthr_t_fd;    /* fd to watch */
	int              evthr_t_sig;   /* signal to watch */
	timeval_T        evthr_t_sleep; /* when to wake up */
	evthr_task_F    *evthr_t_fct;   /* function to execute */
	void            *evthr_t_actx;  /* application context */
	sm_evthr_ctx_P   evthr_t_ctx;   /* evthr context */
	sm_evthr_nc_P    evthr_t_nc;    /* network connection */
#if EVTHR_PRIOS > 1
	int              evthr_t_prio;  /* priority */
# define EVTHR_T_PRIO(task) ((task)->evthr_t_prio)
# define EVTHR_T_PRIO_SET(task, prio) ((task)->evthr_t_prio) = (prio)
#else
# define EVTHR_T_PRIO(task) 0
# define EVTHR_T_PRIO_SET(task, prio)   SM_NOOP
#endif
};

/*
**  evthr_t_rqevf: types of event on which this task is waiting
**  (8 bits max: 0xFF)
*/
#define EVTHR_EV_RD     0x00000001      /* read */
#define EVTHR_EV_WR     0x00000002      /* write */
#define EVTHR_EV_LI     0x00000004      /* listen (accept()) */
#define EVTHR_EV_IOM    0x00000007      /* mask for I/O */
#define EVTHR_EV_SL     0x00000008      /* sleep (timeout) */
#define EVTHR_EV_SG     0x00000010      /* signal */

/*
**  evthr_t_evocc: types of event which occurred
**  (8 bits max: 0xFF00, currently only 5 bits)
*/
#define EVTHR_EV_RD_Y   0x00000100      /* ready for read */
#define EVTHR_EV_WR_Y   0x00000200      /* ready for write */
#define EVTHR_EV_LI_Y   0x00000400      /* ready for listen (accept()) */
#define EVTHR_EV_SL_Y   0x00000800      /* wakeup (after timeout) */
#define EVTHR_EV_SG_Y   0x00001000      /* signal */
#define EVTHR_EV_RDY    0x00003F00      /* mask for ready (event occurred) */

/* status of task (which queue?) */
#if EVTHR_PARANOIA
# define EVTHR_EV_CHK   0x00000001      /* is in waitq, already checked */
#endif
#define EVTHR_EV_IWQ    0x00010000      /* is in waitq */
#define EVTHR_EV_IRQ    0x00020000      /* is in runq */
#define EVTHR_EV_WWQ    0x00100000      /* wants to be in waitq */
#define EVTHR_EV_WRQ    0x00200000      /* wants to be in runq */
#define EVTHR_EV_DEL    0x00800000      /* wants to be deleted */
#define EVTHR_EV_WALL   (EVTHR_EV_WWQ|EVTHR_EV_WRQ|EVTHR_EV_DEL)
#define EVTHR_EV_QALL   (EVTHR_EV_WALL|EVTHR_EV_IWQ|EVTHR_EV_IRQ)
#define EVTHR_IS_INQ(task, q)   do { \
		(task)->evthr_t_state &= ~EVTHR_EV_QALL; \
		(task)->evthr_t_state |= (q); \
	} while (0)
#define EVTHR_WANTS_INQ(task, q)  (task)->evthr_t_state |= (q)
#define EVTHR_REM_FROMQ(task, q)  (task)->evthr_t_state &= ~(q)
#if EVTHR_PARANOIA
# define EVTHR_ALREADY_CHK(task)  (((task)->evthr_t_state &= EVTHR_EV_CHK) != 0)
# define EVTHR_CHECKED(task)      (task)->evthr_t_state |= EVTHR_EV_CHK
# define EVTHR_CLR_CHECKED(task)  (task)->evthr_t_state &= ~EVTHR_EV_CHK
#endif /* EVTHR_PARANOIA */

#define EVTHR_GOT_EV(task, ev)  (task)->evthr_t_evocc |= (ev)

/* manipulate evthr_t_rqevf */
#define evthr_set_ev(task, ev)  (task)->evthr_t_rqevf |= (ev)
#define evthr_clr_ev(task, ev)  (task)->evthr_t_rqevf &= ~(ev)
#define evthr_rqevents(task)    ((task)->evthr_t_rqevf)

#define evthr_is_ev(task, w)    (((task)->evthr_t_rqevf & (w)) != 0)
#define evthr_is_rd(task)       evthr_is_ev((task), EVTHR_EV_RD)
#define evthr_is_wr(task)       evthr_is_ev((task), EVTHR_EV_WR)
#define evthr_is_li(task)       evthr_is_ev((task), EVTHR_EV_LI)
#define evthr_is_io(task)       evthr_is_ev((task), EVTHR_EV_IOM)
#define evthr_is_slp(task)      evthr_is_ev((task), EVTHR_EV_SL)

#define evthr_is_st(task, w)    (((task)->evthr_t_state & (w)) != 0)
#define evthr_is_inq(task, q)   evthr_is_st((task), (q))
#define evthr_is_inwq(task)     evthr_is_st((task), EVTHR_EV_IWQ)
#define evthr_is_inrq(task)     evthr_is_st((task), EVTHR_EV_IRQ)

#define evthr_ev_occ(task, w)   (((task)->evthr_t_evocc & (w)) != 0)
#define evthr_clr_rdy(task)     (task)->evthr_t_evocc &= ~EVTHR_EV_RDY;
#define evthr_got_rd(task)      evthr_ev_occ((task), EVTHR_EV_RD_Y)
#define evthr_got_wr(task)      evthr_ev_occ((task), EVTHR_EV_WR_Y)
#define evthr_got_li(task)      evthr_ev_occ((task), EVTHR_EV_LI_Y)
#define evthr_got_slp(task)     evthr_ev_occ((task), EVTHR_EV_SL_Y)
#define evthr_got_sg(task)      evthr_ev_occ((task), EVTHR_EV_SG_Y)
#define evthr_got_wk(task)      evthr_ev_occ((task), EVTHR_EV_WK_Y)

#define evthr_is_evf(r, w)      (((r) & (w)) != 0)
#define evthr_is_rdf(r)         evthr_is_evf((r), EVTHR_EV_RD)
#define evthr_is_wrf(r)         evthr_is_evf((r), EVTHR_EV_WR)
#define evthr_is_lif(r)         evthr_is_evf((r), EVTHR_EV_LI)
#define evthr_is_iof(r)         evthr_is_evf((r), EVTHR_EV_IOM)
#define evthr_is_slpf(r)        evthr_is_evf((r), EVTHR_EV_SL)
#define evthr_is_sgf(r)         evthr_is_evf((r), EVTHR_EV_SG)
#define evthr_is_wkf(r)         evthr_is_evf((r), EVTHR_EV_WK)

#define evthr_got_rdf(r)        evthr_is_evf((r), EVTHR_EV_RD_Y)
#define evthr_got_wrf(r)        evthr_is_evf((r), EVTHR_EV_WR_Y)
#define evthr_got_lif(r)        evthr_is_evf((r), EVTHR_EV_LI_Y)
#define evthr_got_slpf(r)       evthr_is_evf((r), EVTHR_EV_SL_Y)

/* flags for task */
#define EVTHRT_FL_NONE  0x00000000
#define EVTHRT_FL_BLK_RD 0x00000001 /* task could block after read */
#define EVTHRT_FL_BLK_WR 0x00000002 /* task could block after write */
#define EVTHRT_FL_BLK_SL 0x00000004 /* task could block after sleep */
#define EVTHRT_FL_BLK_LI 0x00000008 /* task could block after listen */
#define EVTHRT_FL_BLOCK 0x0000000F /* task could block (| of previous values) */

#define EVTHRT_SET_FLAG(evthr_task, fl) (evthr_task)->evthr_t_flags |= (fl)
#define EVTHRT_CLR_FLAG(evthr_task, fl) (evthr_task)->evthr_t_flags &= ~(fl)
#define EVTHRT_IS_FLAG(evthr_task, fl) (((evthr_task)->evthr_t_flags & (fl)) != 0)

/* "why" parameter for evthr_term() and other read()/write() args */
#define EVTHR_STOP      'S'
#define EVTHR_ABRT      'A'
#define EVTHR_CONT      'C'     /* just wake up scheduler (continue) */
#define EVTHR_USR1      '1'
#define EVTHR_USR2      '2'
#define EVTHR_ERROR     'E'     /* check error variables */

#define EVTHR_SIG2IDX(sig) ((sig) == SIGUSR1 ? 0 : ((sig) == SIGUSR2 ? 1 : (-1)))
#define EVTHR_WHY2IDX(why) ((why) == EVTHR_USR1 ? 0 : ((why) == EVTHR_USR2 ? 1 : (-1)))
#define EVTHR_IDX2SIG(idx) ((idx) == 0 ? SIGUSR1 : ((idx) == 1 ? SIGUSR2 : (-1)))

/* result of evthr_task */
#define EVTHR_OK        0x0000  /* do nothing, task has been taken care of */
#define EVTHR_WAITQ     0x0001  /* put in waitq */
#define EVTHR_RUNQ      0x0002  /* put in runq */
#define EVTHR_SLPQ      0x0003  /* sleep for a while */
#define EVTHR_DEL       0x0004  /* delete task */
#define EVTHR_ACT_M     0x0007  /* action mask */
#define EVTHR_TERM      0x1000  /* terminate event thread loop */
#define EVTHR_S_M       0x00F0  /* mask for "wants X" */
#define EVTHR_C_M       0x0F00  /* mask for "clear X" */
#define EVTHR_S_OFF     4       /* shift offset for "wants X" */
#define EVTHR_C_OFF     8       /* shift offset for "clear X" */
#define EVTHR_FL_M      (EVTHR_S_M|EVTHR_C_M)   /* flag mask */
#define evthr_r_get_fl(r)       ((r) & EVTHR_FL_M)
#define evthr_r_set_fl(r, fl)   (r) |= (fl) & EVTHR_FL_M

#define evthr_act_waitq(r)      (((r) & EVTHR_ACT_M) == EVTHR_WAITQ)
#define evthr_act_runq(r)       (((r) & EVTHR_ACT_M) == EVTHR_RUNQ)
#define evthr_act_slpq(r)       (((r) & EVTHR_ACT_M) == EVTHR_SLPQ)
#define evthr_act_del(r)        (((r) & EVTHR_ACT_M) == EVTHR_DEL)
#define evthr_act_async(r)      (((r) & EVTHR_ACT_M) == EVTHR_OK)
#define evthr_act_term(r)       (((r) & EVTHR_TERM) != 0)
#define evthr_r_set(r)          (((r) & EVTHR_S_M) != 0)
#define evthr_r_clr(r)          (((r) & EVTHR_C_M) != 0)
#define evthr_r_set_ev(r)       (((r) & EVTHR_S_M) >> EVTHR_S_OFF)
#define evthr_r_clr_ev(r)       (((r) & EVTHR_C_M) >> EVTHR_C_OFF)

/* macros to construct return value */
#define evthr_r_yes(ev)         (((ev) << EVTHR_S_OFF) & EVTHR_S_M)
#define evthr_r_no(ev)          (((ev) << EVTHR_C_OFF) & EVTHR_C_M)

/* macros to manipulate the queues */
#if EVTHR_PRIOS <= 1
#define EVTHR_RUNQ_INIT(ctx)    CIRCLEQ_INIT(&((ctx)->evthr_c_runq))
#define EVTHR_RUNQ_FIRST(ctx, prio)     CIRCLEQ_FIRST(&((ctx)->evthr_c_runq))
#define EVTHR_RUNQ_LAST(ctx, prio)      CIRCLEQ_LAST(&((ctx)->evthr_c_runq))
#define EVTHR_RUNQ_END(ctx, prio)       CIRCLEQ_END(&((ctx)->evthr_c_runq))
#define EVTHR_RUNQ_EMPTY_ALL(ctx, prio) CIRCLEQ_EMPTY(&((ctx)->evthr_c_runq))
#define EVTHR_RUNQ_EMPTY(ctx, prio)     CIRCLEQ_EMPTY(&((ctx)->evthr_c_runq))
#define EVTHR_RUNQ_LOOP(ctx, prio, task)        CIRCLEQ_FOREACH(task, &((ctx)->evthr_c_runq), evthr_t_next)
#define EVTHR_RUNQ_APP(ctx, prio, task) CIRCLEQ_INSERT_TAIL(&((ctx)->evthr_c_runq), task, evthr_t_next)
#define EVTHR_RUNQ_PRE(ctx, prio, task) CIRCLEQ_INSERT_HEAD(&((ctx)->evthr_c_runq), task, evthr_t_next)
#define EVTHR_RUNQ_INS(ctx, prio, task, new)    CIRCLEQ_INSERT_BEFORE(&((ctx)->evthr_c_runq), (task), (new), evthr_t_next)
#define EVTHR_RUNQ_DEL(ctx, prio, task) CIRCLEQ_REMOVE(&((ctx)->evthr_c_runq), task, evthr_t_next)
#else /* EVTHR_PRIOS <= 1 */
#define EVTHR_RUNQ_INIT(ctx) do { \
		int i; \
		for (i = 0; i < EVTHR_PRIOS; i++) \
			CIRCLEQ_INIT(&((ctx)->evthr_c_runq[i])); \
	} while (0)
#define EVTHR_RUNQ_FIRST(ctx, prio)     CIRCLEQ_FIRST(&((ctx)->evthr_c_runq[prio]))
#define EVTHR_RUNQ_LAST(ctx, prio)      CIRCLEQ_LAST(&((ctx)->evthr_c_runq[prio]))
#define EVTHR_RUNQ_END(ctx, prio)       CIRCLEQ_END(&((ctx)->evthr_c_runq[prio]))
#define EVTHR_RUNQ_EMPTY_ALL(ctx, prio) evthr_runq_empty_all((ctx), &(prio))
#define EVTHR_RUNQ_EMPTY(ctx, prio)     CIRCLEQ_EMPTY(&((ctx)->evthr_c_runq[prio]))
#define EVTHR_RUNQ_LOOP(ctx, prio, task)        CIRCLEQ_FOREACH(task, &((ctx)->evthr_c_runq[prio]), evthr_t_next)
#define EVTHR_RUNQ_APP(ctx, prio, task) CIRCLEQ_INSERT_TAIL(&((ctx)->evthr_c_runq[prio]), task, evthr_t_next)
#define EVTHR_RUNQ_PRE(ctx, prio, task) CIRCLEQ_INSERT_HEAD(&((ctx)->evthr_c_runq[prio]), task, evthr_t_next)
#define EVTHR_RUNQ_INS(ctx, prio, task, new)    CIRCLEQ_INSERT_BEFORE(&((ctx)->evthr_c_runq[prio]), (task), (new), evthr_t_next)
#define EVTHR_RUNQ_DEL(ctx, prio, task) CIRCLEQ_REMOVE(&((ctx)->evthr_c_runq[prio]), task, evthr_t_next)
#endif /* EVTHR_PRIOS <= 1 */

#define EVTHR_WAITQ_INIT(ctx)   CIRCLEQ_INIT(&((ctx)->evthr_c_waitq))
#define EVTHR_REQ_INIT(ctx)     CIRCLEQ_INIT(&((ctx)->evthr_c_reqs))

#define EVTHR_WAITQ_FIRST(ctx)  CIRCLEQ_FIRST(&((ctx)->evthr_c_waitq))
#define EVTHR_REQ_FIRST(ctx)    CIRCLEQ_FIRST(&((ctx)->evthr_c_reqs))
#define EVTHR_WAITQ_LAST(ctx)   CIRCLEQ_LAST(&((ctx)->evthr_c_waitq))
#define EVTHR_REQ_LAST(ctx)     CIRCLEQ_LAST(&((ctx)->evthr_c_reqs))
#define EVTHR_WAITQ_END(ctx)    CIRCLEQ_END(&((ctx)->evthr_c_waitq))
#define EVTHR_REQ_END(ctx)      CIRCLEQ_END(&((ctx)->evthr_c_reqs))
#define EVTHR_WAITQ_EMPTY(ctx)  CIRCLEQ_EMPTY(&((ctx)->evthr_c_waitq))
#define EVTHR_REQ_EMPTY(ctx)    CIRCLEQ_EMPTY(&((ctx)->evthr_c_reqs))

#define EVTHR_RUNQ_NEXT(task)   CIRCLEQ_NEXT(task, evthr_t_next)
#define EVTHR_WAITQ_NEXT(task)  CIRCLEQ_NEXT(task, evthr_t_next)
#define EVTHR_REQ_NEXT(req)     CIRCLEQ_NEXT(req, evthr_r_next)
#define EVTHR_WAITQ_PREV(task)  CIRCLEQ_PREV(task, evthr_t_next)

#define EVTHR_WAITQ_LOOP(ctx, task)     CIRCLEQ_FOREACH(task, &((ctx)->evthr_c_waitq), evthr_t_next)

#define EVTHR_WAITQ_APP(ctx, task) do { \
		SM_ASSERT(!evthr_is_inwq(task)); \
		CIRCLEQ_INSERT_TAIL(&((ctx)->evthr_c_waitq), task, evthr_t_next); \
	} while (0)
#define EVTHR_REQ_APP(ctx, req) CIRCLEQ_INSERT_TAIL(&((ctx)->evthr_c_reqs), req, evthr_r_next)
#define EVTHR_WAITQ_PRE(ctx, task) do { \
		SM_ASSERT(!evthr_is_inwq(task)); \
	    CIRCLEQ_INSERT_HEAD(&((ctx)->evthr_c_waitq), task, evthr_t_next); \
	} while (0)

#define EVTHR_WAITQ_INS(ctx, task_old, task_new) do { \
		SM_ASSERT(!evthr_is_inwq(task_new)); \
		CIRCLEQ_INSERT_BEFORE(&((ctx)->evthr_c_waitq), (task_old), (task_new), evthr_t_next); \
	} while (0)

#define EVTHR_WAITQ_DEL(ctx, task)      CIRCLEQ_REMOVE(&((ctx)->evthr_c_waitq), task, evthr_t_next)
#define EVTHR_REQ_DEL(ctx, req) CIRCLEQ_REMOVE(&((ctx)->evthr_c_reqs), req, evthr_r_next)

#if 0
#define EVTHR_CTX_REMOVE_FREE(addr, tok) do { \
		CIRCLEQ_REMOVE(&((addr)->sm_a2821_hd), tok, sm_t2821_l); \
		t2821_free((addr)->sm_a2821_rpool, tok); \
	} while (0)
#endif /* 0 */


/* queues */


/* function prototypes */
sm_ret_T evthr_init(sm_evthr_ctx_P *_pctx, uint _minthr, uint _maxthr, uint _maxfd);
sm_ret_T evthr_comptoptions(sm_evthr_ctx_P _evthr_ctx, sm_file_T *_fp);

sm_ret_T evthr_set_max_h(sm_evthr_ctx_P _ctx, uint _maxthr_h);
sm_ret_T evthr_set_max_s(sm_evthr_ctx_P _ctx, uint _maxthr_s);

sm_ret_T evthr_task_new(sm_evthr_ctx_P _evthr_ctx, sm_evthr_task_P *_ptask, int _ev, int _fd, timeval_T *_sleept, evthr_task_F *_fct, void *_taskctx);
sm_ret_T evthr_loop(sm_evthr_ctx_P _ctx);
sm_ret_T evthr_timeval(sm_evthr_ctx_P _ctx, timeval_T *_ct);
time_T   evthr_time(sm_evthr_ctx_P _ctx);
sm_ret_T evthr_waitq_app(sm_evthr_task_P _task);

sm_ret_T evthr_en_wr(sm_evthr_task_P _task);
sm_ret_T evthr_new_sl(sm_evthr_task_P _task, timeval_T _slpt, bool _change);
sm_ret_T evthr_a2del(sm_evthr_task_P _task);
sm_ret_T evthr_wakeup_task(sm_evthr_task_P _task);

/* internal functions, but also used by libdns */
sm_ret_T evthr_slpq_ins(sm_evthr_ctx_P _ctx, sm_evthr_task_P _task);
sm_ret_T evthr_task_del(sm_evthr_ctx_P _ctx, sm_evthr_task_P _task, thr_lock_T _locktype);
#if 0
sm_ret_T evthr_gotsignal(sm_evthr_ctx_P _ctx, int _why);
#endif
sm_ret_T evthr_stop(sm_evthr_ctx_P _ctx);
void    *evthr_worker(void *_ctx);
sm_evthr_req_P   evthr_req_new(sm_evthr_ctx_P _ctx);
sm_ret_T evthr_reqs_free(sm_evthr_ctx_P _ctx);

sm_ret_T evthr_signal_init(sm_evthr_ctx_P _ctx);

sm_ret_T evthr_set_dbglvl(sm_evthr_ctx_P _ctx, uint _dbglvl);

sm_ret_T evthr_before_block(sm_evthr_ctx_P _ctx);
sm_ret_T evthr_after_block(sm_evthr_ctx_P _ctx);

#endif /* SM_EVTHR_H */


syntax highlighted by Code2HTML, v. 0.9.1