Compare commits
2
Commits
04e826a6db
...
95246943e6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95246943e6 | ||
|
|
d5b4a1290f |
+2
-1
@@ -75,7 +75,8 @@ hak_DEPENDENCIES = ../lib/libhak.la
|
|||||||
if ENABLE_ISOCLINE
|
if ENABLE_ISOCLINE
|
||||||
hak_CPPFLAGS += -I$(srcdir)/isocline/include -DHAVE_ISOCLINE_H -DHAVE_ISOCLINE_LIB
|
hak_CPPFLAGS += -I$(srcdir)/isocline/include -DHAVE_ISOCLINE_H -DHAVE_ISOCLINE_LIB
|
||||||
hak_LDADD += ./libisocline.a
|
hak_LDADD += ./libisocline.a
|
||||||
hak_DEPENDENCIES += ./libisocline.a
|
##hak_DEPENDENCIES += ./libisocline.a
|
||||||
|
hak_DEPENDENCIES += libisocline.a
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ENABLE_HAKX
|
if ENABLE_HAKX
|
||||||
|
|||||||
+1
-1
@@ -101,7 +101,7 @@ host_triplet = @host@
|
|||||||
bin_PROGRAMS = hak$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2)
|
bin_PROGRAMS = hak$(EXEEXT) $(am__EXEEXT_1) $(am__EXEEXT_2)
|
||||||
@ENABLE_ISOCLINE_TRUE@am__append_3 = -I$(srcdir)/isocline/include -DHAVE_ISOCLINE_H -DHAVE_ISOCLINE_LIB
|
@ENABLE_ISOCLINE_TRUE@am__append_3 = -I$(srcdir)/isocline/include -DHAVE_ISOCLINE_H -DHAVE_ISOCLINE_LIB
|
||||||
@ENABLE_ISOCLINE_TRUE@am__append_4 = ./libisocline.a
|
@ENABLE_ISOCLINE_TRUE@am__append_4 = ./libisocline.a
|
||||||
@ENABLE_ISOCLINE_TRUE@am__append_5 = ./libisocline.a
|
@ENABLE_ISOCLINE_TRUE@am__append_5 = libisocline.a
|
||||||
@ENABLE_HAKX_TRUE@am__append_6 = hakx
|
@ENABLE_HAKX_TRUE@am__append_6 = hakx
|
||||||
@ENABLE_HAKGO_TRUE@am__append_7 = hakgo
|
@ENABLE_HAKGO_TRUE@am__append_7 = hakgo
|
||||||
subdir = bin
|
subdir = bin
|
||||||
|
|||||||
@@ -16895,6 +16895,12 @@ if test "x$ac_cv_header_sys_devpoll_h" = xyes
|
|||||||
then :
|
then :
|
||||||
printf "%s\n" "#define HAVE_SYS_DEVPOLL_H 1" >>confdefs.h
|
printf "%s\n" "#define HAVE_SYS_DEVPOLL_H 1" >>confdefs.h
|
||||||
|
|
||||||
|
fi
|
||||||
|
ac_fn_c_check_header_compile "$LINENO" "sys/event.h" "ac_cv_header_sys_event_h" "$ac_includes_default"
|
||||||
|
if test "x$ac_cv_header_sys_event_h" = xyes
|
||||||
|
then :
|
||||||
|
printf "%s\n" "#define HAVE_SYS_EVENT_H 1" >>confdefs.h
|
||||||
|
|
||||||
fi
|
fi
|
||||||
ac_fn_c_check_header_compile "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default"
|
ac_fn_c_check_header_compile "$LINENO" "sys/epoll.h" "ac_cv_header_sys_epoll_h" "$ac_includes_default"
|
||||||
if test "x$ac_cv_header_sys_epoll_h" = xyes
|
if test "x$ac_cv_header_sys_epoll_h" = xyes
|
||||||
|
|||||||
+1
-1
@@ -110,7 +110,7 @@ AC_PROG_EGREP
|
|||||||
AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h])
|
AC_CHECK_HEADERS([stddef.h wchar.h wctype.h errno.h signal.h fcntl.h dirent.h])
|
||||||
AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h])
|
AC_CHECK_HEADERS([time.h sys/time.h utime.h spawn.h execinfo.h ucontext.h])
|
||||||
AC_CHECK_HEADERS([dlfcn.h ltdl.h sys/mman.h sys/uio.h])
|
AC_CHECK_HEADERS([dlfcn.h ltdl.h sys/mman.h sys/uio.h])
|
||||||
AC_CHECK_HEADERS([sys/devpoll.h sys/epoll.h poll.h])
|
AC_CHECK_HEADERS([sys/devpoll.h sys/event.h sys/epoll.h poll.h])
|
||||||
AC_CHECK_HEADERS([libunwind.h quadmath.h])
|
AC_CHECK_HEADERS([libunwind.h quadmath.h])
|
||||||
AC_CHECK_HEADERS([sys/ioctl.h net/if.h])
|
AC_CHECK_HEADERS([sys/ioctl.h net/if.h])
|
||||||
AC_CHECK_HEADERS([sys/wait.h sys/resource.h])
|
AC_CHECK_HEADERS([sys/wait.h sys/resource.h])
|
||||||
|
|||||||
+7
-2
@@ -5450,12 +5450,17 @@ static HAK_INLINE int compile_dsymbol (hak_t* hak, hak_cnode_t* obj)
|
|||||||
val = hak->_nil;
|
val = hak->_nil;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HAK_PFBASE_CONST:
|
case HAK_PFBASE_CONST_SMOOI:
|
||||||
|
{
|
||||||
/* TODO: create a value from the pfbase information. it needs to get extended first
|
/* TODO: create a value from the pfbase information. it needs to get extended first
|
||||||
* can i make use of pfbase->handler type-cast to a differnt type? */
|
* can i make use of pfbase->handler type-cast to a differnt type? */
|
||||||
|
/* maxarg -> actual value cast to (hak_oow_t)(hak_ooi_t) */
|
||||||
|
hak_ooi_t v = (hak_ooi_t)pfbase->maxargs;
|
||||||
|
HAK_ASSERT(hak, HAK_IN_SMOOI_RANGE(v));
|
||||||
kernel_bits = 2;
|
kernel_bits = 2;
|
||||||
val = hak->_nil;
|
val = HAK_SMOOI_TO_OOP(v);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
hak_popvolat(hak);
|
hak_popvolat(hak);
|
||||||
|
|||||||
+75
-5
@@ -1470,6 +1470,29 @@ static HAK_INLINE int can_await_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
|||||||
return (hak_oop_t)sem->group == hak->_nil;
|
return (hak_oop_t)sem->group == hak->_nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HAK_INLINE void drop_unawaited_io_signal_count_in_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
||||||
|
{
|
||||||
|
hak_ooi_t index;
|
||||||
|
hak_ooi_t io_type;
|
||||||
|
|
||||||
|
if (sem->subtype != HAK_SMOOI_TO_OOP(HAK_SEMAPHORE_SUBTYPE_IO)) return;
|
||||||
|
|
||||||
|
/* io.index must be nil or smooi */
|
||||||
|
/*if ((hak_oop_t)sem->u.io.index == hak->_nil) return;*/
|
||||||
|
if (!HAK_OOP_IS_SMOOI(sem->u.io.index)) return;
|
||||||
|
|
||||||
|
/* u.io.index is nil once the semaphore has been unbound, so a stale IO
|
||||||
|
* subtype cannot lead us into the tuple array with a dead index. */
|
||||||
|
index = HAK_OOP_TO_SMOOI(sem->u.io.index);
|
||||||
|
io_type = HAK_OOP_TO_SMOOI(sem->u.io.type);
|
||||||
|
|
||||||
|
HAK_ASSERT(hak, index >= 0 && index < (hak_ooi_t)hak->sem_io_tuple_count);
|
||||||
|
HAK_ASSERT(hak, io_type == HAK_SEMAPHORE_IO_TYPE_INPUT || io_type == HAK_SEMAPHORE_IO_TYPE_OUTPUT);
|
||||||
|
|
||||||
|
if (hak->sem_io_tuple[index].unawaited[io_type] > 0)
|
||||||
|
hak->sem_io_tuple[index].unawaited[io_type]--;
|
||||||
|
}
|
||||||
|
|
||||||
static HAK_INLINE void await_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
static HAK_INLINE void await_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
||||||
{
|
{
|
||||||
hak_oop_process_t proc;
|
hak_oop_process_t proc;
|
||||||
@@ -1487,10 +1510,10 @@ static HAK_INLINE void await_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
|||||||
/* it's already signaled */
|
/* it's already signaled */
|
||||||
count--;
|
count--;
|
||||||
sem->count = HAK_SMOOI_TO_OOP(count);
|
sem->count = HAK_SMOOI_TO_OOP(count);
|
||||||
|
drop_unawaited_io_signal_count_in_semaphore(hak, sem);
|
||||||
|
|
||||||
if ((hak_oop_t)semgrp != hak->_nil && count == 0)
|
if ((hak_oop_t)semgrp != hak->_nil && count == 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
int sems_idx;
|
int sems_idx;
|
||||||
/* TODO: if i disallow individual wait on a semaphore in a group,
|
/* TODO: if i disallow individual wait on a semaphore in a group,
|
||||||
* this membership manipulation is redundant */
|
* this membership manipulation is redundant */
|
||||||
@@ -1552,6 +1575,7 @@ static HAK_INLINE hak_oop_t await_semaphore_group (hak_t* hak, hak_oop_semaphore
|
|||||||
HAK_ASSERT(hak, count > 0);
|
HAK_ASSERT(hak, count > 0);
|
||||||
count--;
|
count--;
|
||||||
sem->count = HAK_SMOOI_TO_OOP(count);
|
sem->count = HAK_SMOOI_TO_OOP(count);
|
||||||
|
drop_unawaited_io_signal_count_in_semaphore(hak, sem);
|
||||||
|
|
||||||
HAK_DELETE_FROM_OOP_LIST(hak, &semgrp->sems[HAK_SEMAPHORE_GROUP_SEMS_SIG], sem, grm);
|
HAK_DELETE_FROM_OOP_LIST(hak, &semgrp->sems[HAK_SEMAPHORE_GROUP_SEMS_SIG], sem, grm);
|
||||||
sems_idx = count > 0? HAK_SEMAPHORE_GROUP_SEMS_SIG: HAK_SEMAPHORE_GROUP_SEMS_UNSIG;
|
sems_idx = count > 0? HAK_SEMAPHORE_GROUP_SEMS_SIG: HAK_SEMAPHORE_GROUP_SEMS_UNSIG;
|
||||||
@@ -1778,6 +1802,7 @@ int hak_add_sem_to_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, hak_ooi_t
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* initialize it to -1 to indicate no binding yet */
|
||||||
for (i = hak->sem_io_map_capa; i < new_capa; i++) tmp[i] = -1;
|
for (i = hak->sem_io_map_capa; i < new_capa; i++) tmp[i] = -1;
|
||||||
|
|
||||||
hak->sem_io_map = tmp;
|
hak->sem_io_map = tmp;
|
||||||
@@ -1805,6 +1830,9 @@ int hak_add_sem_to_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, hak_ooi_t
|
|||||||
tmp = (hak_sem_tuple_t*)hak_reallocmem(hak, hak->sem_io_tuple, HAK_SIZEOF(hak_sem_tuple_t) * new_capa);
|
tmp = (hak_sem_tuple_t*)hak_reallocmem(hak, hak->sem_io_tuple, HAK_SIZEOF(hak_sem_tuple_t) * new_capa);
|
||||||
if (HAK_UNLIKELY(!tmp)) return -1;
|
if (HAK_UNLIKELY(!tmp)) return -1;
|
||||||
|
|
||||||
|
/* initialize the newly added tuples with zeros */
|
||||||
|
HAK_MEMSET(&tmp[hak->sem_io_tuple_capa], 0, HAK_SIZEOF(hak_sem_tuple_t) * SEM_IO_TUPLE_INC);
|
||||||
|
|
||||||
hak->sem_io_tuple = tmp;
|
hak->sem_io_tuple = tmp;
|
||||||
hak->sem_io_tuple_capa = new_capa;
|
hak->sem_io_tuple_capa = new_capa;
|
||||||
}
|
}
|
||||||
@@ -1822,6 +1850,8 @@ int hak_add_sem_to_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, hak_ooi_t
|
|||||||
hak->sem_io_tuple[index].sem[HAK_SEMAPHORE_IO_TYPE_OUTPUT] = HAK_NULL;
|
hak->sem_io_tuple[index].sem[HAK_SEMAPHORE_IO_TYPE_OUTPUT] = HAK_NULL;
|
||||||
hak->sem_io_tuple[index].handle = io_handle;
|
hak->sem_io_tuple[index].handle = io_handle;
|
||||||
hak->sem_io_tuple[index].mask = 0;
|
hak->sem_io_tuple[index].mask = 0;
|
||||||
|
hak->sem_io_tuple[index].unawaited[HAK_SEMAPHORE_IO_TYPE_INPUT] = 0;
|
||||||
|
hak->sem_io_tuple[index].unawaited[HAK_SEMAPHORE_IO_TYPE_OUTPUT] = 0;
|
||||||
|
|
||||||
new_mask = ((hak_ooi_t)1 << io_type);
|
new_mask = ((hak_ooi_t)1 << io_type);
|
||||||
|
|
||||||
@@ -1861,6 +1891,7 @@ int hak_add_sem_to_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, hak_ooi_t
|
|||||||
hak->sem_io_tuple[index].handle = io_handle;
|
hak->sem_io_tuple[index].handle = io_handle;
|
||||||
hak->sem_io_tuple[index].mask = new_mask;
|
hak->sem_io_tuple[index].mask = new_mask;
|
||||||
hak->sem_io_tuple[index].sem[io_type] = sem;
|
hak->sem_io_tuple[index].sem[io_type] = sem;
|
||||||
|
hak->sem_io_tuple[index].unawaited[io_type] = 0; /* init for a new binding into the existing slot */
|
||||||
|
|
||||||
hak->sem_io_count++;
|
hak->sem_io_count++;
|
||||||
if (tuple_added)
|
if (tuple_added)
|
||||||
@@ -1883,7 +1914,7 @@ int hak_add_sem_to_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, hak_ooi_t
|
|||||||
|
|
||||||
static int delete_sem_from_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, int force)
|
static int delete_sem_from_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, int force)
|
||||||
{
|
{
|
||||||
hak_ooi_t index;
|
hak_ooi_t index, unawaited;
|
||||||
hak_ooi_t new_mask, io_handle, io_type;
|
hak_ooi_t new_mask, io_handle, io_type;
|
||||||
int x;
|
int x;
|
||||||
|
|
||||||
@@ -1945,6 +1976,33 @@ static int delete_sem_from_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, in
|
|||||||
sem->group->sem_io_count = HAK_SMOOI_TO_OOP(count);
|
sem->group->sem_io_count = HAK_SMOOI_TO_OOP(count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
* [OPTIMIZATION] it would work without this part and unawaited handling.
|
||||||
|
* ----------------------------------------------------------------------
|
||||||
|
* retract only what the multiplexer signaled. Those counts stand for an
|
||||||
|
* unconsumed edge on THIS descriptor; with the binding gone they refer to
|
||||||
|
* nothing, and a rebind re-arms the multiplexer anyway. Counts from a
|
||||||
|
* manual sem-signal are left alone: hak_pf_semaphore_signal() accepts an
|
||||||
|
* IO semaphore, so both sources share sem->count.
|
||||||
|
* ---------------------------------------------------------------------- */
|
||||||
|
unawaited = hak->sem_io_tuple[index].unawaited[io_type];
|
||||||
|
hak->sem_io_tuple[index].unawaited[io_type] = 0;
|
||||||
|
if (unawaited > 0)
|
||||||
|
{
|
||||||
|
hak_ooi_t count = HAK_OOP_TO_SMOOI(sem->count);
|
||||||
|
HAK_ASSERT(hak, unawaited <= count);
|
||||||
|
count -= unawaited;
|
||||||
|
sem->count = HAK_SMOOI_TO_OOP(count);
|
||||||
|
|
||||||
|
if (count == 0 && (hak_oop_t)sem->group != hak->_nil)
|
||||||
|
{
|
||||||
|
HAK_DELETE_FROM_OOP_LIST(hak, &sem->group->sems[HAK_SEMAPHORE_GROUP_SEMS_SIG], sem, grm);
|
||||||
|
HAK_APPEND_TO_OOP_LIST(hak, &sem->group->sems[HAK_SEMAPHORE_GROUP_SEMS_UNSIG], hak_oop_semaphore_t, sem, grm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* ---------------------------------------------------------------------- */
|
||||||
|
|
||||||
if (new_mask)
|
if (new_mask)
|
||||||
{
|
{
|
||||||
hak->sem_io_tuple[index].mask = new_mask;
|
hak->sem_io_tuple[index].mask = new_mask;
|
||||||
@@ -1975,7 +2033,7 @@ static int delete_sem_from_sem_io_tuple (hak_t* hak, hak_oop_semaphore_t sem, in
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _signal_io_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
static hak_oop_process_t _signal_io_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
||||||
{
|
{
|
||||||
hak_oop_process_t proc;
|
hak_oop_process_t proc;
|
||||||
|
|
||||||
@@ -1998,6 +2056,8 @@ static void _signal_io_semaphore (hak_t* hak, hak_oop_semaphore_t sem)
|
|||||||
switch_to_process_from_nil(hak, proc);
|
switch_to_process_from_nil(hak, proc);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return proc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_io_semaphore (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask)
|
static void signal_io_semaphore (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask)
|
||||||
@@ -2016,7 +2076,12 @@ static void signal_io_semaphore (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask
|
|||||||
if ((mask & (HAK_SEMAPHORE_IO_MASK_OUTPUT | HAK_SEMAPHORE_IO_MASK_ERROR)) ||
|
if ((mask & (HAK_SEMAPHORE_IO_MASK_OUTPUT | HAK_SEMAPHORE_IO_MASK_ERROR)) ||
|
||||||
(!insem && (mask & HAK_SEMAPHORE_IO_MASK_HANGUP)))
|
(!insem && (mask & HAK_SEMAPHORE_IO_MASK_HANGUP)))
|
||||||
{
|
{
|
||||||
_signal_io_semaphore(hak, outsem);
|
if ((hak_oop_t)_signal_io_semaphore(hak, outsem) == hak->_nil)
|
||||||
|
{
|
||||||
|
/* no process was waiting so the signal is pending and not consumed.
|
||||||
|
* raise the io signal count unawaited */
|
||||||
|
hak->sem_io_tuple[sem_io_index].unawaited[HAK_SEMAPHORE_IO_TYPE_OUTPUT]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2024,7 +2089,12 @@ static void signal_io_semaphore (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask
|
|||||||
{
|
{
|
||||||
if (mask & (HAK_SEMAPHORE_IO_MASK_INPUT | HAK_SEMAPHORE_IO_MASK_HANGUP | HAK_SEMAPHORE_IO_MASK_ERROR))
|
if (mask & (HAK_SEMAPHORE_IO_MASK_INPUT | HAK_SEMAPHORE_IO_MASK_HANGUP | HAK_SEMAPHORE_IO_MASK_ERROR))
|
||||||
{
|
{
|
||||||
_signal_io_semaphore(hak, insem);
|
if ((hak_oop_t)_signal_io_semaphore(hak, insem) == hak->_nil)
|
||||||
|
{
|
||||||
|
/* no process was waiting so the signal is pending and not consumed.
|
||||||
|
* raise the io signal count unawaited */
|
||||||
|
hak->sem_io_tuple[sem_io_index].unawaited[HAK_SEMAPHORE_IO_TYPE_INPUT]++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,6 +403,9 @@
|
|||||||
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
/* Define to 1 if you have the <sys/epoll.h> header file. */
|
||||||
#undef HAVE_SYS_EPOLL_H
|
#undef HAVE_SYS_EPOLL_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <sys/event.h> header file. */
|
||||||
|
#undef HAVE_SYS_EVENT_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
/* Define to 1 if you have the <sys/ioctl.h> header file. */
|
||||||
#undef HAVE_SYS_IOCTL_H
|
#undef HAVE_SYS_IOCTL_H
|
||||||
|
|
||||||
|
|||||||
@@ -237,14 +237,18 @@ void hak_fini (hak_t* hak)
|
|||||||
hak_cb_t* cb;
|
hak_cb_t* cb;
|
||||||
hak_oow_t i;
|
hak_oow_t i;
|
||||||
|
|
||||||
|
/* BEFORE the modules are unloaded. a handle's destructor is a function in
|
||||||
|
* the module that created it - mod/sys.c's proc_dtor(), say - so unloading
|
||||||
|
* first leaves hnd->dtor pointing into an unmapped object, and calling it
|
||||||
|
* jumps into nowhere. glibc often keeps a dlclose()d object mapped, which
|
||||||
|
* hides this; FreeBSD unmaps it and the process dies with a wild PC.
|
||||||
|
* we must finalize the handle table before unloading modules. */
|
||||||
|
hak_finihndtab(hak);
|
||||||
|
|
||||||
hak_rbt_walk(&hak->modtab, unload_module, hak);
|
hak_rbt_walk(&hak->modtab, unload_module, hak);
|
||||||
hak_rbt_fini(&hak->modtab);
|
hak_rbt_fini(&hak->modtab);
|
||||||
hak_htb_fini(&hak->static_mods);
|
hak_htb_fini(&hak->static_mods);
|
||||||
|
|
||||||
/* after the modules, so that a module's unload can close its own handles
|
|
||||||
* first; whatever hak code leaked is closed here. */
|
|
||||||
hak_finihndtab(hak);
|
|
||||||
|
|
||||||
if (hak->log.len > 0)
|
if (hak->log.len > 0)
|
||||||
{
|
{
|
||||||
/* flush pending log messages just in case. */
|
/* flush pending log messages just in case. */
|
||||||
|
|||||||
@@ -857,6 +857,9 @@ struct hak_semaphore_t
|
|||||||
} waiting; /* list of processes waiting on this semaphore */
|
} waiting; /* list of processes waiting on this semaphore */
|
||||||
/* [END IMPORTANT] */
|
/* [END IMPORTANT] */
|
||||||
|
|
||||||
|
/* number of signals not consumed on ths semaphore.
|
||||||
|
* it's incremented when the semaphore is signaled.
|
||||||
|
* it's decremented when it's signaled at least once and awaited */
|
||||||
hak_oop_t count; /* SmallInteger */
|
hak_oop_t count; /* SmallInteger */
|
||||||
|
|
||||||
/* nil for normal. SmallInteger if associated with
|
/* nil for normal. SmallInteger if associated with
|
||||||
@@ -1572,7 +1575,7 @@ enum hak_pfbase_type_t
|
|||||||
{
|
{
|
||||||
HAK_PFBASE_FUNC = 0,
|
HAK_PFBASE_FUNC = 0,
|
||||||
HAK_PFBASE_VAR = 1,
|
HAK_PFBASE_VAR = 1,
|
||||||
HAK_PFBASE_CONST = 2
|
HAK_PFBASE_CONST_SMOOI = 2
|
||||||
};
|
};
|
||||||
typedef enum hak_pfbase_type_t hak_pfbase_type_t;
|
typedef enum hak_pfbase_type_t hak_pfbase_type_t;
|
||||||
|
|
||||||
@@ -1640,11 +1643,14 @@ struct hak_mod_data_t
|
|||||||
typedef struct hak_mod_data_t hak_mod_data_t;
|
typedef struct hak_mod_data_t hak_mod_data_t;
|
||||||
|
|
||||||
|
|
||||||
|
/* The hak_sem_tuple_t type holds extra information on IO driven semaphore state.
|
||||||
|
* It doesn't belong to the object memory and is not visible outside the VM instance */
|
||||||
struct hak_sem_tuple_t
|
struct hak_sem_tuple_t
|
||||||
{
|
{
|
||||||
hak_oop_semaphore_t sem[2]; /* [0] input, [1] output */
|
hak_oop_semaphore_t sem[2]; /* [0] input, [1] output */
|
||||||
hak_ooi_t handle; /* io handle */
|
hak_ooi_t handle; /* io handle */
|
||||||
hak_ooi_t mask;
|
hak_ooi_t mask;
|
||||||
|
hak_ooi_t unawaited[2]; /* the number of IO-raised signal counts unawaited yet and not consumed */
|
||||||
};
|
};
|
||||||
typedef struct hak_sem_tuple_t hak_sem_tuple_t;
|
typedef struct hak_sem_tuple_t hak_sem_tuple_t;
|
||||||
|
|
||||||
|
|||||||
@@ -221,7 +221,7 @@
|
|||||||
# define XPOLLERR POLLERR
|
# define XPOLLERR POLLERR
|
||||||
# define XPOLLHUP POLLHUP
|
# define XPOLLHUP POLLHUP
|
||||||
# elif defined(HAVE_SYS_EVENT_H) && defined(HAVE_KQUEUE)
|
# elif defined(HAVE_SYS_EVENT_H) && defined(HAVE_KQUEUE)
|
||||||
/* netbsd, openbsd, etc */
|
/* netbsd, openbsd, freebsd, etc */
|
||||||
# include <sys/event.h>
|
# include <sys/event.h>
|
||||||
# define USE_KQUEUE
|
# define USE_KQUEUE
|
||||||
/* fake XPOLLXXX values */
|
/* fake XPOLLXXX values */
|
||||||
@@ -1557,7 +1557,7 @@ static int _add_poll_fd (hak_t* hak, int fd, int event_mask)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
HAK_MEMSET(&tmp[xtn->ev.reg.capa], 0, newcapa - xtn->ev.reg.capa);
|
HAK_MEMSET(&tmp[xtn->ev.reg.capa], 0, (newcapa - xtn->ev.reg.capa) * HAK_SIZEOF(*tmp));
|
||||||
xtn->ev.reg.ptr = tmp;
|
xtn->ev.reg.ptr = tmp;
|
||||||
xtn->ev.reg.capa = newcapa;
|
xtn->ev.reg.capa = newcapa;
|
||||||
}
|
}
|
||||||
@@ -1699,7 +1699,6 @@ static int _add_poll_fd (hak_t* hak, int fd, int event_mask)
|
|||||||
|
|
||||||
static int _del_poll_fd (hak_t* hak, int fd)
|
static int _del_poll_fd (hak_t* hak, int fd)
|
||||||
{
|
{
|
||||||
|
|
||||||
#if defined(USE_DEVPOLL)
|
#if defined(USE_DEVPOLL)
|
||||||
xtn_t* xtn = GET_XTN(hak);
|
xtn_t* xtn = GET_XTN(hak);
|
||||||
struct pollfd ev;
|
struct pollfd ev;
|
||||||
@@ -1792,7 +1791,6 @@ static int _del_poll_fd (hak_t* hak, int fd)
|
|||||||
}
|
}
|
||||||
MUTEX_UNLOCK(&xtn->ev.reg.pmtx);
|
MUTEX_UNLOCK(&xtn->ev.reg.pmtx);
|
||||||
|
|
||||||
|
|
||||||
HAK_DEBUG1(hak, "Cannot remove file descriptor %d from poll - not found\n", fd);
|
HAK_DEBUG1(hak, "Cannot remove file descriptor %d from poll - not found\n", fd);
|
||||||
hak_seterrnum(hak, HAK_ENOENT);
|
hak_seterrnum(hak, HAK_ENOENT);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1818,7 +1816,6 @@ static int _del_poll_fd (hak_t* hak, int fd)
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
HAK_DEBUG1(hak, "Cannot remove file descriptor %d from poll - not implemented\n", fd);
|
HAK_DEBUG1(hak, "Cannot remove file descriptor %d from poll - not implemented\n", fd);
|
||||||
hak_seterrnum(hak, HAK_ENOIMPL);
|
hak_seterrnum(hak, HAK_ENOIMPL);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -1994,8 +1991,8 @@ kqueue_syserr:
|
|||||||
FD_SET(fd, &xtn->ev.reg.wfds);
|
FD_SET(fd, &xtn->ev.reg.wfds);
|
||||||
else
|
else
|
||||||
FD_CLR(fd, &xtn->ev.reg.wfds);
|
FD_CLR(fd, &xtn->ev.reg.wfds);
|
||||||
MUTEX_UNLOCK(&xtn->ev.reg.smtx);
|
|
||||||
|
|
||||||
|
MUTEX_UNLOCK(&xtn->ev.reg.smtx);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@@ -2005,6 +2002,52 @@ kqueue_syserr:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(USE_THREAD)
|
||||||
|
/* Drop multiplexer events already sitting in the buffer for this descriptor.
|
||||||
|
*
|
||||||
|
* iothr_main() reads events straight into xtn->ev.buf and publishes ev.len;
|
||||||
|
* the VM consumes them later. Removing a descriptor from the underlying
|
||||||
|
* multiplexer therefore does not reach events that have already been handed
|
||||||
|
* back. If the descriptor is then closed and its number reused before the VM
|
||||||
|
* drains the buffer - which sys.popen/sys.pclose does on every call - the
|
||||||
|
* stale event is dispatched against whatever now owns that number: a semaphore
|
||||||
|
* is signalled for a descriptor that was never ready, and the read that
|
||||||
|
* follows answers nothing. See t/mux-01.hak.
|
||||||
|
*
|
||||||
|
* Must not be called from inside the dispatch loop in vm_muxwait(). That loop
|
||||||
|
* caches ev.len and would walk entries this function compacts away. Nothing
|
||||||
|
* does today - signalling a semaphore only makes a process runnable, it does
|
||||||
|
* not run hak code - but the loop has no defence if that ever changes. */
|
||||||
|
static void purge_muxevts (hak_t* hak, int fd)
|
||||||
|
{
|
||||||
|
xtn_t* xtn = GET_XTN(hak);
|
||||||
|
hak_oow_t i, j;
|
||||||
|
|
||||||
|
MUTEX_LOCK(&xtn->ev.mtx);
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < xtn->ev.len; i++)
|
||||||
|
{
|
||||||
|
#if defined(USE_DEVPOLL) || defined(USE_POLL) || defined(USE_SELECT)
|
||||||
|
if (xtn->ev.buf[i].fd == fd) continue;
|
||||||
|
#elif defined(USE_KQUEUE)
|
||||||
|
if ((int)xtn->ev.buf[i].ident == fd) continue;
|
||||||
|
#elif defined(USE_EPOLL)
|
||||||
|
if (xtn->ev.buf[i].data.fd == fd) continue;
|
||||||
|
#endif
|
||||||
|
if (j != i) xtn->ev.buf[j] = xtn->ev.buf[i];
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j != xtn->ev.len)
|
||||||
|
{
|
||||||
|
xtn->ev.len = j;
|
||||||
|
if (j <= 0) pthread_cond_signal(&xtn->ev.cnd); // TODO: use a generic wrapper??
|
||||||
|
}
|
||||||
|
MUTEX_UNLOCK(&xtn->ev.mtx);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int vm_muxadd (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask)
|
static int vm_muxadd (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask)
|
||||||
{
|
{
|
||||||
int event_mask;
|
int event_mask;
|
||||||
@@ -2039,11 +2082,32 @@ static int vm_muxmod (hak_t* hak, hak_ooi_t io_handle, hak_ooi_t mask)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return _mod_poll_fd(hak, io_handle, event_mask);
|
return _mod_poll_fd(hak, io_handle, event_mask);
|
||||||
|
|
||||||
|
/* [NOTE]
|
||||||
|
* this may need the same mux event purge as vm_muxdel() for accuracy.
|
||||||
|
* if a file descriptor is removed for one direction while another direction
|
||||||
|
* is still watched, this function is invoked. in that case, xtn->evt.buf
|
||||||
|
* may have some stale events and they can raise spurious signals.
|
||||||
|
*
|
||||||
|
* TODO: per-direction event purge
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vm_muxdel (hak_t* hak, hak_ooi_t io_handle)
|
static int vm_muxdel (hak_t* hak, hak_ooi_t io_handle)
|
||||||
{
|
{
|
||||||
return _del_poll_fd(hak, io_handle);
|
int n;
|
||||||
|
|
||||||
|
n = _del_poll_fd(hak, io_handle);
|
||||||
|
|
||||||
|
#if defined(USE_THREAD)
|
||||||
|
/* purge after the descriptor is out of the multiplexer, so nothing new can
|
||||||
|
* be queued for it behind us - and unconditionally, because a failed
|
||||||
|
* delete does not make a buffered event any less stale.
|
||||||
|
* delete_sem_from_sem_io_tuple() carries on regardless when force is set.
|
||||||
|
*/
|
||||||
|
purge_muxevts(hak, (int)io_handle);
|
||||||
|
#endif
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_THREAD)
|
#if defined(USE_THREAD)
|
||||||
@@ -2138,7 +2202,7 @@ static void* iothr_main (void* arg)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
pthread_mutex_lock (&xtn->ev.mtx);
|
MUTEX_LOCK(&xtn->ev.mtx);
|
||||||
if (n <= -1)
|
if (n <= -1)
|
||||||
{
|
{
|
||||||
/* TODO: don't use HAK_DEBUG2. it's not thread safe... */
|
/* TODO: don't use HAK_DEBUG2. it's not thread safe... */
|
||||||
@@ -2150,18 +2214,18 @@ static void* iothr_main (void* arg)
|
|||||||
xtn->ev.len = n;
|
xtn->ev.len = n;
|
||||||
}
|
}
|
||||||
pthread_cond_signal(&xtn->ev.cnd2);
|
pthread_cond_signal(&xtn->ev.cnd2);
|
||||||
pthread_mutex_unlock (&xtn->ev.mtx);
|
MUTEX_UNLOCK(&xtn->ev.mtx);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* the event buffer has not been emptied yet */
|
/* the event buffer has not been emptied yet */
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
pthread_mutex_lock (&xtn->ev.mtx);
|
MUTEX_LOCK(&xtn->ev.mtx);
|
||||||
if (xtn->ev.len <= 0)
|
if (xtn->ev.len <= 0)
|
||||||
{
|
{
|
||||||
/* it got emptied between the if check and pthread_mutex_lock() above */
|
/* it got emptied between the if check and pthread_mutex_lock() above */
|
||||||
pthread_mutex_unlock (&xtn->ev.mtx);
|
MUTEX_UNLOCK(&xtn->ev.mtx);
|
||||||
goto poll_for_event;
|
goto poll_for_event;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2177,7 +2241,7 @@ static void* iothr_main (void* arg)
|
|||||||
#endif
|
#endif
|
||||||
ts.tv_sec += 10;
|
ts.tv_sec += 10;
|
||||||
pthread_cond_timedwait(&xtn->ev.cnd, &xtn->ev.mtx, &ts);
|
pthread_cond_timedwait(&xtn->ev.cnd, &xtn->ev.mtx, &ts);
|
||||||
pthread_mutex_unlock (&xtn->ev.mtx);
|
MUTEX_UNLOCK(&xtn->ev.mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*sched_yield ();*/
|
/*sched_yield ();*/
|
||||||
@@ -2231,13 +2295,13 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
|
|||||||
ts.tv_sec = ns.sec;
|
ts.tv_sec = ns.sec;
|
||||||
ts.tv_nsec = ns.nsec;
|
ts.tv_nsec = ns.nsec;
|
||||||
|
|
||||||
pthread_mutex_lock (&xtn->ev.mtx);
|
MUTEX_LOCK(&xtn->ev.mtx);
|
||||||
if (xtn->ev.len <= 0)
|
if (xtn->ev.len <= 0)
|
||||||
{
|
{
|
||||||
/* the event buffer is still empty */
|
/* the event buffer is still empty */
|
||||||
pthread_cond_timedwait(&xtn->ev.cnd2, &xtn->ev.mtx, &ts);
|
pthread_cond_timedwait(&xtn->ev.cnd2, &xtn->ev.mtx, &ts);
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock (&xtn->ev.mtx);
|
MUTEX_UNLOCK(&xtn->ev.mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
n = xtn->ev.len;
|
n = xtn->ev.len;
|
||||||
@@ -2278,10 +2342,11 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
|
|||||||
#if defined(USE_DEVPOLL)
|
#if defined(USE_DEVPOLL)
|
||||||
revents = xtn->ev.buf[n].revents;
|
revents = xtn->ev.buf[n].revents;
|
||||||
#elif defined(USE_KQUEUE)
|
#elif defined(USE_KQUEUE)
|
||||||
if (xtn->ev.buf[n].filter == EVFILT_READ) mask = HAK_SEMAPHORE_IO_MASK_INPUT;
|
revents = 0;
|
||||||
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) mask = HAK_SEMAPHORE_IO_MASK_OUTPUT;
|
if (xtn->ev.buf[n].filter == EVFILT_READ) revents |= XPOLLIN;
|
||||||
else mask = 0;
|
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) revents |= XPOLLOUT;
|
||||||
goto call_muxwcb_kqueue;
|
if (xtn->ev.buf[n].flags & EV_EOF) revents |= XPOLLHUP;
|
||||||
|
if (xtn->ev.buf[n].flags & EV_ERROR) revents |= XPOLLERR;
|
||||||
#elif defined(USE_EPOLL)
|
#elif defined(USE_EPOLL)
|
||||||
revents = xtn->ev.buf[n].events;
|
revents = xtn->ev.buf[n].events;
|
||||||
#elif defined(USE_POLL)
|
#elif defined(USE_POLL)
|
||||||
@@ -2299,7 +2364,6 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
|
|||||||
#if defined(USE_DEVPOLL)
|
#if defined(USE_DEVPOLL)
|
||||||
muxwcb(hak, xtn->ev.buf[n].fd, mask);
|
muxwcb(hak, xtn->ev.buf[n].fd, mask);
|
||||||
#elif defined(USE_KQUEUE)
|
#elif defined(USE_KQUEUE)
|
||||||
call_muxwcb_kqueue:
|
|
||||||
muxwcb(hak, xtn->ev.buf[n].ident, mask);
|
muxwcb(hak, xtn->ev.buf[n].ident, mask);
|
||||||
#elif defined(USE_EPOLL)
|
#elif defined(USE_EPOLL)
|
||||||
muxwcb(hak, xtn->ev.buf[n].data.fd, mask);
|
muxwcb(hak, xtn->ev.buf[n].data.fd, mask);
|
||||||
@@ -2314,10 +2378,10 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
|
|||||||
}
|
}
|
||||||
while (n > 0);
|
while (n > 0);
|
||||||
|
|
||||||
pthread_mutex_lock (&xtn->ev.mtx);
|
MUTEX_LOCK(&xtn->ev.mtx);
|
||||||
xtn->ev.len = 0;
|
xtn->ev.len = 0;
|
||||||
pthread_cond_signal(&xtn->ev.cnd);
|
pthread_cond_signal(&xtn->ev.cnd);
|
||||||
pthread_mutex_unlock (&xtn->ev.mtx);
|
MUTEX_UNLOCK(&xtn->ev.mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* USE_THREAD */
|
#else /* USE_THREAD */
|
||||||
@@ -2450,10 +2514,11 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
|
|||||||
#if defined(USE_DEVPOLL)
|
#if defined(USE_DEVPOLL)
|
||||||
revents = xtn->ev.buf[n].revents;
|
revents = xtn->ev.buf[n].revents;
|
||||||
#elif defined(USE_KQUEUE)
|
#elif defined(USE_KQUEUE)
|
||||||
if (xtn->ev.buf[n].filter == EVFILT_READ) mask = HAK_SEMAPHORE_IO_MASK_INPUT;
|
revents = 0;
|
||||||
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) mask = HAK_SEMAPHORE_IO_MASK_OUTPUT;
|
if (xtn->ev.buf[n].filter == EVFILT_READ) revents |= XPOLLIN;
|
||||||
else mask = 0;
|
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) revents |= XPOLLOUT;
|
||||||
goto call_muxwcb_kqueue;
|
if (xtn->ev.buf[n].flags & EV_EOF) revents |= XPOLLHUP;
|
||||||
|
if (xtn->ev.buf[n].flags & EV_ERROR) revents |= XPOLLERR;
|
||||||
#elif defined(USE_EPOLL)
|
#elif defined(USE_EPOLL)
|
||||||
revents = xtn->ev.buf[n].events;
|
revents = xtn->ev.buf[n].events;
|
||||||
#elif defined(USE_POLL)
|
#elif defined(USE_POLL)
|
||||||
@@ -2473,7 +2538,6 @@ static void vm_muxwait (hak_t* hak, const hak_ntime_t* dur, hak_vmprim_muxwait_c
|
|||||||
#if defined(USE_DEVPOLL)
|
#if defined(USE_DEVPOLL)
|
||||||
muxwcb(hak, xtn->ev.buf[n].fd, mask);
|
muxwcb(hak, xtn->ev.buf[n].fd, mask);
|
||||||
#elif defined(USE_KQUEUE)
|
#elif defined(USE_KQUEUE)
|
||||||
call_muxwcb_kqueue:
|
|
||||||
muxwcb(hak, xtn->ev.buf[n].ident, mask);
|
muxwcb(hak, xtn->ev.buf[n].ident, mask);
|
||||||
#elif defined(USE_EPOLL)
|
#elif defined(USE_EPOLL)
|
||||||
muxwcb(hak, xtn->ev.buf[n].data.fd, mask);
|
muxwcb(hak, xtn->ev.buf[n].data.fd, mask);
|
||||||
|
|||||||
@@ -35,6 +35,7 @@
|
|||||||
#include <hak-pio.h>
|
#include <hak-pio.h>
|
||||||
#include <hak-str.h>
|
#include <hak-str.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
@@ -734,6 +735,76 @@ static hak_pfrc_t pf_sys_pclose (hak_t* hak, hak_mod_t* mod, hak_ooi_t nargs)
|
|||||||
|
|
||||||
static hak_pfinfo_t pfinfos[] =
|
static hak_pfinfo_t pfinfos[] =
|
||||||
{
|
{
|
||||||
|
#if defined(SIGABRT)
|
||||||
|
{ "SIGABRT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGABRT }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGALRM)
|
||||||
|
{ "SIGALRM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGALRM }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGBUS)
|
||||||
|
{ "SIGBUS", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGBUS }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGCHLD)
|
||||||
|
{ "SIGCHLD", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGCHLD }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGCONT)
|
||||||
|
{ "SIGCONT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGCONT }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGFPE)
|
||||||
|
{ "SIGFPE", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGFPE }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGHUP)
|
||||||
|
{ "SIGHUP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGHUP }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGILL)
|
||||||
|
{ "SIGILL", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGILL }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGINT)
|
||||||
|
{ "SIGINT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGINT }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGKILL)
|
||||||
|
{ "SIGKILL", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGKILL }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGPIPE)
|
||||||
|
{ "SIGPIPE", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGPIPE }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGQUIT)
|
||||||
|
{ "SIGQUIT", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGQUIT }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGSEGV)
|
||||||
|
{ "SIGSEGV", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGSEGV }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGSTOP)
|
||||||
|
{ "SIGSTOP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGSTOP }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGTERM)
|
||||||
|
{ "SIGTERM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTERM }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGTSTP)
|
||||||
|
{ "SIGTSTP", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTSTP }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGTTIN)
|
||||||
|
{ "SIGTTIN", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTTIN }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGTTOU)
|
||||||
|
{ "SIGTTOU", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGTTOU }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGURG)
|
||||||
|
{ "SIGURG", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGURG }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGUSR1)
|
||||||
|
{ "SIGUSR1", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGUSR1 }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGUSR2)
|
||||||
|
{ "SIGUSR2", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGUSR2 }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGVTALRM)
|
||||||
|
{ "SIGVTALRM", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGVTALRM }},
|
||||||
|
#endif
|
||||||
|
#if defined(SIGWINCH)
|
||||||
|
{ "SIGWINCH", { HAK_PFBASE_CONST_SMOOI, HAK_NULL, 0, (hak_oow_t)(hak_ooi_t)SIGWINCH }},
|
||||||
|
#endif
|
||||||
|
|
||||||
{ "close", { HAK_PFBASE_FUNC, pf_sys_close, 1, 1 } },
|
{ "close", { HAK_PFBASE_FUNC, pf_sys_close, 1, 1 } },
|
||||||
{ "open", { HAK_PFBASE_FUNC, pf_sys_open, 2, 3 } },
|
{ "open", { HAK_PFBASE_FUNC, pf_sys_open, 2, 3 } },
|
||||||
{ "pclose", { HAK_PFBASE_FUNC, pf_sys_pclose, 1, 1 } },
|
{ "pclose", { HAK_PFBASE_FUNC, pf_sys_pclose, 1, 1 } },
|
||||||
|
|||||||
+2
-2
@@ -107,7 +107,7 @@ class ChildGroup(
|
|||||||
## semaphore on the signal descriptor for the whole group, once.
|
## semaphore on the signal descriptor for the whole group, once.
|
||||||
if (not self.shared) {
|
if (not self.shared) {
|
||||||
set shared true
|
set shared true
|
||||||
system-catch-sig 17 ## SIGCHLD - define this as a constant...
|
system-catch-sig sys.SIGCHLD
|
||||||
set sigsem (sem-new)
|
set sigsem (sem-new)
|
||||||
semgr-add self.sg self.sigsem
|
semgr-add self.sg self.sigsem
|
||||||
sem-signal-on-input self.sigsem (system-get-sigfd)
|
sem-signal-on-input self.sigsem (system-get-sigfd)
|
||||||
@@ -228,7 +228,7 @@ class ChildGroup(
|
|||||||
}
|
}
|
||||||
if self.shared {
|
if self.shared {
|
||||||
sem-unsignal self.sigsem
|
sem-unsignal self.sigsem
|
||||||
system-uncatch-sig 17
|
system-uncatch-sig sys.SIGCHLD
|
||||||
set shared false
|
set shared false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,15 @@ check_SCRIPTS = \
|
|||||||
hnd-03.hak \
|
hnd-03.hak \
|
||||||
insta-01.hak \
|
insta-01.hak \
|
||||||
insta-02.hak \
|
insta-02.hak \
|
||||||
|
mux-01.hak \
|
||||||
|
mux-02.hak \
|
||||||
prim-01.hak \
|
prim-01.hak \
|
||||||
proc-01.hak \
|
proc-01.hak \
|
||||||
proclib-01.hak \
|
proclib-01.hak \
|
||||||
ret-01.hak \
|
ret-01.hak \
|
||||||
retvar-01.hak \
|
retvar-01.hak \
|
||||||
sig-01.hak \
|
sig-01.hak \
|
||||||
|
sig-02.hak \
|
||||||
sysproc-01.hak \
|
sysproc-01.hak \
|
||||||
sysproc-02.hak \
|
sysproc-02.hak \
|
||||||
tick-01.hak \
|
tick-01.hak \
|
||||||
|
|||||||
@@ -557,12 +557,15 @@ check_SCRIPTS = \
|
|||||||
hnd-03.hak \
|
hnd-03.hak \
|
||||||
insta-01.hak \
|
insta-01.hak \
|
||||||
insta-02.hak \
|
insta-02.hak \
|
||||||
|
mux-01.hak \
|
||||||
|
mux-02.hak \
|
||||||
prim-01.hak \
|
prim-01.hak \
|
||||||
proc-01.hak \
|
proc-01.hak \
|
||||||
proclib-01.hak \
|
proclib-01.hak \
|
||||||
ret-01.hak \
|
ret-01.hak \
|
||||||
retvar-01.hak \
|
retvar-01.hak \
|
||||||
sig-01.hak \
|
sig-01.hak \
|
||||||
|
sig-02.hak \
|
||||||
sysproc-01.hak \
|
sysproc-01.hak \
|
||||||
sysproc-02.hak \
|
sysproc-02.hak \
|
||||||
tick-01.hak \
|
tick-01.hak \
|
||||||
|
|||||||
+1
-7
@@ -23,7 +23,7 @@ sys.read r (core.basicNew ByteArray 4) ##ERROR: system handle 0
|
|||||||
|
|
||||||
## a regular file is never accepted by the multiplexer: epoll refuses one
|
## a regular file is never accepted by the multiplexer: epoll refuses one
|
||||||
## outright, and poll() would report it permanently ready
|
## outright, and poll() would report it permanently ready
|
||||||
f := (sys.open "/proc/version" "r")
|
f := (sys.open "/etc/passwd" "r")
|
||||||
s := (sem-new)
|
s := (sem-new)
|
||||||
sem-signal-on-input s f ##ERROR: not of an acceptable kind
|
sem-signal-on-input s f ##ERROR: not of an acceptable kind
|
||||||
|
|
||||||
@@ -41,12 +41,6 @@ sys.read (core.basicAt p 0) (core.basicNew ByteArray 4) ##ERROR: not of an accep
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## an exit handle is muxable but carries no bytes
|
|
||||||
p := (sys.popen "true" "r")
|
|
||||||
sys.read (core.basicAt p 4) (core.basicNew ByteArray 4) ##ERROR: not readable
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## a missing file is reported, not guessed at
|
## a missing file is reported, not guessed at
|
||||||
sys.open "/nonexistent/definitely-not-here" "r" ##ERROR: open /nonexistent/definitely-not-here
|
sys.open "/nonexistent/definitely-not-here" "r" ##ERROR: open /nonexistent/definitely-not-here
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
## a recycled descriptor number must not inherit a readiness event
|
||||||
|
##
|
||||||
|
## The io thread reads multiplexer events into a buffer that the VM drains
|
||||||
|
## later, so unregistering a descriptor does not reach events already handed
|
||||||
|
## back. sys.pclose then closes the descriptor and the next sys.popen gets the
|
||||||
|
## same number, at which point a leftover event is delivered against the new
|
||||||
|
## pipe: the semaphore fires for something that was never ready and the read
|
||||||
|
## finds nothing.
|
||||||
|
##
|
||||||
|
## The child sleeps before writing, so a wakeup that arrives before the write
|
||||||
|
## is unmistakably spurious rather than merely early - which is what makes this
|
||||||
|
## deterministic instead of a race. Each round must read its own three bytes.
|
||||||
|
|
||||||
|
fun chk(ok msg) {
|
||||||
|
if ok { printf "OK: %s\n" msg } \
|
||||||
|
else { printf "ERROR: %s\n" msg }
|
||||||
|
}
|
||||||
|
|
||||||
|
iosem := (sem-new)
|
||||||
|
tmo := (sem-new)
|
||||||
|
sg := (semgr-new)
|
||||||
|
semgr-add sg iosem
|
||||||
|
semgr-add sg tmo
|
||||||
|
|
||||||
|
## 1 when the handle became readable, 0 when the timer won instead
|
||||||
|
fun waitin(h secs) {
|
||||||
|
| s |
|
||||||
|
sem-signal tmo secs 0
|
||||||
|
sem-signal-on-input iosem h
|
||||||
|
s := (semgr-wait sg)
|
||||||
|
sem-unsignal iosem
|
||||||
|
sem-unsignal tmo
|
||||||
|
if (eqv? s tmo) { return 0 } else { return 1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun round(n) {
|
||||||
|
| p outh buf ready got |
|
||||||
|
p := (sys.popen "sleep 0.4; echo hi" "r")
|
||||||
|
outh := (core.basicAt p 2)
|
||||||
|
ready := (waitin outh 5)
|
||||||
|
buf := (core.basicNew ByteArray 8)
|
||||||
|
got := (sys.read outh buf)
|
||||||
|
chk (== ready 1) "the child's output was reported ready"
|
||||||
|
## -1 here means the wakeup belonged to a previous round's pipe
|
||||||
|
chk (== got 3) "the ready descriptor really had the child's bytes"
|
||||||
|
sys.pclose (core.basicAt p 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
## every round closes its pipe, so the next popen gets the same descriptor
|
||||||
|
## number back - that reuse is what exposes a stale event
|
||||||
|
round 1
|
||||||
|
round 2
|
||||||
|
round 3
|
||||||
|
round 4
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
## several io bindings alive at once, and unbinding one from the middle
|
||||||
|
##
|
||||||
|
## Each sem-signal-on-input adds an entry to the VM's io tuple array; removing
|
||||||
|
## one compacts the gap by migrating the last entry into the freed slot, which
|
||||||
|
## has to fix up the moved semaphore's recorded index. Nothing exercises that
|
||||||
|
## unless two or more bindings exist simultaneously - a single binding always
|
||||||
|
## occupies the last slot and compaction is a no-op.
|
||||||
|
##
|
||||||
|
## The children finish in a known order, so the semaphore each wait answers is
|
||||||
|
## predictable, and a mixed-up index shows as the wrong semaphore or a read
|
||||||
|
## that finds nothing.
|
||||||
|
|
||||||
|
fun chk(ok msg) {
|
||||||
|
if ok { printf "OK: %s\n" msg } \
|
||||||
|
else { printf "ERROR: %s\n" msg }
|
||||||
|
}
|
||||||
|
|
||||||
|
sg := (semgr-new)
|
||||||
|
sa := (sem-new)
|
||||||
|
sb := (sem-new)
|
||||||
|
sc := (sem-new)
|
||||||
|
tmo := (sem-new)
|
||||||
|
semgr-add sg sa
|
||||||
|
semgr-add sg sb
|
||||||
|
semgr-add sg sc
|
||||||
|
semgr-add sg tmo
|
||||||
|
|
||||||
|
## staggered so the completion order is a, then b, then c
|
||||||
|
pa := (sys.popen "sleep 0.2; echo aaa" "r")
|
||||||
|
pb := (sys.popen "sleep 0.5; echo bbb" "r")
|
||||||
|
pc := (sys.popen "sleep 0.8; echo ccc" "r")
|
||||||
|
|
||||||
|
ha := (core.basicAt pa 2)
|
||||||
|
hb := (core.basicAt pb 2)
|
||||||
|
hc := (core.basicAt pc 2)
|
||||||
|
|
||||||
|
## all three bound at the same time - three live tuple entries
|
||||||
|
sem-signal-on-input sa ha
|
||||||
|
sem-signal-on-input sb hb
|
||||||
|
sem-signal-on-input sc hc
|
||||||
|
sem-signal tmo 9 0
|
||||||
|
|
||||||
|
fun expect(want h name) {
|
||||||
|
| s buf got |
|
||||||
|
s := (semgr-wait sg)
|
||||||
|
chk (eqv? s want) name
|
||||||
|
buf := (core.basicNew ByteArray 8)
|
||||||
|
got := (sys.read h buf)
|
||||||
|
chk (== got 4) "the woken handle carried its child's bytes"
|
||||||
|
}
|
||||||
|
|
||||||
|
## unbinding sa frees the first slot, so the last entry migrates into it and
|
||||||
|
## sb/sc must still resolve to their own handles afterwards
|
||||||
|
expect sa ha "the first child woke its own semaphore"
|
||||||
|
sem-unsignal sa
|
||||||
|
|
||||||
|
expect sb hb "the second child woke its own semaphore after compaction"
|
||||||
|
sem-unsignal sb
|
||||||
|
|
||||||
|
expect sc hc "the third child woke its own semaphore after compaction"
|
||||||
|
sem-unsignal sc
|
||||||
|
|
||||||
|
sem-unsignal tmo
|
||||||
|
sys.pclose (core.basicAt pa 0)
|
||||||
|
sys.pclose (core.basicAt pb 0)
|
||||||
|
sys.pclose (core.basicAt pc 0)
|
||||||
+7
-7
@@ -27,15 +27,15 @@ sys.close (core.basicAt q 0)
|
|||||||
sys.close (core.basicAt q 1)
|
sys.close (core.basicAt q 1)
|
||||||
|
|
||||||
## --- catch and uncatch are idempotent ---
|
## --- catch and uncatch are idempotent ---
|
||||||
chk (= (system-catch-sig 10) 10) "system-catch-sig returns the signal number"
|
chk (= (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "system-catch-sig returns the signal number"
|
||||||
chk (= (system-catch-sig 10) 10) "catching an already caught signal is fine"
|
chk (= (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "catching an already caught signal is fine"
|
||||||
chk (= (system-uncatch-sig 10) 10) "system-uncatch-sig returns the signal number"
|
chk (= (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "system-uncatch-sig returns the signal number"
|
||||||
chk (= (system-uncatch-sig 10) 10) "uncatching an uncaught signal is fine"
|
chk (= (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "uncatching an uncaught signal is fine"
|
||||||
|
|
||||||
## --- a real signal reaches hak code, without stalling the coprocesses ---
|
## --- a real signal reaches hak code, without stalling the coprocesses ---
|
||||||
## SIGCHLD is used because a child exiting is something this test can arrange
|
## SIGCHLD is used because a child exiting is something this test can arrange
|
||||||
## on its own, with no outside help.
|
## on its own, with no outside help.
|
||||||
system-catch-sig 17
|
system-catch-sig sys.SIGCHLD
|
||||||
|
|
||||||
h := (system-get-sigfd)
|
h := (system-get-sigfd)
|
||||||
s := (sem-new)
|
s := (sem-new)
|
||||||
@@ -76,7 +76,7 @@ fork ticker
|
|||||||
sem-wait fin
|
sem-wait fin
|
||||||
|
|
||||||
chk (= ticks 4) "coprocesses ran while a coprocess waited on a signal"
|
chk (= ticks 4) "coprocesses ran while a coprocess waited on a signal"
|
||||||
chk (= signo 17) "the signal number came through the signal descriptor"
|
chk (= signo sys.SIGCHLD) "the signal number came through the signal descriptor"
|
||||||
chk (= (sys.pwait proc) 4) "and the child's exit status is readable"
|
chk (= (sys.pwait proc) 4) "and the child's exit status is readable"
|
||||||
sys.pclose proc
|
sys.pclose proc
|
||||||
system-uncatch-sig 17
|
system-uncatch-sig sys.SIGCHLD
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
## the signal constants exported by the sys module
|
||||||
|
##
|
||||||
|
## Signal numbers differ between platforms - 10 is SIGUSR1 on Linux but SIGBUS
|
||||||
|
## on FreeBSD, 17 is SIGCHLD on Linux but SIGSTOP on FreeBSD - so hak code must
|
||||||
|
## name them rather than spell the numbers. These constants exist for that.
|
||||||
|
##
|
||||||
|
## Naming one that does not resolve is a compile-time error, which makes this
|
||||||
|
## file a guard on the module's pfinfo table too: that table is binary-searched
|
||||||
|
## by hak_findpfbase(), so an entry out of C-collation order stops resolving
|
||||||
|
## with no other symptom.
|
||||||
|
|
||||||
|
fun chk(ok msg) {
|
||||||
|
if ok { printf "OK: %s\n" msg } \
|
||||||
|
else { printf "ERROR: %s\n" msg }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isnum(v name) { chk (integer? v) name }
|
||||||
|
|
||||||
|
isnum sys.SIGABRT "sys.SIGABRT"
|
||||||
|
isnum sys.SIGALRM "sys.SIGALRM"
|
||||||
|
isnum sys.SIGBUS "sys.SIGBUS"
|
||||||
|
isnum sys.SIGCHLD "sys.SIGCHLD"
|
||||||
|
isnum sys.SIGCONT "sys.SIGCONT"
|
||||||
|
isnum sys.SIGFPE "sys.SIGFPE"
|
||||||
|
isnum sys.SIGHUP "sys.SIGHUP"
|
||||||
|
isnum sys.SIGILL "sys.SIGILL"
|
||||||
|
isnum sys.SIGINT "sys.SIGINT"
|
||||||
|
isnum sys.SIGKILL "sys.SIGKILL"
|
||||||
|
isnum sys.SIGPIPE "sys.SIGPIPE"
|
||||||
|
isnum sys.SIGQUIT "sys.SIGQUIT"
|
||||||
|
isnum sys.SIGSEGV "sys.SIGSEGV"
|
||||||
|
isnum sys.SIGSTOP "sys.SIGSTOP"
|
||||||
|
isnum sys.SIGTERM "sys.SIGTERM"
|
||||||
|
isnum sys.SIGTSTP "sys.SIGTSTP"
|
||||||
|
isnum sys.SIGTTIN "sys.SIGTTIN"
|
||||||
|
isnum sys.SIGTTOU "sys.SIGTTOU"
|
||||||
|
isnum sys.SIGURG "sys.SIGURG"
|
||||||
|
isnum sys.SIGUSR1 "sys.SIGUSR1"
|
||||||
|
isnum sys.SIGUSR2 "sys.SIGUSR2"
|
||||||
|
isnum sys.SIGVTALRM "sys.SIGVTALRM"
|
||||||
|
isnum sys.SIGWINCH "sys.SIGWINCH"
|
||||||
|
|
||||||
|
## the constants must be distinct from one another - a table entry pointing at
|
||||||
|
## the wrong value would otherwise pass every check above
|
||||||
|
chk (not (== sys.SIGKILL sys.SIGSTOP)) "SIGKILL and SIGSTOP differ"
|
||||||
|
chk (not (== sys.SIGUSR1 sys.SIGUSR2)) "SIGUSR1 and SIGUSR2 differ"
|
||||||
|
chk (not (== sys.SIGCHLD sys.SIGSTOP)) "SIGCHLD and SIGSTOP differ"
|
||||||
|
chk (not (== sys.SIGBUS sys.SIGUSR1)) "SIGBUS and SIGUSR1 differ"
|
||||||
|
|
||||||
|
## these three are the same number everywhere hak runs, so they can be pinned
|
||||||
|
chk (== sys.SIGKILL 9) "SIGKILL is 9"
|
||||||
|
chk (== sys.SIGSEGV 11) "SIGSEGV is 11"
|
||||||
|
chk (== sys.SIGTERM 15) "SIGTERM is 15"
|
||||||
|
|
||||||
|
## and the constants behave: a routable one can be caught, an unroutable one
|
||||||
|
## cannot, whatever the numbers happen to be here
|
||||||
|
chk (== (system-catch-sig sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is catchable"
|
||||||
|
chk (== (system-uncatch-sig sys.SIGUSR1) sys.SIGUSR1) "SIGUSR1 is uncatchable again"
|
||||||
|
raised := false
|
||||||
|
try { system-catch-sig sys.SIGKILL } catch (e) { raised := true }
|
||||||
|
chk raised "SIGKILL is refused"
|
||||||
+7
-7
@@ -1,32 +1,32 @@
|
|||||||
## signals that cannot be caught
|
## signals that cannot be caught
|
||||||
system-catch-sig 9 ##ERROR: 9 not routable
|
system-catch-sig sys.SIGKILL ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
system-catch-sig 19 ##ERROR: 19 not routable
|
system-catch-sig sys.SIGSTOP ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## signals that indicate a crash: turning one into a byte on a pipe and
|
## signals that indicate a crash: turning one into a byte on a pipe and
|
||||||
## carrying on would hide the fault rather than report it
|
## carrying on would hide the fault rather than report it
|
||||||
system-catch-sig 11 ##ERROR: 11 not routable
|
system-catch-sig sys.SIGSEGV ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
system-catch-sig 7 ##ERROR: 7 not routable
|
system-catch-sig sys.SIGBUS ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
system-catch-sig 8 ##ERROR: 8 not routable
|
system-catch-sig sys.SIGFPE ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
system-catch-sig 4 ##ERROR: 4 not routable
|
system-catch-sig sys.SIGILL ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## the timer signal hak itself uses to switch processes
|
## the timer signal hak itself uses to switch processes
|
||||||
system-catch-sig 26 ##ERROR: 26 not routable
|
system-catch-sig sys.SIGVTALRM ##ERROR: not routable
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -98,3 +98,17 @@ p := (sys.popen "sleep 60" "r")
|
|||||||
outh := (core.basicAt p 2)
|
outh := (core.basicAt p 2)
|
||||||
sys.pclose (core.basicAt p 0)
|
sys.pclose (core.basicAt p 0)
|
||||||
chk true "pclose released the group"
|
chk true "pclose released the group"
|
||||||
|
|
||||||
|
## --- the exit handle ---
|
||||||
|
## it is muxable but carries no bytes. it exists only where the platform has
|
||||||
|
## pidfd_open(); elsewhere sys.popen answers nil for it, so guard the check
|
||||||
|
## rather than assuming Linux.
|
||||||
|
p := (sys.popen "true" "r")
|
||||||
|
xh := (core.basicAt p 4)
|
||||||
|
if (nil? xh) { printf "OK: no exit handle where the platform has no pidfd\n" } \
|
||||||
|
else {
|
||||||
|
raised := false
|
||||||
|
try { sys.read xh (core.basicNew ByteArray 4) } catch (e) { raised := true }
|
||||||
|
chk raised "the exit handle carries no bytes"
|
||||||
|
}
|
||||||
|
sys.pclose (core.basicAt p 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user