diff --git a/Makefile.in b/Makefile.in index 841455f..94f144e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -333,6 +333,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/bin/Makefile.in b/bin/Makefile.in index d825d78..6cb28f2 100644 --- a/bin/Makefile.in +++ b/bin/Makefile.in @@ -344,6 +344,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ diff --git a/bin/main.c b/bin/main.c index 8fa140a..de8ad36 100644 --- a/bin/main.c +++ b/bin/main.c @@ -84,63 +84,17 @@ struct bb_t hcl_bch_t* fn; }; -enum logfd_flag_t -{ - LOGFD_TTY = (1 << 0), - LOGFD_OPENED_HERE = (1 << 1) -}; - typedef struct xtn_t xtn_t; struct xtn_t { -#if defined(_WIN32) - HANDLE waitable_timer; -#endif const char* read_path; /* main source file */ const char* print_path; int vm_running; - - struct - { - int fd; - int fd_flag; /* bitwise OR'ed fo logfd_flag_t bits */ - - struct - { - hcl_bch_t buf[4096]; - hcl_oow_t len; - } out; - } log; - int reader_istty; hcl_oop_t sym_errstr; }; -/* ========================================================================= */ - -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 -}; /* ========================================================================= */ @@ -449,240 +403,9 @@ static int print_handler (hcl_t* hcl, hcl_iocmd_t cmd, void* arg) /* ========================================================================= */ -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_t* hcl, int fd, const hcl_bch_t* ptr, hcl_oow_t len) -{ - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - - while (len > 0) - { - if (xtn->log.out.len > 0) - { - hcl_oow_t rcapa, cplen; - - rcapa = HCL_COUNTOF(xtn->log.out.buf) - xtn->log.out.len; - cplen = (len >= rcapa)? rcapa: len; - - HCL_MEMCPY (&xtn->log.out.buf[xtn->log.out.len], ptr, cplen); - xtn->log.out.len += cplen; - ptr += cplen; - len -= cplen; - - if (xtn->log.out.len >= HCL_COUNTOF(xtn->log.out.buf)) - { - int n; - n = write_all(fd, xtn->log.out.buf, xtn->log.out.len); - xtn->log.out.len = 0; - if (n <= -1) return -1; - } - } - else - { - hcl_oow_t rcapa; - - rcapa = HCL_COUNTOF(xtn->log.out.buf); - if (len >= rcapa) - { - if (write_all(fd, ptr, rcapa) <= -1) return -1; - ptr += rcapa; - len -= rcapa; - } - else - { - HCL_MEMCPY (xtn->log.out.buf, ptr, len); - xtn->log.out.len += len; - ptr += len; - len -= len; - } - } - } - - return 0; -} - -static void flush_log (hcl_t* hcl, int fd) -{ - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - if (xtn->log.out.len > 0) - { - write_all (fd, xtn->log.out.buf, xtn->log.out.len); - xtn->log.out.len = 0; - } -} - - -static void log_write (hcl_t* hcl, hcl_bitmask_t mask, const hcl_ooch_t* msg, hcl_oow_t len) -{ - hcl_bch_t buf[256]; - hcl_oow_t ucslen, bcslen, msgidx; - int n; - - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - int logfd; - - if (mask & HCL_LOG_STDERR) logfd = 2; - else if (mask & HCL_LOG_STDOUT) logfd = 1; - else - { - logfd = xtn->log.fd; - 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(HCL_NULL); - #if defined(_WIN32) - tmp = localtime(&now); - tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp); - if (tslen == 0) - { - tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - } - #elif defined(__OS2__) - #if defined(__WATCOMC__) - tmp = _localtime(&now, &tm); - #else - tmp = localtime(&now); - #endif - - #if defined(__BORLANDC__) - /* the borland compiler doesn't handle %z properly - it showed 00 all the time */ - 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) - { - tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - } - - #elif defined(__DOS__) - tmp = localtime(&now); - /* since i know that %z/%Z is not available in strftime, i switch to sprintf immediately */ - tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - #else - #if defined(HAVE_LOCALTIME_R) - tmp = localtime_r(&now, &tm); - #else - tmp = localtime(&now); - #endif - - #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) - { - tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - } - #endif - write_log (hcl, logfd, ts, tslen); - } - - if (logfd == xtn->log.fd && (xtn->log.fd_flag & LOGFD_TTY)) - { - if (mask & HCL_LOG_FATAL) write_log (hcl, logfd, "\x1B[1;31m", 7); - else if (mask & HCL_LOG_ERROR) write_log (hcl, logfd, "\x1B[1;32m", 7); - else if (mask & HCL_LOG_WARN) write_log (hcl, logfd, "\x1B[1;33m", 7); - } - -#if defined(HCL_OOCH_IS_UCH) - msgidx = 0; - while (len > 0) - { - ucslen = len; - bcslen = HCL_COUNTOF(buf); - - n = hcl_convootobchars(hcl, &msg[msgidx], &ucslen, buf, &bcslen); - 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 */ - - /* attempt to write all converted characters */ - if (write_log(hcl, logfd, buf, bcslen) <= -1) break; - - if (n == 0) break; - else - { - msgidx += ucslen; - len -= ucslen; - } - } - else if (n <= -1) - { - /* conversion error */ - break; - } - } -#else - write_log (hcl, logfd, msg, len); -#endif - - if (logfd == xtn->log.fd && (xtn->log.fd_flag & LOGFD_TTY)) - { - if (mask & (HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN)) write_log (hcl, logfd, "\x1B[0m", 4); - } - - flush_log (hcl, logfd); -} - -/* ========================================================================= */ - static int vm_startup (hcl_t* hcl) { xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - -#if defined(_WIN32) - xtn->waitable_timer = CreateWaitableTimer(HCL_NULL, TRUE, HCL_NULL); -#endif - xtn->vm_running = 1; return 0; } @@ -690,16 +413,7 @@ static int vm_startup (hcl_t* hcl) static void vm_cleanup (hcl_t* hcl) { xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - xtn->vm_running = 0; - -#if defined(_WIN32) - if (xtn->waitable_timer) - { - CloseHandle (xtn->waitable_timer); - xtn->waitable_timer = HCL_NULL; - } -#endif } /* @@ -714,49 +428,26 @@ static void gc_hcl (hcl_t* hcl) if (xtn->sym_errstr) xtn->sym_errstr = hcl_moveoop(hcl, xtn->sym_errstr); } -static HCL_INLINE void reset_log_to_default (xtn_t* xtn) -{ -#if defined(ENABLE_LOG_INITIALLY) - xtn->log.fd = 2; - xtn->log.fd_flag = 0; - #if defined(HAVE_ISATTY) - if (isatty(xtn->log.fd)) xtn->log.fd_flag |= LOGFD_TTY; - #endif -#else - xtn->log.fd = -1; - xtn->log.fd_flag = 0; -#endif -} - -static void fini_hcl (hcl_t* hcl) -{ - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - if ((xtn->log.fd_flag & LOGFD_OPENED_HERE) && xtn->log.fd >= 0) close (xtn->log.fd); - reset_log_to_default (xtn); -} - /* ========================================================================= */ static int handle_logopt (hcl_t* hcl, const hcl_bch_t* str) { - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); - hcl_bch_t* xstr = (hcl_bch_t*)str; - hcl_bch_t* cm, * flt; + hcl_ooch_t* xstr, * cm, * flt; hcl_bitmask_t logmask; - cm = hcl_find_bchar_in_bcstr (xstr, ','); + xstr = hcl_dupbtooochars(hcl, str, hcl_count_bcstr(str), HCL_NULL); + if (!xstr) + { + fprintf (stderr, "ERROR: out of memory in duplicating %s\n", str); + return -1; + } + + cm = hcl_find_oochar_in_oocstr(xstr, ','); if (cm) { /* i duplicate this string for open() below as open() doesn't * accept a length-bounded string */ - xstr = hcl_dupbchars (hcl, str, hcl_count_bcstr(str)); - if (!xstr) - { - fprintf (stderr, "ERROR: out of memory in duplicating %s\n", str); - return -1; - } - - cm = hcl_find_bchar_in_bcstr(xstr, ','); + cm = hcl_find_oochar_in_oocstr(xstr, ','); *cm = '\0'; logmask = 0; @@ -764,33 +455,33 @@ static int handle_logopt (hcl_t* hcl, const hcl_bch_t* str) { flt = cm + 1; - cm = hcl_find_bchar_in_bcstr(flt, ','); + cm = hcl_find_oochar_in_oocstr(flt, ','); if (cm) *cm = '\0'; - if (hcl_comp_bcstr(flt, "app") == 0) logmask |= HCL_LOG_APP; - else if (hcl_comp_bcstr(flt, "compiler") == 0) logmask |= HCL_LOG_COMPILER; - else if (hcl_comp_bcstr(flt, "vm") == 0) logmask |= HCL_LOG_VM; - else if (hcl_comp_bcstr(flt, "mnemonic") == 0) logmask |= HCL_LOG_MNEMONIC; - else if (hcl_comp_bcstr(flt, "gc") == 0) logmask |= HCL_LOG_GC; - else if (hcl_comp_bcstr(flt, "ic") == 0) logmask |= HCL_LOG_IC; - else if (hcl_comp_bcstr(flt, "primitive") == 0) logmask |= HCL_LOG_PRIMITIVE; + if (hcl_comp_oocstr_bcstr(flt, "app") == 0) logmask |= HCL_LOG_APP; + else if (hcl_comp_oocstr_bcstr(flt, "compiler") == 0) logmask |= HCL_LOG_COMPILER; + else if (hcl_comp_oocstr_bcstr(flt, "vm") == 0) logmask |= HCL_LOG_VM; + else if (hcl_comp_oocstr_bcstr(flt, "mnemonic") == 0) logmask |= HCL_LOG_MNEMONIC; + else if (hcl_comp_oocstr_bcstr(flt, "gc") == 0) logmask |= HCL_LOG_GC; + else if (hcl_comp_oocstr_bcstr(flt, "ic") == 0) logmask |= HCL_LOG_IC; + else if (hcl_comp_oocstr_bcstr(flt, "primitive") == 0) logmask |= HCL_LOG_PRIMITIVE; - else if (hcl_comp_bcstr(flt, "fatal") == 0) logmask |= HCL_LOG_FATAL; - else if (hcl_comp_bcstr(flt, "error") == 0) logmask |= HCL_LOG_ERROR; - else if (hcl_comp_bcstr(flt, "warn") == 0) logmask |= HCL_LOG_WARN; - else if (hcl_comp_bcstr(flt, "info") == 0) logmask |= HCL_LOG_INFO; - else if (hcl_comp_bcstr(flt, "debug") == 0) logmask |= HCL_LOG_DEBUG; + else if (hcl_comp_oocstr_bcstr(flt, "fatal") == 0) logmask |= HCL_LOG_FATAL; + else if (hcl_comp_oocstr_bcstr(flt, "error") == 0) logmask |= HCL_LOG_ERROR; + else if (hcl_comp_oocstr_bcstr(flt, "warn") == 0) logmask |= HCL_LOG_WARN; + else if (hcl_comp_oocstr_bcstr(flt, "info") == 0) logmask |= HCL_LOG_INFO; + else if (hcl_comp_oocstr_bcstr(flt, "debug") == 0) logmask |= HCL_LOG_DEBUG; - else if (hcl_comp_bcstr(flt, "fatal+") == 0) logmask |= HCL_LOG_FATAL; - else if (hcl_comp_bcstr(flt, "error+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR; - else if (hcl_comp_bcstr(flt, "warn+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN; - else if (hcl_comp_bcstr(flt, "info+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN | HCL_LOG_INFO; - else if (hcl_comp_bcstr(flt, "debug+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN | HCL_LOG_INFO | HCL_LOG_DEBUG; + else if (hcl_comp_oocstr_bcstr(flt, "fatal+") == 0) logmask |= HCL_LOG_FATAL; + else if (hcl_comp_oocstr_bcstr(flt, "error+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR; + else if (hcl_comp_oocstr_bcstr(flt, "warn+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN; + else if (hcl_comp_oocstr_bcstr(flt, "info+") == 0) logmask |= HCL_LOG_FATAL | HCL_LOG_ERROR | HCL_LOG_WARN | HCL_LOG_INFO; + else if (hcl_comp_oocstr_bcstr(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) hcl_freemem (hcl, xstr); + fprintf (stderr, "ERROR: invalid value - %s\n", str); + hcl_freemem (hcl, xstr); return -1; } } @@ -805,24 +496,11 @@ static int handle_logopt (hcl_t* hcl, const hcl_bch_t* str) logmask = HCL_LOG_ALL_LEVELS | HCL_LOG_ALL_TYPES; } -#if defined(_WIN32) - xtn->log.fd = _open(xstr, _O_CREAT | _O_WRONLY | _O_APPEND | _O_BINARY , 0644); -#else - xtn->log.fd = open(xstr, O_CREAT | O_WRONLY | O_APPEND , 0644); -#endif - if (xtn->log.fd == -1) - { - fprintf (stderr, "ERROR: cannot open a log file %s\n", xstr); - if (str != xstr) hcl_freemem (hcl, xstr); - return -1; - } - xtn->log.fd_flag |= LOGFD_OPENED_HERE; -#if defined(HAVE_ISATTY) - if (isatty(xtn->log.fd)) xtn->log.fd_flag |= LOGFD_TTY; -#endif + hcl_setoption (hcl, HCL_LOG_TARGET, xstr); + hcl_freemem (hcl, xstr); + - if (str != xstr) hcl_freemem (hcl, xstr); hcl_setoption (hcl, HCL_LOG_MASK, &logmask); return 0; } @@ -977,7 +655,6 @@ int main (int argc, char* argv[]) { hcl_t* hcl = HCL_NULL; xtn_t* xtn; - hcl_vmprim_t vmprim; hcl_cb_t hclcb; hcl_bci_t c; @@ -1066,30 +743,14 @@ int main (int argc, char* argv[]) if (opt.ind >= argc) goto print_usage; #endif - memset (&vmprim, 0, HCL_SIZEOF(vmprim)); - if (large_pages) - { - vmprim.alloc_heap = hcl_vmprim_alloc_heap; - vmprim.free_heap = hcl_vmprim_free_heap; - } - vmprim.log_write = log_write; - vmprim.syserrstrb = hcl_vmprim_syserrstrb; - vmprim.assertfail = hcl_vmprim_assertfail; - vmprim.dl_startup = hcl_vmprim_dl_startup; - vmprim.dl_cleanup = hcl_vmprim_dl_cleanup; - vmprim.dl_open = hcl_vmprim_dl_open; - vmprim.dl_close = hcl_vmprim_dl_close; - vmprim.dl_getsym = hcl_vmprim_dl_getsym; - vmprim.vm_gettime = hcl_vmprim_vm_gettime; - vmprim.vm_sleep = hcl_vmprim_vm_sleep; - - hcl = hcl_open(&sys_mmgr, HCL_SIZEOF(xtn_t), heapsize, &vmprim, HCL_NULL); - if (!hcl) + hcl = hcl_openstd(HCL_SIZEOF(xtn_t), heapsize, HCL_NULL); + if (HCL_UNLIKELY(!hcl)) { printf ("ERROR: cannot open hcl\n"); goto oops; } + { hcl_oow_t tab_size; tab_size = 5000; @@ -1113,10 +774,8 @@ int main (int argc, char* argv[]) } xtn = (xtn_t*)hcl_getxtn(hcl); - reset_log_to_default (xtn); memset (&hclcb, 0, HCL_SIZEOF(hclcb)); - hclcb.fini = fini_hcl; hclcb.gc = gc_hcl; hclcb.vm_startup = vm_startup; hclcb.vm_cleanup = vm_cleanup; diff --git a/configure b/configure index c0ea813..92921a7 100755 --- a/configure +++ b/configure @@ -759,6 +759,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -850,6 +851,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1102,6 +1104,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1239,7 +1250,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1392,6 +1403,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] @@ -14326,7 +14338,6 @@ done - for ac_func in gettimeofday settimeofday clock_gettime clock_settime getitimer setitimer do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` @@ -14387,7 +14398,7 @@ _ACEOF fi done -for ac_func in snprintf _vsnprintf _vsnwprintf +for ac_func in sigaction signal do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -14399,7 +14410,31 @@ _ACEOF fi done -for ac_func in isatty mmap munmap readv writev +for ac_func in snprintf _vsnprintf _vsnwprintf strerror_r +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in accept4 pipe2 epoll_create epoll_create1 kqueue kqueue1 +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in isatty mmap munmap do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.ac b/configure.ac index 1cd70d3..9820f5a 100644 --- a/configure.ac +++ b/configure.ac @@ -120,14 +120,15 @@ dnl [], dnl [#include ]) dnl check functions - AC_CHECK_FUNCS([gettimeofday settimeofday clock_gettime clock_settime getitimer setitimer]) AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_CHECK_FUNCS([makecontext swapcontext getcontext setcontext]) AC_CHECK_FUNCS([clock_nanosleep nanosleep usleep]) AC_CHECK_FUNCS([localtime_r gmtime_r]) -AC_CHECK_FUNCS([snprintf _vsnprintf _vsnwprintf]) -AC_CHECK_FUNCS([isatty mmap munmap readv writev]) +AC_CHECK_FUNCS([sigaction signal]) +AC_CHECK_FUNCS([snprintf _vsnprintf _vsnwprintf strerror_r]) +AC_CHECK_FUNCS([accept4 pipe2 epoll_create epoll_create1 kqueue kqueue1]) +AC_CHECK_FUNCS([isatty mmap munmap]) save_LIBS="$LIBS" AC_SEARCH_LIBS([dlopen], [dl dld], [ diff --git a/lib/Makefile.am b/lib/Makefile.am index e93498e..caaa400 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -84,6 +84,7 @@ libhcl_la_SOURCES = \ print.c \ rbt.c \ read.c \ + std.c \ sym.c \ utf8.c \ utl.c \ diff --git a/lib/Makefile.in b/lib/Makefile.in index fb15ffc..f6029e3 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -156,8 +156,9 @@ am_libhcl_la_OBJECTS = libhcl_la-bigint.lo libhcl_la-cnode.lo \ libhcl_la-fmt.lo libhcl_la-gc.lo libhcl_la-hcl.lo \ libhcl_la-heap.lo libhcl_la-number.lo libhcl_la-obj.lo \ libhcl_la-opt.lo libhcl_la-prim.lo libhcl_la-print.lo \ - libhcl_la-rbt.lo libhcl_la-read.lo libhcl_la-sym.lo \ - libhcl_la-utf8.lo libhcl_la-utl.lo libhcl_la-xma.lo + libhcl_la-rbt.lo libhcl_la-read.lo libhcl_la-std.lo \ + libhcl_la-sym.lo libhcl_la-utf8.lo libhcl_la-utl.lo \ + libhcl_la-xma.lo libhcl_la_OBJECTS = $(am_libhcl_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) @@ -205,9 +206,9 @@ am__depfiles_remade = ./$(DEPDIR)/libhcl_la-bigint.Plo \ ./$(DEPDIR)/libhcl_la-number.Plo ./$(DEPDIR)/libhcl_la-obj.Plo \ ./$(DEPDIR)/libhcl_la-opt.Plo ./$(DEPDIR)/libhcl_la-prim.Plo \ ./$(DEPDIR)/libhcl_la-print.Plo ./$(DEPDIR)/libhcl_la-rbt.Plo \ - ./$(DEPDIR)/libhcl_la-read.Plo ./$(DEPDIR)/libhcl_la-sym.Plo \ - ./$(DEPDIR)/libhcl_la-utf8.Plo ./$(DEPDIR)/libhcl_la-utl.Plo \ - ./$(DEPDIR)/libhcl_la-xma.Plo \ + ./$(DEPDIR)/libhcl_la-read.Plo ./$(DEPDIR)/libhcl_la-std.Plo \ + ./$(DEPDIR)/libhcl_la-sym.Plo ./$(DEPDIR)/libhcl_la-utf8.Plo \ + ./$(DEPDIR)/libhcl_la-utl.Plo ./$(DEPDIR)/libhcl_la-xma.Plo \ ./$(DEPDIR)/libhclx_la-cb-impl.Plo \ ./$(DEPDIR)/libhclx_la-hcl-c.Plo \ ./$(DEPDIR)/libhclx_la-hcl-s.Plo \ @@ -392,6 +393,7 @@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ +runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ @@ -456,6 +458,7 @@ libhcl_la_SOURCES = \ print.c \ rbt.c \ read.c \ + std.c \ sym.c \ utf8.c \ utl.c \ @@ -591,6 +594,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-print.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-rbt.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-read.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-std.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-sym.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-utf8.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhcl_la-utl.Plo@am__quote@ # am--include-marker @@ -765,6 +769,13 @@ libhcl_la-read.lo: read.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhcl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhcl_la-read.lo `test -f 'read.c' || echo '$(srcdir)/'`read.c +libhcl_la-std.lo: std.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhcl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhcl_la-std.lo -MD -MP -MF $(DEPDIR)/libhcl_la-std.Tpo -c -o libhcl_la-std.lo `test -f 'std.c' || echo '$(srcdir)/'`std.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhcl_la-std.Tpo $(DEPDIR)/libhcl_la-std.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='std.c' object='libhcl_la-std.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhcl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhcl_la-std.lo `test -f 'std.c' || echo '$(srcdir)/'`std.c + libhcl_la-sym.lo: sym.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhcl_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhcl_la-sym.lo -MD -MP -MF $(DEPDIR)/libhcl_la-sym.Tpo -c -o libhcl_la-sym.lo `test -f 'sym.c' || echo '$(srcdir)/'`sym.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhcl_la-sym.Tpo $(DEPDIR)/libhcl_la-sym.Plo @@ -1009,6 +1020,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libhcl_la-print.Plo -rm -f ./$(DEPDIR)/libhcl_la-rbt.Plo -rm -f ./$(DEPDIR)/libhcl_la-read.Plo + -rm -f ./$(DEPDIR)/libhcl_la-std.Plo -rm -f ./$(DEPDIR)/libhcl_la-sym.Plo -rm -f ./$(DEPDIR)/libhcl_la-utf8.Plo -rm -f ./$(DEPDIR)/libhcl_la-utl.Plo @@ -1084,6 +1096,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libhcl_la-print.Plo -rm -f ./$(DEPDIR)/libhcl_la-rbt.Plo -rm -f ./$(DEPDIR)/libhcl_la-read.Plo + -rm -f ./$(DEPDIR)/libhcl_la-std.Plo -rm -f ./$(DEPDIR)/libhcl_la-sym.Plo -rm -f ./$(DEPDIR)/libhcl_la-utf8.Plo -rm -f ./$(DEPDIR)/libhcl_la-utl.Plo diff --git a/lib/cb-impl.c b/lib/cb-impl.c index 8e6ec00..d188c67 100644 --- a/lib/cb-impl.c +++ b/lib/cb-impl.c @@ -19,9 +19,23 @@ # define USE_WIN_DLL # endif + +# include "poll-msw.h" +# define USE_POLL +# define XPOLLIN POLLIN +# define XPOLLOUT POLLOUT +# define XPOLLERR POLLERR +# define XPOLLHUP POLLHUP + + +#if !defined(SIZE_T) +# define SIZE_T unsigned long int +#endif + #elif defined(__OS2__) # define INCL_DOSMODULEMGR # define INCL_DOSPROCESS +# define INCL_DOSSEMAPHORES # define INCL_DOSEXCEPTIONS # define INCL_DOSMISC # define INCL_DOSDATETIME @@ -29,21 +43,40 @@ # define INCL_DOSERRORS # include # include +# include # include +# include + + /* fake XPOLLXXX values */ +# define XPOLLIN (1 << 0) +# define XPOLLOUT (1 << 1) +# define XPOLLERR (1 << 2) +# define XPOLLHUP (1 << 3) + #elif defined(__DOS__) # include # include # include # include # include +# include +# include /* inp, outp */ # if defined(_INTELC32_) # define DOS_EXIT 0x4C +# include +# include # else # include # endif + /* fake XPOLLXXX values */ +# define XPOLLIN (1 << 0) +# define XPOLLOUT (1 << 1) +# define XPOLLERR (1 << 2) +# define XPOLLHUP (1 << 3) + #elif defined(macintosh) # include # include @@ -85,6 +118,65 @@ # else # error UNSUPPORTED DYNAMIC LINKER # endif + +# 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(USE_THREAD) +# include +# include +# endif + +# if defined(HAVE_SYS_DEVPOLL_H) + /* solaris */ +# include +# define USE_DEVPOLL +# define XPOLLIN POLLIN +# define XPOLLOUT POLLOUT +# define XPOLLERR POLLERR +# define XPOLLHUP POLLHUP +# elif defined(HAVE_SYS_EVENT_H) && defined(HAVE_KQUEUE) + /* netbsd, openbsd, etc */ +# include +# define USE_KQUEUE + /* fake XPOLLXXX values */ +# define XPOLLIN (1 << 0) +# define XPOLLOUT (1 << 1) +# define XPOLLERR (1 << 2) +# define XPOLLHUP (1 << 3) +# elif defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE) + /* linux */ +# include +# define USE_EPOLL +# define XPOLLIN EPOLLIN +# define XPOLLOUT EPOLLOUT +# define XPOLLERR EPOLLERR +# define XPOLLHUP EPOLLHUP +# elif defined(HAVE_POLL_H) +# include +# define USE_POLL +# define XPOLLIN POLLIN +# define XPOLLOUT POLLOUT +# define XPOLLERR POLLERR +# define XPOLLHUP POLLHUP +# else +# define USE_SELECT + /* fake XPOLLXXX values */ +# define XPOLLIN (1 << 0) +# define XPOLLOUT (1 << 1) +# define XPOLLERR (1 << 2) +# define XPOLLHUP (1 << 3) +# endif #endif #if !defined(HCL_DEFAULT_PFMODDIR) @@ -535,7 +627,7 @@ void hcl_vmprim_vm_gettime (hcl_t* hcl, hcl_ntime_t* now) hcl_uint64_t bigsec, bigmsec; bigmsec = GetTickCount64(); #else - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); + xtn_t* xtn = GET_XTN(hcl); hcl_uint64_t bigsec, bigmsec; DWORD msec; @@ -556,7 +648,7 @@ void hcl_vmprim_vm_gettime (hcl_t* hcl, hcl_ntime_t* now) HCL_INIT_NTIME(now, bigsec, HCL_MSEC_TO_NSEC(bigmsec)); #elif defined(__OS2__) - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); + xtn_t* xtn = GET_XTN(hcl); hcl_uint64_t bigsec, bigmsec; ULONG msec; @@ -615,11 +707,983 @@ void hcl_vmprim_vm_gettime (hcl_t* hcl, hcl_ntime_t* now) } /* ----------------------------------------------------------------- - * TODO: MUX + * IO MULTIPLEXING * ----------------------------------------------------------------- */ - #if 0 -TODO TODO TODO +static int _add_poll_fd (hcl_t* hcl, int fd, int event_mask) +{ +#if defined(USE_DEVPOLL) + xtn_t* xtn = GET_XTN(hcl); + struct pollfd ev; + + HCL_ASSERT (hcl, xtn->ep >= 0); + ev.fd = fd; + ev.events = event_mask; + ev.revents = 0; + if (write(xtn->ep, &ev, HCL_SIZEOF(ev)) != HCL_SIZEOF(ev)) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot add file descriptor %d to devpoll - %hs\n", fd, strerror(errno)); + return -1; + } + + return 0; + +#elif defined(USE_KQUEUE) + xtn_t* xtn = GET_XTN(hcl); + struct kevent ev; + hcl_oow_t rindex, roffset; + hcl_oow_t rv = 0; + + rindex = (hcl_oow_t)fd / (HCL_BITSOF(hcl_oow_t) >> 1); + roffset = ((hcl_oow_t)fd << 1) % HCL_BITSOF(hcl_oow_t); + + if (rindex >= xtn->ev.reg.capa) + { + hcl_oow_t* tmp; + hcl_oow_t newcapa; + + HCL_STATIC_ASSERT (HCL_SIZEOF(*tmp) == HCL_SIZEOF(*xtn->ev.reg.ptr)); + + newcapa = rindex + 1; + newcapa = HCL_ALIGN_POW2(newcapa, 16); + + tmp = (hcl_oow_t*)hcl_reallocmem(hcl, xtn->ev.reg.ptr, newcapa * HCL_SIZEOF(*tmp)); + if (!tmp) + { + const hcl_ooch_t* oldmsg = hcl_backuperrmsg(hcl); + hcl_seterrbfmt (hcl, HCL_ESYSERR, "unable to add file descriptor %d to kqueue - %js", fd, oldmsg); + HCL_DEBUG1 (hcl, "%js", hcl_geterrmsg(hcl)); + return -1; + } + + HCL_MEMSET (&tmp[xtn->ev.reg.capa], 0, newcapa - xtn->ev.reg.capa); + xtn->ev.reg.ptr = tmp; + xtn->ev.reg.capa = newcapa; + } + + if (event_mask & XPOLLIN) + { + /*EV_SET (&ev, fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);*/ + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_ADD; + #if defined(USE_THREAD) + ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */ + #endif + ev.filter = EVFILT_READ; + if (kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL) == -1) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot add file descriptor %d to kqueue for read - %hs\n", fd, strerror(errno)); + return -1; + } + + rv |= 1; + } + if (event_mask & XPOLLOUT) + { + /*EV_SET (&ev, fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);*/ + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_ADD; + #if defined(USE_THREAD) + ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */ + #endif + ev.filter = EVFILT_WRITE; + if (kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL) == -1) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot add file descriptor %d to kqueue for write - %hs\n", fd, strerror(errno)); + + if (event_mask & XPOLLIN) + { + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_DELETE; + ev.filter = EVFILT_READ; + kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL); + } + return -1; + } + + rv |= 2; + } + + HCL_SETBITS (hcl_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2, rv); + return 0; + +#elif defined(USE_EPOLL) + xtn_t* xtn = GET_XTN(hcl); + struct epoll_event ev; + + HCL_ASSERT (hcl, xtn->ep >= 0); + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.events = event_mask; + #if defined(USE_THREAD) && defined(EPOLLET) + /* epoll_wait may return again if the worker thread consumes events. + * switch to level-trigger. */ + /* TODO: verify if EPOLLLET is desired */ + ev.events |= EPOLLET/* | EPOLLRDHUP | EPOLLHUP */; + #endif + /*ev.data.ptr = (void*)event_data;*/ + ev.data.fd = fd; + if (epoll_ctl(xtn->ep, EPOLL_CTL_ADD, fd, &ev) == -1) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot add file descriptor %d to epoll - %hs\n", fd, strerror(errno)); + return -1; + } + return 0; + +#elif defined(USE_POLL) + xtn_t* xtn = GET_XTN(hcl); + + MUTEX_LOCK (&xtn->ev.reg.pmtx); + if (xtn->ev.reg.len >= xtn->ev.reg.capa) + { + struct pollfd* tmp, * tmp2; + hcl_oow_t newcapa; + + newcapa = HCL_ALIGN_POW2 (xtn->ev.reg.len + 1, 256); + tmp = (struct pollfd*)hcl_reallocmem(hcl, xtn->ev.reg.ptr, newcapa * HCL_SIZEOF(*tmp)); + tmp2 = (struct pollfd*)hcl_reallocmem(hcl, xtn->ev.buf, newcapa * HCL_SIZEOF(*tmp2)); + if (!tmp || !tmp2) + { + HCL_DEBUG2 (hcl, "Cannot add file descriptor %d to poll - %hs\n", fd, strerror(errno)); + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + if (tmp) hcl_freemem (hcl, tmp); + return -1; + } + + xtn->ev.reg.ptr = tmp; + xtn->ev.reg.capa = newcapa; + + xtn->ev.buf = tmp2; + } + + xtn->ev.reg.ptr[xtn->ev.reg.len].fd = fd; + xtn->ev.reg.ptr[xtn->ev.reg.len].events = event_mask; + xtn->ev.reg.ptr[xtn->ev.reg.len].revents = 0; + xtn->ev.reg.len++; + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + + return 0; + +#elif defined(USE_SELECT) + xtn_t* xtn = GET_XTN(hcl); + + MUTEX_LOCK (&xtn->ev.reg.smtx); + if (event_mask & XPOLLIN) + { + FD_SET (fd, &xtn->ev.reg.rfds); + if (fd > xtn->ev.reg.maxfd) xtn->ev.reg.maxfd = fd; + } + if (event_mask & XPOLLOUT) + { + FD_SET (fd, &xtn->ev.reg.wfds); + if (fd > xtn->ev.reg.maxfd) xtn->ev.reg.maxfd = fd; + } + MUTEX_UNLOCK (&xtn->ev.reg.smtx); + + return 0; + +#else + + HCL_DEBUG1 (hcl, "Cannot add file descriptor %d to poll - not implemented\n", fd); + hcl_seterrnum (hcl, HCL_ENOIMPL); + return -1; +#endif + +} + +static int _del_poll_fd (hcl_t* hcl, int fd) +{ + +#if defined(USE_DEVPOLL) + xtn_t* xtn = GET_XTN(hcl); + struct pollfd ev; + + HCL_ASSERT (hcl, xtn->ep >= 0); + ev.fd = fd; + ev.events = POLLREMOVE; + ev.revents = 0; + if (write(xtn->ep, &ev, HCL_SIZEOF(ev)) != HCL_SIZEOF(ev)) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot remove file descriptor %d from devpoll - %hs\n", fd, strerror(errno)); + return -1; + } + + return 0; + +#elif defined(USE_KQUEUE) + xtn_t* xtn = GET_XTN(hcl); + hcl_oow_t rindex, roffset; + int rv; + struct kevent ev; + + rindex = (hcl_oow_t)fd / (HCL_BITSOF(hcl_oow_t) >> 1); + roffset = ((hcl_oow_t)fd << 1) % HCL_BITSOF(hcl_oow_t); + + if (rindex >= xtn->ev.reg.capa) + { + hcl_seterrbfmt (hcl, HCL_EINVAL, "unknown file descriptor %d", fd); + HCL_DEBUG2 (hcl, "Cannot remove file descriptor %d from kqueue - %js\n", fd, hcl_geterrmsg(hcl)); + return -1; + }; + + rv = HCL_GETBITS (hcl_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2); + + if (rv & 1) + { + /*EV_SET (&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);*/ + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_DELETE; + ev.filter = EVFILT_READ; + kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL); + /* no error check for now */ + } + + if (rv & 2) + { + /*EV_SET (&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);*/ + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_DELETE; + ev.filter = EVFILT_WRITE; + kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL); + /* no error check for now */ + } + + HCL_SETBITS (hcl_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2, 0); + return 0; + +#elif defined(USE_EPOLL) + xtn_t* xtn = GET_XTN(hcl); + struct epoll_event ev; + + HCL_ASSERT (hcl, xtn->ep >= 0); + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + if (epoll_ctl(xtn->ep, EPOLL_CTL_DEL, fd, &ev) == -1) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot remove file descriptor %d from epoll - %hs\n", fd, strerror(errno)); + return -1; + } + return 0; + +#elif defined(USE_POLL) + xtn_t* xtn = GET_XTN(hcl); + hcl_oow_t i; + + /* TODO: performance boost. no linear search */ + MUTEX_LOCK (&xtn->ev.reg.pmtx); + for (i = 0; i < xtn->ev.reg.len; i++) + { + if (xtn->ev.reg.ptr[i].fd == fd) + { + xtn->ev.reg.len--; + HCL_MEMMOVE (&xtn->ev.reg.ptr[i], &xtn->ev.reg.ptr[i+1], (xtn->ev.reg.len - i) * HCL_SIZEOF(*xtn->ev.reg.ptr)); + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + return 0; + } + } + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + + + HCL_DEBUG1 (hcl, "Cannot remove file descriptor %d from poll - not found\n", fd); + hcl_seterrnum (hcl, HCL_ENOENT); + return -1; + +#elif defined(USE_SELECT) + xtn_t* xtn = GET_XTN(hcl); + + MUTEX_LOCK (&xtn->ev.reg.smtx); + FD_CLR (fd, &xtn->ev.reg.rfds); + FD_CLR (fd, &xtn->ev.reg.wfds); + if (fd >= xtn->ev.reg.maxfd) + { + int i; + /* TODO: any way to make this search faster or to do without the search like this */ + for (i = fd - 1; i >= 0; i--) + { + if (FD_ISSET(i, &xtn->ev.reg.rfds) || FD_ISSET(i, &xtn->ev.reg.wfds)) break; + } + xtn->ev.reg.maxfd = i; + } + MUTEX_UNLOCK (&xtn->ev.reg.smtx); + + return 0; + +#else + + HCL_DEBUG1 (hcl, "Cannot remove file descriptor %d from poll - not implemented\n", fd); + hcl_seterrnum (hcl, HCL_ENOIMPL); + return -1; +#endif +} + + +static int _mod_poll_fd (hcl_t* hcl, int fd, int event_mask) +{ +#if defined(USE_DEVPOLL) + + if (_del_poll_fd (hcl, fd) <= -1) return -1; + + if (_add_poll_fd (hcl, fd, event_mask) <= -1) + { + /* TODO: any good way to rollback successful deletion? */ + return -1; + } + + return 0; +#elif defined(USE_KQUEUE) + xtn_t* xtn = GET_XTN(hcl); + hcl_oow_t rindex, roffset; + int rv, newrv = 0; + struct kevent ev; + + rindex = (hcl_oow_t)fd / (HCL_BITSOF(hcl_oow_t) >> 1); + roffset = ((hcl_oow_t)fd << 1) % HCL_BITSOF(hcl_oow_t); + + if (rindex >= xtn->ev.reg.capa) + { + hcl_seterrbfmt (hcl, HCL_EINVAL, "unknown file descriptor %d", fd); + HCL_DEBUG2 (hcl, "Cannot modify file descriptor %d in kqueue - %js\n", fd, hcl_geterrmsg(hcl)); + return -1; + }; + + rv = HCL_GETBITS(hcl_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2); + + if (rv & 1) + { + if (!(event_mask & XPOLLIN)) + { + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_DELETE; + ev.filter = EVFILT_READ; + if (kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL) == -1) goto kqueue_syserr; + + newrv &= ~1; + } + } + else + { + if (event_mask & XPOLLIN) + { + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_ADD; + #if defined(USE_THREAD) + ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */ + #endif + ev.filter = EVFILT_READ; + if (kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL) == -1) goto kqueue_syserr; + + newrv |= 1; + } + } + + if (rv & 2) + { + if (!(event_mask & XPOLLOUT)) + { + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_DELETE; + ev.filter = EVFILT_WRITE; + /* there is no operation rollback for the (rv & 1) case. + * the rollback action may fail again even if i try it */ + if (kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL) == -1) goto kqueue_syserr; + + newrv &= ~2; + } + } + else + { + if (event_mask & XPOLLOUT) + { + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.ident = fd; + ev.flags = EV_ADD; + #if defined(USE_THREAD) + ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */ + #endif + ev.filter = EVFILT_WRITE; + + /* there is no operation rollback for the (rv & 1) case. + * the rollback action may fail again even if i try it */ + if (kevent(xtn->ep, &ev, 1, HCL_NULL, 0, HCL_NULL) == -1) goto kqueue_syserr; + + newrv |= 2; + } + } + + HCL_SETBITS (hcl_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2, newrv); + return 0; + +kqueue_syserr: + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot modify file descriptor %d in kqueue - %hs\n", fd, strerror(errno)); + return -1; + +#elif defined(USE_EPOLL) + xtn_t* xtn = GET_XTN(hcl); + struct epoll_event ev; + + HCL_ASSERT (hcl, xtn->ep >= 0); + HCL_MEMSET (&ev, 0, HCL_SIZEOF(ev)); + ev.events = event_mask; + #if defined(USE_THREAD) && defined(EPOLLET) + /* epoll_wait may return again if the worker thread consumes events. + * switch to level-trigger. */ + /* TODO: verify if EPOLLLET is desired */ + ev.events |= EPOLLET; + #endif + ev.data.fd = fd; + if (epoll_ctl(xtn->ep, EPOLL_CTL_MOD, fd, &ev) == -1) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Cannot modify file descriptor %d in epoll - %hs\n", fd, strerror(errno)); + return -1; + } + + return 0; + +#elif defined(USE_POLL) + + xtn_t* xtn = GET_XTN(hcl); + hcl_oow_t i; + + MUTEX_LOCK (&xtn->ev.reg.pmtx); + for (i = 0; i < xtn->ev.reg.len; i++) + { + if (xtn->ev.reg.ptr[i].fd == fd) + { + HCL_MEMMOVE (&xtn->ev.reg.ptr[i], &xtn->ev.reg.ptr[i+1], (xtn->ev.reg.len - i - 1) * HCL_SIZEOF(*xtn->ev.reg.ptr)); + xtn->ev.reg.ptr[i].fd = fd; + xtn->ev.reg.ptr[i].events = event_mask; + xtn->ev.reg.ptr[i].revents = 0; + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + + return 0; + } + } + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + + HCL_DEBUG1 (hcl, "Cannot modify file descriptor %d in poll - not found\n", fd); + hcl_seterrnum (hcl, HCL_ENOENT); + return -1; + +#elif defined(USE_SELECT) + + xtn_t* xtn = GET_XTN(hcl); + + MUTEX_LOCK (&xtn->ev.reg.smtx); + HCL_ASSERT (hcl, fd <= xtn->ev.reg.maxfd); + + if (event_mask & XPOLLIN) + FD_SET (fd, &xtn->ev.reg.rfds); + else + FD_CLR (fd, &xtn->ev.reg.rfds); + + if (event_mask & XPOLLOUT) + FD_SET (fd, &xtn->ev.reg.wfds); + else + FD_CLR (fd, &xtn->ev.reg.wfds); + MUTEX_UNLOCK (&xtn->ev.reg.smtx); + + return 0; + +#else + HCL_DEBUG1 (hcl, "Cannot modify file descriptor %d in poll - not implemented\n", fd); + hcl_seterrnum (hcl, HCL_ENOIMPL); + return -1; +#endif +} + +int hcl_vmprim_vm_muxadd (hcl_t* hcl, hcl_ooi_t io_handle, hcl_ooi_t mask) +{ + int event_mask; + + event_mask = 0; + if (mask & HCL_SEMAPHORE_IO_MASK_INPUT) event_mask |= XPOLLIN; + if (mask & HCL_SEMAPHORE_IO_MASK_OUTPUT) event_mask |= XPOLLOUT; + + if (event_mask == 0) + { + HCL_DEBUG2 (hcl, " Invalid semaphore mask %zd on handle %zd\n", mask, io_handle); + hcl_seterrbfmt (hcl, HCL_EINVAL, "invalid semaphore mask %zd on handle %zd", mask, io_handle); + return -1; + } + + return _add_poll_fd(hcl, io_handle, event_mask); +} + +int hcl_vmprim_vm_muxmod (hcl_t* hcl, hcl_ooi_t io_handle, hcl_ooi_t mask) +{ + int event_mask; + + event_mask = 0; + if (mask & HCL_SEMAPHORE_IO_MASK_INPUT) event_mask |= XPOLLIN; + if (mask & HCL_SEMAPHORE_IO_MASK_OUTPUT) event_mask |= XPOLLOUT; + + if (event_mask == 0) + { + HCL_DEBUG2 (hcl, " Invalid semaphore mask %zd on handle %zd\n", mask, io_handle); + hcl_seterrbfmt (hcl, HCL_EINVAL, "invalid semaphore mask %zd on handle %zd", mask, io_handle); + return -1; + } + + return _mod_poll_fd(hcl, io_handle, event_mask); +} + +int hcl_vmprim_vm_muxdel (hcl_t* hcl, hcl_ooi_t io_handle) +{ + return _del_poll_fd(hcl, io_handle); +} + +#if defined(USE_THREAD) +static void* iothr_main (void* arg) +{ + hcl_t* hcl = (hcl_t*)arg; + xtn_t* xtn = GET_XTN(hcl); + + /*while (!hcl->abort_req)*/ + while (!xtn->iothr.abort) + { + if (xtn->ev.len <= 0) /* TODO: no mutex needed for this check? */ + { + int n; + #if defined(USE_DEVPOLL) + struct dvpoll dvp; + #elif defined(USE_KQUEUE) + struct timespec ts; + #elif defined(USE_POLL) + hcl_oow_t nfds; + #elif defined(USE_SELECT) + struct timeval tv; + fd_set rfds; + fd_set wfds; + int maxfd; + #endif + + poll_for_event: + + #if defined(USE_DEVPOLL) + dvp.dp_timeout = 10000; /* milliseconds */ + dvp.dp_fds = xtn->ev.buf; + dvp.dp_nfds = HCL_COUNTOF(xtn->ev.buf); + n = ioctl (xtn->ep, DP_POLL, &dvp); + #elif defined(USE_KQUEUE) + ts.tv_sec = 10; + ts.tv_nsec = 0; + n = kevent(xtn->ep, HCL_NULL, 0, xtn->ev.buf, HCL_COUNTOF(xtn->ev.buf), &ts); + /* n == 0: timeout + * n == -1: error */ + #elif defined(USE_EPOLL) + n = epoll_wait(xtn->ep, xtn->ev.buf, HCL_COUNTOF(xtn->ev.buf), 10000); /* TODO: make this timeout value in the io thread */ + #elif defined(USE_POLL) + MUTEX_LOCK (&xtn->ev.reg.pmtx); + HCL_MEMCPY (xtn->ev.buf, xtn->ev.reg.ptr, xtn->ev.reg.len * HCL_SIZEOF(*xtn->ev.buf)); + nfds = xtn->ev.reg.len; + MUTEX_UNLOCK (&xtn->ev.reg.pmtx); + n = poll(xtn->ev.buf, nfds, 10000); + if (n > 0) + { + /* compact the return buffer as poll() doesn't */ + hcl_oow_t i, j; + for (i = 0, j = 0; i < nfds && j < n; i++) + { + if (xtn->ev.buf[i].revents) + { + if (j != i) xtn->ev.buf[j] = xtn->ev.buf[i]; + j++; + } + } + n = j; + } + #elif defined(USE_SELECT) + tv.tv_sec = 10; + tv.tv_usec = 0; + MUTEX_LOCK (&xtn->ev.reg.smtx); + maxfd = xtn->ev.reg.maxfd; + HCL_MEMCPY (&rfds, &xtn->ev.reg.rfds, HCL_SIZEOF(rfds)); + HCL_MEMCPY (&wfds, &xtn->ev.reg.wfds, HCL_SIZEOF(wfds)); + MUTEX_UNLOCK (&xtn->ev.reg.smtx); + n = select (maxfd + 1, &rfds, &wfds, HCL_NULL, &tv); + if (n > 0) + { + int fd, count = 0; + for (fd = 0; fd <= maxfd; fd++) + { + int events = 0; + if (FD_ISSET(fd, &rfds)) events |= XPOLLIN; + if (FD_ISSET(fd, &wfds)) events |= XPOLLOUT; + + if (events) + { + HCL_ASSERT (hcl, count < HCL_COUNTOF(xtn->ev.buf)); + xtn->ev.buf[count].fd = fd; + xtn->ev.buf[count].events = events; + count++; + } + } + + n = count; + HCL_ASSERT (hcl, n > 0); + } + #endif + + pthread_mutex_lock (&xtn->ev.mtx); + if (n <= -1) + { + /* TODO: don't use HCL_DEBUG2. it's not thread safe... */ + /* the following call has a race-condition issue when called in this separate thread */ + /*HCL_DEBUG2 (hcl, "Warning: multiplexer wait failure - %d, %hs\n", errno, strerror(errno));*/ + } + else if (n > 0) + { + xtn->ev.len = n; + } + pthread_cond_signal (&xtn->ev.cnd2); + pthread_mutex_unlock (&xtn->ev.mtx); + } + else + { + /* the event buffer has not been emptied yet */ + struct timespec ts; + + pthread_mutex_lock (&xtn->ev.mtx); + if (xtn->ev.len <= 0) + { + /* it got emptied between the if check and pthread_mutex_lock() above */ + pthread_mutex_unlock (&xtn->ev.mtx); + goto poll_for_event; + } + + #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + clock_gettime (CLOCK_REALTIME, &ts); + #else + { + struct timeval tv; + gettimeofday (&tv, HCL_NULL); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = HCL_USEC_TO_NSEC(tv.tv_usec); + } + #endif + ts.tv_sec += 10; + pthread_cond_timedwait (&xtn->ev.cnd, &xtn->ev.mtx, &ts); + pthread_mutex_unlock (&xtn->ev.mtx); + } + + /*sched_yield ();*/ + } + + return HCL_NULL; +} +#endif + +void hcl_vmprim_vm_muxwait (hcl_t* hcl, const hcl_ntime_t* dur, hcl_vmprim_muxwait_cb_t muxwcb) +{ + xtn_t* xtn = GET_XTN(hcl); + +#if defined(USE_THREAD) + int n; + + /* create a thread if mux wait is started at least once. */ + if (!xtn->iothr.up) + { + xtn->iothr.up = 1; + if (pthread_create(&xtn->iothr.thr, HCL_NULL, iothr_main, hcl) != 0) + { + HCL_LOG2 (hcl, HCL_LOG_WARN, "Warning: pthread_create failure - %d, %hs\n", errno, strerror(errno)); + xtn->iothr.up = 0; +/* TODO: switch to the non-threaded mode? */ + } + } + + if (xtn->iothr.abort) return; + + if (xtn->ev.len <= 0) + { + struct timespec ts; + hcl_ntime_t ns; + + if (!dur) return; /* immediate check is requested. and there is no event */ + + #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME) + clock_gettime (CLOCK_REALTIME, &ts); + ns.sec = ts.tv_sec; + ns.nsec = ts.tv_nsec; + #else + { + struct timeval tv; + gettimeofday (&tv, HCL_NULL); + ns.sec = tv.tv_sec; + ns.nsec = HCL_USEC_TO_NSEC(tv.tv_usec); + } + #endif + HCL_ADD_NTIME (&ns, &ns, dur); + ts.tv_sec = ns.sec; + ts.tv_nsec = ns.nsec; + + pthread_mutex_lock (&xtn->ev.mtx); + if (xtn->ev.len <= 0) + { + /* the event buffer is still empty */ + pthread_cond_timedwait (&xtn->ev.cnd2, &xtn->ev.mtx, &ts); + } + pthread_mutex_unlock (&xtn->ev.mtx); + } + + n = xtn->ev.len; + + if (n > 0) + { + do + { + --n; + + #if defined(USE_DEVPOLL) + if (xtn->ev.buf[n].fd == xtn->iothr.p[0]) + #elif defined(USE_KQUEUE) + if (xtn->ev.buf[n].ident == xtn->iothr.p[0]) + #elif defined(USE_EPOLL) + /*if (xtn->ev.buf[n].data.ptr == (void*)HCL_TYPE_MAX(hcl_oow_t))*/ + if (xtn->ev.buf[n].data.fd == xtn->iothr.p[0]) + #elif defined(USE_POLL) + if (xtn->ev.buf[n].fd == xtn->iothr.p[0]) + #elif defined(USE_SELECT) + if (xtn->ev.buf[n].fd == xtn->iothr.p[0]) + #else + # error UNSUPPORTED + #endif + { + hcl_uint8_t u8; + while (read(xtn->iothr.p[0], &u8, HCL_SIZEOF(u8)) > 0) + { + /* consume as much as possible */; + if (u8 == 'Q') xtn->iothr.abort = 1; + } + } + else if (muxwcb) + { + int revents; + hcl_ooi_t mask; + + #if defined(USE_DEVPOLL) + revents = xtn->ev.buf[n].revents; + #elif defined(USE_KQUEUE) + if (xtn->ev.buf[n].filter == EVFILT_READ) mask = HCL_SEMAPHORE_IO_MASK_INPUT; + else if (xtn->ev.buf[n].filter == EVFILT_WRITE) mask = HCL_SEMAPHORE_IO_MASK_OUTPUT; + else mask = 0; + goto call_muxwcb_kqueue; + #elif defined(USE_EPOLL) + revents = xtn->ev.buf[n].events; + #elif defined(USE_POLL) + revents = xtn->ev.buf[n].revents; + #elif defined(USE_SELECT) + revents = xtn->ev.buf[n].events; + #endif + + mask = 0; + if (revents & XPOLLIN) mask |= HCL_SEMAPHORE_IO_MASK_INPUT; + if (revents & XPOLLOUT) mask |= HCL_SEMAPHORE_IO_MASK_OUTPUT; + if (revents & XPOLLERR) mask |= HCL_SEMAPHORE_IO_MASK_ERROR; + if (revents & XPOLLHUP) mask |= HCL_SEMAPHORE_IO_MASK_HANGUP; + + #if defined(USE_DEVPOLL) + muxwcb (hcl, xtn->ev.buf[n].fd, mask); + #elif defined(USE_KQUEUE) + call_muxwcb_kqueue: + muxwcb (hcl, xtn->ev.buf[n].ident, mask); + #elif defined(USE_EPOLL) + muxwcb (hcl, xtn->ev.buf[n].data.fd, mask); + #elif defined(USE_POLL) + muxwcb (hcl, xtn->ev.buf[n].fd, mask); + #elif defined(USE_SELECT) + muxwcb (hcl, xtn->ev.buf[n].fd, mask); + #else + # error UNSUPPORTED + #endif + } + } + while (n > 0); + + pthread_mutex_lock (&xtn->ev.mtx); + xtn->ev.len = 0; + pthread_cond_signal (&xtn->ev.cnd); + pthread_mutex_unlock (&xtn->ev.mtx); + } + +#else /* USE_THREAD */ + int n; + #if defined(USE_DEVPOLL) + int tmout; + struct dvpoll dvp; + #elif defined(USE_KQUEUE) + struct timespec ts; + #elif defined(USE_EPOLL) + int tmout; + #elif defined(USE_POLL) + int tmout; + #elif defined(USE_SELECT) + struct timeval tv; + fd_set rfds, wfds; + int maxfd; + #endif + + + #if defined(USE_DEVPOLL) + tmout = dur? HCL_SECNSEC_TO_MSEC(dur->sec, dur->nsec): 0; + + dvp.dp_timeout = tmout; /* milliseconds */ + dvp.dp_fds = xtn->ev.buf; + dvp.dp_nfds = HCL_COUNTOF(xtn->ev.buf); + n = ioctl(xtn->ep, DP_POLL, &dvp); + + #elif defined(USE_KQUEUE) + + if (dur) + { + ts.tv_sec = dur->sec; + ts.tv_nsec = dur->nsec; + } + else + { + ts.tv_sec = 0; + ts.tv_nsec = 0; + } + + n = kevent(xtn->ep, HCL_NULL, 0, xtn->ev.buf, HCL_COUNTOF(xtn->ev.buf), &ts); + /* n == 0: timeout + * n == -1: error */ + + #elif defined(USE_EPOLL) + tmout = dur? HCL_SECNSEC_TO_MSEC(dur->sec, dur->nsec): 0; + n = epoll_wait(xtn->ep, xtn->ev.buf, HCL_COUNTOF(xtn->ev.buf), tmout); + + #elif defined(USE_POLL) + tmout = dur? HCL_SECNSEC_TO_MSEC(dur->sec, dur->nsec): 0; + HCL_MEMCPY (xtn->ev.buf, xtn->ev.reg.ptr, xtn->ev.reg.len * HCL_SIZEOF(*xtn->ev.buf)); + n = poll(xtn->ev.buf, xtn->ev.reg.len, tmout); + if (n > 0) + { + /* compact the return buffer as poll() doesn't */ + hcl_oow_t i, j; + for (i = 0, j = 0; i < xtn->ev.reg.len && j < n; i++) + { + if (xtn->ev.buf[i].revents) + { + if (j != i) xtn->ev.buf[j] = xtn->ev.buf[i]; + j++; + } + } + n = j; + } + #elif defined(USE_SELECT) + if (dur) + { + tv.tv_sec = dur->sec; + tv.tv_usec = HCL_NSEC_TO_USEC(dur->nsec); + } + else + { + tv.tv_sec = 0; + tv.tv_usec = 0; + } + maxfd = xtn->ev.reg.maxfd; + HCL_MEMCPY (&rfds, &xtn->ev.reg.rfds, HCL_SIZEOF(rfds)); + HCL_MEMCPY (&wfds, &xtn->ev.reg.wfds, HCL_SIZEOF(wfds)); + n = select(maxfd + 1, &rfds, &wfds, HCL_NULL, &tv); + if (n > 0) + { + int fd, count = 0; + for (fd = 0; fd <= maxfd; fd++) + { + int events = 0; + if (FD_ISSET(fd, &rfds)) events |= XPOLLIN; + if (FD_ISSET(fd, &wfds)) events |= XPOLLOUT; + + if (events) + { + HCL_ASSERT (hcl, count < HCL_COUNTOF(xtn->ev.buf)); + xtn->ev.buf[count].fd = fd; + xtn->ev.buf[count].events = events; + count++; + } + } + + n = count; + HCL_ASSERT (hcl, n > 0); + } + #endif + + if (n <= -1) + { + hcl_seterrwithsyserr (hcl, 0, errno); + HCL_DEBUG2 (hcl, "Warning: multiplexer wait failure - %d, %s\n", errno, hcl_geterrmsg(hcl)); + } + else + { + xtn->ev.len = n; + } + + /* the muxwcb must be valid all the time in a non-threaded mode */ + HCL_ASSERT (hcl, muxwcb != HCL_NULL); + + while (n > 0) + { + int revents; + hcl_ooi_t mask; + + --n; + + #if defined(USE_DEVPOLL) + revents = xtn->ev.buf[n].revents; + #elif defined(USE_KQUEUE) + if (xtn->ev.buf[n].filter == EVFILT_READ) mask = HCL_SEMAPHORE_IO_MASK_INPUT; + else if (xtn->ev.buf[n].filter == EVFILT_WRITE) mask = HCL_SEMAPHORE_IO_MASK_OUTPUT; + else mask = 0; + goto call_muxwcb_kqueue; + #elif defined(USE_EPOLL) + revents = xtn->ev.buf[n].events; + #elif defined(USE_POLL) + revents = xtn->ev.buf[n].revents; + #elif defined(USE_SELECT) + revents = xtn->ev.buf[n].events; + #else + revents = 0; /* TODO: fake. unsupported but to compile on such an unsupported system.*/ + #endif + + mask = 0; + if (revents & XPOLLIN) mask |= HCL_SEMAPHORE_IO_MASK_INPUT; + if (revents & XPOLLOUT) mask |= HCL_SEMAPHORE_IO_MASK_OUTPUT; + if (revents & XPOLLERR) mask |= HCL_SEMAPHORE_IO_MASK_ERROR; + if (revents & XPOLLHUP) mask |= HCL_SEMAPHORE_IO_MASK_HANGUP; + + #if defined(USE_DEVPOLL) + muxwcb (hcl, xtn->ev.buf[n].fd, mask); + #elif defined(USE_KQUEUE) + call_muxwcb_kqueue: + muxwcb (hcl, xtn->ev.buf[n].ident, mask); + #elif defined(USE_EPOLL) + muxwcb (hcl, xtn->ev.buf[n].data.fd, mask); + #elif defined(USE_POLL) + muxwcb (hcl, xtn->ev.buf[n].fd, mask); + #elif defined(USE_SELECT) + muxwcb (hcl, xtn->ev.buf[n].fd, mask); + #endif + } + + xtn->ev.len = 0; +#endif /* USE_THREAD */ +} + #endif /* ----------------------------------------------------------------- @@ -638,7 +1702,7 @@ TODO TODO TODO int hcl_vmprim_vm_sleep (hcl_t* hcl, const hcl_ntime_t* dur) { #if defined(_WIN32) - xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl); + xtn_t* xtn = GET_XTN(hcl); if (xtn->waitable_timer) { LARGE_INTEGER li; diff --git a/lib/exec.c b/lib/exec.c index b8fb31f..6ecb2fd 100644 --- a/lib/exec.c +++ b/lib/exec.c @@ -3824,33 +3824,6 @@ hcl_pfrc_t hcl_pf_semaphore_new (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) return HCL_PF_SUCCESS; } -hcl_pfrc_t hcl_pf_semaphore_wait (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) -{ - hcl_oop_semaphore_t sem; - - sem = (hcl_oop_semaphore_t)HCL_STACK_GETARG(hcl, nargs, 0); - if (!HCL_IS_SEMAPHORE(hcl, sem)) - { - hcl_seterrbfmt (hcl, HCL_EINVAL, "parameter not semaphore - %O", sem); - return HCL_PF_FAILURE; - } - - if (!can_await_semaphore(hcl, sem)) - { - hcl_seterrbfmt (hcl, HCL_EPERM, "not allowed to wait on a semaphore that belongs to a semaphore group"); - return HCL_PF_FAILURE; - } - - /* i must set the return value before calling await_semaphore(). - * await_semaphore() may switch the active process and the stack - * manipulation macros target at the active process. i'm not supposed - * to change the return value of a new active process. */ - HCL_STACK_SETRET (hcl, nargs, (hcl_oop_t)sem); - - await_semaphore (hcl, sem); - return HCL_PF_SUCCESS; -} - hcl_pfrc_t hcl_pf_semaphore_signal (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) { hcl_oop_semaphore_t sem; @@ -3952,16 +3925,19 @@ hcl_pfrc_t hcl_pf_semaphore_signal (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) return HCL_PF_SUCCESS; } -#if 0 static hcl_pfrc_t __semaphore_signal_on_io (hcl_t* hcl, hcl_ooi_t nargs, hcl_semaphore_io_type_t io_type) { hcl_oop_semaphore_t sem; hcl_oop_t fd; - sem = (hcl_oop_semaphore_t)HCL_STACK_GETRCV(hcl, nargs); - HCL_PF_CHECK_RCV (hcl, hcl_iskindof(hcl, (hcl_oop_t)sem, hcl->_semaphore)); + sem = (hcl_oop_semaphore_t)HCL_STACK_GETARG(hcl, nargs, 0); + if (!HCL_IS_SEMAPHORE(hcl, sem)) + { + hcl_seterrbfmt (hcl, HCL_EINVAL, "parameter not semaphore - %O", sem); + return HCL_PF_FAILURE; + } - fd = HCL_STACK_GETARG(hcl, nargs, 0); + fd = HCL_STACK_GETARG(hcl, nargs, 1); if (!HCL_OOP_IS_SMOOI(fd)) { @@ -3997,7 +3973,7 @@ static hcl_pfrc_t __semaphore_signal_on_io (hcl_t* hcl, hcl_ooi_t nargs, hcl_sem return HCL_PF_FAILURE; } - HCL_STACK_SETRETTORCV (hcl, nargs); /* ^self */ + HCL_STACK_SETRET (hcl, nargs, (hcl_oop_t)sem); return HCL_PF_SUCCESS; } @@ -4011,6 +3987,7 @@ hcl_pfrc_t hcl_pf_semaphore_signal_on_output (hcl_t* hcl, hcl_mod_t* mod, hcl_oo return __semaphore_signal_on_io(hcl, nargs, HCL_SEMAPHORE_IO_TYPE_OUTPUT); } +#if 0 hcl_pfrc_t hcl_pf_semaphore_signal_on_gcfin (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) { hcl_oop_semaphore_t sem; @@ -4026,6 +4003,34 @@ hcl_pfrc_t hcl_pf_semaphore_signal_on_gcfin (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi } #endif +hcl_pfrc_t hcl_pf_semaphore_wait (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) +{ + hcl_oop_semaphore_t sem; + + sem = (hcl_oop_semaphore_t)HCL_STACK_GETARG(hcl, nargs, 0); + if (!HCL_IS_SEMAPHORE(hcl, sem)) + { + hcl_seterrbfmt (hcl, HCL_EINVAL, "parameter not semaphore - %O", sem); + return HCL_PF_FAILURE; + } + + if (!can_await_semaphore(hcl, sem)) + { + hcl_seterrbfmt (hcl, HCL_EPERM, "not allowed to wait on a semaphore that belongs to a semaphore group"); + return HCL_PF_FAILURE; + } + + /* i must set the return value before calling await_semaphore(). + * await_semaphore() may switch the active process and the stack + * manipulation macros target at the active process. i'm not supposed + * to change the return value of a new active process. */ + HCL_STACK_SETRET (hcl, nargs, (hcl_oop_t)sem); + + await_semaphore (hcl, sem); + return HCL_PF_SUCCESS; +} + + hcl_pfrc_t hcl_pf_semaphore_unsignal (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) { /* remove a semaphore from processor's signal scheduling. @@ -4090,8 +4095,6 @@ TODO: add this back if gcfin support is added return HCL_PF_SUCCESS; } -/* ------------------------------------------------------------------ */ - /* ------------------------------------------------------------------ */ hcl_pfrc_t hcl_pf_semaphore_group_new (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) { diff --git a/lib/hcl-cfg.h.in b/lib/hcl-cfg.h.in index b2998c2..f920468 100644 --- a/lib/hcl-cfg.h.in +++ b/lib/hcl-cfg.h.in @@ -3,6 +3,9 @@ /* Define if building universal (internal helper macro) */ #undef AC_APPLE_UNIVERSAL_BUILD +/* Define to 1 if you have the `accept4' function. */ +#undef HAVE_ACCEPT4 + /* Define to 1 if you have the `acosq' function. */ #undef HAVE_ACOSQ @@ -45,6 +48,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H +/* Define to 1 if you have the `epoll_create' function. */ +#undef HAVE_EPOLL_CREATE + +/* Define to 1 if you have the `epoll_create1' function. */ +#undef HAVE_EPOLL_CREATE1 + /* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H @@ -81,6 +90,12 @@ /* Define to 1 if you have the `isatty' function. */ #undef HAVE_ISATTY +/* Define to 1 if you have the `kqueue' function. */ +#undef HAVE_KQUEUE + +/* Define to 1 if you have the `kqueue1' function. */ +#undef HAVE_KQUEUE1 + /* Define to 1 if you have the header file. */ #undef HAVE_LIBUNWIND_H @@ -111,6 +126,9 @@ /* Define to 1 if you have the `nanosleep' function. */ #undef HAVE_NANOSLEEP +/* Define to 1 if you have the `pipe2' function. */ +#undef HAVE_PIPE2 + /* Define to 1 if you have the header file. */ #undef HAVE_POLL_H @@ -129,9 +147,6 @@ /* Define to 1 if you have the `quadmath_snprintf' function. */ #undef HAVE_QUADMATH_SNPRINTF -/* Define to 1 if you have the `readv' function. */ -#undef HAVE_READV - /* Define to 1 if you have the `roundq' function. */ #undef HAVE_ROUNDQ @@ -144,6 +159,12 @@ /* Define to 1 if you have the `settimeofday' function. */ #undef HAVE_SETTIMEOFDAY +/* Define to 1 if you have the `sigaction' function. */ +#undef HAVE_SIGACTION + +/* Define to 1 if you have the `signal' function. */ +#undef HAVE_SIGNAL + /* Define to 1 if you have the header file. */ #undef HAVE_SIGNAL_H @@ -171,6 +192,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H +/* Define to 1 if you have the `strerror_r' function. */ +#undef HAVE_STRERROR_R + /* strftime supports %z */ #undef HAVE_STRFTIME_SMALL_Z @@ -240,9 +264,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_WCTYPE_H -/* Define to 1 if you have the `writev' function. */ -#undef HAVE_WRITEV - /* Define to 1 if you have the `_vsnprintf' function. */ #undef HAVE__VSNPRINTF diff --git a/lib/hcl-prv.h b/lib/hcl-prv.h index 47308c0..b58b6c4 100644 --- a/lib/hcl-prv.h +++ b/lib/hcl-prv.h @@ -1356,7 +1356,7 @@ hcl_pfrc_t hcl_pf_semaphore_signal (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs) hcl_pfrc_t hcl_pf_semaphore_signal_timed (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs); hcl_pfrc_t hcl_pf_semaphore_signal_on_input (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs); hcl_pfrc_t hcl_pf_semaphore_signal_on_output (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs); -hcl_pfrc_t hcl_pf_semaphore_signal_on_gcfin (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs); +/*hcl_pfrc_t hcl_pf_semaphore_signal_on_gcfin (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs);*/ hcl_pfrc_t hcl_pf_semaphore_unsignal (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs); hcl_pfrc_t hcl_pf_semaphore_group_new (hcl_t* hcl, hcl_mod_t* mod, hcl_ooi_t nargs); diff --git a/lib/hcl.c b/lib/hcl.c index 42c81c9..39cd67b 100644 --- a/lib/hcl.c +++ b/lib/hcl.c @@ -318,6 +318,18 @@ void hcl_fini (hcl_t* hcl) hcl->log.len = 0; } + if (hcl->option.log_target) + { + hcl_freemem (hcl, hcl->option.log_target); + hcl->option.log_target = HCL_NULL; + } + + if (hcl->option.log_targetx) + { + hcl_freemem (hcl, hcl->option.log_targetx); + hcl->option.log_targetx = HCL_NULL; + } + if (hcl->inttostr.xbuf.ptr) { hcl_freemem (hcl, hcl->inttostr.xbuf.ptr); @@ -378,6 +390,8 @@ void hcl_setinloc (hcl_t* hcl, hcl_oow_t line, hcl_oow_t colm) int hcl_setoption (hcl_t* hcl, hcl_option_t id, const void* value) { + hcl_cb_t* cb; + switch (id) { case HCL_TRAIT: @@ -385,15 +399,43 @@ int hcl_setoption (hcl_t* hcl, hcl_option_t id, const void* value) #if defined(HCL_BUILD_DEBUG) hcl->option.karatsuba_cutoff = ((hcl->option.trait & HCL_TRAIT_DEBUG_BIGINT)? HCL_KARATSUBA_CUTOFF_DEBUG: HCL_KARATSUBA_CUTOFF); #endif - return 0; + break; case HCL_LOG_MASK: hcl->option.log_mask = *(const hcl_bitmask_t*)value; - return 0; + break; case HCL_LOG_MAXCAPA: hcl->option.log_maxcapa = *(hcl_oow_t*)value; - return 0; + break; + + case HCL_LOG_TARGET: + { + hcl_ooch_t* v1; + #if defined(HCL_OOCH_IS_UCH) + hcl_bch_t* v2; + #else + hcl_uch_t* v2; + #endif + + v1 = hcl_dupoochars(hcl, value, hcl_count_oocstr(value)); + if (HCL_UNLIKELY(!v1)) return -1; + + #if defined(HCL_OOCH_IS_UCH) + v2 = hcl_dupootobcstr(hcl, value, HCL_NULL); + #else + v2 = hcl_dupootoucstr(hcl, value, HCL_NULL); + #endif + if (HCL_UNLIKELY(!v2)) + { + hcl_freemem (hcl, v1); + return -1; + } + hcl->option.log_targetx = v2; + hcl->option.log_target = v1; + break; + } + case HCL_SYMTAB_SIZE: { @@ -403,7 +445,7 @@ int hcl_setoption (hcl_t* hcl, hcl_option_t id, const void* value) if (w <= 0 || w > HCL_SMOOI_MAX) goto einval; hcl->option.dfl_symtab_size = *(hcl_oow_t*)value; - return 0; + break; } case HCL_SYSDIC_SIZE: @@ -414,7 +456,7 @@ int hcl_setoption (hcl_t* hcl, hcl_option_t id, const void* value) if (w <= 0 || w > HCL_SMOOI_MAX) goto einval; hcl->option.dfl_sysdic_size = *(hcl_oow_t*)value; - return 0; + break; } case HCL_PROCSTK_SIZE: @@ -425,14 +467,25 @@ int hcl_setoption (hcl_t* hcl, hcl_option_t id, const void* value) if (w <= 0 || w > HCL_SMOOI_MAX) goto einval; hcl->option.dfl_procstk_size = *(hcl_oow_t*)value; - return 0; + break; } case HCL_MOD_INCTX: hcl->option.mod_inctx = *(void**)value; - return 0; + break; + + + default: + goto einval; } + for (cb = hcl->cblist; cb; cb = cb->next) + { + if (cb->opt_set) cb->opt_set (hcl, id, value); + } + + return 0; + einval: hcl_seterrnum (hcl, HCL_EINVAL); return -1; @@ -454,6 +507,10 @@ int hcl_getoption (hcl_t* hcl, hcl_option_t id, void* value) *(hcl_oow_t*)value = hcl->option.log_maxcapa; return 0; + case HCL_LOG_TARGET: + *(hcl_ooch_t**)value = hcl->option.log_target; + return 0; + case HCL_SYMTAB_SIZE: *(hcl_oow_t*)value = hcl->option.dfl_symtab_size; return 0; diff --git a/lib/hcl.h b/lib/hcl.h index 933ab3b..1631662 100644 --- a/lib/hcl.h +++ b/lib/hcl.h @@ -163,6 +163,7 @@ enum hcl_option_t HCL_TRAIT, HCL_LOG_MASK, HCL_LOG_MAXCAPA, + HCL_LOG_TARGET, HCL_SYMTAB_SIZE, /* default system table size */ HCL_SYSDIC_SIZE, /* default system dictionary size */ HCL_PROCSTK_SIZE, /* default process stack size */ @@ -1183,6 +1184,7 @@ typedef int (*hcl_ioimpl_t) ( * ========================================================================= */ +typedef void (*hcl_cb_opt_set_t) (hcl_t* hcl, hcl_option_t id, const void* val); typedef void (*hcl_cb_fini_t) (hcl_t* hcl); typedef void (*hcl_cb_gc_t) (hcl_t* hcl); typedef int (*hcl_cb_vm_startup_t) (hcl_t* hcl); @@ -1192,6 +1194,7 @@ typedef void (*hcl_cb_vm_checkbc_t) (hcl_t* hcl, hcl_oob_t bcode); typedef struct hcl_cb_t hcl_cb_t; struct hcl_cb_t { + hcl_cb_opt_set_t opt_set; hcl_cb_gc_t gc; hcl_cb_fini_t fini; @@ -1356,6 +1359,12 @@ struct hcl_t hcl_bitmask_t trait; hcl_bitmask_t log_mask; hcl_oow_t log_maxcapa; + hcl_ooch_t* log_target; + #if defined(HCL_OOCH_IS_UCH) + hcl_bch_t* log_targetx; + #else + hcl_uch_t* log_targetx; + #endif hcl_oow_t dfl_symtab_size; hcl_oow_t dfl_sysdic_size; hcl_oow_t dfl_procstk_size; @@ -1737,6 +1746,12 @@ HCL_EXPORT hcl_t* hcl_open ( hcl_errnum_t* errnum ); +HCL_EXPORT hcl_t* hcl_openstd ( + hcl_oow_t xtnsize, + hcl_oow_t heapsize, + hcl_errnum_t* errnum +); + HCL_EXPORT void hcl_close ( hcl_t* vm ); diff --git a/lib/prim.c b/lib/prim.c index 4a7d559..d6955f1 100644 --- a/lib/prim.c +++ b/lib/prim.c @@ -848,6 +848,8 @@ static pf_t builtin_prims[] = { 0, 0, hcl_pf_semaphore_new, 7, { 's','e','m','-','n','e','w'} }, { 1, 1, hcl_pf_semaphore_wait, 8, { 's','e','m','-','w','a','i','t'} }, { 1, 3, hcl_pf_semaphore_signal, 10, { 's','e','m','-','s','i','g','n','a','l'} }, + { 2, 2, hcl_pf_semaphore_signal_on_input, 19, { 's','e','m','-','s','i','g','n','a','l','-','o','n','-','i','n','p','u','t'} }, + { 2, 2, hcl_pf_semaphore_signal_on_output, 20, { 's','e','m','-','s','i','g','n','a','l','-','o','n','-','o','u','t','p','u','t'} }, { 1, 1, hcl_pf_semaphore_unsignal, 12, { 's','e','m','-','u','n','s','i','g','n','a','l'} }, { 0, 0, hcl_pf_semaphore_group_new, 9, { 's','e','m','g','r','-','n','e','w'} },