diff --git a/lib/hcl-c.c b/lib/hcl-c.c index 9e8fbfc..d8418d6 100644 --- a/lib/hcl-c.c +++ b/lib/hcl-c.c @@ -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 +#include +#include -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 +# include +# if defined(HCL_HAVE_CFG_H) && defined(HCL_ENABLE_LIBLTDL) +# include +# define USE_LTDL +# endif +#elif defined(__OS2__) +# define INCL_DOSMODULEMGR +# define INCL_DOSPROCESS +# define INCL_DOSERRORS +# include +#elif defined(__MSDOS__) +# include +# include +#elif defined(macintosh) +# include +#else +# if defined(HAVE_TIME_H) +# include +# endif +# if defined(HAVE_SYS_TIME_H) +# include +# endif +# if defined(HAVE_SIGNAL_H) +# include +# endif +# if defined(HAVE_SYS_MMAN_H) +# include +# endif +# if defined(HAVE_SYS_UIO_H) +# include +# endif + +# include +# include +# include +# include +# include +# include +# include +#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; } - - - diff --git a/lib/hcl-c.h b/lib/hcl-c.h index 586a2d5..e81c8ed 100644 --- a/lib/hcl-c.h +++ b/lib/hcl-c.h @@ -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 diff --git a/lib/hcl-s.h b/lib/hcl-s.h index 3ee5ee4..30211f3 100644 --- a/lib/hcl-s.h +++ b/lib/hcl-s.h @@ -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 ); diff --git a/lib/main-c.c b/lib/main-c.c new file mode 100644 index 0000000..80ac838 --- /dev/null +++ b/lib/main-c.c @@ -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 +#include +#include +#include +#include + +#if defined(HAVE_TIME_H) +# include +#endif +#if defined(HAVE_SYS_TIME_H) +# include +#endif +#if defined(HAVE_SIGNAL_H) +# include +#endif +#if defined(HAVE_SYS_UIO_H) +# include +#endif + +#include +#include + +/* ========================================================================= */ + +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; +} diff --git a/lib/main-s.c b/lib/main-s.c index 9869ec7..c23344d 100644 --- a/lib/main-s.c +++ b/lib/main-s.c @@ -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) {