mirror of
https://github.com/jrbrtsn/ban2fail
synced 2024-06-16 11:58:01 +00:00
Added event server sources
This commit is contained in:
parent
0ef57ad814
commit
2e4c215de2
@ -15,6 +15,9 @@ src := \
|
|||||||
ban2fail.c \
|
ban2fail.c \
|
||||||
cfgmap.c \
|
cfgmap.c \
|
||||||
cntry.c \
|
cntry.c \
|
||||||
|
es.c \
|
||||||
|
ez_es.c \
|
||||||
|
ez_libanl.c \
|
||||||
ez_libc.c \
|
ez_libc.c \
|
||||||
ez_libz.c \
|
ez_libz.c \
|
||||||
iptables.c \
|
iptables.c \
|
||||||
@ -23,11 +26,12 @@ src := \
|
|||||||
logFile.c \
|
logFile.c \
|
||||||
map.c \
|
map.c \
|
||||||
maxoff.c \
|
maxoff.c \
|
||||||
|
msgqueue.c \
|
||||||
ptrvec.c \
|
ptrvec.c \
|
||||||
str.c \
|
str.c \
|
||||||
util.c \
|
util.c \
|
||||||
|
|
||||||
libs := z crypto GeoIP
|
libs := anl z crypto GeoIP pthread
|
||||||
endif
|
endif
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
|
188
ban2fail.c
188
ban2fail.c
@ -16,23 +16,17 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <limits.h>
|
#include <signal.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/file.h>
|
#include <sys/file.h>
|
||||||
#include <sys/stat.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
|
|
||||||
#include "ban2fail.h"
|
#include "ban2fail.h"
|
||||||
#include "cntry.h"
|
#include "cntry.h"
|
||||||
|
#include "ez_libanl.h"
|
||||||
#include "ez_libc.h"
|
#include "ez_libc.h"
|
||||||
#include "ez_libz.h"
|
|
||||||
#include "iptables.h"
|
#include "iptables.h"
|
||||||
#include "logEntry.h"
|
#include "logEntry.h"
|
||||||
#include "logFile.h"
|
#include "logFile.h"
|
||||||
@ -69,10 +63,10 @@ struct initInfo {
|
|||||||
|
|
||||||
static int cntryStat_count_qsort(const void *p1, const void *p2);
|
static int cntryStat_count_qsort(const void *p1, const void *p2);
|
||||||
static int configure(CFGMAP *h_cfgmap, const char *pfix);
|
static int configure(CFGMAP *h_cfgmap, const char *pfix);
|
||||||
|
static const char* reverse_dns_lookup(const char *addr);
|
||||||
static int logentry_count_qsort(const void *p1, const void *p2);
|
static int logentry_count_qsort(const void *p1, const void *p2);
|
||||||
static int map_byCountries(LOGENTRY *e, MAP *h_map);
|
static int map_byCountries(LOGENTRY *e, MAP *h_map);
|
||||||
static int stub_init(CFGMAP *map, char *symStr);
|
static int stub_init(CFGMAP *map, char *symStr);
|
||||||
static int whitelist_init(CFGMAP *h_cfgmap, char *symStr);
|
|
||||||
|
|
||||||
|
|
||||||
/*==================================================================*/
|
/*==================================================================*/
|
||||||
@ -133,6 +127,17 @@ static struct {
|
|||||||
PTRVEC toBlock_vec,
|
PTRVEC toBlock_vec,
|
||||||
toUnblock_vec;
|
toUnblock_vec;
|
||||||
|
|
||||||
|
/* Used for reverse DNS lookups */
|
||||||
|
struct {
|
||||||
|
struct gaicb **cbPtrArr,
|
||||||
|
*cbArr;
|
||||||
|
} gai;
|
||||||
|
|
||||||
|
/* Used to place LOGENTRY address objects into linear
|
||||||
|
* access container.
|
||||||
|
*/
|
||||||
|
LOGENTRY **lePtrArr;
|
||||||
|
|
||||||
} S;
|
} S;
|
||||||
|
|
||||||
/*==================================================================*/
|
/*==================================================================*/
|
||||||
@ -162,7 +167,7 @@ main(int argc, char **argv)
|
|||||||
MAP_constructor(&G.logType_map, 10, 10);
|
MAP_constructor(&G.logType_map, 10, 10);
|
||||||
|
|
||||||
// local
|
// local
|
||||||
MAP_constructor(&S.addr2logEntry_map, N_ADDRESSES_HINT/10, 10);
|
MAP_constructor(&S.addr2logEntry_map, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
|
||||||
|
|
||||||
PTRVEC_constructor(&S.toBlock_vec, N_ADDRESSES_HINT);
|
PTRVEC_constructor(&S.toBlock_vec, N_ADDRESSES_HINT);
|
||||||
PTRVEC_constructor(&S.toUnblock_vec, N_ADDRESSES_HINT);
|
PTRVEC_constructor(&S.toUnblock_vec, N_ADDRESSES_HINT);
|
||||||
@ -200,10 +205,11 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
G.flags |= GLB_LIST_ADDR_FLG;
|
G.flags |= GLB_LIST_ADDR_FLG;
|
||||||
if(optarg && *optarg == '+') {
|
if(optarg) {
|
||||||
G.flags |= GLB_DNS_LOOKUP_FLG;
|
if(*optarg == '+')
|
||||||
} else {
|
G.flags |= GLB_DNS_LOOKUP_FLG;
|
||||||
++errflg;
|
else
|
||||||
|
++errflg;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -380,7 +386,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if(G.flags & GLB_LONG_LISTING_FLG) {
|
if(G.flags & GLB_LONG_LISTING_FLG) {
|
||||||
MAP map;
|
MAP map;
|
||||||
MAP_constructor(&map, N_ADDRESSES_HINT/10, 10);
|
MAP_constructor(&map, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
|
||||||
|
|
||||||
unsigned nOffFound= 0,
|
unsigned nOffFound= 0,
|
||||||
nAddrFound;
|
nAddrFound;
|
||||||
@ -414,15 +420,115 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
unsigned nItems= MAP_numItems(&S.addr2logEntry_map);
|
unsigned nItems= MAP_numItems(&S.addr2logEntry_map);
|
||||||
|
|
||||||
LOGENTRY *leArr[nItems];
|
/* allocate this array, let it leak */
|
||||||
MAP_fetchAllItems(&S.addr2logEntry_map, (void**)leArr);
|
S.lePtrArr= malloc(sizeof(void*) * nItems);
|
||||||
qsort(leArr, nItems, sizeof(LOGENTRY*), logentry_count_qsort);
|
assert(S.lePtrArr);
|
||||||
|
|
||||||
|
MAP_fetchAllItems(&S.addr2logEntry_map, (void**)S.lePtrArr);
|
||||||
|
qsort(S.lePtrArr, nItems, sizeof(LOGENTRY*), logentry_count_qsort);
|
||||||
|
|
||||||
|
/* Special processing for DNS lookups */
|
||||||
|
if(G.flags & GLB_DNS_LOOKUP_FLG) {
|
||||||
|
|
||||||
|
static struct sigevent sev= {.sigev_notify= SIGEV_NONE};
|
||||||
|
const static struct addrinfo hints= {
|
||||||
|
.ai_family = AF_UNSPEC,
|
||||||
|
.ai_flags = AI_NUMERICHOST
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Allocate array of structures */
|
||||||
|
S.gai.cbArr= calloc(sizeof(struct gaicb), nItems);
|
||||||
|
assert(S.gai.cbArr);
|
||||||
|
|
||||||
|
/* Allocate pointer array */
|
||||||
|
S.gai.cbPtrArr= malloc(sizeof(struct gaicb*) * nItems);
|
||||||
|
assert(S.gai.cbPtrArr);
|
||||||
|
|
||||||
|
/* Fill out cbPtrArr with addresses, populate structures */
|
||||||
|
for(unsigned i= 0; i < nItems; ++i) {
|
||||||
|
|
||||||
|
LOGENTRY *e= S.lePtrArr[i];
|
||||||
|
struct gaicb *cb= S.gai.cbArr+i;
|
||||||
|
|
||||||
|
/* Populate gaicb object */
|
||||||
|
cb->ar_name= e->addr;
|
||||||
|
cb->ar_request= &hints;
|
||||||
|
|
||||||
|
/* Place object address in cbPtrArr */
|
||||||
|
S.gai.cbPtrArr[i]= cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we can submit all of our requests */
|
||||||
|
eprintf("Submitting %u addresses for lookup", nItems);
|
||||||
|
int rc= ez_getaddrinfo_a(GAI_NOWAIT, S.gai.cbPtrArr, nItems, &sev);
|
||||||
|
if(rc)
|
||||||
|
eprintf("returned %d", rc);
|
||||||
|
assert(0 == rc);
|
||||||
|
|
||||||
|
// TODO: define max timeout on command line
|
||||||
|
static struct timespec ts;
|
||||||
|
ms2timespec(&ts, 10*1000);
|
||||||
|
|
||||||
|
/* Pause for parallel DNS lookups */
|
||||||
|
for(;;) {
|
||||||
|
int rc= ez_gai_suspend((const struct gaicb*const*)S.gai.cbPtrArr, nItems, &ts);
|
||||||
|
switch(rc) {
|
||||||
|
case 0:
|
||||||
|
case EAI_INTR:
|
||||||
|
continue;
|
||||||
|
|
||||||
|
case EAI_ALLDONE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
eprintf("INFO: gai_suspend() failed, rc= %d [%s]", rc, gai_strerror(rc));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
eprintf("All done");
|
||||||
|
unsigned nSucc= 0,
|
||||||
|
nFail= 0;
|
||||||
|
|
||||||
|
/* Cancel any ongoing lookups */
|
||||||
|
gai_cancel(NULL);
|
||||||
|
|
||||||
|
/* Now check each gaicb object */
|
||||||
|
for(unsigned i= 0; i < nItems; ++i) {
|
||||||
|
|
||||||
|
struct gaicb *cb= S.gai.cbArr + i;
|
||||||
|
int status= gai_error(cb);
|
||||||
|
static char hostBuf[PATH_MAX];
|
||||||
|
|
||||||
|
switch(status) {
|
||||||
|
|
||||||
|
case 0: {
|
||||||
|
++nSucc;
|
||||||
|
assert(cb->ar_name && cb->ar_result);
|
||||||
|
struct addrinfo *ai= cb->ar_result;
|
||||||
|
assert(ai->ai_addr && ai->ai_addrlen);
|
||||||
|
|
||||||
|
int rc= ez_getnameinfo(ai->ai_addr, ai->ai_addrlen, hostBuf, sizeof(hostBuf)-1, NULL, 0, NI_NAMEREQD);
|
||||||
|
eprintf("%s= %s", cb->ar_name, rc ? "unknown" : hostBuf);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
++nFail;
|
||||||
|
eprintf("INFO: status= %d [%s]", status, gai_strerror(status));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use the result
|
||||||
|
}
|
||||||
|
eprintf("nItems= %u, nSucc= %u, nFail= %u", nItems, nSucc, nFail);
|
||||||
|
} /* End of GLB_DNS_LOOKUP_FLG */
|
||||||
|
|
||||||
/* Process each LOGENTRY item */
|
/* Process each LOGENTRY item */
|
||||||
for(unsigned i= 0; i < nItems; ++i) {
|
for(unsigned i= 0; i < nItems; ++i) {
|
||||||
int flags=0;
|
int flags=0;
|
||||||
|
|
||||||
LOGENTRY *e= leArr[i];
|
LOGENTRY *e= S.lePtrArr[i];
|
||||||
|
|
||||||
if(IPTABLES_is_currently_blocked(e->addr))
|
if(IPTABLES_is_currently_blocked(e->addr))
|
||||||
flags |= BLOCKED_FLG;
|
flags |= BLOCKED_FLG;
|
||||||
@ -451,13 +557,22 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
/* Print out only for list option */
|
/* Print out only for list option */
|
||||||
if(G.flags & GLB_LIST_ADDR_FLG) {
|
if(G.flags & GLB_LIST_ADDR_FLG) {
|
||||||
|
const char *dns_name= NULL;
|
||||||
|
#if 0
|
||||||
|
if(G.flags & GLB_DNS_LOOKUP_FLG)
|
||||||
|
dns_name= reverse_dns_lookup(e->addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
ez_fprintf(G.listing_fh, "%-15s\t%5u/%-4d offenses %s (%s)\n"
|
const static char *dns_fmt= "%-15s\t%5u/%-4d offenses %s (%s) [%s]\n",
|
||||||
|
*fmt= "%-15s\t%5u/%-4d offenses %s (%s)\n";
|
||||||
|
|
||||||
|
ez_fprintf(G.listing_fh, dns_name ? dns_fmt : fmt
|
||||||
, e->addr
|
, e->addr
|
||||||
, e->count
|
, e->count
|
||||||
, nAllowed
|
, nAllowed
|
||||||
, e->cntry[0] ? e->cntry : "--"
|
, e->cntry[0] ? e->cntry : "--"
|
||||||
, bits2str(flags, BlockBitTuples)
|
, bits2str(flags, BlockBitTuples)
|
||||||
|
, dns_name
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -662,4 +777,33 @@ map_byCountries(LOGENTRY *e, MAP *h_map)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char*
|
||||||
|
reverse_dns_lookup(const char *addr)
|
||||||
|
/**************************************************************
|
||||||
|
* Do a getaddrinfo() reverse lookup on addr
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const char *rtn= NULL;
|
||||||
|
static char hostBuf[PATH_MAX];
|
||||||
|
static struct addrinfo hints,
|
||||||
|
*res;
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
res= NULL;
|
||||||
|
|
||||||
|
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
|
||||||
|
hints.ai_flags = AI_NUMERICHOST; /* Only doing reverse lookups */
|
||||||
|
|
||||||
|
int rc= ez_getaddrinfo(addr, NULL, &hints, &res);
|
||||||
|
assert(0 == rc);
|
||||||
|
|
||||||
|
assert(res && res->ai_addr && res->ai_addrlen);
|
||||||
|
|
||||||
|
rc= ez_getnameinfo(res->ai_addr, res->ai_addrlen, hostBuf, sizeof(hostBuf)-1, NULL, 0, NI_NAMEREQD);
|
||||||
|
if(rc) return NULL;
|
||||||
|
|
||||||
|
rtn= hostBuf;
|
||||||
|
|
||||||
|
abort:
|
||||||
|
if(res) freeaddrinfo(res);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
/* For sizing maps and vectors, this a starting point */
|
/* For sizing maps and vectors, this a starting point */
|
||||||
#define N_ADDRESSES_HINT 10000
|
#define N_ADDRESSES_HINT 10000
|
||||||
|
#define BUCKET_DEPTH_HINT 10
|
||||||
|
|
||||||
/* Where to find stuff */
|
/* Where to find stuff */
|
||||||
#define CONFIGFILE "/etc/ban2fail/ban2fail.cfg"
|
#define CONFIGFILE "/etc/ban2fail/ban2fail.cfg"
|
||||||
|
978
es.c
Normal file
978
es.c
Normal file
@ -0,0 +1,978 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "msgqueue.h"
|
||||||
|
#include "es.h"
|
||||||
|
|
||||||
|
/* Types of registered callbacks */
|
||||||
|
enum ES_type {
|
||||||
|
ES_FD_TYPE,
|
||||||
|
ES_SIG_TYPE,
|
||||||
|
ES_VSIG_TYPE,
|
||||||
|
ES_TIMER_TYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NUMSIGS 30
|
||||||
|
|
||||||
|
#define VSIG_QUEUE_MAX 100
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
* We get one of these anonymous structs per-process.
|
||||||
|
****************************************************/
|
||||||
|
static struct {
|
||||||
|
pthread_mutex_t mtx; /* global initialization mutex */
|
||||||
|
|
||||||
|
volatile int keySrc;
|
||||||
|
|
||||||
|
volatile enum {
|
||||||
|
GLOBAL_INIT_FLG=1<<0
|
||||||
|
} flags;
|
||||||
|
|
||||||
|
/* Default sigaction stuff */
|
||||||
|
struct {
|
||||||
|
sigset_t set;
|
||||||
|
struct sigaction arr[NUMSIGS];
|
||||||
|
} dflt_sa;
|
||||||
|
|
||||||
|
struct { /* Stuff for ES_spawn_thread_sched() */
|
||||||
|
pthread_cond_t cond; /* Condition used for thread synchronization */
|
||||||
|
pthread_mutex_t cond_mtx; /* condition mutex */
|
||||||
|
pthread_mutex_t mtx; /* mutex for ES spawn operation */
|
||||||
|
int release_parent; /* Value to test for pthread_cond_wait() */
|
||||||
|
} spawn;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
pthread_mutex_t mtx; /* mutex for virtual signal operations */
|
||||||
|
MAP thrd_ts_map; /* Map associating thread identifier to TS object */
|
||||||
|
} vsig;
|
||||||
|
|
||||||
|
} S= {
|
||||||
|
.mtx= PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
|
||||||
|
.spawn.cond= PTHREAD_COND_INITIALIZER,
|
||||||
|
.spawn.cond_mtx= PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
.spawn.mtx= PTHREAD_MUTEX_INITIALIZER,
|
||||||
|
|
||||||
|
.vsig.mtx= PTHREAD_MUTEX_INITIALIZER
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************
|
||||||
|
* We get one of these anonymous structs per-thread.
|
||||||
|
****************************************************/
|
||||||
|
static _Thread_local struct _TS {
|
||||||
|
|
||||||
|
/* Current pthread identifier. If it doesn't match
|
||||||
|
* pthread_self(), then we are not yet initialized
|
||||||
|
* in the current thread.
|
||||||
|
*/
|
||||||
|
pthread_t tid;
|
||||||
|
|
||||||
|
/* Vectors of Cb by type, for fast processing */
|
||||||
|
PTRVEC fd_vec,
|
||||||
|
timer_vec;
|
||||||
|
PTRVEC sig_vec_arr[NUMSIGS]; // One vector for each Unix signal
|
||||||
|
|
||||||
|
/* Hash table to quickly find Cb's */
|
||||||
|
MAP key_map;
|
||||||
|
|
||||||
|
/* Simple bit field to know if a signal has been
|
||||||
|
* raised at least once.
|
||||||
|
*/
|
||||||
|
sigset_t sigsRaised;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/* virtual signal message queue */
|
||||||
|
MSGQUEUE mq;
|
||||||
|
MAP map;
|
||||||
|
} vsig;
|
||||||
|
|
||||||
|
} TS;
|
||||||
|
|
||||||
|
static void
|
||||||
|
UnixSignalHandler (int signo)
|
||||||
|
/****************************************************
|
||||||
|
* Unix signal handler
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Simply note that a signal has been raised */
|
||||||
|
sigaddset(&TS.sigsRaised, signo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
/** Class for callback objects ************************************/
|
||||||
|
/******************************************************************/
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
int64_t lastActivity_ms;
|
||||||
|
|
||||||
|
/* Process-wide unique integer */
|
||||||
|
int key;
|
||||||
|
|
||||||
|
/* Which type of callback object */
|
||||||
|
enum ES_type type;
|
||||||
|
|
||||||
|
/* Registrant's supplied context pointer, passed back
|
||||||
|
* into callback function
|
||||||
|
*/
|
||||||
|
void *ctxt;
|
||||||
|
|
||||||
|
union { /* Union to accommodate the different callback types */
|
||||||
|
|
||||||
|
/* Unix file descriptors */
|
||||||
|
struct {
|
||||||
|
int fd;
|
||||||
|
short events;
|
||||||
|
int (*callback_f)(void *ctxt, int fd, short events);
|
||||||
|
} fd;
|
||||||
|
|
||||||
|
/* Unix & virtual signals */
|
||||||
|
struct {
|
||||||
|
int signum;
|
||||||
|
int (*callback_f)(void *ctxt, int signo);
|
||||||
|
} sig;
|
||||||
|
|
||||||
|
/* Interval timers */
|
||||||
|
struct {
|
||||||
|
int64_t register_ms,
|
||||||
|
pause_ms,
|
||||||
|
interval_ms,
|
||||||
|
remaining_ms,
|
||||||
|
count;
|
||||||
|
int (*callback_f)(void *ctxt);
|
||||||
|
} timer;
|
||||||
|
|
||||||
|
} un;
|
||||||
|
|
||||||
|
} Cb;
|
||||||
|
|
||||||
|
static int64_t
|
||||||
|
msec2timeout(const Cb *cb, int64_t time_ms)
|
||||||
|
/*********************************************************************
|
||||||
|
* Compute the number of milliseconds remaining for an interval timer.
|
||||||
|
* May be negative if timeout should have already happened.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(ES_TIMER_TYPE == cb->type);
|
||||||
|
|
||||||
|
int64_t when_ms= cb->un.timer.register_ms +
|
||||||
|
cb->un.timer.pause_ms +
|
||||||
|
cb->un.timer.count * cb->un.timer.interval_ms;
|
||||||
|
|
||||||
|
return when_ms - time_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Cb_FdCreate(self, fd, events, callback_f, ctxt)\
|
||||||
|
(Cb_FdConstructor((self)=malloc(sizeof(Cb)), fd, events, callback_f, ctxt) ? (self) : ( self ? realloc(Cb_destructor(self),0): 0))
|
||||||
|
static Cb*
|
||||||
|
Cb_FdConstructor(
|
||||||
|
Cb *self,
|
||||||
|
int fd,
|
||||||
|
short events,
|
||||||
|
int (*callback_f)(void *ctxt, int fd, short events),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/*********************************************************************
|
||||||
|
* Initialize for Unix fd.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->key= ++S.keySrc;
|
||||||
|
self->type= ES_FD_TYPE;
|
||||||
|
self->un.fd.fd= fd;
|
||||||
|
self->un.fd.callback_f= callback_f;
|
||||||
|
self->un.fd.events= events;
|
||||||
|
self->ctxt= ctxt;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define Cb_SignalCreate(self, signum, callback_f, ctxt)\
|
||||||
|
(Cb_SignalConstructor((self)=malloc(sizeof(Cb)), signum, callback_f, ctxt) ? (self) : ( self ? realloc(Cb_destructor(self),0): 0))
|
||||||
|
static Cb*
|
||||||
|
Cb_SignalConstructor(
|
||||||
|
Cb *self,
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signum),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/*********************************************************************
|
||||||
|
* Initialize for Unix signal.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->key= ++S.keySrc;
|
||||||
|
self->type= ES_SIG_TYPE;
|
||||||
|
self->un.sig.signum= signum;
|
||||||
|
self->un.sig.callback_f= callback_f;
|
||||||
|
self->ctxt= ctxt;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Cb_VSignalCreate(self, signum, callback_f, ctxt)\
|
||||||
|
(Cb_VSignalConstructor((self)=malloc(sizeof(Cb)), signum, callback_f, ctxt) ? (self) : ( self ? realloc(Cb_destructor(self),0): 0))
|
||||||
|
static Cb*
|
||||||
|
Cb_VSignalConstructor(
|
||||||
|
Cb *self,
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signum),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/*********************************************************************
|
||||||
|
* Initialize for Unix signal.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->key= ++S.keySrc;
|
||||||
|
self->type= ES_VSIG_TYPE;
|
||||||
|
self->un.sig.signum= signum;
|
||||||
|
self->un.sig.callback_f= callback_f;
|
||||||
|
self->ctxt= ctxt;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Cb_TimerCreate(self, pause_secs, interval_secs, callback_f, ctxt)\
|
||||||
|
(Cb_TimerConstructor((self)=malloc(sizeof(Cb)), pause_secs, interval_secs, callback_f, ctxt) ? (self) : ( self ? realloc(Cb_destructor(self),0): 0))
|
||||||
|
static Cb*
|
||||||
|
Cb_TimerConstructor(
|
||||||
|
Cb *self,
|
||||||
|
int64_t pause_ms,
|
||||||
|
int64_t interval_ms,
|
||||||
|
int (*callback_f)(void *ctxt),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/*********************************************************************
|
||||||
|
* Initialize for an interval timer.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(self);
|
||||||
|
self->key= ++S.keySrc;
|
||||||
|
self->type= ES_TIMER_TYPE;
|
||||||
|
#if ! (defined (_WIN32) || defined (__CYGWIN__))
|
||||||
|
self->un.timer.register_ms= clock_gettime_ms(CLOCK_MONOTONIC_COARSE);
|
||||||
|
#else
|
||||||
|
self->un.timer.register_ms= clock_gettime_ms(CLOCK_MONOTONIC);
|
||||||
|
#endif
|
||||||
|
self->un.timer.pause_ms= pause_ms;
|
||||||
|
self->un.timer.interval_ms= interval_ms;
|
||||||
|
self->un.timer.callback_f= callback_f;
|
||||||
|
self->un.timer.count= 0;
|
||||||
|
self->ctxt= ctxt;
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Cb_destroy(s)\
|
||||||
|
{if(Cb_destructor(s)) {free(s); (s)=NULL;}}
|
||||||
|
static void*
|
||||||
|
Cb_destructor(Cb *self)
|
||||||
|
/************************************************
|
||||||
|
* Free resources associated with object.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************/
|
||||||
|
/***************** ES *********************************************/
|
||||||
|
/******************************************************************/
|
||||||
|
|
||||||
|
static int
|
||||||
|
sigusr2_h(void *ctxt, int unused)
|
||||||
|
/**********************************************************************
|
||||||
|
* Handle any vsignals.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int vsigno;
|
||||||
|
Cb *cb_arr[VSIG_QUEUE_MAX];
|
||||||
|
|
||||||
|
while(EOF != MSGQUEUE_extractMsg(&TS.vsig.mq, &vsigno)) {
|
||||||
|
|
||||||
|
int rc= MAP_findItems(&TS.vsig.map, (void**)cb_arr, VSIG_QUEUE_MAX, &vsigno, sizeof(int));
|
||||||
|
assert(-1 != rc);
|
||||||
|
if(!rc) continue;
|
||||||
|
|
||||||
|
for(int i= 0; i < rc; ++i) {
|
||||||
|
Cb *cb= cb_arr[i];
|
||||||
|
int error= (* cb->un.sig.callback_f)(cb->ctxt, vsigno);
|
||||||
|
if(error) return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
initialize()
|
||||||
|
/**********************************************************************
|
||||||
|
* Initialization for current thread, and once for the whole process.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Get the global mutex */
|
||||||
|
if(pthread_mutex_lock(&S.mtx)) assert (0);
|
||||||
|
|
||||||
|
/* Processwide static data */
|
||||||
|
if(!(S.flags & GLOBAL_INIT_FLG)) {
|
||||||
|
|
||||||
|
S.flags |= GLOBAL_INIT_FLG;
|
||||||
|
if(-1 == sigemptyset(&S.dflt_sa.set)) assert(0);
|
||||||
|
MAP_constructor(&S.vsig.thrd_ts_map, 10, 10);
|
||||||
|
}
|
||||||
|
/* Release the global mutex */
|
||||||
|
if(pthread_mutex_unlock(&S.mtx)) assert (0);
|
||||||
|
|
||||||
|
/* Per-thread static data */
|
||||||
|
PTRVEC_constructor(&TS.fd_vec, 10);
|
||||||
|
PTRVEC_constructor(&TS.timer_vec, 10);
|
||||||
|
for(int i= 0; i < NUMSIGS; ++i) {
|
||||||
|
PTRVEC_constructor(&TS.sig_vec_arr[i], 10);
|
||||||
|
}
|
||||||
|
if(-1 == sigemptyset(&TS.sigsRaised)) assert(0);
|
||||||
|
|
||||||
|
MAP_constructor(&TS.key_map, 10, 10);
|
||||||
|
|
||||||
|
/* Remember so we don't call ourselves more than once in the same thread */
|
||||||
|
TS.tid= pthread_self();
|
||||||
|
|
||||||
|
/* Add ourself to the vsig thread to TS map */
|
||||||
|
if(pthread_mutex_lock(&S.vsig.mtx)) assert (0);
|
||||||
|
MAP_addTypedKey(&S.vsig.thrd_ts_map, TS.tid, &TS);
|
||||||
|
if(pthread_mutex_unlock(&S.vsig.mtx)) assert (0);
|
||||||
|
|
||||||
|
/*--- virtual signal infrastructure ---*/
|
||||||
|
MSGQUEUE_constructor(&TS.vsig.mq, sizeof(int), VSIG_QUEUE_MAX);
|
||||||
|
MAP_constructor(&TS.vsig.map, 10, 10);
|
||||||
|
/* Register a signal handler for SIGUSR2 so we can have virtual signals. */
|
||||||
|
if(-1 == ES_registerSignal(SIGUSR2, sigusr2_h, NULL)) assert(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static unsigned
|
||||||
|
signum2dflt_sa_ndx(int signum)
|
||||||
|
/**********************************************************************
|
||||||
|
* Convert signum to an index for S.dflt_sa.XX
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(SIGKILL != signum && SIGSTOP != signum);
|
||||||
|
if(signum < SIGKILL) return signum - 1;
|
||||||
|
if(signum < SIGSTOP) return signum - 2;
|
||||||
|
return signum - 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerSignal (
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when a particular Unix signal is
|
||||||
|
* raised.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(TS.tid != pthread_self()) initialize();
|
||||||
|
|
||||||
|
Cb *cb;
|
||||||
|
unsigned ndx= signum2dflt_sa_ndx(signum);
|
||||||
|
|
||||||
|
/* Only install a new Unix signal handler if we do not already handle this signal */
|
||||||
|
if(!PTRVEC_numItems(&TS.sig_vec_arr[ndx])) {
|
||||||
|
|
||||||
|
struct sigaction act;
|
||||||
|
|
||||||
|
act.sa_handler = UnixSignalHandler;
|
||||||
|
sigemptyset (&act.sa_mask);
|
||||||
|
act.sa_flags = SA_RESTART|SA_NODEFER;
|
||||||
|
|
||||||
|
/* We only store the default action once per process */
|
||||||
|
if(!sigismember(&S.dflt_sa.set, signum)) {
|
||||||
|
|
||||||
|
sigaddset(&S.dflt_sa.set, signum);
|
||||||
|
|
||||||
|
if (sigaction (signum, &act, &S.dflt_sa.arr[ndx])) assert (0);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (sigaction (signum, &act, NULL)) assert (0);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Cb_SignalCreate(cb, signum, callback_f, ctxt)) assert(0);
|
||||||
|
|
||||||
|
/* All callbacks are put in the key table */
|
||||||
|
MAP_addTypedKey(&TS.key_map, cb->key, cb);
|
||||||
|
|
||||||
|
|
||||||
|
/* Add to the signal vector */
|
||||||
|
PTRVEC_addTail(&TS.sig_vec_arr[signum2dflt_sa_ndx(signum)], cb);
|
||||||
|
|
||||||
|
return cb->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerVSignal (
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when a particular virtual signal is
|
||||||
|
* raised. Virtual signals are implemented on top of the Unix signal, SIGUSR2.
|
||||||
|
*
|
||||||
|
* signum: Any integer number which is meaningful to your application.
|
||||||
|
* callback_f: callback function for when activity is detected.
|
||||||
|
* ctxt: Pointer which will be passed as the last argument to callback_f().
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* If successful, a positive integer which can be used to unregister the callback.
|
||||||
|
* On failure, -1 is returned.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
Cb *cb;
|
||||||
|
|
||||||
|
if(!Cb_VSignalCreate(cb, signum, callback_f, ctxt)) assert(0);
|
||||||
|
|
||||||
|
/* Place in the virtual signal map indexed on signum */
|
||||||
|
MAP_addTypedKey(&TS.vsig.map, cb->un.sig.signum, cb);
|
||||||
|
|
||||||
|
/* All callbacks are put in the key table */
|
||||||
|
MAP_addTypedKey(&TS.key_map, cb->key, cb);
|
||||||
|
|
||||||
|
return cb->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerFd (
|
||||||
|
int fd,
|
||||||
|
short events,
|
||||||
|
int (*callback_f)(void *ctxt, int fd, short events),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when there is activity on the
|
||||||
|
* file descriptor (which may be a file, socket, pipe, etc. under Unix).
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(TS.tid != pthread_self()) initialize();
|
||||||
|
|
||||||
|
Cb *cb;
|
||||||
|
if(!Cb_FdCreate(cb, fd, events, callback_f, ctxt)) assert(0);
|
||||||
|
|
||||||
|
/* Index to vector for quick processing */
|
||||||
|
PTRVEC_addTail(&TS.fd_vec, cb);
|
||||||
|
|
||||||
|
/* All callbacks are put in the key table */
|
||||||
|
MAP_addTypedKey(&TS.key_map, cb->key, cb);
|
||||||
|
return cb->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerTimer (
|
||||||
|
int64_t pause_ms,
|
||||||
|
int64_t interval_ms,
|
||||||
|
int (*callback_f)(void *ctxt),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when a timer times out.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(TS.tid != pthread_self()) initialize();
|
||||||
|
|
||||||
|
Cb *cb;
|
||||||
|
if(!Cb_TimerCreate(cb, pause_ms, interval_ms, callback_f, ctxt)) assert(0);
|
||||||
|
|
||||||
|
/* Add to the timer vector */
|
||||||
|
PTRVEC_addTail(&TS.timer_vec, cb);
|
||||||
|
|
||||||
|
/* All callbacks are put in the key table */
|
||||||
|
MAP_addTypedKey(&TS.key_map, cb->key, cb);
|
||||||
|
|
||||||
|
return cb->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_unregister (int key)
|
||||||
|
/**********************************************************************
|
||||||
|
* Unegister a previously registered callback.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(TS.tid != pthread_self()) initialize();
|
||||||
|
|
||||||
|
// unsigned i;
|
||||||
|
Cb *cb = MAP_findTypedItem(&TS.key_map, key);
|
||||||
|
if(!cb) return -1;
|
||||||
|
|
||||||
|
/* Remove from key table */
|
||||||
|
if(!MAP_removeTypedItem(&TS.key_map, key)) assert(0);;
|
||||||
|
|
||||||
|
/* Different operations needed based on type */
|
||||||
|
switch(cb->type) {
|
||||||
|
|
||||||
|
case ES_FD_TYPE:
|
||||||
|
/* Remove from file descriptor vector */
|
||||||
|
if(!PTRVEC_remove(&TS.fd_vec, cb)) assert(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ES_SIG_TYPE:
|
||||||
|
{
|
||||||
|
unsigned ndx= signum2dflt_sa_ndx(cb->un.sig.signum);
|
||||||
|
|
||||||
|
/* Remove from appropriate signals vector */
|
||||||
|
if(!PTRVEC_remove(&TS.sig_vec_arr[ndx], cb)) assert(0);
|
||||||
|
|
||||||
|
/* If there are no more signals in this vector */
|
||||||
|
if(!PTRVEC_numItems(&TS.sig_vec_arr[ndx])) {
|
||||||
|
|
||||||
|
assert(sigismember(&S.dflt_sa.set, cb->un.sig.signum));
|
||||||
|
|
||||||
|
/* Restore default signal handling */
|
||||||
|
if (sigaction (cb->un.sig.signum, &S.dflt_sa.arr[ndx], NULL)) assert (0);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case ES_VSIG_TYPE:
|
||||||
|
if(!MAP_removeSpecificTypedItem(&TS.vsig.map, cb->un.sig.signum, cb)) assert(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ES_TIMER_TYPE:
|
||||||
|
/* Remove from timer vector */
|
||||||
|
if(!PTRVEC_remove(&TS.timer_vec, cb)) assert(0);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Free the callback object */
|
||||||
|
Cb_destroy(cb);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmp_remaining_ms (const void *const*p1, const void *const*p2)
|
||||||
|
/**********************************************************************
|
||||||
|
* Compare the time remaining for PTRVEC_sort().
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
const Cb *cb1= (const Cb*)(*p1),
|
||||||
|
*cb2= (const Cb*)(*p2);
|
||||||
|
|
||||||
|
assert(ES_TIMER_TYPE == cb1->type &&
|
||||||
|
ES_TIMER_TYPE == cb2->type);
|
||||||
|
|
||||||
|
if(cb1->un.timer.remaining_ms < cb2->un.timer.remaining_ms) return -1;
|
||||||
|
if(cb1->un.timer.remaining_ms == cb2->un.timer.remaining_ms) return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
lastActivity_cmp(const void *const* pp1, const void *const* pp2)
|
||||||
|
{
|
||||||
|
const Cb *cb1= *(const Cb *const*)pp1,
|
||||||
|
*cb2= *(const Cb *const*)pp2;
|
||||||
|
|
||||||
|
/* Put oldest at the top of the vector */
|
||||||
|
if(cb1->lastActivity_ms < cb2->lastActivity_ms) return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_run (void)
|
||||||
|
/**********************************************************************
|
||||||
|
* For this thread, use poll() to monitor socket activity until one
|
||||||
|
* of the registered callback_f() returns non-zero.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* Whatever nonzero value one of the callbacks() returned.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
|
||||||
|
if(TS.tid != pthread_self())
|
||||||
|
initialize();
|
||||||
|
|
||||||
|
/* Loop forever */
|
||||||
|
for(;;) {
|
||||||
|
|
||||||
|
int numFds= PTRVEC_numItems(&TS.fd_vec);
|
||||||
|
struct pollfd pollItemArr[numFds];
|
||||||
|
Cb *cbArr[numFds];
|
||||||
|
|
||||||
|
|
||||||
|
/* This sort provides fair queuing */
|
||||||
|
PTRVEC_sort(&TS.fd_vec, lastActivity_cmp);
|
||||||
|
|
||||||
|
/****** Load up the ZeroMQ pollItemArr *****/
|
||||||
|
unsigned i;
|
||||||
|
Cb *cb;
|
||||||
|
PTRVEC_loopFwd(&TS.fd_vec, i, cb) {
|
||||||
|
|
||||||
|
struct pollfd *item= pollItemArr+i;
|
||||||
|
|
||||||
|
switch(cb->type) {
|
||||||
|
|
||||||
|
case ES_FD_TYPE:
|
||||||
|
item->fd= cb->un.fd.fd;
|
||||||
|
item->events= cb->un.fd.events;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear the return event field for good measure */
|
||||||
|
item->revents= 0;
|
||||||
|
/* Remember the Cb object */
|
||||||
|
cbArr[i]= cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There may not be any timers */
|
||||||
|
int64_t poll_ms= -1;
|
||||||
|
|
||||||
|
/***** If there are any timers to consider ****/
|
||||||
|
if(PTRVEC_numItems(&TS.timer_vec)) {
|
||||||
|
|
||||||
|
#if ! (defined (_WIN32) || defined (__CYGWIN__))
|
||||||
|
int64_t time_ms= clock_gettime_ms(CLOCK_MONOTONIC_COARSE);
|
||||||
|
#else
|
||||||
|
int64_t time_ms= clock_gettime_ms(CLOCK_MONOTONIC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Prepare timers to be sorted */
|
||||||
|
unsigned i;
|
||||||
|
PTRVEC_loopFwd(&TS.timer_vec, i, cb) {
|
||||||
|
assert(ES_TIMER_TYPE == cb->type);
|
||||||
|
cb->un.timer.remaining_ms= msec2timeout(cb, time_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sort them so the most urgent timer is at the top */
|
||||||
|
PTRVEC_sort(&TS.timer_vec, cmp_remaining_ms);
|
||||||
|
|
||||||
|
/* Get the top item */
|
||||||
|
cb= PTRVEC_first(&TS.timer_vec);
|
||||||
|
assert(cb);
|
||||||
|
|
||||||
|
/* This is how long we need to wait */
|
||||||
|
poll_ms= MAX(cb->un.timer.remaining_ms, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************/
|
||||||
|
/******** Wait for something to happen *****************/
|
||||||
|
/*******************************************************/
|
||||||
|
|
||||||
|
int poll_rc= poll(pollItemArr, numFds, poll_ms);
|
||||||
|
|
||||||
|
|
||||||
|
/********* Check return code *****/
|
||||||
|
if(-1 == poll_rc) {
|
||||||
|
switch(errno) {
|
||||||
|
|
||||||
|
case EFAULT:
|
||||||
|
eprintf("\tpoll() failed");
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
case EINTR:
|
||||||
|
/* Signal caused poll() to return, which is OK */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* Respond to signals *****/
|
||||||
|
int signum;
|
||||||
|
for(signum= 1; signum < 32; ++signum) {
|
||||||
|
/* Can't do anything with these signals */
|
||||||
|
if(signum == SIGKILL || signum == SIGSTOP) continue;
|
||||||
|
|
||||||
|
/* See if signum was raised */
|
||||||
|
while(sigismember(&TS.sigsRaised, signum)) {
|
||||||
|
|
||||||
|
/* Clear signum from the set of raised signals */
|
||||||
|
if(-1 == sigdelset(&TS.sigsRaised, signum)) assert(0);
|
||||||
|
|
||||||
|
unsigned ndx= signum2dflt_sa_ndx(signum);
|
||||||
|
|
||||||
|
/* See if any of our callbacks are for signum */
|
||||||
|
PTRVEC_loopFwd(&TS.sig_vec_arr[ndx], i, cb) {
|
||||||
|
|
||||||
|
assert(ES_SIG_TYPE == cb->type);
|
||||||
|
|
||||||
|
/* Call the callback function */
|
||||||
|
int error= (* cb->un.sig.callback_f)(cb->ctxt, signum);
|
||||||
|
|
||||||
|
if(error) return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/********* Service timers ********/
|
||||||
|
if(PTRVEC_numItems(&TS.timer_vec)) {
|
||||||
|
|
||||||
|
int64_t remaining_ms,
|
||||||
|
time_ms;
|
||||||
|
|
||||||
|
#if ! (defined (_WIN32) || defined (__CYGWIN__))
|
||||||
|
time_ms= clock_gettime_ms(CLOCK_MONOTONIC_COARSE);
|
||||||
|
#else
|
||||||
|
time_ms= clock_gettime_ms(CLOCK_MONOTONIC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PTRVEC_loopFwd(&TS.timer_vec, i, cb) {
|
||||||
|
|
||||||
|
/* See how much time remains for this callback */
|
||||||
|
remaining_ms= msec2timeout(cb, time_ms);
|
||||||
|
|
||||||
|
/* close enough */
|
||||||
|
if(remaining_ms < 2) {
|
||||||
|
|
||||||
|
/* Keep track of how many times this timer has fired */
|
||||||
|
++cb->un.timer.count;
|
||||||
|
|
||||||
|
/* Call the callback function */
|
||||||
|
int error= (* cb->un.timer.callback_f)(cb->ctxt);
|
||||||
|
|
||||||
|
/* If this is a single-shot timer, get rid of it now */
|
||||||
|
if(!cb->un.timer.interval_ms) {
|
||||||
|
ES_unregister(cb->key);
|
||||||
|
/* Do this so next vector entry doesn't get skipped */
|
||||||
|
--i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the callback returned non-zero, bail out */
|
||||||
|
if(error) return error;
|
||||||
|
|
||||||
|
} else break; /* time remaining will increase from here on out */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/********** Service file descriptors *******/
|
||||||
|
for(int i= 0; i < numFds; ++i) {
|
||||||
|
|
||||||
|
struct pollfd *item= pollItemArr+i;
|
||||||
|
|
||||||
|
if(!item->revents) continue;
|
||||||
|
|
||||||
|
Cb *cb= cbArr[i];
|
||||||
|
|
||||||
|
#if ! (defined (_WIN32) || defined (__CYGWIN__))
|
||||||
|
cb->lastActivity_ms= clock_gettime_ms(CLOCK_MONOTONIC_COARSE);
|
||||||
|
#else
|
||||||
|
cb->lastActivity_ms= clock_gettime_ms(CLOCK_MONOTONIC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int error;
|
||||||
|
switch(cb->type) {
|
||||||
|
|
||||||
|
case ES_FD_TYPE:
|
||||||
|
/* Call the callback function */
|
||||||
|
error= (* cb->un.fd.callback_f)(cb->ctxt, item->fd, item->revents);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the callback returned non-zero, bail out */
|
||||||
|
if(error) return error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Shouldn't ever get to here */
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_t
|
||||||
|
ES_spawn_thread_sched(
|
||||||
|
void *(*user_main) (void *),
|
||||||
|
void *arg,
|
||||||
|
int sched_policy, /* SCHED_NORMAL || SCHED_FIFO || SCHED_RR || SCHED_BATCH */
|
||||||
|
int priority
|
||||||
|
)
|
||||||
|
/**********************************************************************
|
||||||
|
* Spawn a thread which will begin executing user_main(arg).
|
||||||
|
* NOTE: the calling thread will be blocked until ES_release_parent()
|
||||||
|
* is called from user_main()!
|
||||||
|
*
|
||||||
|
* user_main: function pointer where thread will execute.
|
||||||
|
* arg: address passed to user_main(arg).
|
||||||
|
* sched_policy: Which pthreads scheduling policy to use.
|
||||||
|
* priority: pthreads priority to use.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 for success, nonzero for error
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
pthread_t tid;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
int rtn;
|
||||||
|
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||||
|
|
||||||
|
if(sched_policy == -1) {
|
||||||
|
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
|
||||||
|
} else {
|
||||||
|
struct sched_param sp;
|
||||||
|
pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
||||||
|
if(priority < sched_get_priority_min(sched_policy) ||
|
||||||
|
priority > sched_get_priority_max(sched_policy)) {
|
||||||
|
eprintf("ERROR: priority= %d must be between %d and %d inclusive.", priority, sched_get_priority_min(sched_policy), sched_get_priority_max(sched_policy));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pthread_attr_setschedpolicy(&attr, sched_policy)) assert(0);
|
||||||
|
sp.sched_priority= priority;
|
||||||
|
if(pthread_attr_setschedparam(&attr, &sp)) assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the global mutex */
|
||||||
|
if(pthread_mutex_lock(&S.spawn.mtx)) assert (0);
|
||||||
|
|
||||||
|
/* Get the condition ready for use */
|
||||||
|
pthread_cond_init(&S.spawn.cond, NULL);
|
||||||
|
|
||||||
|
/* This is the flag we will test to know when the child is ready to recieve signals */
|
||||||
|
S.spawn.release_parent= 0;
|
||||||
|
|
||||||
|
/* Get the condition mutex */
|
||||||
|
if(pthread_mutex_lock(&S.spawn.cond_mtx)) assert (0);
|
||||||
|
|
||||||
|
/* Spawn the new thread */
|
||||||
|
rtn = pthread_create (&tid, &attr, user_main, arg);
|
||||||
|
|
||||||
|
/* Now we, the parent, wait on the child */
|
||||||
|
while(!S.spawn.release_parent) {
|
||||||
|
if(pthread_cond_wait(&S.spawn.cond, &S.spawn.cond_mtx)) assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the condition mutex */
|
||||||
|
if(pthread_mutex_unlock(&S.spawn.cond_mtx)) assert (0);
|
||||||
|
|
||||||
|
/* Release the global lock */
|
||||||
|
if(pthread_mutex_unlock(&S.spawn.mtx)) assert (0);
|
||||||
|
|
||||||
|
return tid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ES_release_parent(void)
|
||||||
|
/**********************************************************************
|
||||||
|
* Called by a new thread created with ES_spawn_thread_sched(), so
|
||||||
|
* that the parent can continue execution.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Condition manipulation must be protected by a mutex */
|
||||||
|
if (pthread_mutex_lock (&S.spawn.cond_mtx)) assert (0);
|
||||||
|
|
||||||
|
/* Note that parent may be released */
|
||||||
|
S.spawn.release_parent= 1;
|
||||||
|
|
||||||
|
/* Signal the parent */
|
||||||
|
if(pthread_cond_signal(&S.spawn.cond)) assert(0);
|
||||||
|
|
||||||
|
/* Free up the condition mutex */
|
||||||
|
if (pthread_mutex_unlock (&S.spawn.cond_mtx)) assert (0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ES_cleanup(void)
|
||||||
|
/**********************************************************************
|
||||||
|
* Called by a thread when it exits, to clean up resources.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
assert(TS.tid == pthread_self());
|
||||||
|
|
||||||
|
/* Remove ourself from the vsig thread to TS map */
|
||||||
|
if(pthread_mutex_lock(&S.vsig.mtx)) assert (0);
|
||||||
|
MAP_removeTypedItem(&S.vsig.thrd_ts_map, TS.tid);
|
||||||
|
if(pthread_mutex_unlock(&S.vsig.mtx)) assert (0);
|
||||||
|
|
||||||
|
{ /* Destroy key map */
|
||||||
|
unsigned len= MAP_numItems(&TS.key_map);
|
||||||
|
Cb *cbArr[len];
|
||||||
|
MAP_fetchAllItems(&TS.key_map, (void**)cbArr);
|
||||||
|
for(unsigned i= 0; i < len; ++i) {
|
||||||
|
Cb_destroy(cbArr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
MAP_destructor(&TS.key_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* Destroy vsignal infrastructure */
|
||||||
|
unsigned len= MAP_numItems(&TS.vsig.map);
|
||||||
|
Cb *cbArr[len];
|
||||||
|
MAP_fetchAllItems(&TS.vsig.map, (void**)cbArr);
|
||||||
|
for(unsigned i= 0; i < len; ++i) {
|
||||||
|
Cb_destroy(cbArr[i]);
|
||||||
|
}
|
||||||
|
MAP_destructor(&TS.vsig.map);
|
||||||
|
|
||||||
|
/* Tear down the message queue */
|
||||||
|
MSGQUEUE_destructor(&TS.vsig.mq);
|
||||||
|
}
|
||||||
|
|
||||||
|
PTRVEC_destructor(&TS.fd_vec);
|
||||||
|
PTRVEC_destructor(&TS.timer_vec);
|
||||||
|
|
||||||
|
for(unsigned i= 0; i < NUMSIGS; ++i) {
|
||||||
|
PTRVEC_destructor(TS.sig_vec_arr+i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_VSignal (pthread_t tid, int signum)
|
||||||
|
/**********************************************************************
|
||||||
|
* Send a virtual signal to tid by placing signum in a mutex protected
|
||||||
|
* message queue, and then call pthread_kill(tid, SIGHUP) to notify the thread.
|
||||||
|
*
|
||||||
|
* tid: Target thread identifier.
|
||||||
|
* signum: Any integer number which is meaningful to your application.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0: successful
|
||||||
|
* EOF: the message queue is full
|
||||||
|
* -1: All other failures.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn= EOF-1;
|
||||||
|
/* find the correct TS by thread identifier */
|
||||||
|
if(pthread_mutex_lock(&S.vsig.mtx)) assert (0);
|
||||||
|
struct _TS *ts= MAP_findTypedItem(&S.vsig.thrd_ts_map, tid);
|
||||||
|
if(pthread_mutex_unlock(&S.vsig.mtx)) assert (0);
|
||||||
|
|
||||||
|
if(!ts) {
|
||||||
|
eprintf("ERROR: tid= %s not found!", pthread_t_str(tid));
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(tid == ts->tid);
|
||||||
|
|
||||||
|
/* Place virtual signal in message queue */
|
||||||
|
int rc= MSGQUEUE_submitMsg(&ts->vsig.mq, &signum);
|
||||||
|
if(rc) {
|
||||||
|
rtn= EOF;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And finally tell the target thread to check it's message queue */
|
||||||
|
if(pthread_kill(tid, SIGUSR2)) {
|
||||||
|
sys_eprintf("ERROR: kill(%s, SIGUSR2)", pthread_t_str(tid));
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
|
||||||
|
rtn= 0;
|
||||||
|
abort:
|
||||||
|
return rtn;
|
||||||
|
}
|
186
es.h
Normal file
186
es.h
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
#ifndef ES_H
|
||||||
|
#define ES_H
|
||||||
|
|
||||||
|
/****************************************************************************************
|
||||||
|
* ES is short for "Event Server". This is a per-thread event server
|
||||||
|
* for multiplexing sockets, regular file descriptors, Unix signals, and interval
|
||||||
|
* timers.
|
||||||
|
****************************************************************************************/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerFd (
|
||||||
|
int fd,
|
||||||
|
short events,
|
||||||
|
int (*callback_f)(void *ctxt, int fd, short events),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when there is activity on the
|
||||||
|
* file descriptor (which may be a file, socket, pipe, etc. under Unix).
|
||||||
|
*
|
||||||
|
* fd: the file descriptor to be registered.
|
||||||
|
* events: event bits to monitor (see: man 2 poll).
|
||||||
|
* callback_f: callback function for when activity is detected.
|
||||||
|
* ctxt: Pointer which will be passed as the last argument to callback_f().
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* If successful, a positive integer which can be used to unregister the callback.
|
||||||
|
* On failure, -1 is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerSignal (
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when a particular Unix signal is
|
||||||
|
* raised. Note: callback_f() is not called from a Unix signal handler,
|
||||||
|
* so it is safe to modify data within callback_f().
|
||||||
|
*
|
||||||
|
* signum: Unix signal number of interest (type "trap -l" on command line to see a list of signals)
|
||||||
|
* callback_f: callback function for when activity is detected.
|
||||||
|
* ctxt: Pointer which will be passed as the last argument to callback_f().
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* If successful, a positive integer which can be used to unregister the callback.
|
||||||
|
* On failure, -1 is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerVSignal (
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt,int signo),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when a particular virtual signal is
|
||||||
|
* raised. Virtual signals are implemented on top of the Unix signal, SIGUSR2.
|
||||||
|
*
|
||||||
|
* signum: Any integer number which is meaningful to your application.
|
||||||
|
* callback_f: callback function for when activity is detected.
|
||||||
|
* ctxt: Pointer which will be passed as the last argument to callback_f().
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* If successful, a positive integer which can be used to unregister the callback.
|
||||||
|
* On failure, -1 is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_VSignal (pthread_t tid, int signum);
|
||||||
|
/**********************************************************************
|
||||||
|
* Send a virtual signal to tid by placing signum in a mutex protected
|
||||||
|
* message queue, and then call pthread_kill(tid, SIGHUP) to notify the thread.
|
||||||
|
*
|
||||||
|
* tid: Target thread identifier.
|
||||||
|
* signum: Any integer number which is meaningful to your application.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0: successful
|
||||||
|
* EOF: the message queue is full
|
||||||
|
* -1: All other failures.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_registerTimer (
|
||||||
|
int64_t pause_ms,
|
||||||
|
int64_t interval_ms,
|
||||||
|
int (*callback_f)(void *ctxt),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
/**********************************************************************
|
||||||
|
* Register a function to be called when an interval or single-shot
|
||||||
|
* timer expires. If interval_ms == 0, the timer is single shot, and
|
||||||
|
* can only be ES_unregister()'d before it expires.
|
||||||
|
*
|
||||||
|
* pause_ms: How many milliseconds to wait before initially firing.
|
||||||
|
* interval_ms: How many milliseconds to wait between successive firings.
|
||||||
|
* if this is 0, the timer is single shot.
|
||||||
|
* callback_f: callback function for when timer expires.
|
||||||
|
* ctxt: Pointer which will be passed as the last argument to callback_f().
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* If successful, a positive integer which can be used to unregister the callback.
|
||||||
|
* On failure, -1 is returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_unregister (int key);
|
||||||
|
/**********************************************************************
|
||||||
|
* Unegister a previously registered callback.
|
||||||
|
*
|
||||||
|
* key: value obtained from ES_registerXXX().
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 for success.
|
||||||
|
* -1 for failure (key not found)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ES_run (void);
|
||||||
|
/**********************************************************************
|
||||||
|
* For this thread, use poll() to process socket activity until one
|
||||||
|
* of the registered callback_f() returns non-zero.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* Whatever nonzero value callback_f() returned.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pthread_t
|
||||||
|
ES_spawn_thread_sched(
|
||||||
|
void *(*user_main) (void *),
|
||||||
|
void *arg,
|
||||||
|
int sched_policy, /* SCHED_NORMAL || SCHED_FIFO || SCHED_RR || SCHED_BATCH */
|
||||||
|
int priority
|
||||||
|
);
|
||||||
|
/**********************************************************************
|
||||||
|
* Spawn a thread which will begin executing user_main(arg).
|
||||||
|
* NOTE: the calling thread will be blocked until ES_release_parent()
|
||||||
|
* is called from user_main()!
|
||||||
|
*
|
||||||
|
* user_main: function pointer where thread will execute.
|
||||||
|
* arg: address passed to user_main(arg).
|
||||||
|
* sched_policy: Which pthreads scheduling policy to use.
|
||||||
|
* priority: pthreads priority to use.
|
||||||
|
*
|
||||||
|
* RETURNS:
|
||||||
|
* 0 for success, nonzero for error
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ES_spawn_thread(user_main, arg) \
|
||||||
|
ES_spawn_thread_sched(user_main, arg, -1, 0)
|
||||||
|
/**********************************************************************
|
||||||
|
* This is a convenience macro.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
ES_release_parent(void);
|
||||||
|
/**********************************************************************
|
||||||
|
* Called by a new thread created with ES_spawn_thread_sched(), so
|
||||||
|
* that the parent can continue execution.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
ES_cleanup(void);
|
||||||
|
/**********************************************************************
|
||||||
|
* Called by a thread when it exits, to clean up resources.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
129
ez_es.c
Normal file
129
ez_es.c
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "ez_es.h"
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_ES_registerFd (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd,
|
||||||
|
short events,
|
||||||
|
int (*callback_f)(void *ctxt, int fd, short events),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_registerFd(fd, events, callback_f, ctxt);
|
||||||
|
if(-1 == rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_registerFd() failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
|
||||||
|
int _ez_ES_registerSignal (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_registerSignal(signum, callback_f, ctxt);
|
||||||
|
if(-1 == rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_registerSignal() failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
|
||||||
|
int _ez_ES_registerVSignal (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_registerVSignal(signum, callback_f, ctxt);
|
||||||
|
if(-1 == rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_registerVSignal() failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_ES_VSignal (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
pthread_t tid,
|
||||||
|
int signum
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_VSignal(tid, signum);
|
||||||
|
if(rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_VSignal() returned %d.", rtn);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_ES_registerTimer (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int64_t pause_ms,
|
||||||
|
int64_t interval_ms,
|
||||||
|
int (*callback_f)(void *ctxt),
|
||||||
|
void *ctxt
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_registerTimer(pause_ms, interval_ms, callback_f, ctxt);
|
||||||
|
if(-1 == rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_registerTimer() failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_ES_unregister (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int key
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_unregister(key);
|
||||||
|
if(-1 == rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_unregister() failed.");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_ES_run (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int rtn= ES_run();
|
||||||
|
if(rtn) {
|
||||||
|
_eprintf(fileName, lineNo, funcName, "ES_run() returned %d", rtn);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
95
ez_es.h
Normal file
95
ez_es.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/****************************************************************************************************************************
|
||||||
|
* NOTE: look in "es.h" for function documentation. The ez_XXX() macros here only wrap the ES_XXX() functions
|
||||||
|
* for the purpose of boilerplate error handling.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EZ_ES_H
|
||||||
|
#define EZ_ES_H
|
||||||
|
|
||||||
|
#include "es.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ez_ES_registerFd(fd, events, callback_f, ctxt) \
|
||||||
|
_ez_ES_registerFd(__FILE__, __LINE__, __FUNCTION__, fd, events, callback_f, ctxt)
|
||||||
|
int _ez_ES_registerFd (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int fd,
|
||||||
|
short events,
|
||||||
|
int (*callback_f)(void *ctxt, int fd, short events),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define ez_ES_registerSignal(signum, callback_f, ctxt) \
|
||||||
|
_ez_ES_registerSignal(__FILE__, __LINE__, __FUNCTION__, signum, callback_f, ctxt)
|
||||||
|
int _ez_ES_registerSignal (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_ES_registerVSignal(signum, callback_f, ctxt) \
|
||||||
|
_ez_ES_registerVSignal(__FILE__, __LINE__, __FUNCTION__, signum, callback_f, ctxt)
|
||||||
|
int _ez_ES_registerVSignal (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int signum,
|
||||||
|
int (*callback_f)(void *ctxt, int signo),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_ES_VSignal(tid, signum) \
|
||||||
|
_ez_ES_VSignal(__FILE__, __LINE__, __FUNCTION__, tid, signum)
|
||||||
|
int _ez_ES_VSignal (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
pthread_t tid,
|
||||||
|
int signum
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_ES_registerTimer(pause_ms, interval_ms, callback_f, ctxt) \
|
||||||
|
_ez_ES_registerTimer(__FILE__, __LINE__, __FUNCTION__, pause_ms, interval_ms, callback_f, ctxt)
|
||||||
|
int _ez_ES_registerTimer (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int64_t pause_ms,
|
||||||
|
int64_t interval_ms,
|
||||||
|
int (*callback_f)(void *ctxt),
|
||||||
|
void *ctxt
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#define ez_ES_unregister(key) \
|
||||||
|
{_ez_ES_unregister(__FILE__, __LINE__, __FUNCTION__, key); (key)= 0;}
|
||||||
|
int _ez_ES_unregister (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int key
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_ES_run() \
|
||||||
|
_ez_ES_run(__FILE__, __LINE__, __FUNCTION__)
|
||||||
|
int _ez_ES_run (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
74
ez_libanl.c
Normal file
74
ez_libanl.c
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "ez_libanl.h"
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_getaddrinfo_a(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int mode,
|
||||||
|
struct gaicb *list[],
|
||||||
|
int nitems,
|
||||||
|
struct sigevent *sevp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
errno= 0;
|
||||||
|
int rtn= getaddrinfo_a (mode, list, nitems, sevp);
|
||||||
|
switch(rtn) {
|
||||||
|
case 0:
|
||||||
|
case EAI_AGAIN:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _sys_eprintf() will pass errno to gai_sterror */
|
||||||
|
errno= rtn;
|
||||||
|
_sys_eprintf(gai_strerror, fileName, lineNo, funcName, "getaddrinfo_a() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_gai_suspend(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const struct gaicb * const list[],
|
||||||
|
int nitems,
|
||||||
|
const struct timespec *timeout
|
||||||
|
)
|
||||||
|
{
|
||||||
|
errno= 0;
|
||||||
|
int rtn= gai_suspend (list, nitems, timeout);
|
||||||
|
switch(rtn) {
|
||||||
|
case 0:
|
||||||
|
case EAI_AGAIN:
|
||||||
|
case EAI_ALLDONE:
|
||||||
|
case EAI_INTR:
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _sys_eprintf() will pass errno to gai_sterror */
|
||||||
|
errno= rtn;
|
||||||
|
_sys_eprintf(gai_strerror, fileName, lineNo, funcName, "gai_suspend() failed");
|
||||||
|
abort();
|
||||||
|
}
|
59
ez_libanl.h
Normal file
59
ez_libanl.h
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2019 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef EZ_LIBANL_H
|
||||||
|
#define EZ_LIBANL_H
|
||||||
|
|
||||||
|
/* Simplified interface to libanl functions */
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ez_getaddrinfo_a(mode, list, nItems, sevp) \
|
||||||
|
_ez_getaddrinfo_a(__FILE__, __LINE__, __FUNCTION__, mode, list, nItems, sevp)
|
||||||
|
int _ez_getaddrinfo_a(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
int mode,
|
||||||
|
struct gaicb *list[],
|
||||||
|
int nitems,
|
||||||
|
struct sigevent *sevp
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_gai_suspend(list, nItems, timeout) \
|
||||||
|
_ez_gai_suspend(__FILE__, __LINE__, __FUNCTION__, list, nItems, timeout)
|
||||||
|
int _ez_gai_suspend(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const struct gaicb * const list[],
|
||||||
|
int nitems,
|
||||||
|
const struct timespec *timeout
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
69
ez_libc.c
69
ez_libc.c
@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
@ -388,3 +389,71 @@ int _ez_unlink (
|
|||||||
}
|
}
|
||||||
return rtn;
|
return rtn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_getaddrinfo(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *node,
|
||||||
|
const char *service,
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res
|
||||||
|
)
|
||||||
|
{
|
||||||
|
errno= 0;
|
||||||
|
int rtn= getaddrinfo (node, service, hints, res);
|
||||||
|
switch(rtn) {
|
||||||
|
case 0:
|
||||||
|
case EAI_AGAIN:
|
||||||
|
case EAI_FAIL:
|
||||||
|
#ifdef EAI_NODATA
|
||||||
|
case EAI_NODATA:
|
||||||
|
#endif
|
||||||
|
return rtn;
|
||||||
|
|
||||||
|
case EAI_SYSTEM:
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "getaddrinfo(\"%s:%s\") failed", node, service);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _sys_eprintf() will pass errno to gai_sterror */
|
||||||
|
errno= rtn;
|
||||||
|
_sys_eprintf(gai_strerror, fileName, lineNo, funcName, "getaddrinfo(\"%s:%s\") failed", node, service);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************/
|
||||||
|
int _ez_getnameinfo(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const struct sockaddr *addr,
|
||||||
|
socklen_t addrlen,
|
||||||
|
char *host,
|
||||||
|
socklen_t hostlen,
|
||||||
|
char *serv,
|
||||||
|
socklen_t servlen,
|
||||||
|
int flags
|
||||||
|
)
|
||||||
|
{
|
||||||
|
errno= 0;
|
||||||
|
int rtn= getnameinfo (addr, addrlen, host, hostlen, serv, servlen, flags);
|
||||||
|
switch(rtn) {
|
||||||
|
case 0:
|
||||||
|
case EAI_AGAIN:
|
||||||
|
case EAI_FAIL:
|
||||||
|
case EAI_NONAME:
|
||||||
|
return rtn;
|
||||||
|
|
||||||
|
case EAI_SYSTEM:
|
||||||
|
_sys_eprintf((const char*(*)(int))strerror, fileName, lineNo, funcName, "getnameinfo() failed");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* _sys_eprintf() will pass errno to gai_sterror */
|
||||||
|
errno= rtn;
|
||||||
|
_sys_eprintf(gai_strerror, fileName, lineNo, funcName, "getnameinfo() failed", rtn);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
170
ez_libc.h
170
ez_libc.h
@ -19,7 +19,7 @@
|
|||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
ez_libc.h - description
|
ez_libc.h - description
|
||||||
libc calls with boilerplate error handling.
|
glibc calls with boilerplate error handling.
|
||||||
|
|
||||||
-------------------
|
-------------------
|
||||||
begin : Tue Nov 13 19:42:23 EST 2018
|
begin : Tue Nov 13 19:42:23 EST 2018
|
||||||
@ -28,12 +28,14 @@ libc calls with boilerplate error handling.
|
|||||||
#ifndef EZ_LIBC_H
|
#ifndef EZ_LIBC_H
|
||||||
#define EZ_LIBC_H
|
#define EZ_LIBC_H
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <netdb.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -43,9 +45,9 @@ extern "C" {
|
|||||||
#define ez_fputs(s, stream) \
|
#define ez_fputs(s, stream) \
|
||||||
_ez_fputs(__FILE__, __LINE__, __FUNCTION__, s, stream)
|
_ez_fputs(__FILE__, __LINE__, __FUNCTION__, s, stream)
|
||||||
int _ez_fputs (
|
int _ez_fputs (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *s,
|
const char *s,
|
||||||
FILE *stream
|
FILE *stream
|
||||||
);
|
);
|
||||||
@ -53,9 +55,9 @@ int _ez_fputs (
|
|||||||
#define ez_fputc(c, stream) \
|
#define ez_fputc(c, stream) \
|
||||||
_ez_fputc(__FILE__, __LINE__, __FUNCTION__, c, stream)
|
_ez_fputc(__FILE__, __LINE__, __FUNCTION__, c, stream)
|
||||||
int _ez_fputc (
|
int _ez_fputc (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
int c,
|
int c,
|
||||||
FILE *stream
|
FILE *stream
|
||||||
);
|
);
|
||||||
@ -63,9 +65,9 @@ int _ez_fputc (
|
|||||||
#define ez_fprintf(stream, fmt, ...) \
|
#define ez_fprintf(stream, fmt, ...) \
|
||||||
_ez_fprintf(__FILE__, __LINE__, __FUNCTION__, stream, fmt, ##__VA_ARGS__)
|
_ez_fprintf(__FILE__, __LINE__, __FUNCTION__, stream, fmt, ##__VA_ARGS__)
|
||||||
int _ez_fprintf (
|
int _ez_fprintf (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
FILE *stream,
|
FILE *stream,
|
||||||
const char *fmt,
|
const char *fmt,
|
||||||
...
|
...
|
||||||
@ -74,9 +76,9 @@ int _ez_fprintf (
|
|||||||
#define ez_popen(command, type) \
|
#define ez_popen(command, type) \
|
||||||
_ez_popen(__FILE__, __LINE__, __FUNCTION__, command, type)
|
_ez_popen(__FILE__, __LINE__, __FUNCTION__, command, type)
|
||||||
FILE* _ez_popen (
|
FILE* _ez_popen (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *command,
|
const char *command,
|
||||||
const char *type
|
const char *type
|
||||||
);
|
);
|
||||||
@ -84,9 +86,9 @@ FILE* _ez_popen (
|
|||||||
#define ez_fopen(pathname, mode) \
|
#define ez_fopen(pathname, mode) \
|
||||||
_ez_fopen(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
_ez_fopen(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
||||||
FILE* _ez_fopen (
|
FILE* _ez_fopen (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *pathname,
|
const char *pathname,
|
||||||
const char *mode
|
const char *mode
|
||||||
);
|
);
|
||||||
@ -94,18 +96,18 @@ FILE* _ez_fopen (
|
|||||||
#define ez_fclose(stream) \
|
#define ez_fclose(stream) \
|
||||||
_ez_fclose(__FILE__, __LINE__, __FUNCTION__, stream)
|
_ez_fclose(__FILE__, __LINE__, __FUNCTION__, stream)
|
||||||
int _ez_fclose (
|
int _ez_fclose (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
FILE *stream
|
FILE *stream
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_fread(ptr, size, nmemb, stream) \
|
#define ez_fread(ptr, size, nmemb, stream) \
|
||||||
_ez_fread(__FILE__, __LINE__, __FUNCTION__, ptr, size, nmemb, stream)
|
_ez_fread(__FILE__, __LINE__, __FUNCTION__, ptr, size, nmemb, stream)
|
||||||
size_t _ez_fread(
|
size_t _ez_fread(
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
void *ptr,
|
void *ptr,
|
||||||
size_t size,
|
size_t size,
|
||||||
size_t nmemb,
|
size_t nmemb,
|
||||||
@ -115,9 +117,9 @@ size_t _ez_fread(
|
|||||||
#define ez_fwrite(ptr, size, nmemb, stream) \
|
#define ez_fwrite(ptr, size, nmemb, stream) \
|
||||||
_ez_fwrite(__FILE__, __LINE__, __FUNCTION__, ptr, size, nmemb, stream)
|
_ez_fwrite(__FILE__, __LINE__, __FUNCTION__, ptr, size, nmemb, stream)
|
||||||
size_t _ez_fwrite(
|
size_t _ez_fwrite(
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const void *ptr,
|
const void *ptr,
|
||||||
size_t size,
|
size_t size,
|
||||||
size_t nmemb,
|
size_t nmemb,
|
||||||
@ -128,18 +130,18 @@ size_t _ez_fwrite(
|
|||||||
#define ez_pclose(stream) \
|
#define ez_pclose(stream) \
|
||||||
_ez_pclose(__FILE__, __LINE__, __FUNCTION__, stream)
|
_ez_pclose(__FILE__, __LINE__, __FUNCTION__, stream)
|
||||||
int _ez_pclose (
|
int _ez_pclose (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
FILE *stream
|
FILE *stream
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_fgets(s, size, stream) \
|
#define ez_fgets(s, size, stream) \
|
||||||
_ez_fgets(__FILE__, __LINE__, __FUNCTION__, s, size, stream)
|
_ez_fgets(__FILE__, __LINE__, __FUNCTION__, s, size, stream)
|
||||||
char* _ez_fgets (
|
char* _ez_fgets (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
char *s,
|
char *s,
|
||||||
int size,
|
int size,
|
||||||
FILE *stream
|
FILE *stream
|
||||||
@ -148,18 +150,18 @@ char* _ez_fgets (
|
|||||||
#define ez_remove(pathname) \
|
#define ez_remove(pathname) \
|
||||||
_ez_remove(__FILE__, __LINE__, __FUNCTION__, pathname)
|
_ez_remove(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
int _ez_remove (
|
int _ez_remove (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *pathname
|
const char *pathname
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_rename(oldpath, newpath) \
|
#define ez_rename(oldpath, newpath) \
|
||||||
_ez_rename(__FILE__, __LINE__, __FUNCTION__, oldpath, newpath)
|
_ez_rename(__FILE__, __LINE__, __FUNCTION__, oldpath, newpath)
|
||||||
int _ez_rename (
|
int _ez_rename (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *oldpath,
|
const char *oldpath,
|
||||||
const char *newpath
|
const char *newpath
|
||||||
);
|
);
|
||||||
@ -167,36 +169,36 @@ int _ez_rename (
|
|||||||
#define ez_opendir(name) \
|
#define ez_opendir(name) \
|
||||||
_ez_opendir(__FILE__, __LINE__, __FUNCTION__, name)
|
_ez_opendir(__FILE__, __LINE__, __FUNCTION__, name)
|
||||||
DIR* _ez_opendir (
|
DIR* _ez_opendir (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *name
|
const char *name
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_closedir(dirp) \
|
#define ez_closedir(dirp) \
|
||||||
_ez_closedir(__FILE__, __LINE__, __FUNCTION__, dirp)
|
_ez_closedir(__FILE__, __LINE__, __FUNCTION__, dirp)
|
||||||
int _ez_closedir (
|
int _ez_closedir (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
DIR *dirp
|
DIR *dirp
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_readdir(dirp) \
|
#define ez_readdir(dirp) \
|
||||||
_ez_readdir(__FILE__, __LINE__, __FUNCTION__, dirp)
|
_ez_readdir(__FILE__, __LINE__, __FUNCTION__, dirp)
|
||||||
struct dirent* _ez_readdir (
|
struct dirent* _ez_readdir (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
DIR *dirp
|
DIR *dirp
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_close(fd) \
|
#define ez_close(fd) \
|
||||||
_ez_close(__FILE__, __LINE__, __FUNCTION__, fd)
|
_ez_close(__FILE__, __LINE__, __FUNCTION__, fd)
|
||||||
int _ez_close (
|
int _ez_close (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
int fd
|
int fd
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -217,9 +219,9 @@ ssize_t _ez_read (
|
|||||||
#define ez_write(fd, buf, count) \
|
#define ez_write(fd, buf, count) \
|
||||||
_ez_write(__FILE__, __LINE__, __FUNCTION__, fd, buf, count)
|
_ez_write(__FILE__, __LINE__, __FUNCTION__, fd, buf, count)
|
||||||
ssize_t _ez_write (
|
ssize_t _ez_write (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
int fd,
|
int fd,
|
||||||
const void *buf,
|
const void *buf,
|
||||||
size_t count
|
size_t count
|
||||||
@ -228,10 +230,10 @@ ssize_t _ez_write (
|
|||||||
#define ez_stat(pathname, statbuf) \
|
#define ez_stat(pathname, statbuf) \
|
||||||
_ez_stat(__FILE__, __LINE__, __FUNCTION__, pathname, statbuf)
|
_ez_stat(__FILE__, __LINE__, __FUNCTION__, pathname, statbuf)
|
||||||
int _ez_stat (
|
int _ez_stat (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *pathname,
|
const char *pathname,
|
||||||
struct stat *statbuf
|
struct stat *statbuf
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -239,9 +241,9 @@ int _ez_stat (
|
|||||||
#define ez_mkdir(pathname, mode) \
|
#define ez_mkdir(pathname, mode) \
|
||||||
_ez_mkdir(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
_ez_mkdir(__FILE__, __LINE__, __FUNCTION__, pathname, mode)
|
||||||
int _ez_mkdir (
|
int _ez_mkdir (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *pathname,
|
const char *pathname,
|
||||||
mode_t mode
|
mode_t mode
|
||||||
);
|
);
|
||||||
@ -249,21 +251,57 @@ int _ez_mkdir (
|
|||||||
#define ez_rmdir(pathname) \
|
#define ez_rmdir(pathname) \
|
||||||
_ez_rmdir(__FILE__, __LINE__, __FUNCTION__, pathname)
|
_ez_rmdir(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
int _ez_rmdir (
|
int _ez_rmdir (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *pathname
|
const char *pathname
|
||||||
);
|
);
|
||||||
|
|
||||||
#define ez_unlink(pathname) \
|
#define ez_unlink(pathname) \
|
||||||
_ez_unlink(__FILE__, __LINE__, __FUNCTION__, pathname)
|
_ez_unlink(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
int _ez_unlink (
|
int _ez_unlink (
|
||||||
const char *fileName,
|
const char *fileName,
|
||||||
int lineNo,
|
int lineNo,
|
||||||
const char *funcName,
|
const char *funcName,
|
||||||
const char *pathname
|
const char *pathname
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#define ez_unlink(pathname) \
|
||||||
|
_ez_unlink(__FILE__, __LINE__, __FUNCTION__, pathname)
|
||||||
|
int _ez_unlink (
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *pathname
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_getaddrinfo(node, service, hints, res) \
|
||||||
|
_ez_getaddrinfo(__FILE__, __LINE__, __FUNCTION__, node, service, hints, res)
|
||||||
|
int _ez_getaddrinfo(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const char *node,
|
||||||
|
const char *service,
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res
|
||||||
|
);
|
||||||
|
|
||||||
|
#define ez_getnameinfo(addr, addrlen, host, hostlen, serv, servlen, flags) \
|
||||||
|
_ez_getnameinfo(__FILE__, __LINE__, __FUNCTION__, addr, addrlen, host, hostlen, serv, servlen, flags)
|
||||||
|
int _ez_getnameinfo(
|
||||||
|
const char *fileName,
|
||||||
|
int lineNo,
|
||||||
|
const char *funcName,
|
||||||
|
const struct sockaddr *addr,
|
||||||
|
socklen_t addrlen,
|
||||||
|
char *host,
|
||||||
|
socklen_t hostlen,
|
||||||
|
char *serv,
|
||||||
|
socklen_t servlen,
|
||||||
|
int flags
|
||||||
|
);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -44,7 +45,7 @@ initialize (void)
|
|||||||
{
|
{
|
||||||
S.is_init= 1;
|
S.is_init= 1;
|
||||||
|
|
||||||
MAP_constructor(&S.addr_map, N_ADDRESSES_HINT/10, 10);
|
MAP_constructor(&S.addr_map, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
|
||||||
|
|
||||||
const static struct ipv {
|
const static struct ipv {
|
||||||
const char *cmd,
|
const char *cmd,
|
||||||
@ -71,7 +72,7 @@ initialize (void)
|
|||||||
|
|
||||||
if(regex_compile(&re, ipv->pattern, REG_EXTENDED)) {
|
if(regex_compile(&re, ipv->pattern, REG_EXTENDED)) {
|
||||||
eprintf("ERROR: regex_compile(\"%s\") failed.", ipv->pattern);
|
eprintf("ERROR: regex_compile(\"%s\") failed.", ipv->pattern);
|
||||||
exit(1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fh= ez_popen(ipv->cmd, "r");
|
fh= ez_popen(ipv->cmd, "r");
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
* Free Software Foundation, Inc., *
|
* Free Software Foundation, Inc., *
|
||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -47,7 +48,7 @@ common_constructor(LOGFILE *self)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
memset(self, 0, sizeof(*self));
|
memset(self, 0, sizeof(*self));
|
||||||
MAP_constructor(&self->addr2logEntry_map, N_ADDRESSES_HINT/10, 10);
|
MAP_constructor(&self->addr2logEntry_map, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOGFILE*
|
LOGFILE*
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
@ -199,7 +200,7 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
|||||||
rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, sumStr);
|
rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, sumStr);
|
||||||
if(sizeof(CacheFname) == rc) {
|
if(sizeof(CacheFname) == rc) {
|
||||||
eprintf("FATAL: File path truncated!");
|
eprintf("FATAL: File path truncated!");
|
||||||
exit(1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
LOGFILE *f;
|
LOGFILE *f;
|
||||||
|
|
||||||
@ -259,7 +260,7 @@ LOGTYPE_proto_constructor(LOGTYPE *self, const struct logProtoType *proto)
|
|||||||
rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, entry->d_name);
|
rc= snprintf(CacheFname, sizeof(CacheFname), "%s/%s", CacheDname, entry->d_name);
|
||||||
if(sizeof(CacheFname) == rc) {
|
if(sizeof(CacheFname) == rc) {
|
||||||
eprintf("FATAL: File path truncated!");
|
eprintf("FATAL: File path truncated!");
|
||||||
exit(1);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
ez_unlink(CacheFname);
|
ez_unlink(CacheFname);
|
||||||
}
|
}
|
||||||
@ -474,7 +475,7 @@ LOGTYPE_addressCount(LOGTYPE *self)
|
|||||||
{
|
{
|
||||||
/* We'll need a map in which to collect unique addresses */
|
/* We'll need a map in which to collect unique addresses */
|
||||||
static MAP smap;
|
static MAP smap;
|
||||||
MAP_sinit(&smap, N_ADDRESSES_HINT/10, 10);
|
MAP_sinit(&smap, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
|
||||||
|
|
||||||
/* Collect results for all LOGILE objects we own */
|
/* Collect results for all LOGILE objects we own */
|
||||||
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_map_addr, &smap);
|
MAP_visitAllEntries(&self->file_map, (int(*)(void*,void*))LOGFILE_map_addr, &smap);
|
||||||
|
2
maxoff.c
2
maxoff.c
@ -36,7 +36,7 @@ initialize(void)
|
|||||||
{
|
{
|
||||||
S.is_init= 1;
|
S.is_init= 1;
|
||||||
MAP_constructor(&S.cntry_map, 10, 10);
|
MAP_constructor(&S.cntry_map, 10, 10);
|
||||||
MAP_constructor(&S.addr_map, N_ADDRESSES_HINT/10, 10);
|
MAP_constructor(&S.addr_map, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compiler doesn't like that we use integers in place of item pointers */
|
// Compiler doesn't like that we use integers in place of item pointers */
|
||||||
|
157
msgqueue.c
Normal file
157
msgqueue.c
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2008 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "msgqueue.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
MSGQUEUE *
|
||||||
|
MSGQUEUE_constructor (MSGQUEUE * self, size_t msgSize, unsigned int queueLen)
|
||||||
|
{
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pthread_mutex_init (&self->mtx, NULL);
|
||||||
|
|
||||||
|
/* Allocate the memory in which to store messages */
|
||||||
|
if (!(self->buff_ptr = (char *) malloc (msgSize * queueLen)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize the header segment */
|
||||||
|
self->numItems = 0;
|
||||||
|
self->head = 0;
|
||||||
|
self->tail = 0;
|
||||||
|
self->msgSize = msgSize;
|
||||||
|
self->maxItems = queueLen;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
MSGQUEUE_destructor (MSGQUEUE * self)
|
||||||
|
{
|
||||||
|
pthread_mutex_destroy (&self->mtx);
|
||||||
|
free (self->buff_ptr);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MSGQUEUE_submitMsg (MSGQUEUE * self, const void *msgBuf)
|
||||||
|
/*******************************************************************
|
||||||
|
* Submit a message to the message queue.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn = 0;
|
||||||
|
|
||||||
|
if (pthread_mutex_lock (&self->mtx))
|
||||||
|
assert (0);
|
||||||
|
|
||||||
|
if (self->numItems == self->maxItems)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
eprintf("WARNING: %p queue full.", self);
|
||||||
|
#endif
|
||||||
|
rtn = EOF;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is not the first item to be added */
|
||||||
|
if (self->numItems)
|
||||||
|
self->tail = (self->tail + 1) % self->maxItems;
|
||||||
|
|
||||||
|
memcpy (self->buff_ptr + self->tail * self->msgSize, msgBuf, self->msgSize);
|
||||||
|
|
||||||
|
self->numItems++;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (pthread_mutex_unlock (&self->mtx))
|
||||||
|
assert (0);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MSGQUEUE_extractMsg (MSGQUEUE * self, void *msgBuf)
|
||||||
|
/*****************************************************************************
|
||||||
|
* Extract a message from the message queue. Returns EOF when queue is empty.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn = 0;
|
||||||
|
|
||||||
|
if (pthread_mutex_lock (&self->mtx))
|
||||||
|
assert (0);
|
||||||
|
if (!self->numItems)
|
||||||
|
{
|
||||||
|
rtn = EOF;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->numItems--;
|
||||||
|
memcpy (msgBuf, self->buff_ptr + self->head * self->msgSize, self->msgSize);
|
||||||
|
|
||||||
|
if (self->numItems)
|
||||||
|
self->head = (self->head + 1) % self->maxItems;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (pthread_mutex_unlock (&self->mtx))
|
||||||
|
assert (0);
|
||||||
|
return rtn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
MSGQUEUE_checkQueue (MSGQUEUE * self,
|
||||||
|
int (*check) (void *data_ptr, void *arg), void *arg)
|
||||||
|
/*****************************************************************************
|
||||||
|
* Runs through the message queuue calling check() until it returns non-zero,
|
||||||
|
* or the queue is fully traversed.
|
||||||
|
* Return: 0 -> check() always returned zero, or queue was empty.
|
||||||
|
* otherwise, return value of check().
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
int rtn = 0;
|
||||||
|
unsigned int i;
|
||||||
|
void *ptr;
|
||||||
|
|
||||||
|
if (pthread_mutex_lock (&self->mtx))
|
||||||
|
assert (0);
|
||||||
|
|
||||||
|
if (!self->numItems)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
for (i = 0, ptr = self->buff_ptr + self->head * self->msgSize;
|
||||||
|
i < self->numItems;
|
||||||
|
i++, ptr =
|
||||||
|
self->buff_ptr + ((self->head + i) % self->maxItems) * self->msgSize)
|
||||||
|
{
|
||||||
|
if ((rtn = (*check) (ptr, arg)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (pthread_mutex_unlock (&self->mtx))
|
||||||
|
assert (0);
|
||||||
|
return rtn;
|
||||||
|
}
|
138
msgqueue.h
Normal file
138
msgqueue.h
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* Copyright (C) 2008 by John D. Robertson *
|
||||||
|
* john@rrci.com *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||||
|
***************************************************************************/
|
||||||
|
#ifndef MSGQUEUE_H
|
||||||
|
#define MSGQUEUE_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
/*******************************
|
||||||
|
* Necessary info for circular message
|
||||||
|
* ring.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
pthread_mutex_t mtx;
|
||||||
|
unsigned int numItems, head, tail;
|
||||||
|
unsigned int msgSize, maxItems;
|
||||||
|
char *buff_ptr;
|
||||||
|
} MSGQUEUE;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MSGQUEUE*
|
||||||
|
MSGQUEUE_constructor (
|
||||||
|
MSGQUEUE *self,
|
||||||
|
size_t msgSize,
|
||||||
|
unsigned int queueLen
|
||||||
|
);
|
||||||
|
/*****************************************************************************
|
||||||
|
* Prepare the MSGQUEUE structure for service.
|
||||||
|
*
|
||||||
|
* self - Address of the MSGQUEUE structure on which to operate.
|
||||||
|
* msgSize - The size of messages this queue will handle.
|
||||||
|
* queueLen - How many messages can be stored in this queue.
|
||||||
|
*
|
||||||
|
* Returns: NULL for failure, 'self' otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define MSGQUEUE_create(self, msgSize, queueLen)\
|
||||||
|
(MSGQUEUE_constructor((self)=malloc(sizeof(MSGQUEUE)), msgSize, queueLen) ? (self) : ( self ? realloc(MSGQUEUE_destructor(self),0): 0))
|
||||||
|
/*****************************************************************************
|
||||||
|
* Allocate and prepare the MSGQUEUE structure for service.
|
||||||
|
*
|
||||||
|
* self - Pointer that will be set to the address of the MSGQUEUE structure.
|
||||||
|
* msgSize - The size of messages this queue will handle.
|
||||||
|
* queueLen - How many messages can be stored in this queue.
|
||||||
|
*
|
||||||
|
* Returns: NULL for failure, 'self' otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void*
|
||||||
|
MSGQUEUE_destructor (MSGQUEUE *self);
|
||||||
|
/*****************************************************************************
|
||||||
|
* Free resources associated with a MSGQUEUE. Note that 'self' is not free()'d.
|
||||||
|
*
|
||||||
|
* self - Address of the MSGQUEUE structure on which to operate.
|
||||||
|
*
|
||||||
|
* Returns: NULL for failure, 'self' otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define MSGQUEUE_destroy(s) \
|
||||||
|
{if(MSGQUEUE_destructor(s)) {free(s);}}
|
||||||
|
/*****************************************************************************
|
||||||
|
* Free resources associated with a MSGQUEUE, and free the structure.
|
||||||
|
*
|
||||||
|
* self - Address of the MSGQUEUE structure on which to operate.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MSGQUEUE_submitMsg (
|
||||||
|
MSGQUEUE *self,
|
||||||
|
const void *msgBuf
|
||||||
|
);
|
||||||
|
/*******************************************************************
|
||||||
|
* Submit a message to the message queue.
|
||||||
|
*
|
||||||
|
* self - Address of the MSGQUEUE structure on which to operate.
|
||||||
|
* msgBuf - buffer containing the message to be copied into the queue.
|
||||||
|
*
|
||||||
|
* Returns: 0 for success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MSGQUEUE_extractMsg (
|
||||||
|
MSGQUEUE *self,
|
||||||
|
void *msgBuf
|
||||||
|
);
|
||||||
|
/*****************************************************************************
|
||||||
|
* Extract a message from the message queue if possible.
|
||||||
|
*
|
||||||
|
* self - Address of the MSGQUEUE structure on which to operate.
|
||||||
|
* msgBuf - buffer to which the message will be copied.
|
||||||
|
*
|
||||||
|
* Returns: 0 for success, EOF if the queue is empty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
MSGQUEUE_checkQueue (
|
||||||
|
MSGQUEUE *self,
|
||||||
|
int (*check) (void *pMsg, void *pData),
|
||||||
|
void *pData
|
||||||
|
);
|
||||||
|
/*****************************************************************************
|
||||||
|
* Runs through the message queuue calling check() until it returns non-zero,
|
||||||
|
* or the queue is fully traversed.
|
||||||
|
*
|
||||||
|
* self - Address of the MSGQUEUE structure on which to operate.
|
||||||
|
* check - Function to be called for each message in the queue.
|
||||||
|
* pData - A pointer that will be passed into check() when it is called.
|
||||||
|
*
|
||||||
|
* Return: 0 -> check() always returned zero, or queue was empty.
|
||||||
|
* otherwise, return value of check().
|
||||||
|
*/
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
16
util.c
16
util.c
@ -24,6 +24,7 @@ Common utility routines needed by most c and c++ applications.
|
|||||||
begin : Fri Oct 19 10:09:38 EDT 2018
|
begin : Fri Oct 19 10:09:38 EDT 2018
|
||||||
email : john@rrci.com
|
email : john@rrci.com
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
|
#define _GNU_SOURCE
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -144,7 +145,7 @@ void _sys_eprintf(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
timespec_ms(const struct timespec *ts)
|
timespec2ms(const struct timespec *ts)
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Convert a timespec structure to integer milliseconds.
|
* Convert a timespec structure to integer milliseconds.
|
||||||
*/
|
*/
|
||||||
@ -152,6 +153,17 @@ timespec_ms(const struct timespec *ts)
|
|||||||
return ts->tv_sec*1000 + ts->tv_nsec/1000000;
|
return ts->tv_sec*1000 + ts->tv_nsec/1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct timespec*
|
||||||
|
ms2timespec(struct timespec *rtnBuf, int64_t ms)
|
||||||
|
/**********************************************************************
|
||||||
|
* Load up a timespec struct given number of milliseconds.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
rtnBuf->tv_sec= ms/1000;
|
||||||
|
rtnBuf->tv_nsec= (ms%1000)*1000000;
|
||||||
|
return rtnBuf;
|
||||||
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
bits2str(int64_t bits, const struct bitTuple *btArr)
|
bits2str(int64_t bits, const struct bitTuple *btArr)
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
@ -308,7 +320,7 @@ clock_gettime_ms(clockid_t whichClock)
|
|||||||
sys_eprintf("\tclock_gettime() failed");
|
sys_eprintf("\tclock_gettime() failed");
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
return timespec_ms(&ts);
|
return timespec2ms(&ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
|
8
util.h
8
util.h
@ -145,11 +145,17 @@ void _sys_eprintf(
|
|||||||
struct timespec;
|
struct timespec;
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
timespec_ms(const struct timespec *ts);
|
timespec2ms(const struct timespec *ts);
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* Convert a timespec structure to integer milliseconds.
|
* Convert a timespec structure to integer milliseconds.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct timespec*
|
||||||
|
ms2timespec(struct timespec *rtnBuf, int64_t ms);
|
||||||
|
/**********************************************************************
|
||||||
|
* Load up a timespec struct given number of milliseconds.
|
||||||
|
*/
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
clock_gettime_ms(clockid_t whichClock);
|
clock_gettime_ms(clockid_t whichClock);
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
|
Loading…
Reference in New Issue
Block a user