added some hcl client code

This commit is contained in:
hyung-hwan 2018-03-20 10:36:00 +00:00
parent 11dbde8380
commit f9cf5e6554
5 changed files with 1018 additions and 155 deletions

View File

@ -27,29 +27,100 @@
#include "hcl-c.h"
#include "hcl-prv.h"
enum hcl_reply_type_t
{
HCL_REPLY_TYPE_OK = 0,
HCL_REPLY_TYPE_ERROR = 1
};
typedef enum hcl_reply_type_t hcl_reply_type_t;
#include <stdio.h>
#include <string.h>
#include <errno.h>
enum hcl_client_proto_state_t
{
HCL_CLIENT_PROTO_STATE_START,
HCL_CLIENT_PROTO_STATE_IN_REPLY_NAME,
HCL_CLIENT_PROTO_STATE_IN_REPLY_VALUE,
HCL_CLIENT_PROTO_STATE_IN_HEADER_NAME,
HCL_CLIENT_PROTO_STATE_IN_HEADER_VALUE,
HCL_CLIENT_PROTO_STATE_IN_DATA,
HCL_CLIENT_PROTO_STATE_IN_BINARY_DATA,
HCL_CLIENT_PROTO_STATE_IN_CHUNK,
};
typedef enum hcl_client_proto_state_t hcl_client_proto_state_t;
#define HCL_SERVER_TOKEN_NAME_ALIGN 64
#define HCL_SERVER_WID_MAP_ALIGN 512
#define HCL_SERVER_PROTO_REPLY_BUF_SIZE 1300
struct hcl_client_proto_t
#if defined(_WIN32)
# include <windows.h>
# include <tchar.h>
# if defined(HCL_HAVE_CFG_H) && defined(HCL_ENABLE_LIBLTDL)
# include <ltdl.h>
# define USE_LTDL
# endif
#elif defined(__OS2__)
# define INCL_DOSMODULEMGR
# define INCL_DOSPROCESS
# define INCL_DOSERRORS
# include <os2.h>
#elif defined(__MSDOS__)
# include <dos.h>
# include <time.h>
#elif defined(macintosh)
# include <Timer.h>
#else
# if defined(HAVE_TIME_H)
# include <time.h>
# endif
# if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
# endif
# if defined(HAVE_SIGNAL_H)
# include <signal.h>
# endif
# if defined(HAVE_SYS_MMAN_H)
# include <sys/mman.h>
# endif
# if defined(HAVE_SYS_UIO_H)
# include <sys/uio.h>
# endif
# include <unistd.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <pthread.h>
# include <poll.h>
#endif
enum hcl_client_reply_type_t
{
hcl_client_t* client;
HCL_CLIENT_REPLY_TYPE_OK = 0,
HCL_CLIENT_REPLY_TYPE_ERROR = 1
};
typedef enum hcl_client_reply_type_t hcl_client_reply_type_t;
enum hcl_client_state_t
{
HCL_CLIENT_STATE_START,
HCL_CLIENT_STATE_IN_REPLY_NAME,
HCL_CLIENT_STATE_IN_REPLY_VALUE,
HCL_CLIENT_STATE_IN_HEADER_NAME,
HCL_CLIENT_STATE_IN_HEADER_VALUE,
HCL_CLIENT_STATE_IN_DATA,
HCL_CLIENT_STATE_IN_BINARY_DATA,
HCL_CLIENT_STATE_IN_CHUNK,
};
typedef enum hcl_client_state_t hcl_client_state_t;
struct hcl_client_t
{
hcl_mmgr_t* mmgr;
hcl_cmgr_t* cmgr;
/*hcl_t* dummy_hcl;*/
hcl_errnum_t errnum;
struct
{
hcl_ooch_t buf[HCL_ERRMSG_CAPA];
hcl_oow_t len;
} errmsg;
int stopreq;
struct
{
unsigned int trait;
unsigned int logmask;
hcl_oow_t worker_max_count;
hcl_oow_t worker_stack_size;
hcl_ntime_t worker_idle_timeout;
} cfg;
struct
{
@ -58,7 +129,7 @@ struct hcl_client_proto_t
hcl_oow_t capa;
} req;
hcl_client_proto_state_t state;
hcl_client_state_t state;
struct
{
/*
@ -73,56 +144,13 @@ struct hcl_client_proto_t
hcl_oow_t capa;
} tok;
hcl_reply_type_t type;
hcl_client_reply_type_t type;
} rep;
};
typedef struct hcl_client_proto_t hcl_client_proto_t;
struct hcl_client_t
{
hcl_mmgr_t* mmgr;
hcl_cmgr_t* cmgr;
/*hcl_t* dummy_hcl;*/
hcl_errnum_t errnum;
struct
{
hcl_ooch_t buf[HCL_ERRMSG_CAPA];
hcl_oow_t len;
} errmsg;
};
/* ========================================================================= */
#if 0
static void proto_start_request (hcl_client_proto_t* proto)
{
proto->req.len = 0;
}
static void proto_feed_request_data (hcl_client_proto_t* proto, xxxx);
{
}
static int proto_end_request (hcl_client_proto_t* proto)
{
if (proto->req.len <= 0) return -1;
return 0;
}
#endif
static void proto_start_response (hcl_client_proto_t* proto)
{
proto->state = HCL_CLIENT_PROTO_STATE_START;
//proto->rep.len = 0;
}
static HCL_INLINE int is_spacechar (hcl_bch_t c)
{
/* TODO: handle other space unicode characters */
@ -152,39 +180,40 @@ static HCL_INLINE int is_digitchar (hcl_ooci_t c)
return (c >= '0' && c <= '9');
}
static void clear_reply_token (hcl_client_proto_t* proto)
static void clear_reply_token (hcl_client_t* client)
{
proto->rep.tok.len = 0;
client->rep.tok.len = 0;
}
static int add_to_reply_token (hcl_client_proto_t* proto, hcl_ooch_t ch)
static int add_to_reply_token (hcl_client_t* client, hcl_ooch_t ch)
{
if (proto->rep.tok.len >= proto->rep.tok.capa)
if (client->rep.tok.len >= client->rep.tok.capa)
{
hcl_ooch_t* tmp;
hcl_oow_t newcapa;
newcapa = HCL_ALIGN_POW2(proto->rep.tok.len + 1, 128);
tmp = hcl_client_reallocmem(proto->client, proto->rep.tok.ptr, newcapa * HCL_SIZEOF(*tmp));
newcapa = HCL_ALIGN_POW2(client->rep.tok.len + 1, 128);
tmp = hcl_client_reallocmem(client, client->rep.tok.ptr, newcapa * HCL_SIZEOF(*tmp));
if (!tmp) return -1;
proto->rep.tok.capa = newcapa;
proto->rep.tok.ptr = tmp;
client->rep.tok.capa = newcapa;
client->rep.tok.ptr = tmp;
}
proto->rep.tok.ptr[proto->rep.tok.len++] = ch;
return -1;
client->rep.tok.ptr[client->rep.tok.len++] = ch;
return 0;
}
static int proto_feed_reply_data (hcl_client_proto_t* proto, const hcl_bch_t* data, hcl_oow_t len)
static int feed_reply_data (hcl_client_t* client, const hcl_bch_t* data, hcl_oow_t len, hcl_oow_t* xlen)
{
const hcl_bch_t* ptr;
const hcl_bch_t* end;
ptr = data;
end = ptr + len;
if (proto->state == HCL_CLIENT_PROTO_STATE_IN_BINARY_DATA)
printf ("<<<%.*s>>>\n", (int)len, data);
if (client->state == HCL_CLIENT_STATE_IN_BINARY_DATA)
{
}
else
@ -200,29 +229,32 @@ static int proto_feed_reply_data (hcl_client_proto_t* proto, const hcl_bch_t* da
bcslen = end - ptr;
ucslen = 1;
n = hcl_conv_bcsn_to_ucsn_with_cmgr(ptr, &bcslen, &c, &ucslen, proto->client->cmgr, 0);
n = hcl_conv_bcsn_to_ucsn_with_cmgr(ptr, &bcslen, &c, &ucslen, client->cmgr, 0);
if (n <= -1)
{
if (n == -3)
{
/* incomplete sequence */
printf ("incompelete....feed me more\n");
*xlen = ptr - data;
return 0; /* feed more for incomplete sequence */
}
}
ptr += bcslen;
#else
c = *ptr++;
#endif
switch (proto->state)
printf ("[%lc]\n", c);
switch (client->state)
{
case HCL_CLIENT_PROTO_STATE_START:
case HCL_CLIENT_STATE_START:
if (c == '.')
{
proto->state = HCL_CLIENT_PROTO_STATE_IN_REPLY_NAME;
clear_reply_token (proto);
if (add_to_reply_token(proto, c) <= -1) goto oops;
break;
client->state = HCL_CLIENT_STATE_IN_REPLY_NAME;
clear_reply_token (client);
if (add_to_reply_token(client, c) <= -1) goto oops;
}
else if (!is_spacechar(c))
{
@ -231,49 +263,51 @@ static int proto_feed_reply_data (hcl_client_proto_t* proto, const hcl_bch_t* da
}
break;
case HCL_CLIENT_PROTO_STATE_IN_REPLY_NAME:
if (is_alphachar(c) || (proto->rep.tok.len > 2 && c == '-'))
case HCL_CLIENT_STATE_IN_REPLY_NAME:
if (is_alphachar(c) || (client->rep.tok.len > 2 && c == '-'))
{
if (add_to_reply_token(proto, c) <= -1) goto oops;
if (add_to_reply_token(client, c) <= -1) goto oops;
}
else
{
if (hcl_compoocharsbcstr(proto->rep.tok.ptr, proto->rep.tok.len, ".OK") == 0)
if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".OK") == 0)
{
proto->rep.type = HCL_REPLY_TYPE_OK;
client->rep.type = HCL_CLIENT_REPLY_TYPE_OK;
}
else if (hcl_compoocharsbcstr(proto->rep.tok.ptr, proto->rep.tok.len, ".ERROR") == 0)
else if (hcl_compoocharsbcstr(client->rep.tok.ptr, client->rep.tok.len, ".ERROR") == 0)
{
proto->rep.type = HCL_REPLY_TYPE_ERROR;
client->rep.type = HCL_CLIENT_REPLY_TYPE_ERROR;
}
clear_reply_token (proto);
if (add_to_reply_token(proto, c) <= -1) goto oops;
clear_reply_token (client);
if (add_to_reply_token(client, c) <= -1) goto oops;
}
break;
/*case HCL_CLIENT_PROTO_STATE_IN_START_LINE:*/
/*case HCL_CLIENT_STATE_IN_START_LINE:*/
case HCL_CLIENT_PROTO_STATE_IN_HEADER_NAME:
case HCL_CLIENT_STATE_IN_HEADER_NAME:
break;
case HCL_CLIENT_PROTO_STATE_IN_HEADER_VALUE:
case HCL_CLIENT_STATE_IN_HEADER_VALUE:
break;
}
}
}
return 0;
*xlen = ptr - data;
return 1;
oops:
/* TODO: compute the number of processes bytes so far and return it via a parameter??? */
printf ("feed oops....\n");
return -1;
}
/* ========================================================================= */
hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_errnum_t* errnum)
hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_client_prim_t* prim, hcl_errnum_t* errnum)
{
hcl_client_t* client;
#if 0
@ -376,8 +410,6 @@ hcl_client_t* hcl_client_open (hcl_mmgr_t* mmgr, hcl_oow_t xtnsize, hcl_errnum_t
if (client->cfg.trait & HCL_SERVER_TRAIT_DEBUG_BIGINT) trait |= HCL_DEBUG_BIGINT;
#endif
hcl_setoption (client->dummy_hcl, HCL_TRAIT, &trait);
#else
HCL_MEMSET (client, 0, HCL_SIZEOF(*client) + xtnsize);
@ -395,6 +427,112 @@ void hcl_client_close (hcl_client_t* client)
}
int hcl_client_setoption (hcl_client_t* client, hcl_client_option_t id, const void* value)
{
switch (id)
{
case HCL_CLIENT_TRAIT:
client->cfg.trait = *(const unsigned int*)value;
#if 0
if (client->dummy_hcl)
{
/* setting this affects the dummy hcl immediately.
* existing hcl instances inside worker threads won't get
* affected. new hcl instances to be created later
* is supposed to use the new value */
unsigned int trait;
hcl_getoption (client->dummy_hcl, HCL_TRAIT, &trait);
#if defined(HCL_BUILD_DEBUG)
if (client->cfg.trait & HCL_CLIENT_TRAIT_DEBUG_GC) trait |= HCL_DEBUG_GC;
if (client->cfg.trait & HCL_CLIENT_TRAIT_DEBUG_BIGINT) trait |= HCL_DEBUG_BIGINT;
#endif
hcl_setoption (client->dummy_hcl, HCL_TRAIT, &trait);
}
#endif
return 0;
case HCL_CLIENT_LOG_MASK:
client->cfg.logmask = *(const unsigned int*)value;
#if 0
if (client->dummy_hcl)
{
/* setting this affects the dummy hcl immediately.
* existing hcl instances inside worker threads won't get
* affected. new hcl instances to be created later
* is supposed to use the new value */
hcl_setoption (client->dummy_hcl, HCL_LOG_MASK, value);
}
#endif
return 0;
case HCL_CLIENT_WORKER_MAX_COUNT:
client->cfg.worker_max_count = *(hcl_oow_t*)value;
return 0;
case HCL_CLIENT_WORKER_STACK_SIZE:
client->cfg.worker_stack_size = *(hcl_oow_t*)value;
return 0;
case HCL_CLIENT_WORKER_IDLE_TIMEOUT:
client->cfg.worker_idle_timeout = *(hcl_ntime_t*)value;
return 0;
}
hcl_client_seterrnum (client, HCL_EINVAL);
return -1;
}
int hcl_client_getoption (hcl_client_t* client, hcl_client_option_t id, void* value)
{
switch (id)
{
case HCL_CLIENT_TRAIT:
*(unsigned int*)value = client->cfg.trait;
return 0;
case HCL_CLIENT_LOG_MASK:
*(unsigned int*)value = client->cfg.logmask;
return 0;
case HCL_CLIENT_WORKER_MAX_COUNT:
*(hcl_oow_t*)value = client->cfg.worker_max_count;
return 0;
case HCL_CLIENT_WORKER_STACK_SIZE:
*(hcl_oow_t*)value = client->cfg.worker_stack_size;
return 0;
case HCL_CLIENT_WORKER_IDLE_TIMEOUT:
*(hcl_ntime_t*)value = client->cfg.worker_idle_timeout;
return 0;
};
hcl_client_seterrnum (client, HCL_EINVAL);
return -1;
}
void* hcl_client_getxtn (hcl_client_t* client)
{
return (void*)(client + 1);
}
hcl_mmgr_t* hcl_client_getmmgr (hcl_client_t* client)
{
return client->mmgr;
}
hcl_cmgr_t* hcl_client_getcmgr (hcl_client_t* client)
{
return client->cmgr;
}
void hcl_client_setcmgr (hcl_client_t* client, hcl_cmgr_t* cmgr)
{
client->cmgr = cmgr;
}
hcl_errnum_t hcl_client_geterrnum (hcl_client_t* client)
{
return client->errnum;
@ -452,17 +590,66 @@ void hcl_client_freemem (hcl_client_t* client, void* ptr)
/* ========================================================================= */
static int feed_all_reply_data (hcl_client_t* client, hcl_bch_t* buf, hcl_oow_t n, hcl_oow_t* xlen)
{
int x;
hcl_oow_t total, ylen;
total = 0;
while (total < n)
{
x = feed_reply_data(client, &buf[total], n - total, &ylen);
if (x <= -1) return -1;
total += ylen;
if (ylen == 0) break; /* incomplete sequence */
}
*xlen = total;
return 0;
}
int hcl_client_start (hcl_client_t* client, const hcl_bch_t* addrs)
{
/* connect */
/* send request */
hcl_oow_t xlen, offset;
int x;
int fd = 0; /* read from stdin for testing */
hcl_bch_t buf[256];
ssize_t n;
client->stopreq = 0;
offset = 0;
while (1)
{
n = read(fd, &buf[offset], HCL_SIZEOF(buf) - offset); /* switch to recv */
if (n <= -1)
{
printf ("error....%s\n", strerror(n));
return -1;
}
if (n == 0)
{
/* TODO: check if there is residue in the receiv buffer */
break;
}
x = feed_all_reply_data (client, buf, n, &xlen);
if (x <= -1) return -1;
offset = n - xlen;
if (offset > 0) HCL_MEMMOVE (&buf[0], &buf[xlen], offset);
}
printf ("hcl client start returns success\n");
return 0;
}
int hcl_client_sendreq (hcl_client_t* client, const hcl_bch_t* addrs)
void hcl_client_stop (hcl_client_t* client)
{
client->stopreq = 1;
}

View File

@ -32,6 +32,42 @@
typedef struct hcl_client_t hcl_client_t;
enum hcl_client_option_t
{
HCL_CLIENT_TRAIT,
HCL_CLIENT_LOG_MASK,
HCL_CLIENT_WORKER_MAX_COUNT,
HCL_CLIENT_WORKER_STACK_SIZE,
HCL_CLIENT_WORKER_IDLE_TIMEOUT
};
typedef enum hcl_client_option_t hcl_client_option_t;
enum hcl_client_trait_t
{
#if defined(HCL_BUILD_DEBUG)
HCL_CLIENT_TRAIT_DEBUG_GC = (1 << 0),
HCL_CLIENT_TRAIT_DEBUG_BIGINT = (1 << 1),
#endif
HCL_CLIENT_TRAIT_READABLE_PROTO = (1 << 2),
HCL_CLIENT_TRAIT_USE_LARGE_PAGES = (1 << 3)
};
typedef enum hcl_client_trait_t hcl_client_trait_t;
typedef void (*hcl_client_log_write_t) (
hcl_client_t* client,
hcl_oow_t wid,
unsigned int mask,
const hcl_ooch_t* msg,
hcl_oow_t len
);
struct hcl_client_prim_t
{
hcl_client_log_write_t log_write;
};
typedef struct hcl_client_prim_t hcl_client_prim_t;
#if defined(__cplusplus)
extern "C" {
@ -40,7 +76,7 @@ extern "C" {
HCL_EXPORT hcl_client_t* hcl_client_open (
hcl_mmgr_t* mmgr,
hcl_oow_t xtnsize,
/*hcl_client_prim_t* prim,*/
hcl_client_prim_t* prim,
hcl_errnum_t* errnum
);
@ -48,6 +84,45 @@ HCL_EXPORT void hcl_client_close (
hcl_client_t* client
);
HCL_EXPORT int hcl_client_start (
hcl_client_t* client,
const hcl_bch_t* addrs
);
HCL_EXPORT void hcl_client_stop (
hcl_client_t* client
);
HCL_EXPORT int hcl_client_setoption (
hcl_client_t* client,
hcl_client_option_t id,
const void* value
);
HCL_EXPORT int hcl_client_getoption (
hcl_client_t* client,
hcl_client_option_t id,
void* value
);
HCL_EXPORT void* hcl_client_getxtn (
hcl_client_t* client
);
HCL_EXPORT hcl_mmgr_t* hcl_client_getmmgr (
hcl_client_t* client
);
HCL_EXPORT hcl_cmgr_t* hcl_client_getcmgr (
hcl_client_t* client
);
HCL_EXPORT void hcl_client_setcmgr (
hcl_client_t* client,
hcl_cmgr_t* cmgr
);
HCL_EXPORT hcl_errnum_t hcl_client_geterrnum (
hcl_client_t* client
@ -93,48 +168,6 @@ HCL_EXPORT void hcl_client_freemem (
);
HCL_EXPORT hcl_errnum_t hcl_client_geterrnum (
hcl_client_t* client
);
HCL_EXPORT const hcl_ooch_t* hcl_client_geterrstr (
hcl_client_t* client
);
HCL_EXPORT const hcl_ooch_t* hcl_client_geterrmsg (
hcl_client_t* client
);
HCL_EXPORT void hcl_client_seterrnum (
hcl_client_t* client,
hcl_errnum_t errnum
);
HCL_EXPORT void* hcl_client_allocmem (
hcl_client_t* client,
hcl_oow_t size
);
HCL_EXPORT void* hcl_client_callocmem (
hcl_client_t* client,
hcl_oow_t size
);
HCL_EXPORT void* hcl_client_reallocmem (
hcl_client_t* client,
void* ptr,
hcl_oow_t size
);
HCL_EXPORT void hcl_client_freemem (
hcl_client_t* client,
void* ptr
);
#if defined(__cplusplus)
}
#endif

View File

@ -68,7 +68,7 @@ typedef void (*hcl_server_log_write_t) (
const hcl_ooch_t* msg,
hcl_oow_t len
);
struct hcl_server_prim_t
{
hcl_server_log_write_t log_write;
@ -116,7 +116,6 @@ HCL_EXPORT void* hcl_server_getxtn (
hcl_server_t* server
);
HCL_EXPORT hcl_mmgr_t* hcl_server_getmmgr (
hcl_server_t* server
);

644
lib/main-c.c Normal file
View File

@ -0,0 +1,644 @@
/*
* $Id$
*
Copyright (c) 2016-2018 Chung, Hyung-Hwan. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "hcl-c.h"
#include "hcl-opt.h"
#include "hcl-utl.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
#if defined(HAVE_TIME_H)
# include <time.h>
#endif
#if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
#endif
#if defined(HAVE_SIGNAL_H)
# include <signal.h>
#endif
#if defined(HAVE_SYS_UIO_H)
# include <sys/uio.h>
#endif
#include <unistd.h>
#include <fcntl.h>
/* ========================================================================= */
typedef struct client_xtn_t client_xtn_t;
struct client_xtn_t
{
int logfd;
unsigned int logmask;
int logfd_istty;
struct
{
hcl_bch_t buf[4096];
hcl_oow_t len;
} logbuf;
};
/* ========================================================================= */
static void* sys_alloc (hcl_mmgr_t* mmgr, hcl_oow_t size)
{
return malloc(size);
}
static void* sys_realloc (hcl_mmgr_t* mmgr, void* ptr, hcl_oow_t size)
{
return realloc(ptr, size);
}
static void sys_free (hcl_mmgr_t* mmgr, void* ptr)
{
free (ptr);
}
static hcl_mmgr_t sys_mmgr =
{
sys_alloc,
sys_realloc,
sys_free,
HCL_NULL
};
/* ========================================================================= */
static int write_all (int fd, const hcl_bch_t* ptr, hcl_oow_t len)
{
while (len > 0)
{
hcl_ooi_t wr;
wr = write(fd, ptr, len);
if (wr <= -1)
{
#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN == EWOULDBLOCK)
if (errno == EAGAIN) continue;
#else
#if defined(EAGAIN)
if (errno == EAGAIN) continue;
#elif defined(EWOULDBLOCK)
if (errno == EWOULDBLOCK) continue;
#endif
#endif
#if defined(EINTR)
/* TODO: would this interfere with non-blocking nature of this VM? */
if (errno == EINTR) continue;
#endif
return -1;
}
ptr += wr;
len -= wr;
}
return 0;
}
static int write_log (hcl_client_t* client, int fd, const hcl_bch_t* ptr, hcl_oow_t len)
{
client_xtn_t* xtn;
xtn = hcl_client_getxtn(client);
while (len > 0)
{
if (xtn->logbuf.len > 0)
{
hcl_oow_t rcapa, cplen;
rcapa = HCL_COUNTOF(xtn->logbuf.buf) - xtn->logbuf.len;
cplen = (len >= rcapa)? rcapa: len;
memcpy (&xtn->logbuf.buf[xtn->logbuf.len], ptr, cplen);
xtn->logbuf.len += cplen;
ptr += cplen;
len -= cplen;
if (xtn->logbuf.len >= HCL_COUNTOF(xtn->logbuf.buf))
{
write_all(fd, xtn->logbuf.buf, xtn->logbuf.len);
xtn->logbuf.len = 0;
}
}
else
{
hcl_oow_t rcapa;
rcapa = HCL_COUNTOF(xtn->logbuf.buf);
if (len >= rcapa)
{
write_all (fd, ptr, rcapa);
ptr += rcapa;
len -= rcapa;
}
else
{
memcpy (xtn->logbuf.buf, ptr, len);
xtn->logbuf.len += len;
ptr += len;
len -= len;
}
}
}
return 0;
}
static void flush_log (hcl_client_t* client, int fd)
{
client_xtn_t* xtn;
xtn = hcl_client_getxtn(client);
if (xtn->logbuf.len > 0)
{
write_all (fd, xtn->logbuf.buf, xtn->logbuf.len);
xtn->logbuf.len = 0;
}
}
static void log_write (hcl_client_t* client, hcl_oow_t wid, unsigned int mask, const hcl_ooch_t* msg, hcl_oow_t len)
{
hcl_bch_t buf[256];
hcl_oow_t ucslen, bcslen;
client_xtn_t* xtn;
hcl_oow_t msgidx;
int n, logfd;
xtn = hcl_client_getxtn(client);
if (mask & HCL_LOG_STDERR)
{
/* the messages that go to STDERR don't get masked out */
logfd = 2;
}
else
{
if (!(xtn->logmask & mask & ~HCL_LOG_ALL_LEVELS)) return; /* check log types */
if (!(xtn->logmask & mask & ~HCL_LOG_ALL_TYPES)) return; /* check log levels */
if (mask & HCL_LOG_STDOUT) logfd = 1;
else
{
logfd = xtn->logfd;
if (logfd <= -1) return;
}
}
/* TODO: beautify the log message.
* do classification based on mask. */
if (!(mask & (HCL_LOG_STDOUT | HCL_LOG_STDERR)))
{
time_t now;
char ts[32];
size_t tslen;
struct tm tm, *tmp;
now = time(NULL);
tmp = localtime_r (&now, &tm);
#if defined(HAVE_STRFTIME_SMALL_Z)
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
#else
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp);
#endif
if (tslen == 0)
{
strcpy (ts, "0000-00-00 00:00:00 +0000");
tslen = 25;
}
write_log (client, logfd, ts, tslen);
#if 0
if (wid != HCL_CLIENT_WID_INVALID)
{
/* TODO: check if the underlying snprintf support %zd */
tslen = snprintf (ts, sizeof(ts), "[%zu] ", wid);
write_log (client, logfd, ts, tslen);
}
#endif
}
if (logfd == xtn->logfd && xtn->logfd_istty)
{
if (mask & HCL_LOG_FATAL) write_log (client, logfd, "\x1B[1;31m", 7);
else if (mask & HCL_LOG_ERROR) write_log (client, logfd, "\x1B[1;32m", 7);
else if (mask & HCL_LOG_WARN) write_log (client, logfd, "\x1B[1;33m", 7);
}
#if defined(HCL_OOCH_IS_UCH)
msgidx = 0;
while (len > 0)
{
ucslen = len;
bcslen = HCL_COUNTOF(buf);
n = hcl_conv_oocsn_to_bcsn_with_cmgr(&msg[msgidx], &ucslen, buf, &bcslen, hcl_get_utf8_cmgr());
if (n == 0 || n == -2)
{
/* n = 0:
* converted all successfully
* n == -2:
* buffer not sufficient. not all got converted yet.
* write what have been converted this round. */
/*HCL_ASSERT (hcl, ucslen > 0); */ /* if this fails, the buffer size must be increased */
/*assert (ucslen > 0);*/
/* attempt to write all converted characters */
if (write_log(client, logfd, buf, bcslen) <= -1) break;
if (n == 0) break;
else
{
msgidx += ucslen;
len -= ucslen;
}
}
else if (n <= -1)
{
/* conversion error */
break;
}
}
#else
write_log (client, logfd, msg, len);
#endif
if (logfd == xtn->logfd && xtn->logfd_istty)
{
if (mask & (HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN)) write_log (client, logfd, "\x1B[0m", 4);
}
flush_log (client, logfd);
}
/* ========================================================================= */
static hcl_client_t* g_client = HCL_NULL;
/* ========================================================================= */
typedef void (*signal_handler_t) (int, siginfo_t*, void*);
static void handle_sigint (int sig, siginfo_t* siginfo, void* ctx)
{
/*if (g_client) hcl_client_stop (g_client);*/
}
static void set_signal (int sig, signal_handler_t handler)
{
struct sigaction sa;
memset (&sa, 0, sizeof(sa));
/*sa.sa_handler = handler;*/
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
sigemptyset (&sa.sa_mask);
sigaction (sig, &sa, NULL);
}
static void set_signal_to_ignore (int sig)
{
struct sigaction sa;
memset (&sa, 0, sizeof(sa));
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
sigaction (sig, &sa, NULL);
}
static void set_signal_to_default (int sig)
{
struct sigaction sa;
memset (&sa, 0, sizeof(sa));
sa.sa_handler = SIG_DFL;
sa.sa_flags = 0;
sigemptyset (&sa.sa_mask);
sigaction (sig, &sa, NULL);
}
/* ========================================================================= */
static int handle_logopt (hcl_client_t* client, const hcl_bch_t* str)
{
hcl_bch_t* xstr = (hcl_bch_t*)str;
hcl_bch_t* cm, * flt;
unsigned int logmask;
client_xtn_t* xtn;
xtn = (client_xtn_t*)hcl_client_getxtn(client);
cm = hcl_findbcharinbcstr(xstr, ',');
if (cm)
{
/* i duplicate this string for open() below as open() doesn't
* accept a length-bounded string */
xstr = strdup(str);
if (!xstr)
{
fprintf (stderr, "ERROR: out of memory in duplicating %s\n", str);
return -1;
}
cm = hcl_findbcharinbcstr(xstr, ',');
*cm = '\0';
logmask = xtn->logmask;
do
{
flt = cm + 1;
cm = hcl_findbcharinbcstr(flt, ',');
if (cm) *cm = '\0';
if (hcl_compbcstr(flt, "app") == 0) logmask |= HCL_LOG_APP;
else if (hcl_compbcstr(flt, "compiler") == 0) logmask |= HCL_LOG_COMPILER;
else if (hcl_compbcstr(flt, "vm") == 0) logmask |= HCL_LOG_VM;
else if (hcl_compbcstr(flt, "mnemonic") == 0) logmask |= HCL_LOG_MNEMONIC;
else if (hcl_compbcstr(flt, "gc") == 0) logmask |= HCL_LOG_GC;
else if (hcl_compbcstr(flt, "ic") == 0) logmask |= HCL_LOG_IC;
else if (hcl_compbcstr(flt, "primitive") == 0) logmask |= HCL_LOG_PRIMITIVE;
else if (hcl_compbcstr(flt, "fatal") == 0) logmask |= HCL_LOG_FATAL;
else if (hcl_compbcstr(flt, "error") == 0) logmask |= HCL_LOG_ERROR;
else if (hcl_compbcstr(flt, "warn") == 0) logmask |= HCL_LOG_WARN;
else if (hcl_compbcstr(flt, "info") == 0) logmask |= HCL_LOG_INFO;
else if (hcl_compbcstr(flt, "debug") == 0) logmask |= HCL_LOG_DEBUG;
else if (hcl_compbcstr(flt, "fatal+") == 0) logmask |= HCL_LOG_FATAL;
else if (hcl_compbcstr(flt, "error+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR;
else if (hcl_compbcstr(flt, "warn+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN;
else if (hcl_compbcstr(flt, "info+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN | HCL_LOG_INFO;
else if (hcl_compbcstr(flt, "debug+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN | HCL_LOG_INFO | HCL_LOG_DEBUG;
else
{
fprintf (stderr, "ERROR: unknown log option value - %s\n", flt);
if (str != xstr) free (xstr);
return -1;
}
}
while (cm);
if (!(logmask & HCL_LOG_ALL_TYPES)) logmask |= HCL_LOG_ALL_TYPES; /* no types specified. force to all types */
if (!(logmask & HCL_LOG_ALL_LEVELS)) logmask |= HCL_LOG_ALL_LEVELS; /* no levels specified. force to all levels */
}
else
{
logmask = HCL_LOG_ALL_LEVELS | HCL_LOG_ALL_TYPES;
}
xtn->logfd = open(xstr, O_CREAT | O_WRONLY | O_APPEND , 0644);
if (xtn->logfd == -1)
{
fprintf (stderr, "ERROR: cannot open a log file %s\n", xstr);
if (str != xstr) free (xstr);
return -1;
}
xtn->logmask = logmask;
#if defined(HAVE_ISATTY)
xtn->logfd_istty = isatty(xtn->logfd);
#endif
if (str != xstr) free (xstr);
return 0;
}
#if defined(HCL_BUILD_DEBUG)
static int handle_dbgopt (hcl_client_t* client, const char* str)
{
const hcl_bch_t* cm, * flt;
hcl_oow_t len;
unsigned int trait;
hcl_client_getoption (client, HCL_CLIENT_TRAIT, &trait);
cm = str - 1;
do
{
flt = cm + 1;
cm = hcl_findbcharinbcstr(flt, ',');
len = cm? (cm - flt): hcl_countbcstr(flt);
if (hcl_compbcharsbcstr(flt, len, "gc") == 0) trait |= HCL_CLIENT_TRAIT_DEBUG_GC;
else if (hcl_compbcharsbcstr(flt, len, "bigint") == 0) trait |= HCL_CLIENT_TRAIT_DEBUG_BIGINT;
else
{
fprintf (stderr, "ERROR: unknown debug option value - %.*s\n", (int)len, flt);
return -1;
}
}
while (cm);
hcl_client_setoption (client, HCL_CLIENT_TRAIT, &trait);
return 0;
}
#endif
/* ========================================================================= */
#define MIN_WORKER_STACK_SIZE 512000ul
#define MIN_ACTOR_HEAP_SIZE 512000ul
int main (int argc, char* argv[])
{
hcl_bci_t c;
static hcl_bopt_lng_t lopt[] =
{
{ ":log", 'l' },
{ "large-pages", '\0' },
{ ":worker-max-count", '\0' },
{ ":worker-stack-size", '\0' },
{ ":worker-idle-timeout", '\0' },
#if defined(HCL_BUILD_DEBUG)
{ ":debug", '\0' }, /* NOTE: there is no short option for --debug */
#endif
{ HCL_NULL, '\0' }
};
static hcl_bopt_t opt =
{
"l:",
lopt
};
hcl_client_t* client;
client_xtn_t* xtn;
hcl_client_prim_t client_prim;
int n;
const char* logopt = HCL_NULL;
const char* dbgopt = HCL_NULL;
hcl_oow_t worker_max_count = 0;
hcl_oow_t worker_stack_size = MIN_ACTOR_HEAP_SIZE;
hcl_ntime_t worker_idle_timeout = { 0, 0 };
int large_pages = 0;
unsigned int trait;
setlocale (LC_ALL, "");
if (argc < 2)
{
print_usage:
fprintf (stderr, "Usage: %s bind-address:port\n", argv[0]);
return -1;
}
while ((c = hcl_getbopt (argc, argv, &opt)) != HCL_BCI_EOF)
{
switch (c)
{
case 'l':
logopt = opt.arg;
break;
case '\0':
if (hcl_compbcstr(opt.lngopt, "large-pages") == 0)
{
large_pages = 1;
}
else if (hcl_compbcstr(opt.lngopt, "worker-max-count") == 0)
{
worker_max_count = strtoul(opt.arg, HCL_NULL, 0);
}
else if (hcl_compbcstr(opt.lngopt, "worker-stack-size") == 0)
{
worker_stack_size = strtoul(opt.arg, HCL_NULL, 0);
if (worker_stack_size <= MIN_WORKER_STACK_SIZE) worker_stack_size = MIN_WORKER_STACK_SIZE;
}
else if (hcl_compbcstr(opt.lngopt, "worker-idle-timeout") == 0)
{
worker_idle_timeout.sec = strtoul(opt.arg, HCL_NULL, 0);
}
#if defined(HCL_BUILD_DEBUG)
else if (hcl_compbcstr(opt.lngopt, "debug") == 0)
{
dbgopt = opt.arg;
}
#endif
else goto print_usage;
break;
case ':':
if (opt.lngopt)
fprintf (stderr, "bad argument for '%s'\n", opt.lngopt);
else
fprintf (stderr, "bad argument for '%c'\n", opt.opt);
return -1;
default:
goto print_usage;
}
}
if (opt.ind >= argc) goto print_usage;
memset (&client_prim, 0, HCL_SIZEOF(client_prim));
client_prim.log_write = log_write;
client = hcl_client_open(&sys_mmgr, HCL_SIZEOF(client_xtn_t), &client_prim, HCL_NULL);
if (!client)
{
fprintf (stderr, "cannot open client\n");
return -1;
}
xtn = (client_xtn_t*)hcl_client_getxtn(client);
xtn->logfd = -1;
xtn->logfd_istty = 0;
if (logopt)
{
if (handle_logopt(client, logopt) <= -1) goto oops;
}
else
{
/* default logging mask when no logging option is set */
xtn->logmask = HCL_LOG_ALL_TYPES | HCL_LOG_ERROR | HCL_LOG_FATAL;
}
#if defined(HCL_BUILD_DEBUG)
if (dbgopt)
{
if (handle_dbgopt(client, dbgopt) <= -1) goto oops;
}
#endif
hcl_client_getoption (client, HCL_CLIENT_TRAIT, &trait);
if (large_pages) trait |= HCL_CLIENT_TRAIT_USE_LARGE_PAGES;
else trait &= ~HCL_CLIENT_TRAIT_USE_LARGE_PAGES;
hcl_client_setoption (client, HCL_CLIENT_TRAIT, &trait);
hcl_client_setoption (client, HCL_CLIENT_WORKER_MAX_COUNT, &worker_max_count);
hcl_client_setoption (client, HCL_CLIENT_WORKER_STACK_SIZE, &worker_stack_size);
hcl_client_setoption (client, HCL_CLIENT_WORKER_IDLE_TIMEOUT, &worker_idle_timeout);
g_client = client;
set_signal (SIGINT, handle_sigint);
set_signal_to_ignore (SIGPIPE);
n = hcl_client_start(client, argv[opt.ind]);
set_signal_to_default (SIGINT);
set_signal_to_default (SIGPIPE);
g_client = NULL;
if (n <= -1)
{
// hcl_client_logbfmt (client, HCL_LOG_APP | HCL_LOG_FATAL, "client error[%d] - %js\n", hcl_client_geterrnum(client), hcl_client_geterrmsg(client));
printf ("hcl client error... = %d\n", hcl_client_geterrnum(client));
}
close (xtn->logfd);
xtn->logfd = -1;
xtn->logfd_istty = 0;
hcl_client_close (client);
return n;
oops:
if (client) hcl_client_close (client);
return -1;
}

View File

@ -567,7 +567,7 @@ int main (int argc, char* argv[])
else if (hcl_compbcstr(opt.lngopt, "worker-stack-size") == 0)
{
worker_stack_size = strtoul(opt.arg, HCL_NULL, 0);
if (worker_stack_size <= MIN_WORKER_STACK_SIZE) actor_heap_size = MIN_WORKER_STACK_SIZE;
if (worker_stack_size <= MIN_WORKER_STACK_SIZE) worker_stack_size = MIN_WORKER_STACK_SIZE;
}
else if (hcl_compbcstr(opt.lngopt, "worker-idle-timeout") == 0)
{