added more vm primitives
This commit is contained in:
parent
49363231a1
commit
95b4c5e0d7
@ -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])
|
||||||
|
|
||||||
|
179
lib/exec.c
179
lib/exec.c
@ -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)
|
||||||
|
@ -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
|
||||||
|
18
lib/hcl.h
18
lib/hcl.h
@ -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 == */
|
||||||
|
318
lib/main.c
318
lib/main.c
@ -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);
|
||||||
@ -906,8 +1218,12 @@ 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)
|
||||||
|
Loading…
Reference in New Issue
Block a user