added more vm primitives

This commit is contained in:
hyung-hwan 2018-02-08 14:40:56 +00:00
parent 49363231a1
commit 95b4c5e0d7
5 changed files with 352 additions and 167 deletions

View File

@ -134,6 +134,7 @@ dnl check functions
AC_CHECK_FUNCS([gettimeofday settimeofday clock_gettime clock_settime getitimer setitimer]) AC_CHECK_FUNCS([gettimeofday settimeofday clock_gettime clock_settime getitimer setitimer])
AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_CHECK_FUNCS([makecontext swapcontext getcontext setcontext]) AC_CHECK_FUNCS([makecontext swapcontext getcontext setcontext])
AC_CHECK_FUNCS([clock_nanosleep nanosleep usleep])
AC_CHECK_FUNCS([snprintf _vsnprintf _vsnwprintf]) AC_CHECK_FUNCS([snprintf _vsnprintf _vsnwprintf])
AC_CHECK_FUNCS([isatty]) AC_CHECK_FUNCS([isatty])

View File

@ -27,30 +27,6 @@
#include "hcl-prv.h" #include "hcl-prv.h"
/* TODO: remove these headers after having migrated system-dependent functions of of this file */
#if defined(_WIN32)
# include <windows.h>
#elif defined(__OS2__)
# define INCL_DOSMISC
# define INCL_DOSDATETIME
# define INCL_DOSERRORS
# include <os2.h>
# include <time.h>
#elif defined(__MSDOS__)
# include <time.h>
#elif defined(macintosh)
# include <Types.h>
# include <OSUtils.h>
# include <Timer.h>
#else
# if defined(HAVE_TIME_H)
# include <time.h>
# endif
# if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
# endif
#endif
#define PROC_STATE_RUNNING 3 #define PROC_STATE_RUNNING 3
#define PROC_STATE_WAITING 2 #define PROC_STATE_WAITING 2
#define PROC_STATE_RUNNABLE 1 #define PROC_STATE_RUNNABLE 1
@ -139,147 +115,21 @@ static HCL_INLINE const char* proc_state_to_string (int state)
# define LOG_INST_3(hcl,fmt,a1,a2,a3) # define LOG_INST_3(hcl,fmt,a1,a2,a3)
#endif #endif
/* ------------------------------------------------------------------------- */ static int vm_startup (hcl_t* hcl)
static HCL_INLINE void vm_gettime (hcl_t* hcl, hcl_ntime_t* now)
{ {
#if defined(_WIN32) HCL_DEBUG0 (hcl, "VM started up\n");
/* TODO: */ if (hcl->vmprim.vm_startup(hcl) <= -1) return -1;
hcl->vmprim.vm_gettime (hcl, &hcl->exec_start_time); /* raw time. no adjustment */
#elif defined(__OS2__) return 0;
ULONG out;
/* TODO: handle overflow?? */
/* TODO: use DosTmrQueryTime() and DosTmrQueryFreq()? */
DosQuerySysInfo (QSV_MS_COUNT, QSV_MS_COUNT, &out, HCL_SIZEOF(out)); /* milliseconds */
/* it must return NO_ERROR */
HCL_INITNTIME (now, HCL_MSEC_TO_SEC(out), HCL_MSEC_TO_NSEC(out));
#elif defined(__MSDOS__) && defined(_INTELC32_)
clock_t c;
/* TODO: handle overflow?? */
c = clock ();
now->sec = c / CLOCKS_PER_SEC;
#if (CLOCKS_PER_SEC == 1000)
now->nsec = HCL_MSEC_TO_NSEC(c % CLOCKS_PER_SEC);
#elif (CLOCKS_PER_SEC == 1000000L)
now->nsec = HCL_USEC_TO_NSEC(c % CLOCKS_PER_SEC);
#elif (CLOCKS_PER_SEC == 1000000000L)
now->nsec = (c % CLOCKS_PER_SEC);
#else
# error UNSUPPORTED CLOCKS_PER_SEC
#endif
#elif defined(macintosh)
UnsignedWide tick;
hcl_uint64_t tick64;
Microseconds (&tick);
tick64 = *(hcl_uint64_t*)&tick;
HCL_INITNTIME (now, HCL_USEC_TO_SEC(tick64), HCL_USEC_TO_NSEC(tick64));
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime (CLOCK_MONOTONIC, &ts);
HCL_INITNTIME(now, ts.tv_sec, ts.tv_nsec);
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
struct timespec ts;
clock_gettime (CLOCK_REALTIME, &ts);
HCL_INITNTIME(now, ts.tv_sec, ts.tv_nsec);
HCL_SUBNTIME (now, now, &hcl->vm_time_offset); /* offset */
#else
struct timeval tv;
gettimeofday (&tv, HCL_NULL);
HCL_INITNTIME(now, tv.tv_sec, HCL_USEC_TO_NSEC(tv.tv_usec));
/* at the first call, vm_time_offset should be 0. so subtraction takes
* no effect. once it becomes non-zero, it offsets the actual time.
* this is to keep the returned time small enough to be held in a
* small integer on platforms where the small integer is not large enough */
HCL_SUBNTIME (now, now, &hcl->vm_time_offset);
#endif
}
static HCL_INLINE void vm_sleep (hcl_t* hcl, const hcl_ntime_t* dur)
{
#if defined(_WIN32)
if (hcl->waitable_timer)
{
LARGE_INTEGER li;
li.QuadPart = -HCL_SECNSEC_TO_NSEC(dur->sec, dur->nsec);
if(SetWaitableTimer(timer, &li, 0, HCL_NULL, HCL_NULL, FALSE) == FALSE) goto normal_sleep;
WaitForSingleObject(timer, INFINITE);
}
else
{
normal_sleep:
/* fallback to normal Sleep() */
Sleep (HCL_SECNSEC_TO_MSEC(dur->sec,dur->nsec));
}
#elif defined(__OS2__)
/* TODO: in gui mode, this is not a desirable method???
* this must be made event-driven coupled with the main event loop */
DosSleep (HCL_SECNSEC_TO_MSEC(dur->sec,dur->nsec));
#elif defined(macintosh)
/* TODO: ... */
#elif defined(__MSDOS__) && defined(_INTELC32_)
clock_t c;
c = clock ();
c += dur->sec * CLOCKS_PER_SEC;
#if (CLOCKS_PER_SEC == 1000)
c += HCL_NSEC_TO_MSEC(dur->nsec);
#elif (CLOCKS_PER_SEC == 1000000L)
c += HCL_NSEC_TO_USEC(dur->nsec);
#elif (CLOCKS_PER_SEC == 1000000000L)
c += dur->nsec;
#else
# error UNSUPPORTED CLOCKS_PER_SEC
#endif
/* TODO: handle clock overvlow */
/* TODO: check if there is abortion request or interrupt */
while (c > clock()) ;
#else
struct timespec ts;
ts.tv_sec = dur->sec;
ts.tv_nsec = dur->nsec;
nanosleep (&ts, HCL_NULL);
#endif
}
static void vm_startup (hcl_t* hcl)
{
hcl_ntime_t now;
#if defined(_WIN32)
hcl->waitable_timer = CreateWaitableTimer(HCL_NULL, TRUE, HCL_NULL);
#endif
/* reset hcl->vm_time_offset so that vm_gettime is not affected */
HCL_INITNTIME(&hcl->vm_time_offset, 0, 0);
vm_gettime (hcl, &now);
hcl->vm_time_offset = now;
} }
static void vm_cleanup (hcl_t* hcl) static void vm_cleanup (hcl_t* hcl)
{ {
#if defined(_WIN32) hcl->vmprim.vm_gettime (hcl, &hcl->exec_end_time); /* raw time. no adjustment */
if (hcl->waitable_timer) hcl->vmprim.vm_cleanup (hcl);
{ HCL_DEBUG0 (hcl, "VM started up\n");
CloseHandle (hcl->waitable_timer);
hcl->waitable_timer = HCL_NULL;
}
#endif
} }
/* ------------------------------------------------------------------------- */ /* ------------------------------------------------------------------------- */
@ -1224,7 +1074,7 @@ static int execute (hcl_t* hcl)
HCL_ASSERT (hcl, hcl->active_context != HCL_NULL); HCL_ASSERT (hcl, hcl->active_context != HCL_NULL);
vm_startup (hcl); if (vm_startup (hcl) <= -1) return -1;
hcl->proc_switched = 0; hcl->proc_switched = 0;
while (1) while (1)
@ -1232,7 +1082,7 @@ static int execute (hcl_t* hcl)
if (hcl->sem_heap_count > 0) if (hcl->sem_heap_count > 0)
{ {
hcl_ntime_t ft, now; hcl_ntime_t ft, now;
vm_gettime (hcl, &now); hcl->vmprim.vm_gettime (hcl, &now);
do do
{ {
@ -1276,8 +1126,8 @@ static int execute (hcl_t* hcl)
else if (hcl->processor->active == hcl->nil_process) else if (hcl->processor->active == hcl->nil_process)
{ {
HCL_SUBNTIME (&ft, &ft, (hcl_ntime_t*)&now); HCL_SUBNTIME (&ft, &ft, (hcl_ntime_t*)&now);
vm_sleep (hcl, &ft); /* TODO: change this to i/o multiplexer??? */ hcl->vmprim.vm_sleep (hcl, &ft); /* TODO: change this to i/o multiplexer??? */
vm_gettime (hcl, &now); hcl->vmprim.vm_gettime (hcl, &now);
} }
else else
{ {
@ -1327,8 +1177,9 @@ static int execute (hcl_t* hcl)
if (hcl->ip >= hcl->code.bc.len) if (hcl->ip >= hcl->code.bc.len)
{ {
HCL_DEBUG2 (hcl, "IP(%zd) reached the end of bytecode(%zu). Stopping execution\n", hcl->ip, hcl->code.bc.len); HCL_DEBUG1 (hcl, "IP reached the end of bytecode(%zu). Stopping execution\n", hcl->code.bc.len);
break; return_value = hcl->_nil;
goto handle_return;
} }
#if defined(HCL_DEBUG_VM_EXEC) #if defined(HCL_DEBUG_VM_EXEC)

View File

@ -61,7 +61,8 @@
#if !defined(NDEBUG) #if !defined(NDEBUG)
#define HCL_DEBUG_VM_PROCESSOR 1 #define HCL_DEBUG_VM_PROCESSOR 1
#define HCL_DEBUG_VM_EXEC 1 #define HCL_DEBUG_VM_EXEC 1
#define MOO_DEBUG_BIGINT 1 #define HCL_DEBUG_BIGINT 1
#define HCL_PROFILE_VM 1
#endif #endif
/* allow the caller to drive process switching by calling /* allow the caller to drive process switching by calling

View File

@ -700,14 +700,28 @@ typedef void (*hcl_log_write_t) (hcl_t* hcl, hcl_oow_t mask, const hcl_ooch_t* m
typedef void (*hcl_syserrstrb_t) (hcl_t* hcl, int syserr, hcl_bch_t* buf, hcl_oow_t len); typedef void (*hcl_syserrstrb_t) (hcl_t* hcl, int syserr, hcl_bch_t* buf, hcl_oow_t len);
typedef void (*hcl_syserrstru_t) (hcl_t* hcl, int syserr, hcl_uch_t* buf, hcl_oow_t len); typedef void (*hcl_syserrstru_t) (hcl_t* hcl, int syserr, hcl_uch_t* buf, hcl_oow_t len);
typedef int (*hcl_vmprim_startup_t) (hcl_t* hcl);
typedef void (*hcl_vmprim_cleanup_t) (hcl_t* hcl);
typedef void (*hcl_vmprim_gettime_t) (hcl_t* hcl, hcl_ntime_t* now);
typedef void (*hcl_vmprim_sleep_t) (hcl_t* hcl, const hcl_ntime_t* duration);
struct hcl_vmprim_t struct hcl_vmprim_t
{ {
hcl_vmprim_dlopen_t dl_open; hcl_vmprim_dlopen_t dl_open;
hcl_vmprim_dlclose_t dl_close; hcl_vmprim_dlclose_t dl_close;
hcl_vmprim_dlsym_t dl_getsym; hcl_vmprim_dlsym_t dl_getsym;
hcl_log_write_t log_write; hcl_log_write_t log_write;
hcl_syserrstrb_t syserrstrb; hcl_syserrstrb_t syserrstrb;
hcl_syserrstru_t syserrstru; hcl_syserrstru_t syserrstru;
hcl_vmprim_startup_t vm_startup;
hcl_vmprim_cleanup_t vm_cleanup;
hcl_vmprim_gettime_t vm_gettime;
hcl_vmprim_sleep_t vm_sleep;
}; };
typedef struct hcl_vmprim_t hcl_vmprim_t; typedef struct hcl_vmprim_t hcl_vmprim_t;
@ -992,7 +1006,9 @@ struct hcl_t
hcl_ooi_t ip; hcl_ooi_t ip;
int proc_switched; /* TODO: this is temporary. implement something else to skip immediate context switching */ int proc_switched; /* TODO: this is temporary. implement something else to skip immediate context switching */
int switch_proc; int switch_proc;
hcl_ntime_t vm_time_offset;
hcl_ntime_t exec_start_time;
hcl_ntime_t exec_end_time;
/* == END EXECUTION REGISTERS == */ /* == END EXECUTION REGISTERS == */
/* == BIGINT CONVERSION == */ /* == BIGINT CONVERSION == */

View File

@ -88,6 +88,8 @@ struct xtn_t
const char* read_path; /* main source file */ const char* read_path; /* main source file */
const char* print_path; const char* print_path;
int vm_running;
int logfd; int logfd;
int logmask; int logmask;
int logfd_istty; int logfd_istty;
@ -548,6 +550,316 @@ static void syserrstrb (hcl_t* hcl, int syserr, hcl_bch_t* buf, hcl_oow_t len)
#endif #endif
} }
static int vm_startup (hcl_t* hcl)
{
#if defined(_WIN32)
xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl);
xtn->waitable_timer = CreateWaitableTimer(HCL_NULL, TRUE, HCL_NULL);
#else
xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl);
int pcount = 0, flag;
#if defined(USE_DEVPOLL)
xtn->ep = open ("/dev/poll", O_RDWR);
if (xtn->ep == -1)
{
hcl_syserr_to_errnum (errno);
HCL_DEBUG1 (hcl, "Cannot create devpoll - %hs\n", strerror(errno));
goto oops;
}
flag = fcntl (xtn->ep, F_GETFD);
if (flag >= 0) fcntl (xtn->ep, F_SETFD, flag | FD_CLOEXEC);
#elif defined(USE_EPOLL)
#if defined(EPOLL_CLOEXEC)
xtn->ep = epoll_create1 (EPOLL_CLOEXEC);
#else
xtn->ep = epoll_create (1024);
#endif
if (xtn->ep == -1)
{
hcl_syserr_to_errnum (errno);
HCL_DEBUG1 (hcl, "Cannot create epoll - %hs\n", strerror(errno));
goto oops;
}
#if defined(EPOLL_CLOEXEC)
/* do nothing */
#else
flag = fcntl (xtn->ep, F_GETFD);
if (flag >= 0) fcntl (xtn->ep, F_SETFD, flag | FD_CLOEXEC);
#endif
#elif defined(USE_POLL)
MUTEX_INIT (&xtn->ev.reg.pmtx);
#elif defined(USE_SELECT)
FD_ZERO (&xtn->ev.reg.rfds);
FD_ZERO (&xtn->ev.reg.wfds);
xtn->ev.reg.maxfd = -1;
MUTEX_INIT (&xtn->ev.reg.smtx);
#endif /* USE_DEVPOLL */
#if defined(USE_THREAD)
if (pipe(xtn->p) == -1)
{
hcl_syserr_to_errnum (errno);
HCL_DEBUG1 (hcl, "Cannot create pipes - %hs\n", strerror(errno));
goto oops;
}
pcount = 2;
#if defined(O_CLOEXEC)
flag = fcntl (xtn->p[0], F_GETFD);
if (flag >= 0) fcntl (xtn->p[0], F_SETFD, flag | FD_CLOEXEC);
flag = fcntl (xtn->p[1], F_GETFD);
if (flag >= 0) fcntl (xtn->p[1], F_SETFD, flag | FD_CLOEXEC);
#endif
#if defined(O_NONBLOCK)
flag = fcntl (xtn->p[0], F_GETFL);
if (flag >= 0) fcntl (xtn->p[0], F_SETFL, flag | O_NONBLOCK);
flag = fcntl (xtn->p[1], F_GETFL);
if (flag >= 0) fcntl (xtn->p[1], F_SETFL, flag | O_NONBLOCK);
#endif
if (_add_poll_fd(hcl, xtn->p[0], XPOLLIN) <= -1) goto oops;
pthread_mutex_init (&xtn->ev.mtx, HCL_NULL);
pthread_cond_init (&xtn->ev.cnd, HCL_NULL);
pthread_cond_init (&xtn->ev.cnd2, HCL_NULL);
xtn->iothr_abort = 0;
xtn->iothr_up = 0;
/*pthread_create (&xtn->iothr, HCL_NULL, iothr_main, hcl);*/
#endif /* USE_THREAD */
xtn->vm_running = 1;
return 0;
oops:
#if defined(USE_THREAD)
if (pcount > 0)
{
close (xtn->p[0]);
close (xtn->p[1]);
}
#endif
#if defined(USE_DEVPOLL) || defined(USE_EPOLL)
if (xtn->ep >= 0)
{
close (xtn->ep);
xtn->ep = -1;
}
#endif
return -1;
#endif
}
static void vm_cleanup (hcl_t* hcl)
{
#if defined(_WIN32)
xtn_t* xtn = (xatn_t*)hcl_getxtn(hcl);
if (xtn->waitable_timer)
{
CloseHandle (xtn->waitable_timer);
xtn->waitable_timer = HCL_NULL;
}
#else
xtn_t* xtn = (xtn_t*)hcl_getxtn(hcl);
xtn->vm_running = 0;
#if defined(USE_THREAD)
if (xtn->iothr_up)
{
xtn->iothr_abort = 1;
write (xtn->p[1], "Q", 1);
pthread_cond_signal (&xtn->ev.cnd);
pthread_join (xtn->iothr, HCL_NULL);
xtn->iothr_up = 0;
}
pthread_cond_destroy (&xtn->ev.cnd);
pthread_cond_destroy (&xtn->ev.cnd2);
pthread_mutex_destroy (&xtn->ev.mtx);
_del_poll_fd (hcl, xtn->p[0]);
close (xtn->p[1]);
close (xtn->p[0]);
#endif /* USE_THREAD */
#if defined(USE_DEVPOLL)
if (xtn->ep >= 0)
{
close (xtn->ep);
xtn->ep = -1;
}
/*destroy_poll_data_space (hcl);*/
#elif defined(USE_EPOLL)
if (xtn->ep >= 0)
{
close (xtn->ep);
xtn->ep = -1;
}
#elif defined(USE_POLL)
if (xtn->ev.reg.ptr)
{
hcl_freemem (hcl, xtn->ev.reg.ptr);
xtn->ev.reg.ptr = HCL_NULL;
xtn->ev.reg.len = 0;
xtn->ev.reg.capa = 0;
}
if (xtn->ev.buf)
{
hcl_freemem (hcl, xtn->ev.buf);
xtn->ev.buf = HCL_NULL;
}
/*destroy_poll_data_space (hcl);*/
MUTEX_DESTROY (&xtn->ev.reg.pmtx);
#elif defined(USE_SELECT)
FD_ZERO (&xtn->ev.reg.rfds);
FD_ZERO (&xtn->ev.reg.wfds);
xtn->ev.reg.maxfd = -1;
MUTEX_DESTROY (&xtn->ev.reg.smtx);
#endif
#endif
}
static void vm_gettime (hcl_t* hcl, hcl_ntime_t* now)
{
#if defined(_WIN32)
/* TODO: */
#elif defined(__OS2__)
ULONG out;
/* TODO: handle overflow?? */
/* TODO: use DosTmrQueryTime() and DosTmrQueryFreq()? */
DosQuerySysInfo (QSV_MS_COUNT, QSV_MS_COUNT, &out, HCL_SIZEOF(out)); /* milliseconds */
/* it must return NO_ERROR */
HCL_INITNTIME (now, HCL_MSEC_TO_SEC(out), HCL_MSEC_TO_NSEC(out));
#elif defined(__DOS__) && (defined(_INTELC32_) || defined(__WATCOMC__))
clock_t c;
/* TODO: handle overflow?? */
c = clock ();
now->sec = c / CLOCKS_PER_SEC;
#if (CLOCKS_PER_SEC == 100)
now->nsec = HCL_MSEC_TO_NSEC((c % CLOCKS_PER_SEC) * 10);
#elif (CLOCKS_PER_SEC == 1000)
now->nsec = HCL_MSEC_TO_NSEC(c % CLOCKS_PER_SEC);
#elif (CLOCKS_PER_SEC == 1000000L)
now->nsec = HCL_USEC_TO_NSEC(c % CLOCKS_PER_SEC);
#elif (CLOCKS_PER_SEC == 1000000000L)
now->nsec = (c % CLOCKS_PER_SEC);
#else
# error UNSUPPORTED CLOCKS_PER_SEC
#endif
#elif defined(macintosh)
UnsignedWide tick;
hcl_uint64_t tick64;
Microseconds (&tick);
tick64 = *(hcl_uint64_t*)&tick;
HCL_INITNTIME (now, HCL_USEC_TO_SEC(tick64), HCL_USEC_TO_NSEC(tick64));
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime (CLOCK_MONOTONIC, &ts);
HCL_INITNTIME(now, ts.tv_sec, ts.tv_nsec);
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
struct timespec ts;
clock_gettime (CLOCK_REALTIME, &ts);
HCL_INITNTIME(now, ts.tv_sec, ts.tv_nsec);
#else
struct timeval tv;
gettimeofday (&tv, HCL_NULL);
HCL_INITNTIME(now, tv.tv_sec, HCL_USEC_TO_NSEC(tv.tv_usec));
#endif
}
static void vm_sleep (hcl_t* hcl, const hcl_ntime_t* dur)
{
#if defined(_WIN32)
xtn_t* xtn = hcl_getxtn(hcl);
if (xtn->waitable_timer)
{
LARGE_INTEGER li;
li.QuadPart = -HCL_SECNSEC_TO_NSEC(dur->sec, dur->nsec);
if(SetWaitableTimer(timer, &li, 0, HCL_NULL, HCL_NULL, FALSE) == FALSE) goto normal_sleep;
WaitForSingleObject(timer, INFINITE);
}
else
{
normal_sleep:
/* fallback to normal Sleep() */
Sleep (HCL_SECNSEC_TO_MSEC(dur->sec,dur->nsec));
}
#elif defined(__OS2__)
/* TODO: in gui mode, this is not a desirable method???
* this must be made event-driven coupled with the main event loop */
DosSleep (HCL_SECNSEC_TO_MSEC(dur->sec,dur->nsec));
#elif defined(macintosh)
/* TODO: ... */
#elif defined(__DOS__) && (defined(_INTELC32_) || defined(__WATCOMC__))
clock_t c;
c = clock ();
c += dur->sec * CLOCKS_PER_SEC;
#if (CLOCKS_PER_SEC == 100)
c += HCL_NSEC_TO_MSEC(dur->nsec) / 10;
#elif (CLOCKS_PER_SEC == 1000)
c += HCL_NSEC_TO_MSEC(dur->nsec);
#elif (CLOCKS_PER_SEC == 1000000L)
c += HCL_NSEC_TO_USEC(dur->nsec);
#elif (CLOCKS_PER_SEC == 1000000000L)
c += dur->nsec;
#else
# error UNSUPPORTED CLOCKS_PER_SEC
#endif
/* TODO: handle clock overvlow */
/* TODO: check if there is abortion request or interrupt */
while (c > clock())
{
_halt_cpu();
}
#else
#if defined(USE_THREAD)
/* the sleep callback is called only if there is no IO semaphore
* waiting. so i can safely call vm_muxwait() without a muxwait callback
* when USE_THREAD is true */
vm_muxwait (hcl, dur, HCL_NULL);
#elif defined(HAVE_NANOSLEEP)
struct timespec ts;
ts.tv_sec = dur->sec;
ts.tv_nsec = dur->nsec;
nanosleep (&ts, HCL_NULL);
#elif defined(HAVE_USLEEP)
usleep (HCL_SECNSEC_TO_USEC(dur->sec, dur->nsec));
#else
# error UNSUPPORT SLEEP
#endif
#endif
}
/* ========================================================================= */
static void fini_hcl (hcl_t* hcl) static void fini_hcl (hcl_t* hcl)
{ {
xtn_t* xtn = hcl_getxtn(hcl); xtn_t* xtn = hcl_getxtn(hcl);
@ -908,6 +1220,10 @@ int main (int argc, char* argv[])
memset (&vmprim, 0, HCL_SIZEOF(vmprim)); memset (&vmprim, 0, HCL_SIZEOF(vmprim));
vmprim.log_write = log_write; vmprim.log_write = log_write;
vmprim.syserrstrb = syserrstrb; vmprim.syserrstrb = syserrstrb;
vmprim.vm_startup = vm_startup;
vmprim.vm_cleanup = vm_cleanup;
vmprim.vm_gettime = vm_gettime;
vmprim.vm_sleep = vm_sleep;
hcl = hcl_open (&sys_mmgr, HCL_SIZEOF(xtn_t), 2048000lu, &vmprim, HCL_NULL); hcl = hcl_open (&sys_mmgr, HCL_SIZEOF(xtn_t), 2048000lu, &vmprim, HCL_NULL);
if (!hcl) if (!hcl)