2018-11-07 15:26:30 +00:00
|
|
|
/*
|
|
|
|
* $Id$
|
|
|
|
*
|
2019-11-19 09:40:26 +00:00
|
|
|
Copyright (c) 2014-2019 Chung, Hyung-Hwan. All rights reserved.
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
|
|
modification, are permitted provided that the following conditions
|
|
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer.
|
|
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
notice, this list of conditions and the following disclaimer in the
|
|
|
|
documentation and/or other materials provided with the distribution.
|
|
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
|
|
|
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
|
|
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
|
|
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2018-11-11 16:53:21 +00:00
|
|
|
#include <moo-std.h>
|
2018-11-07 15:26:30 +00:00
|
|
|
#include "moo-prv.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2018-11-13 07:40:30 +00:00
|
|
|
#include <string.h>
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-11-03 09:15:24 +00:00
|
|
|
#if !defined(__DOS__) && !defined(EMSCRIPTEN) && defined(HAVE_PTHREAD) && defined(HAVE_STRERROR_R)
|
2018-11-07 15:26:30 +00:00
|
|
|
# define USE_THREAD
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
2018-11-27 14:43:15 +00:00
|
|
|
# if !defined(_WIN32_WINNT)
|
|
|
|
# define _WIN32_WINNT 0x0400
|
|
|
|
# endif
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
# include <windows.h>
|
2019-03-29 00:04:29 +00:00
|
|
|
# if !(defined(__BORLANDC__) && (__BORLANDC__ <= 0x0520))
|
|
|
|
# include <psapi.h>
|
|
|
|
# endif
|
2018-11-07 15:26:30 +00:00
|
|
|
# include <tchar.h>
|
|
|
|
# include <time.h>
|
|
|
|
# include <io.h>
|
|
|
|
# include <fcntl.h>
|
2019-10-11 03:30:00 +00:00
|
|
|
# include <signal.h>
|
2018-11-07 15:26:30 +00:00
|
|
|
# include <errno.h>
|
|
|
|
# if defined(MOO_HAVE_CFG_H) && defined(MOO_ENABLE_LIBLTDL)
|
|
|
|
# include <ltdl.h>
|
|
|
|
# define USE_LTDL
|
|
|
|
# else
|
|
|
|
# define USE_WIN_DLL
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# include "poll-msw.h"
|
|
|
|
# define USE_POLL
|
|
|
|
# define XPOLLIN POLLIN
|
|
|
|
# define XPOLLOUT POLLOUT
|
|
|
|
# define XPOLLERR POLLERR
|
|
|
|
# define XPOLLHUP POLLHUP
|
|
|
|
|
2019-03-28 23:52:56 +00:00
|
|
|
#if !defined(SIZE_T)
|
|
|
|
# define SIZE_T unsigned long int
|
|
|
|
#endif
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(__OS2__)
|
|
|
|
# define INCL_DOSMODULEMGR
|
|
|
|
# define INCL_DOSPROCESS
|
|
|
|
# define INCL_DOSSEMAPHORES
|
|
|
|
# define INCL_DOSEXCEPTIONS
|
|
|
|
# define INCL_DOSMISC
|
|
|
|
# define INCL_DOSDATETIME
|
|
|
|
# define INCL_DOSFILEMGR
|
|
|
|
# define INCL_DOSERRORS
|
|
|
|
# include <os2.h>
|
|
|
|
# include <time.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <io.h>
|
|
|
|
# include <errno.h>
|
|
|
|
|
2021-03-30 06:11:20 +00:00
|
|
|
# include <types.h> /* some types for socket.h */
|
|
|
|
# include <sys/socket.h> /* for socketpair */
|
|
|
|
# include <sys/time.h>
|
|
|
|
# include <sys/ioctl.h> /* FIONBIO */
|
|
|
|
# include <nerrno.h> /* for SOCEXXX error codes */
|
|
|
|
|
|
|
|
# define BSD_SELECT
|
|
|
|
# if defined(TCPV40HDRS)
|
|
|
|
# include <sys/select.h>
|
|
|
|
# include <sys/un.h> /* for sockaddr_un */
|
|
|
|
# else
|
|
|
|
# include <unistd.h>
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# define USE_SELECT
|
2018-11-07 15:26:30 +00:00
|
|
|
/* fake XPOLLXXX values */
|
|
|
|
# define XPOLLIN (1 << 0)
|
|
|
|
# define XPOLLOUT (1 << 1)
|
|
|
|
# define XPOLLERR (1 << 2)
|
|
|
|
# define XPOLLHUP (1 << 3)
|
|
|
|
|
|
|
|
#elif defined(__DOS__)
|
|
|
|
# include <dos.h>
|
|
|
|
# include <time.h>
|
|
|
|
# include <io.h>
|
|
|
|
# include <signal.h>
|
|
|
|
# include <errno.h>
|
2018-11-30 15:19:33 +00:00
|
|
|
# include <fcntl.h>
|
2018-12-04 08:40:59 +00:00
|
|
|
# include <conio.h> /* inp, outp */
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
# if defined(_INTELC32_)
|
|
|
|
# define DOS_EXIT 0x4C
|
2018-12-02 05:57:10 +00:00
|
|
|
# include <i32.h>
|
|
|
|
# include <stk.h>
|
2018-11-07 15:26:30 +00:00
|
|
|
# else
|
|
|
|
# include <dosfunc.h>
|
|
|
|
# endif
|
|
|
|
|
|
|
|
/* fake XPOLLXXX values */
|
|
|
|
# define XPOLLIN (1 << 0)
|
|
|
|
# define XPOLLOUT (1 << 1)
|
|
|
|
# define XPOLLERR (1 << 2)
|
|
|
|
# define XPOLLHUP (1 << 3)
|
|
|
|
|
|
|
|
#elif defined(macintosh)
|
|
|
|
# include <Types.h>
|
|
|
|
# include <OSUtils.h>
|
|
|
|
# include <Timer.h>
|
|
|
|
|
|
|
|
# include <MacErrors.h>
|
|
|
|
# include <Process.h>
|
|
|
|
# include <Dialogs.h>
|
|
|
|
# include <TextUtils.h>
|
|
|
|
|
|
|
|
/* TODO: a lot to do */
|
|
|
|
|
|
|
|
#elif defined(vms) || defined(__vms)
|
|
|
|
# define __NEW_STARLET 1
|
|
|
|
# include <starlet.h> /* (SYS$...) */
|
|
|
|
# include <ssdef.h> /* (SS$...) */
|
|
|
|
# include <lib$routines.h> /* (lib$...) */
|
|
|
|
|
|
|
|
/* TODO: a lot to do */
|
|
|
|
|
|
|
|
#else
|
|
|
|
# include <sys/types.h>
|
|
|
|
# include <unistd.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <errno.h>
|
|
|
|
|
|
|
|
# if defined(MOO_ENABLE_LIBLTDL)
|
|
|
|
# include <ltdl.h>
|
|
|
|
# define USE_LTDL
|
|
|
|
# elif defined(HAVE_DLFCN_H)
|
|
|
|
# include <dlfcn.h>
|
|
|
|
# define USE_DLFCN
|
|
|
|
# elif defined(__APPLE__) || defined(__MACOSX__)
|
|
|
|
# define USE_MACH_O_DYLD
|
|
|
|
# include <mach-o/dyld.h>
|
|
|
|
# else
|
|
|
|
# error UNSUPPORTED DYNAMIC LINKER
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(HAVE_TIME_H)
|
|
|
|
# include <time.h>
|
|
|
|
# endif
|
|
|
|
# if defined(HAVE_SYS_TIME_H)
|
|
|
|
# include <sys/time.h>
|
|
|
|
# endif
|
|
|
|
# if defined(HAVE_SIGNAL_H)
|
|
|
|
# include <signal.h>
|
|
|
|
# endif
|
|
|
|
# if defined(HAVE_SYS_MMAN_H)
|
|
|
|
# include <sys/mman.h>
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(USE_THREAD)
|
|
|
|
# include <pthread.h>
|
|
|
|
# include <sched.h>
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# if defined(HAVE_SYS_DEVPOLL_H)
|
|
|
|
/* solaris */
|
|
|
|
# include <sys/devpoll.h>
|
|
|
|
# define USE_DEVPOLL
|
|
|
|
# define XPOLLIN POLLIN
|
|
|
|
# define XPOLLOUT POLLOUT
|
|
|
|
# define XPOLLERR POLLERR
|
|
|
|
# define XPOLLHUP POLLHUP
|
2019-09-23 08:44:22 +00:00
|
|
|
# elif defined(HAVE_SYS_EVENT_H) && defined(HAVE_KQUEUE)
|
2019-09-25 10:05:39 +00:00
|
|
|
/* netbsd, openbsd, etc */
|
2019-09-23 08:44:22 +00:00
|
|
|
# include <sys/event.h>
|
|
|
|
# define USE_KQUEUE
|
|
|
|
/* fake XPOLLXXX values */
|
|
|
|
# define XPOLLIN (1 << 0)
|
|
|
|
# define XPOLLOUT (1 << 1)
|
|
|
|
# define XPOLLERR (1 << 2)
|
|
|
|
# define XPOLLHUP (1 << 3)
|
|
|
|
# elif defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
|
2018-11-07 15:26:30 +00:00
|
|
|
/* linux */
|
|
|
|
# include <sys/epoll.h>
|
|
|
|
# define USE_EPOLL
|
|
|
|
# define XPOLLIN EPOLLIN
|
|
|
|
# define XPOLLOUT EPOLLOUT
|
|
|
|
# define XPOLLERR EPOLLERR
|
|
|
|
# define XPOLLHUP EPOLLHUP
|
|
|
|
# elif defined(HAVE_POLL_H)
|
|
|
|
# include <poll.h>
|
|
|
|
# define USE_POLL
|
|
|
|
# define XPOLLIN POLLIN
|
|
|
|
# define XPOLLOUT POLLOUT
|
|
|
|
# define XPOLLERR POLLERR
|
|
|
|
# define XPOLLHUP POLLHUP
|
|
|
|
# else
|
|
|
|
# define USE_SELECT
|
|
|
|
/* fake XPOLLXXX values */
|
|
|
|
# define XPOLLIN (1 << 0)
|
|
|
|
# define XPOLLOUT (1 << 1)
|
|
|
|
# define XPOLLERR (1 << 2)
|
|
|
|
# define XPOLLHUP (1 << 3)
|
|
|
|
# endif
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(MOO_DEFAULT_PFMODDIR)
|
|
|
|
# define MOO_DEFAULT_PFMODDIR ""
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(MOO_DEFAULT_PFMODPREFIX)
|
|
|
|
# if defined(_WIN32)
|
|
|
|
# define MOO_DEFAULT_PFMODPREFIX "moo-"
|
|
|
|
# elif defined(__OS2__)
|
|
|
|
# define MOO_DEFAULT_PFMODPREFIX "moo"
|
|
|
|
# elif defined(__DOS__)
|
|
|
|
# define MOO_DEFAULT_PFMODPREFIX "moo"
|
|
|
|
# else
|
|
|
|
# define MOO_DEFAULT_PFMODPREFIX "libmoo-"
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(MOO_DEFAULT_PFMODPOSTFIX)
|
|
|
|
# if defined(_WIN32)
|
|
|
|
# define MOO_DEFAULT_PFMODPOSTFIX ""
|
|
|
|
# elif defined(__OS2__)
|
|
|
|
# define MOO_DEFAULT_PFMODPOSTFIX ""
|
|
|
|
# elif defined(__DOS__)
|
|
|
|
# define MOO_DEFAULT_PFMODPOSTFIX ""
|
|
|
|
# else
|
|
|
|
# if defined(USE_DLFCN)
|
|
|
|
# define MOO_DEFAULT_PFMODPOSTFIX ".so"
|
|
|
|
# elif defined(USE_MACH_O_DYLD)
|
|
|
|
# define MOO_DEFAULT_PFMODPOSTFIX ".dylib"
|
|
|
|
# else
|
|
|
|
# define MOO_DEFAULT_PFMODPOSTFIX ""
|
|
|
|
# endif
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
# define MUTEX_INIT(x) pthread_mutex_init((x), MOO_NULL)
|
|
|
|
# define MUTEX_DESTROY(x) pthread_mutex_destroy(x)
|
|
|
|
# define MUTEX_LOCK(x) pthread_mutex_lock(x)
|
|
|
|
# define MUTEX_UNLOCK(x) pthread_mutex_unlock(x)
|
|
|
|
#else
|
|
|
|
# define MUTEX_INIT(x)
|
|
|
|
# define MUTEX_DESTROY(x)
|
|
|
|
# define MUTEX_LOCK(x)
|
|
|
|
# define MUTEX_UNLOCK(x)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef struct bb_t bb_t;
|
|
|
|
struct bb_t
|
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
char buf[MOO_IOBUF_CAPA];
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_oow_t pos;
|
|
|
|
moo_oow_t len;
|
|
|
|
|
|
|
|
FILE* fp;
|
|
|
|
moo_bch_t* fn;
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_cmgr_t* cmgr;
|
2018-11-07 15:26:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#if defined(USE_SELECT)
|
|
|
|
struct select_fd_t
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
int events;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
enum logfd_flag_t
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
|
|
|
LOGFD_TTY = (1 << 0),
|
2018-11-13 06:54:30 +00:00
|
|
|
LOGFD_OPENED_HERE = (1 << 1)
|
2018-11-11 16:53:21 +00:00
|
|
|
};
|
|
|
|
|
2018-11-12 09:19:35 +00:00
|
|
|
typedef struct xtn_t xtn_t;
|
|
|
|
struct xtn_t
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-11 16:53:21 +00:00
|
|
|
moo_t* next;
|
|
|
|
moo_t* prev;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
int vm_running;
|
2018-11-19 15:52:26 +00:00
|
|
|
int rcv_tick;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-05-18 18:01:02 +00:00
|
|
|
moo_cmgr_t* input_cmgr;
|
|
|
|
moo_cmgr_t* log_cmgr;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
struct
|
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
int fd;
|
|
|
|
int fd_flag; /* bitwise OR'ed fo logfd_flag_t bits */
|
|
|
|
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
moo_bch_t buf[4096];
|
|
|
|
moo_oow_t len;
|
|
|
|
} out;
|
|
|
|
} log;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
const moo_iostd_t* in;
|
2018-11-12 09:19:35 +00:00
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
HANDLE waitable_timer;
|
|
|
|
DWORD tc_last;
|
|
|
|
DWORD tc_overflow;
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
ULONG tc_last;
|
2018-12-01 14:52:24 +00:00
|
|
|
moo_ntime_t tc_last_ret;
|
2018-11-30 14:18:35 +00:00
|
|
|
#elif defined(__DOS__)
|
|
|
|
clock_t tc_last;
|
2018-12-01 06:15:31 +00:00
|
|
|
moo_ntime_t tc_last_ret;
|
2018-11-07 15:26:30 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
int ep; /* /dev/poll */
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
int ep; /* kqueue */
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
int ep; /* epoll */
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
/* nothing */
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
/* nothing */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_THREAD)
|
2018-11-13 07:40:30 +00:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
int p[2]; /* pipe for signaling */
|
|
|
|
pthread_t thr;
|
|
|
|
int up;
|
|
|
|
int abort;
|
|
|
|
} iothr;
|
2018-11-07 15:26:30 +00:00
|
|
|
#endif
|
|
|
|
|
2019-08-15 15:55:06 +00:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
int p[2]; /* pipe for signaling */
|
|
|
|
} sigfd;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
/*TODO: make it dynamically changeable depending on the number of
|
|
|
|
* file descriptors added */
|
|
|
|
struct pollfd buf[64]; /* buffer for reading events */
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
2019-09-25 10:05:39 +00:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
moo_oow_t* ptr;
|
|
|
|
moo_oow_t capa;
|
|
|
|
} reg;
|
2019-09-23 08:44:22 +00:00
|
|
|
struct kevent buf[64];
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
/*TODO: make it dynamically changeable depending on the number of
|
|
|
|
* file descriptors added */
|
|
|
|
struct epoll_event buf[64]; /* buffer for reading events */
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
struct pollfd* ptr;
|
|
|
|
moo_oow_t capa;
|
|
|
|
moo_oow_t len;
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
pthread_mutex_t pmtx;
|
|
|
|
#endif
|
2019-09-23 08:44:22 +00:00
|
|
|
} reg; /* registry */
|
2018-11-07 15:26:30 +00:00
|
|
|
struct pollfd* buf;
|
|
|
|
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
fd_set rfds;
|
|
|
|
fd_set wfds;
|
|
|
|
int maxfd;
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
pthread_mutex_t smtx;
|
|
|
|
#endif
|
|
|
|
} reg;
|
|
|
|
|
|
|
|
struct select_fd_t buf[FD_SETSIZE];
|
|
|
|
#endif
|
|
|
|
|
|
|
|
moo_oow_t len;
|
|
|
|
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
pthread_mutex_t mtx;
|
|
|
|
pthread_cond_t cnd;
|
|
|
|
pthread_cond_t cnd2;
|
|
|
|
#endif
|
2019-09-03 06:33:58 +00:00
|
|
|
|
|
|
|
int halting;
|
2018-11-07 15:26:30 +00:00
|
|
|
} ev;
|
|
|
|
};
|
|
|
|
|
2019-06-21 07:21:58 +00:00
|
|
|
#define GET_XTN(moo) ((xtn_t*)((moo_uint8_t*)moo_getxtn(moo) - MOO_SIZEOF(xtn_t)))
|
2018-11-11 16:53:21 +00:00
|
|
|
|
|
|
|
static moo_t* g_moo = MOO_NULL;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
static void* sys_alloc (moo_mmgr_t* mmgr, moo_oow_t size)
|
|
|
|
{
|
2019-11-17 16:23:30 +00:00
|
|
|
return malloc(size);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void* sys_realloc (moo_mmgr_t* mmgr, void* ptr, moo_oow_t size)
|
|
|
|
{
|
2019-11-17 16:23:30 +00:00
|
|
|
return realloc(ptr, size);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void sys_free (moo_mmgr_t* mmgr, void* ptr)
|
|
|
|
{
|
|
|
|
free (ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static moo_mmgr_t sys_mmgr =
|
|
|
|
{
|
|
|
|
sys_alloc,
|
|
|
|
sys_realloc,
|
|
|
|
sys_free,
|
|
|
|
MOO_NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
|
|
|
# define IS_PATH_SEP(c) ((c) == '/' || (c) == '\\')
|
|
|
|
#else
|
|
|
|
# define IS_PATH_SEP(c) ((c) == '/')
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* TODO: handle path with a drive letter or in the UNC notation */
|
|
|
|
#define IS_PATH_ABSOLUTE(x) IS_PATH_SEP(x[0])
|
|
|
|
|
|
|
|
static const moo_bch_t* get_base_name (const moo_bch_t* path)
|
|
|
|
{
|
|
|
|
const moo_bch_t* p, * last = MOO_NULL;
|
|
|
|
|
|
|
|
for (p = path; *p != '\0'; p++)
|
|
|
|
{
|
|
|
|
if (IS_PATH_SEP(*p)) last = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (last == MOO_NULL)? path: (last + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE moo_ooi_t open_input (moo_t* moo, moo_ioarg_t* arg)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
bb_t* bb = MOO_NULL;
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_bch_t* at;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
/* TOOD: support predefined include directory as well */
|
|
|
|
if (arg->includer)
|
|
|
|
{
|
|
|
|
/* includee */
|
|
|
|
moo_oow_t ucslen, bcslen, parlen;
|
|
|
|
const moo_bch_t* fn, * fb;
|
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
2019-05-18 18:01:02 +00:00
|
|
|
if (moo_convootobcstr(moo, arg->name, &ucslen, MOO_NULL, &bcslen) <= -1) goto oops;
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
bcslen = moo_count_bcstr(arg->name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
fn = ((bb_t*)arg->includer->handle)->fn;
|
|
|
|
|
|
|
|
fb = get_base_name(fn);
|
|
|
|
parlen = fb - fn;
|
|
|
|
|
|
|
|
bb = moo_callocmem(moo, MOO_SIZEOF(*bb) + (MOO_SIZEOF(moo_bch_t) * (parlen + bcslen + 1)));
|
|
|
|
if (!bb) goto oops;
|
|
|
|
|
|
|
|
bb->fn = (moo_bch_t*)(bb + 1);
|
|
|
|
moo_copy_bchars (bb->fn, fn, parlen);
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
2019-05-18 18:01:02 +00:00
|
|
|
moo_convootobcstr (moo, arg->name, &ucslen, &bb->fn[parlen], &bcslen);
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
moo_copy_bcstr (&bb->fn[parlen], bcslen + 1, arg->name);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* main stream */
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_oow_t ucslen, bcslen;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
switch (xtn->in->type)
|
2018-11-12 09:19:35 +00:00
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
#if defined(MOO_OOCH_IS_BCH)
|
|
|
|
case MOO_IOSTD_FILE:
|
|
|
|
MOO_ASSERT (moo, &xtn->in->u.fileb.path == &xtn->in->u.file.path);
|
|
|
|
#endif
|
2018-11-12 09:19:35 +00:00
|
|
|
case MOO_IOSTD_FILEB:
|
2018-11-13 06:54:30 +00:00
|
|
|
bcslen = moo_count_bcstr(xtn->in->u.fileb.path);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
bb = moo_callocmem(moo, MOO_SIZEOF(*bb) + (MOO_SIZEOF(moo_bch_t) * (bcslen + 1)));
|
2018-11-12 09:19:35 +00:00
|
|
|
if (!bb) goto oops;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-12 09:19:35 +00:00
|
|
|
bb->fn = (moo_bch_t*)(bb + 1);
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_copy_bcstr (bb->fn, bcslen + 1, xtn->in->u.fileb.path);
|
2019-05-14 15:54:16 +00:00
|
|
|
|
2018-11-12 09:19:35 +00:00
|
|
|
break;
|
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
2018-11-12 09:19:35 +00:00
|
|
|
case MOO_IOSTD_FILE:
|
2018-11-13 06:54:30 +00:00
|
|
|
MOO_ASSERT (moo, &xtn->in->u.fileu.path == &xtn->in->u.file.path);
|
|
|
|
#endif
|
2018-11-12 09:19:35 +00:00
|
|
|
case MOO_IOSTD_FILEU:
|
2018-11-13 06:54:30 +00:00
|
|
|
if (moo_convutobcstr(moo, xtn->in->u.fileu.path, &ucslen, MOO_NULL, &bcslen) <= -1)
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, moo_geterrnum(moo), "unable to convert encoding of path %ls", xtn->in->u.fileu.path);
|
|
|
|
goto oops;
|
|
|
|
}
|
|
|
|
|
|
|
|
bb = moo_callocmem(moo, MOO_SIZEOF(*bb) + (MOO_SIZEOF(moo_bch_t) * (bcslen + 1)));
|
|
|
|
if (!bb) goto oops;
|
|
|
|
|
|
|
|
bb->fn = (moo_bch_t*)(bb + 1);
|
|
|
|
bcslen += 1;
|
|
|
|
moo_convutobcstr (moo, xtn->in->u.fileu.path, &ucslen, bb->fn, &bcslen);
|
2019-05-14 10:22:37 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
break;
|
2018-11-12 09:19:35 +00:00
|
|
|
|
|
|
|
default:
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unsupported standard input type - %d", (int)xtn->in->type);
|
2018-11-12 09:19:35 +00:00
|
|
|
goto oops;
|
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
|
2019-05-14 10:22:37 +00:00
|
|
|
/* the path name can be appened with @encoding */
|
|
|
|
at = moo_find_bchar_in_bcstr(bb->fn, '@');
|
|
|
|
if (at && at[1] != '\0')
|
|
|
|
{
|
|
|
|
*at = '\0';
|
|
|
|
bb->cmgr = moo_get_cmgr_by_bcstr(at + 1);
|
2019-05-18 18:01:02 +00:00
|
|
|
if (!bb->cmgr)
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unsupported charset - %hs", at + 1);
|
|
|
|
goto oops;
|
|
|
|
}
|
2019-05-14 10:22:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-05-18 18:01:02 +00:00
|
|
|
bb->cmgr = arg->includer? ((bb_t*)arg->includer->handle)->cmgr: xtn->in->cmgr;
|
|
|
|
if (!bb->cmgr) bb->cmgr = xtn->input_cmgr;
|
2019-05-14 10:22:37 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
/* TODO: support _wfopen or the like */
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(_WIN32) || defined(__OS2__) || defined(__DOS__)
|
|
|
|
bb->fp = fopen(bb->fn, "rb");
|
|
|
|
#else
|
|
|
|
bb->fp = fopen(bb->fn, "r");
|
|
|
|
#endif
|
|
|
|
if (!bb->fp)
|
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_seterrbfmtwithsyserr (moo, 0, errno, "unable to open file %hs", bb->fn);
|
2018-11-07 15:26:30 +00:00
|
|
|
goto oops;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg->handle = bb;
|
2019-07-10 09:19:38 +00:00
|
|
|
if (!arg->name)
|
|
|
|
{
|
|
|
|
/* for the top-level stream, i simply change the arg->name field
|
|
|
|
* so that the compiler knows the file to be read */
|
|
|
|
moo_oocs_t io_name;
|
|
|
|
|
|
|
|
io_name.ptr = moo_dupbtooocstr(moo, get_base_name(bb->fn), &io_name.len);
|
|
|
|
if (!io_name.ptr) goto oops;
|
|
|
|
|
|
|
|
arg->name = moo_addcioname(moo, &io_name);
|
|
|
|
moo_freemem (moo, io_name.ptr);
|
|
|
|
|
|
|
|
if (!arg->name) goto oops;
|
|
|
|
}
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
oops:
|
|
|
|
if (bb)
|
|
|
|
{
|
|
|
|
if (bb->fp) fclose (bb->fp);
|
|
|
|
moo_freemem (moo, bb);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE moo_ooi_t close_input (moo_t* moo, moo_ioarg_t* arg)
|
|
|
|
{
|
|
|
|
bb_t* bb;
|
|
|
|
|
|
|
|
bb = (bb_t*)arg->handle;
|
|
|
|
MOO_ASSERT (moo, bb != MOO_NULL && bb->fp != MOO_NULL);
|
|
|
|
|
|
|
|
fclose (bb->fp);
|
|
|
|
moo_freemem (moo, bb);
|
|
|
|
|
|
|
|
arg->handle = MOO_NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE moo_ooi_t read_input (moo_t* moo, moo_ioarg_t* arg)
|
|
|
|
{
|
|
|
|
bb_t* bb;
|
|
|
|
moo_oow_t bcslen, ucslen, remlen;
|
|
|
|
int x;
|
|
|
|
|
|
|
|
bb = (bb_t*)arg->handle;
|
|
|
|
MOO_ASSERT (moo, bb != MOO_NULL && bb->fp != MOO_NULL);
|
|
|
|
do
|
|
|
|
{
|
2019-05-03 00:43:28 +00:00
|
|
|
x = fgetc(bb->fp);
|
2018-11-07 15:26:30 +00:00
|
|
|
if (x == EOF)
|
|
|
|
{
|
|
|
|
if (ferror((FILE*)bb->fp))
|
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_seterrbfmtwithsyserr (moo, 0, errno, "unable to read file %hs", bb->fn);
|
2018-11-07 15:26:30 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
bb->buf[bb->len++] = x;
|
|
|
|
}
|
|
|
|
while (bb->len < MOO_COUNTOF(bb->buf) && x != '\r' && x != '\n');
|
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
bcslen = bb->len;
|
|
|
|
ucslen = MOO_COUNTOF(arg->buf);
|
2019-05-14 10:22:37 +00:00
|
|
|
/*x = moo_convbtooochars(moo, bb->buf, &bcslen, arg->buf, &ucslen);*/
|
|
|
|
x = moo_conv_bchars_to_uchars_with_cmgr(bb->buf, &bcslen, arg->buf, &ucslen, bb->cmgr, 0);
|
|
|
|
if (x <= -1 /*&& ucslen <= 0 */)
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, (x == -2)? MOO_EBUFFULL: MOO_EECERR, "unable to convert source input - %.*hs", bcslen, bb->buf);
|
|
|
|
return -1;
|
|
|
|
}
|
2019-05-07 17:29:48 +00:00
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
/* if ucslen is greater than 0, i see that some characters have been
|
|
|
|
* converted properly */
|
|
|
|
#else
|
|
|
|
bcslen = (bb->len < MOO_COUNTOF(arg->buf))? bb->len: MOO_COUNTOF(arg->buf);
|
|
|
|
ucslen = bcslen;
|
|
|
|
moo_copy_bchars (arg->buf, bb->buf, bcslen);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
remlen = bb->len - bcslen;
|
2018-11-11 16:53:21 +00:00
|
|
|
if (remlen > 0) MOO_MEMMOVE (bb->buf, &bb->buf[bcslen], remlen);
|
2018-11-07 15:26:30 +00:00
|
|
|
bb->len = remlen;
|
|
|
|
return ucslen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static moo_ooi_t input_handler (moo_t* moo, moo_iocmd_t cmd, moo_ioarg_t* arg)
|
|
|
|
{
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case MOO_IO_OPEN:
|
2018-11-11 16:53:21 +00:00
|
|
|
return open_input(moo, arg);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
case MOO_IO_CLOSE:
|
2018-11-11 16:53:21 +00:00
|
|
|
return close_input(moo, arg);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
case MOO_IO_READ:
|
2018-11-11 16:53:21 +00:00
|
|
|
return read_input(moo, arg);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
moo_seterrnum (moo, MOO_EINTERN);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
2021-02-09 17:37:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
static int get_huge_page_size (moo_t* moo, moo_oow_t* page_size)
|
|
|
|
{
|
|
|
|
FILE* fp;
|
|
|
|
char buf[256];
|
|
|
|
|
|
|
|
fp = fopen("/proc/meminfo", "r");
|
|
|
|
if (!fp) return -1;
|
|
|
|
|
|
|
|
while (!feof(fp))
|
|
|
|
{
|
|
|
|
if (fgets(buf, sizeof(buf) - 1, fp) == NULL) goto oops;
|
|
|
|
|
|
|
|
if (strncmp(buf, "Hugepagesize: ", 13) == 0)
|
|
|
|
{
|
|
|
|
unsigned long int tmp;
|
|
|
|
tmp = strtoul(&buf[13], NULL, 10);
|
|
|
|
if (tmp == MOO_TYPE_MAX(unsigned long int) && errno == ERANGE) goto oops;
|
|
|
|
|
|
|
|
*page_size = tmp * 1024; /* KBytes to Bytes */
|
|
|
|
fclose (fp);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oops:
|
|
|
|
fclose (fp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* alloc_heap (moo_t* moo, moo_oow_t* size)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-27 09:56:59 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
moo_oow_t* ptr;
|
2021-02-09 17:37:45 +00:00
|
|
|
moo_oow_t req_size, align, aligned_size;
|
2018-11-27 09:56:59 +00:00
|
|
|
HINSTANCE k32;
|
|
|
|
SIZE_T (*k32_GetLargePageMinimum) (void);
|
2018-11-27 14:43:15 +00:00
|
|
|
HANDLE token = MOO_NULL;
|
|
|
|
TOKEN_PRIVILEGES new_state, prev_state;
|
|
|
|
TOKEN_PRIVILEGES* prev_state_ptr;
|
|
|
|
DWORD prev_state_reqsize = 0;
|
|
|
|
int token_adjusted = 0;
|
2018-11-27 09:56:59 +00:00
|
|
|
|
2021-02-09 17:37:45 +00:00
|
|
|
align = 2 * 1024 * 1024; /* default 2MB */
|
2018-11-27 09:56:59 +00:00
|
|
|
|
2018-11-27 14:43:15 +00:00
|
|
|
k32 = LoadLibrary(TEXT("kernel32.dll"));
|
2018-11-27 09:56:59 +00:00
|
|
|
if (k32)
|
|
|
|
{
|
|
|
|
k32_GetLargePageMinimum = (SIZE_T(*)(void))GetProcAddress (k32, "GetLargePageMinimum");
|
2021-02-09 17:37:45 +00:00
|
|
|
if (k32_GetLargePageMinimum) align = k32_GetLargePageMinimum();
|
2018-11-27 09:56:59 +00:00
|
|
|
FreeLibrary (k32);
|
|
|
|
}
|
2018-11-28 06:08:42 +00:00
|
|
|
/* the standard page size shouldn't help. so let me comment out this part.
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SYSTEM_INFO si;
|
|
|
|
GetSystemInfo (&si);
|
2021-02-09 17:37:45 +00:00
|
|
|
align = si.dwPageSize;
|
2018-11-28 06:08:42 +00:00
|
|
|
}*/
|
2018-11-27 09:56:59 +00:00
|
|
|
|
2021-02-09 17:37:45 +00:00
|
|
|
req_size = MOO_SIZEOF(moo_oow_t) + size;
|
|
|
|
aligned_size = MOO_ALIGN(req_size, align);
|
2018-11-27 09:56:59 +00:00
|
|
|
|
2018-11-27 14:43:15 +00:00
|
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) goto oops;
|
|
|
|
if (!LookupPrivilegeValue(MOO_NULL, TEXT("SeLockMemoryPrivilege"), &new_state.Privileges[0].Luid)) goto oops;
|
|
|
|
new_state.PrivilegeCount = 1;
|
|
|
|
new_state.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
2018-11-27 09:56:59 +00:00
|
|
|
|
2018-11-27 14:43:15 +00:00
|
|
|
prev_state_ptr = &prev_state;
|
|
|
|
if (!AdjustTokenPrivileges(token, FALSE, &new_state, MOO_SIZEOF(prev_state), prev_state_ptr, &prev_state_reqsize) || GetLastError() != ERROR_SUCCESS)
|
2018-11-27 09:56:59 +00:00
|
|
|
{
|
2018-11-27 14:43:15 +00:00
|
|
|
if (prev_state_reqsize >= MOO_SIZEOF(prev_state))
|
|
|
|
{
|
|
|
|
/* GetLastError() == ERROR_INSUFFICIENT_BUFFER */
|
|
|
|
prev_state_ptr = (TOKEN_PRIVILEGES*)HeapAlloc(GetProcessHeap(), 0, prev_state_reqsize);
|
|
|
|
if (!prev_state_ptr) goto oops;
|
|
|
|
if (!AdjustTokenPrivileges(token, FALSE, &new_state, prev_state_reqsize, prev_state_ptr, &prev_state_reqsize) || GetLastError() != ERROR_SUCCESS) goto oops;
|
|
|
|
}
|
|
|
|
else goto oops;
|
2018-11-27 09:56:59 +00:00
|
|
|
}
|
2018-11-27 14:43:15 +00:00
|
|
|
token_adjusted = 1;
|
2018-11-27 09:56:59 +00:00
|
|
|
|
2019-03-28 23:52:56 +00:00
|
|
|
#if !defined(MEM_LARGE_PAGES)
|
|
|
|
# define MEM_LARGE_PAGES (0x20000000)
|
|
|
|
#endif
|
2021-02-09 17:37:45 +00:00
|
|
|
ptr = VirtualAlloc(MOO_NULL, aligned_size, MEM_COMMIT | MEM_RESERVE | MEM_LARGE_PAGES, PAGE_READWRITE);
|
|
|
|
if (!ptr)
|
|
|
|
{
|
|
|
|
SYSTEM_INFO si;
|
|
|
|
GetSystemInfo (&si);
|
|
|
|
align = si.dwPageSize;
|
|
|
|
aligned_size = MOO_ALIGN(req_size, align);
|
|
|
|
ptr = VirtualAlloc(MOO_NULL, aligned_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
|
|
|
if (!ptr) goto oops;
|
|
|
|
}
|
2018-11-27 14:43:15 +00:00
|
|
|
|
|
|
|
AdjustTokenPrivileges (token, FALSE, prev_state_ptr, 0, MOO_NULL, 0);
|
|
|
|
CloseHandle (token);
|
|
|
|
if (prev_state_ptr && prev_state_ptr != &prev_state) HeapFree (GetProcessHeap(), 0, prev_state_ptr);
|
2021-02-09 17:37:45 +00:00
|
|
|
|
|
|
|
*size = aligned_size;
|
2018-11-27 09:56:59 +00:00
|
|
|
return ptr;
|
|
|
|
|
2018-11-27 14:43:15 +00:00
|
|
|
oops:
|
|
|
|
moo_seterrwithsyserr (moo, 1, GetLastError());
|
|
|
|
if (token)
|
|
|
|
{
|
|
|
|
if (token_adjusted) AdjustTokenPrivileges (token, FALSE, prev_state_ptr, 0, MOO_NULL, 0);
|
|
|
|
CloseHandle (token);
|
|
|
|
}
|
|
|
|
if (prev_state_ptr && prev_state_ptr != &prev_state) HeapFree (GetProcessHeap(), 0, prev_state_ptr);
|
|
|
|
return MOO_NULL;
|
|
|
|
|
2018-11-27 09:56:59 +00:00
|
|
|
#elif defined(HAVE_MMAP) && defined(HAVE_MUNMAP) && defined(MAP_ANONYMOUS)
|
2018-11-07 15:26:30 +00:00
|
|
|
/* It's called via moo_makeheap() when MOO creates a GC heap.
|
|
|
|
* The heap is large in size. I can use a different memory allocation
|
|
|
|
* function instead of an ordinary malloc.
|
|
|
|
* upon failure, it doesn't require to set error information as moo_makeheap()
|
|
|
|
* set the error number to MOO_EOOMEM. */
|
|
|
|
|
|
|
|
#if !defined(MAP_HUGETLB) && (defined(__amd64__) || defined(__x86_64__))
|
|
|
|
# define MAP_HUGETLB 0x40000
|
|
|
|
#endif
|
|
|
|
|
|
|
|
moo_oow_t* ptr;
|
|
|
|
int flags;
|
2021-02-09 17:37:45 +00:00
|
|
|
moo_oow_t req_size, align, aligned_size;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2021-02-09 17:37:45 +00:00
|
|
|
req_size = MOO_SIZEOF(moo_oow_t) + *size;
|
2018-11-07 15:26:30 +00:00
|
|
|
flags = MAP_PRIVATE | MAP_ANONYMOUS;
|
|
|
|
|
|
|
|
#if defined(MAP_UNINITIALIZED)
|
|
|
|
flags |= MAP_UNINITIALIZED;
|
|
|
|
#endif
|
|
|
|
|
2021-02-09 17:37:45 +00:00
|
|
|
#if defined(MAP_HUGETLB)
|
|
|
|
if (get_huge_page_size(moo, &align) <= -1) align = 2 * 1024 * 1024; /* default to 2MB */
|
|
|
|
if (req_size > align / 2)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2021-02-09 17:37:45 +00:00
|
|
|
/* if the requested size is large enough, attempt HUGETLB */
|
|
|
|
flags |= MAP_HUGETLB;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
align = sysconf(_SC_PAGESIZE);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
align = sysconf(_SC_PAGESIZE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
aligned_size = MOO_ALIGN_POW2(req_size, align);
|
|
|
|
ptr = (moo_oow_t*)mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(MAP_HUGETLB)
|
2021-02-09 17:37:45 +00:00
|
|
|
if (ptr == MAP_FAILED && (flags & MAP_HUGETLB))
|
|
|
|
{
|
2018-11-07 15:26:30 +00:00
|
|
|
flags &= ~MAP_HUGETLB;
|
2021-02-09 17:37:45 +00:00
|
|
|
align = sysconf(_SC_PAGESIZE);
|
|
|
|
aligned_size = MOO_ALIGN_POW2(req_size, align);
|
|
|
|
ptr = (moo_oow_t*)mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, flags, -1, 0);
|
2018-11-27 09:56:59 +00:00
|
|
|
if (ptr == MAP_FAILED)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
return MOO_NULL;
|
|
|
|
}
|
2021-02-09 17:37:45 +00:00
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
2021-02-09 17:37:45 +00:00
|
|
|
if (ptr == MAP_FAILED)
|
|
|
|
{
|
2018-11-27 09:56:59 +00:00
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
2018-11-07 15:26:30 +00:00
|
|
|
return MOO_NULL;
|
|
|
|
}
|
2021-02-09 17:37:45 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2021-02-09 17:37:45 +00:00
|
|
|
*ptr = aligned_size;
|
|
|
|
*size = aligned_size - MOO_SIZEOF(moo_oow_t);
|
2018-11-07 15:26:30 +00:00
|
|
|
return (void*)(ptr + 1);
|
|
|
|
|
|
|
|
#else
|
2021-02-09 17:37:45 +00:00
|
|
|
return MOO_MMGR_ALLOC(moo->_mmgr, *size);
|
2018-11-07 15:26:30 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void free_heap (moo_t* moo, void* ptr)
|
|
|
|
{
|
2018-11-27 09:56:59 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
VirtualFree (ptr, 0, MEM_RELEASE); /* release the entire region */
|
|
|
|
|
|
|
|
#elif defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_oow_t* actual_ptr;
|
|
|
|
actual_ptr = (moo_oow_t*)ptr - 1;
|
|
|
|
munmap (actual_ptr, *actual_ptr);
|
|
|
|
#else
|
2019-08-08 03:48:26 +00:00
|
|
|
MOO_MMGR_FREE(moo->_mmgr, ptr);
|
2018-11-07 15:26:30 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-11-03 09:15:24 +00:00
|
|
|
#if defined(EMSCRIPTEN)
|
2019-11-03 16:02:22 +00:00
|
|
|
EM_JS(int, write_all, (int, const moo_bch_t* ptr, moo_oow_t len), {
|
|
|
|
// UTF8ToString() doesn't handle a null byte in the middle of an array.
|
|
|
|
// Use the heap memory and pass the right portion to UTF8Decoder.
|
|
|
|
//console.log ("%s", UTF8ToString(ptr, len));
|
|
|
|
console.log ("%s", UTF8Decoder.decode(HEAPU8.subarray(ptr, ptr + len)));
|
|
|
|
return 0;
|
|
|
|
});
|
2019-11-03 09:15:24 +00:00
|
|
|
|
2019-11-03 16:02:22 +00:00
|
|
|
#else
|
2019-11-03 09:15:24 +00:00
|
|
|
|
2019-11-03 16:02:22 +00:00
|
|
|
static int write_all (int fd, const moo_bch_t* ptr, moo_oow_t len)
|
|
|
|
{
|
|
|
|
#if defined(EMSCRIPTEN)
|
|
|
|
EM_ASM_ ({
|
|
|
|
// UTF8ToString() doesn't handle a null byte in the middle of an array.
|
|
|
|
// Use the heap memory and pass the right portion to UTF8Decoder.
|
|
|
|
//console.log ("%s", UTF8ToString($0, $1));
|
|
|
|
console.log ("%s", UTF8Decoder.decode(HEAPU8.subarray($0, $0 + $1)));
|
|
|
|
}, ptr, len);
|
2019-11-03 09:15:24 +00:00
|
|
|
#else
|
2018-11-07 15:26:30 +00:00
|
|
|
while (len > 0)
|
|
|
|
{
|
|
|
|
moo_ooi_t wr;
|
|
|
|
|
|
|
|
wr = write(fd, ptr, len);
|
|
|
|
|
|
|
|
if (wr <= -1)
|
|
|
|
{
|
|
|
|
#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN == EWOULDBLOCK)
|
|
|
|
if (errno == EAGAIN) continue;
|
|
|
|
#else
|
|
|
|
#if defined(EAGAIN)
|
|
|
|
if (errno == EAGAIN) continue;
|
|
|
|
#elif defined(EWOULDBLOCK)
|
|
|
|
if (errno == EWOULDBLOCK) continue;
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(EINTR)
|
|
|
|
/* TODO: would this interfere with non-blocking nature of this VM? */
|
|
|
|
if (errno == EINTR) continue;
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr += wr;
|
|
|
|
len -= wr;
|
|
|
|
}
|
2019-11-03 09:15:24 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-11-03 16:02:22 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
static int write_log (moo_t* moo, int fd, const moo_bch_t* ptr, moo_oow_t len)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
while (len > 0)
|
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->log.out.len > 0)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
moo_oow_t rcapa, cplen;
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
rcapa = MOO_COUNTOF(xtn->log.out.buf) - xtn->log.out.len;
|
2018-11-07 15:26:30 +00:00
|
|
|
cplen = (len >= rcapa)? rcapa: len;
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
MOO_MEMCPY (&xtn->log.out.buf[xtn->log.out.len], ptr, cplen);
|
|
|
|
xtn->log.out.len += cplen;
|
2018-11-07 15:26:30 +00:00
|
|
|
ptr += cplen;
|
|
|
|
len -= cplen;
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->log.out.len >= MOO_COUNTOF(xtn->log.out.buf))
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
int n;
|
2018-11-13 07:40:30 +00:00
|
|
|
n = write_all(fd, xtn->log.out.buf, xtn->log.out.len);
|
|
|
|
xtn->log.out.len = 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
if (n <= -1) return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
moo_oow_t rcapa;
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
rcapa = MOO_COUNTOF(xtn->log.out.buf);
|
2018-11-07 15:26:30 +00:00
|
|
|
if (len >= rcapa)
|
|
|
|
{
|
|
|
|
if (write_all(fd, ptr, rcapa) <= -1) return -1;
|
|
|
|
ptr += rcapa;
|
|
|
|
len -= rcapa;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
MOO_MEMCPY (xtn->log.out.buf, ptr, len);
|
|
|
|
xtn->log.out.len += len;
|
2018-11-07 15:26:30 +00:00
|
|
|
ptr += len;
|
|
|
|
len -= len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void flush_log (moo_t* moo, int fd)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->log.out.len > 0)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
write_all (fd, xtn->log.out.buf, xtn->log.out.len);
|
|
|
|
xtn->log.out.len = 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void log_write (moo_t* moo, moo_bitmask_t mask, const moo_ooch_t* msg, moo_oow_t len)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_bch_t buf[256];
|
|
|
|
moo_oow_t ucslen, bcslen, msgidx;
|
2018-11-12 09:19:35 +00:00
|
|
|
int n, logfd;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-04-16 15:43:54 +00:00
|
|
|
if (mask & MOO_LOG_STDERR) logfd = 2;
|
|
|
|
else if (mask & MOO_LOG_STDOUT) logfd = 1;
|
2018-11-07 15:26:30 +00:00
|
|
|
else
|
|
|
|
{
|
2019-04-16 15:43:54 +00:00
|
|
|
logfd = xtn->log.fd;
|
2019-11-03 09:15:24 +00:00
|
|
|
#if !defined(EMSCRIPTEN)
|
2019-04-16 15:43:54 +00:00
|
|
|
if (logfd <= -1) return;
|
2019-11-03 09:15:24 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: beautify the log message.
|
|
|
|
* do classification based on mask. */
|
|
|
|
if (!(mask & (MOO_LOG_STDOUT | MOO_LOG_STDERR)))
|
|
|
|
{
|
2019-11-08 04:11:57 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
TIME_ZONE_INFORMATION tzi;
|
|
|
|
SYSTEMTIME now;
|
|
|
|
#else
|
2018-11-07 15:26:30 +00:00
|
|
|
time_t now;
|
2019-11-08 04:11:57 +00:00
|
|
|
struct tm tm, *tmp;
|
|
|
|
#endif
|
2019-05-18 18:01:02 +00:00
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
char ts[32 * MOO_BCSIZE_MAX];
|
|
|
|
#else
|
2018-11-07 15:26:30 +00:00
|
|
|
char ts[32];
|
2019-05-18 18:01:02 +00:00
|
|
|
#endif
|
2019-09-25 14:39:00 +00:00
|
|
|
moo_oow_t tslen;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32)
|
2019-11-08 04:11:57 +00:00
|
|
|
/* %z for strftime() in win32 seems to produce a long non-numeric timezone name.
|
|
|
|
* i don't use strftime() for time formatting. */
|
|
|
|
GetLocalTime (&now);
|
|
|
|
if (GetTimeZoneInformation(&tzi) != TIME_ZONE_ID_INVALID)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2019-11-08 04:11:57 +00:00
|
|
|
tzi.Bias = -tzi.Bias;
|
|
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d %+02.2d%02.2d ",
|
|
|
|
(int)now.wYear, (int)now.wMonth, (int)now.wDay,
|
|
|
|
(int)now.wHour, (int)now.wMinute, (int)now.wSecond,
|
|
|
|
(int)(tzi.Bias / 60), (int)(tzi.Bias % 60));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ",
|
|
|
|
(int)now.wYear, (int)now.wMonth, (int)now.wDay,
|
|
|
|
(int)now.wHour, (int)now.wMinute, (int)now.wSecond);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
2018-12-01 14:52:24 +00:00
|
|
|
#elif defined(__OS2__)
|
2019-11-08 04:11:57 +00:00
|
|
|
now = time(MOO_NULL);
|
|
|
|
|
2018-12-01 14:52:24 +00:00
|
|
|
#if defined(__WATCOMC__)
|
|
|
|
tmp = _localtime(&now, &tm);
|
|
|
|
#else
|
|
|
|
tmp = localtime(&now);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__BORLANDC__)
|
|
|
|
/* the borland compiler doesn't handle %z properly - it showed 00 all the time */
|
|
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp);
|
|
|
|
#else
|
|
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
|
|
|
|
#endif
|
|
|
|
if (tslen == 0)
|
|
|
|
{
|
|
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
|
|
|
}
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(__DOS__)
|
2019-11-08 04:11:57 +00:00
|
|
|
now = time(MOO_NULL);
|
2018-11-07 15:26:30 +00:00
|
|
|
tmp = localtime(&now);
|
2018-12-01 13:44:57 +00:00
|
|
|
/* since i know that %z/%Z is not available in strftime, i switch to sprintf immediately */
|
|
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
2019-11-08 04:11:57 +00:00
|
|
|
now = time(MOO_NULL);
|
2018-12-01 14:52:24 +00:00
|
|
|
#if defined(HAVE_LOCALTIME_R)
|
2018-11-07 15:26:30 +00:00
|
|
|
tmp = localtime_r(&now, &tm);
|
|
|
|
#else
|
|
|
|
tmp = localtime(&now);
|
|
|
|
#endif
|
2018-12-01 14:52:24 +00:00
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(HAVE_STRFTIME_SMALL_Z)
|
|
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %z ", tmp);
|
|
|
|
#else
|
|
|
|
tslen = strftime(ts, sizeof(ts), "%Y-%m-%d %H:%M:%S %Z ", tmp);
|
|
|
|
#endif
|
|
|
|
if (tslen == 0)
|
|
|
|
{
|
2018-12-01 13:44:57 +00:00
|
|
|
tslen = sprintf(ts, "%04d-%02d-%02d %02d:%02d:%02d ", tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
#endif
|
2019-05-18 18:01:02 +00:00
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
if (moo_getcmgr(moo) != xtn->log_cmgr)
|
|
|
|
{
|
|
|
|
moo_uch_t tsu[32];
|
|
|
|
moo_oow_t tsulen;
|
|
|
|
|
|
|
|
/* the timestamp is likely to contain simple ascii characters only.
|
|
|
|
* conversion is not likely to fail regardless of encodings.
|
|
|
|
* so i don't check errors here */
|
|
|
|
tsulen = MOO_COUNTOF(tsu);
|
|
|
|
moo_convbtooochars (moo, ts, &tslen, tsu, &tsulen);
|
|
|
|
tslen = MOO_COUNTOF(ts);
|
|
|
|
moo_conv_uchars_to_bchars_with_cmgr (tsu, &tsulen, ts, &tslen, xtn->log_cmgr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
write_log (moo, logfd, ts, tslen);
|
|
|
|
}
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
if (logfd == xtn->log.fd && (xtn->log.fd_flag & LOGFD_TTY))
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
if (mask & MOO_LOG_FATAL) write_log (moo, logfd, "\x1B[1;31m", 7);
|
|
|
|
else if (mask & MOO_LOG_ERROR) write_log (moo, logfd, "\x1B[1;32m", 7);
|
|
|
|
else if (mask & MOO_LOG_WARN) write_log (moo, logfd, "\x1B[1;33m", 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
msgidx = 0;
|
|
|
|
while (len > 0)
|
|
|
|
{
|
|
|
|
ucslen = len;
|
|
|
|
bcslen = MOO_COUNTOF(buf);
|
|
|
|
|
2019-05-18 18:01:02 +00:00
|
|
|
/*n = moo_convootobchars(moo, &msg[msgidx], &ucslen, buf, &bcslen);*/
|
|
|
|
n = moo_conv_uchars_to_bchars_with_cmgr(&msg[msgidx], &ucslen, buf, &bcslen, xtn->log_cmgr);
|
2018-11-07 15:26:30 +00:00
|
|
|
if (n == 0 || n == -2)
|
|
|
|
{
|
|
|
|
/* n = 0:
|
|
|
|
* converted all successfully
|
|
|
|
* n == -2:
|
|
|
|
* buffer not sufficient. not all got converted yet.
|
|
|
|
* write what have been converted this round. */
|
|
|
|
|
|
|
|
MOO_ASSERT (moo, ucslen > 0); /* if this fails, the buffer size must be increased */
|
|
|
|
|
|
|
|
/* attempt to write all converted characters */
|
|
|
|
if (write_log(moo, logfd, buf, bcslen) <= -1) break;
|
|
|
|
|
|
|
|
if (n == 0) break;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
msgidx += ucslen;
|
|
|
|
len -= ucslen;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (n <= -1)
|
|
|
|
{
|
2019-05-18 18:01:02 +00:00
|
|
|
/* conversion error but i just stop here but don't treat it as a hard error. */
|
2018-11-07 15:26:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
write_log (moo, logfd, msg, len);
|
|
|
|
#endif
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
if (logfd == xtn->log.fd && (xtn->log.fd_flag & LOGFD_TTY))
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
if (mask & (MOO_LOG_FATAL | MOO_LOG_ERROR | MOO_LOG_WARN)) write_log (moo, logfd, "\x1B[0m", 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
flush_log (moo, logfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
static moo_errnum_t errno_to_errnum (int errcode)
|
|
|
|
{
|
|
|
|
switch (errcode)
|
|
|
|
{
|
|
|
|
case ENOMEM: return MOO_ESYSMEM;
|
|
|
|
case EINVAL: return MOO_EINVAL;
|
|
|
|
|
|
|
|
#if defined(EBUSY)
|
|
|
|
case EBUSY: return MOO_EBUSY;
|
|
|
|
#endif
|
|
|
|
case EACCES: return MOO_EACCES;
|
|
|
|
#if defined(EPERM)
|
|
|
|
case EPERM: return MOO_EPERM;
|
|
|
|
#endif
|
|
|
|
#if defined(ENOTDIR)
|
|
|
|
case ENOTDIR: return MOO_ENOTDIR;
|
|
|
|
#endif
|
|
|
|
case ENOENT: return MOO_ENOENT;
|
|
|
|
#if defined(EEXIST)
|
|
|
|
case EEXIST: return MOO_EEXIST;
|
|
|
|
#endif
|
|
|
|
#if defined(EINTR)
|
|
|
|
case EINTR: return MOO_EINTR;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(EPIPE)
|
|
|
|
case EPIPE: return MOO_EPIPE;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(EAGAIN) && defined(EWOULDBLOCK) && (EAGAIN != EWOULDBLOCK)
|
|
|
|
case EAGAIN:
|
|
|
|
case EWOULDBLOCK: return MOO_EAGAIN;
|
|
|
|
#elif defined(EAGAIN)
|
|
|
|
case EAGAIN: return MOO_EAGAIN;
|
|
|
|
#elif defined(EWOULDBLOCK)
|
|
|
|
case EWOULDBLOCK: return MOO_EAGAIN;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(EBADF)
|
|
|
|
case EBADF: return MOO_EBADHND;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(EIO)
|
|
|
|
case EIO: return MOO_EIOERR;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default: return MOO_ESYSERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
static moo_errnum_t winerr_to_errnum (DWORD errcode)
|
|
|
|
{
|
|
|
|
switch (errcode)
|
|
|
|
{
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
|
|
case ERROR_OUTOFMEMORY:
|
|
|
|
return MOO_ESYSMEM;
|
|
|
|
|
|
|
|
case ERROR_INVALID_PARAMETER:
|
|
|
|
case ERROR_INVALID_NAME:
|
|
|
|
return MOO_EINVAL;
|
|
|
|
|
|
|
|
case ERROR_INVALID_HANDLE:
|
|
|
|
return MOO_EBADHND;
|
|
|
|
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
|
|
case ERROR_SHARING_VIOLATION:
|
|
|
|
return MOO_EACCES;
|
|
|
|
|
2018-11-27 09:56:59 +00:00
|
|
|
#if defined(ERROR_IO_PRIVILEGE_FAILED)
|
|
|
|
case ERROR_IO_PRIVILEGE_FAILED:
|
|
|
|
#endif
|
|
|
|
case ERROR_PRIVILEGE_NOT_HELD:
|
|
|
|
return MOO_EPERM;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
|
|
case ERROR_PATH_NOT_FOUND:
|
|
|
|
return MOO_ENOENT;
|
|
|
|
|
|
|
|
case ERROR_ALREADY_EXISTS:
|
|
|
|
case ERROR_FILE_EXISTS:
|
|
|
|
return MOO_EEXIST;
|
|
|
|
|
|
|
|
case ERROR_BROKEN_PIPE:
|
|
|
|
return MOO_EPIPE;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return MOO_ESYSERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(__OS2__)
|
|
|
|
static moo_errnum_t os2err_to_errnum (APIRET errcode)
|
|
|
|
{
|
|
|
|
/* APIRET e */
|
|
|
|
switch (errcode)
|
|
|
|
{
|
|
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
|
|
return MOO_ESYSMEM;
|
|
|
|
|
|
|
|
case ERROR_INVALID_PARAMETER:
|
|
|
|
case ERROR_INVALID_NAME:
|
|
|
|
return MOO_EINVAL;
|
|
|
|
|
|
|
|
case ERROR_INVALID_HANDLE:
|
|
|
|
return MOO_EBADHND;
|
|
|
|
|
|
|
|
case ERROR_ACCESS_DENIED:
|
|
|
|
case ERROR_SHARING_VIOLATION:
|
|
|
|
return MOO_EACCES;
|
|
|
|
|
|
|
|
case ERROR_FILE_NOT_FOUND:
|
|
|
|
case ERROR_PATH_NOT_FOUND:
|
|
|
|
return MOO_ENOENT;
|
|
|
|
|
|
|
|
case ERROR_ALREADY_EXISTS:
|
|
|
|
return MOO_EEXIST;
|
|
|
|
|
|
|
|
/*TODO: add more mappings */
|
|
|
|
default:
|
|
|
|
return MOO_ESYSERR;
|
|
|
|
}
|
|
|
|
}
|
2021-03-30 06:11:20 +00:00
|
|
|
#if !defined(TCPV40HDRS)
|
|
|
|
static moo_errnum_t os2sockerr_to_errnum (int errcode)
|
|
|
|
{
|
|
|
|
switch (errcode)
|
|
|
|
{
|
|
|
|
case SOCEPERM: return MOO_EPERM;
|
|
|
|
case SOCENOENT: return MOO_ENOENT;
|
|
|
|
case SOCEINTR: return MOO_EINTR;
|
|
|
|
case SOCEACCES: return MOO_EACCES;
|
|
|
|
case SOCEINVAL: return MOO_EINVAL;
|
|
|
|
case SOCENOMEM: return MOO_ESYSMEM;
|
|
|
|
case SOCEPIPE: return MOO_EPIPE;
|
|
|
|
default: return MOO_ESYSERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif /* TCPV40HDRS */
|
|
|
|
#endif /* __OS2__ */
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#if defined(macintosh)
|
|
|
|
static moo_errnum_t macerr_to_errnum (int errcode)
|
|
|
|
{
|
|
|
|
switch (e)
|
|
|
|
{
|
|
|
|
case notEnoughMemoryErr:
|
|
|
|
return MOO_ESYSMEM;
|
|
|
|
case paramErr:
|
|
|
|
return MOO_EINVAL;
|
|
|
|
|
|
|
|
case qErr: /* queue element not found during deletion */
|
|
|
|
case fnfErr: /* file not found */
|
|
|
|
case dirNFErr: /* direcotry not found */
|
|
|
|
case resNotFound: /* resource not found */
|
|
|
|
case resFNotFound: /* resource file not found */
|
|
|
|
case nbpNotFound: /* name not found on remove */
|
|
|
|
return MOO_ENOENT;
|
|
|
|
|
|
|
|
/*TODO: add more mappings */
|
|
|
|
default:
|
|
|
|
return MOO_ESYSERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static moo_errnum_t syserrstrb (moo_t* moo, int syserr_type, int syserr_code, moo_bch_t* buf, moo_oow_t len)
|
|
|
|
{
|
|
|
|
switch (syserr_type)
|
|
|
|
{
|
2021-03-30 06:11:20 +00:00
|
|
|
case 2:
|
|
|
|
#if defined(__OS2__)
|
|
|
|
#if defined(TCPV40HDRS)
|
|
|
|
if (buf)
|
|
|
|
{
|
|
|
|
char tmp[64];
|
|
|
|
sprintf (tmp, "socket error %d", (int)syserr_code);
|
|
|
|
moo_copy_bcstr (buf, len, tmp);
|
|
|
|
}
|
|
|
|
return MOO_ESYSERR;
|
|
|
|
#else
|
|
|
|
/* sock_strerror() available in tcpip32.dll only */
|
|
|
|
if (buf) moo_copy_bcstr (buf, len, sock_strerror(syserr_code));
|
|
|
|
return os2sockerr_to_errnum(syserr_code);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/* fall thru for other platforms */
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
case 1:
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (buf)
|
|
|
|
{
|
|
|
|
DWORD rc;
|
|
|
|
rc = FormatMessageA (
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, syserr_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
buf, len, MOO_NULL
|
|
|
|
);
|
|
|
|
while (rc > 0 && buf[rc - 1] == '\r' || buf[rc - 1] == '\n') buf[--rc] = '\0';
|
|
|
|
}
|
|
|
|
return winerr_to_errnum(syserr_code);
|
|
|
|
#elif defined(__OS2__)
|
2021-03-30 06:11:20 +00:00
|
|
|
if (buf)
|
|
|
|
{
|
|
|
|
char tmp[64];
|
|
|
|
sprintf (tmp, "system error %d", (int)syserr_code);
|
|
|
|
hcl_copy_bcstr (buf, len, tmp);
|
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
return os2err_to_errnum(syserr_code);
|
|
|
|
#elif defined(macintosh)
|
|
|
|
/* TODO: convert code to string */
|
|
|
|
if (buf) moo_copy_bcstr (buf, len, "system error");
|
|
|
|
return os2err_to_errnum(syserr_code);
|
|
|
|
#else
|
|
|
|
/* in other systems, errno is still the native system error code.
|
|
|
|
* fall thru */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case 0:
|
|
|
|
#if defined(HAVE_STRERROR_R)
|
|
|
|
if (buf) strerror_r (syserr_code, buf, len);
|
|
|
|
#else
|
|
|
|
/* this is not thread safe */
|
|
|
|
if (buf) moo_copy_bcstr (buf, len, strerror(syserr_code));
|
|
|
|
#endif
|
|
|
|
return errno_to_errnum(syserr_code);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (buf) moo_copy_bcstr (buf, len, "system error");
|
|
|
|
return MOO_ESYSERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
#if defined(MOO_BUILD_RELEASE)
|
|
|
|
|
|
|
|
static void assert_fail (moo_t* moo, const moo_bch_t* expr, const moo_bch_t* file, moo_oow_t line)
|
|
|
|
{
|
|
|
|
/* do nothing */
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* defined(MOO_BUILD_RELEASE) */
|
|
|
|
|
|
|
|
#if defined(MOO_ENABLE_LIBUNWIND)
|
|
|
|
#include <libunwind.h>
|
|
|
|
static void backtrace_stack_frames (moo_t* moo)
|
|
|
|
{
|
|
|
|
unw_cursor_t cursor;
|
|
|
|
unw_context_t context;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
unw_getcontext(&context);
|
|
|
|
unw_init_local(&cursor, &context);
|
|
|
|
|
|
|
|
moo_logbfmt (moo, MOO_LOG_UNTYPED | MOO_LOG_DEBUG, "[BACKTRACE]\n");
|
|
|
|
for (n = 0; unw_step(&cursor) > 0; n++)
|
|
|
|
{
|
|
|
|
unw_word_t ip, sp, off;
|
|
|
|
char symbol[256];
|
|
|
|
|
|
|
|
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
|
|
|
unw_get_reg (&cursor, UNW_REG_SP, &sp);
|
|
|
|
|
|
|
|
if (unw_get_proc_name(&cursor, symbol, MOO_COUNTOF(symbol), &off))
|
|
|
|
{
|
|
|
|
moo_copy_bcstr (symbol, MOO_COUNTOF(symbol), "<unknown>");
|
|
|
|
}
|
|
|
|
|
|
|
|
moo_logbfmt (moo, MOO_LOG_UNTYPED | MOO_LOG_DEBUG,
|
2021-02-11 14:08:43 +00:00
|
|
|
"#%02d ip=0x%*p sp=0x%*p %hs+0x%zu\n",
|
2018-11-07 15:26:30 +00:00
|
|
|
n, MOO_SIZEOF(void*) * 2, (void*)ip, MOO_SIZEOF(void*) * 2, (void*)sp, symbol, (moo_oow_t)off);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#elif defined(HAVE_BACKTRACE)
|
|
|
|
#include <execinfo.h>
|
|
|
|
static void backtrace_stack_frames (moo_t* moo)
|
|
|
|
{
|
|
|
|
void* btarray[128];
|
|
|
|
moo_oow_t btsize;
|
|
|
|
char** btsyms;
|
|
|
|
|
2020-10-26 16:43:09 +00:00
|
|
|
btsize = backtrace(btarray, MOO_COUNTOF(btarray));
|
|
|
|
btsyms = backtrace_symbols(btarray, btsize);
|
2018-11-07 15:26:30 +00:00
|
|
|
if (btsyms)
|
|
|
|
{
|
|
|
|
moo_oow_t i;
|
|
|
|
moo_logbfmt (moo, MOO_LOG_UNTYPED | MOO_LOG_DEBUG, "[BACKTRACE]\n");
|
|
|
|
|
|
|
|
for (i = 0; i < btsize; i++)
|
|
|
|
{
|
2021-02-11 14:08:43 +00:00
|
|
|
moo_logbfmt (moo, MOO_LOG_UNTYPED | MOO_LOG_DEBUG, " %hs\n", btsyms[i]);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
free (btsyms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static void backtrace_stack_frames (moo_t* moo)
|
|
|
|
{
|
|
|
|
/* do nothing. not supported */
|
|
|
|
}
|
|
|
|
#endif /* defined(MOO_ENABLE_LIBUNWIND) */
|
|
|
|
|
|
|
|
static void assert_fail (moo_t* moo, const moo_bch_t* expr, const moo_bch_t* file, moo_oow_t line)
|
|
|
|
{
|
2021-02-11 14:08:43 +00:00
|
|
|
moo_logbfmt (moo, MOO_LOG_UNTYPED | MOO_LOG_FATAL, "ASSERTION FAILURE: %hs at %hs:%zu\n", expr, file, line);
|
2018-11-07 15:26:30 +00:00
|
|
|
backtrace_stack_frames (moo);
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
ExitProcess (249);
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
DosExit (EXIT_PROCESS, 249);
|
|
|
|
#elif defined(__DOS__)
|
|
|
|
{
|
|
|
|
union REGS regs;
|
|
|
|
regs.h.ah = DOS_EXIT;
|
|
|
|
regs.h.al = 249;
|
|
|
|
intdos (®s, ®s);
|
|
|
|
}
|
|
|
|
#elif defined(vms) || defined(__vms)
|
|
|
|
lib$stop (SS$_ABORT); /* use SS$_OPCCUS instead? */
|
|
|
|
/* this won't be reached since lib$stop() terminates the process */
|
|
|
|
sys$exit (SS$_ABORT); /* this condition code can be shown with
|
|
|
|
* 'show symbol $status' from the command-line. */
|
|
|
|
#elif defined(macintosh)
|
|
|
|
|
|
|
|
ExitToShell ();
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
kill (getpid(), SIGABRT);
|
|
|
|
_exit (1);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* defined(MOO_BUILD_RELEASE) */
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
#if defined(USE_LTDL)
|
|
|
|
# define sys_dl_error() lt_dlerror()
|
|
|
|
# define sys_dl_open(x) lt_dlopen(x)
|
|
|
|
# define sys_dl_openext(x) lt_dlopenext(x)
|
|
|
|
# define sys_dl_close(x) lt_dlclose(x)
|
|
|
|
# define sys_dl_getsym(x,n) lt_dlsym(x,n)
|
|
|
|
|
|
|
|
#elif defined(USE_DLFCN)
|
|
|
|
# define sys_dl_error() dlerror()
|
2020-10-20 10:10:37 +00:00
|
|
|
# define sys_dl_open(x) dlopen(x,RTLD_NOW | RTLD_LOCAL)
|
|
|
|
# define sys_dl_openext(x) dlopen(x,RTLD_NOW | RTLD_LOCAL)
|
2018-11-07 15:26:30 +00:00
|
|
|
# define sys_dl_close(x) dlclose(x)
|
|
|
|
# define sys_dl_getsym(x,n) dlsym(x,n)
|
|
|
|
|
|
|
|
#elif defined(USE_WIN_DLL)
|
2018-11-21 13:19:07 +00:00
|
|
|
# define sys_dl_error() msw_dlerror()
|
2018-11-07 15:26:30 +00:00
|
|
|
# define sys_dl_open(x) LoadLibraryExA(x, MOO_NULL, 0)
|
|
|
|
# define sys_dl_openext(x) LoadLibraryExA(x, MOO_NULL, 0)
|
|
|
|
# define sys_dl_close(x) FreeLibrary(x)
|
|
|
|
# define sys_dl_getsym(x,n) GetProcAddress(x,n)
|
|
|
|
|
|
|
|
#elif defined(USE_MACH_O_DYLD)
|
|
|
|
# define sys_dl_error() mach_dlerror()
|
|
|
|
# define sys_dl_open(x) mach_dlopen(x)
|
|
|
|
# define sys_dl_openext(x) mach_dlopen(x)
|
|
|
|
# define sys_dl_close(x) mach_dlclose(x)
|
|
|
|
# define sys_dl_getsym(x,n) mach_dlsym(x,n)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_WIN_DLL)
|
|
|
|
|
2018-11-21 13:19:07 +00:00
|
|
|
static const char* msw_dlerror (void)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
/* TODO: handle wchar_t, moo_ooch_t etc? */
|
|
|
|
static char buf[256];
|
|
|
|
DWORD rc;
|
|
|
|
|
|
|
|
rc = FormatMessageA (
|
|
|
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
|
|
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
|
|
|
buf, MOO_COUNTOF(buf), MOO_NULL
|
|
|
|
);
|
|
|
|
while (rc > 0 && buf[rc - 1] == '\r' || buf[rc - 1] == '\n')
|
|
|
|
{
|
|
|
|
buf[--rc] = '\0';
|
|
|
|
}
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(USE_MACH_O_DYLD)
|
|
|
|
static const char* mach_dlerror_str = "";
|
|
|
|
|
|
|
|
static void* mach_dlopen (const char* path)
|
|
|
|
{
|
|
|
|
NSObjectFileImage image;
|
|
|
|
NSObjectFileImageReturnCode rc;
|
|
|
|
void* handle;
|
|
|
|
|
|
|
|
mach_dlerror_str = "";
|
|
|
|
if ((rc = NSCreateObjectFileImageFromFile(path, &image)) != NSObjectFileImageSuccess)
|
|
|
|
{
|
|
|
|
switch (rc)
|
|
|
|
{
|
|
|
|
case NSObjectFileImageFailure:
|
|
|
|
case NSObjectFileImageFormat:
|
|
|
|
mach_dlerror_str = "unable to crate object file image";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NSObjectFileImageInappropriateFile:
|
|
|
|
mach_dlerror_str = "inappropriate file";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NSObjectFileImageArch:
|
|
|
|
mach_dlerror_str = "incompatible architecture";
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NSObjectFileImageAccess:
|
|
|
|
mach_dlerror_str = "inaccessible file";
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
mach_dlerror_str = "unknown error";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return MOO_NULL;
|
|
|
|
}
|
|
|
|
handle = (void*)NSLinkModule(image, path, NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
|
|
|
|
NSDestroyObjectFileImage (image);
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE void mach_dlclose (void* handle)
|
|
|
|
{
|
|
|
|
mach_dlerror_str = "";
|
|
|
|
NSUnLinkModule (handle, NSUNLINKMODULE_OPTION_NONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE void* mach_dlsym (void* handle, const char* name)
|
|
|
|
{
|
|
|
|
mach_dlerror_str = "";
|
|
|
|
return (void*)NSAddressOfSymbol(NSLookupSymbolInModule(handle, name));
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* mach_dlerror (void)
|
|
|
|
{
|
|
|
|
int err_no;
|
|
|
|
const char* err_file;
|
|
|
|
NSLinkEditErrors err;
|
|
|
|
|
|
|
|
if (mach_dlerror_str[0] == '\0')
|
|
|
|
NSLinkEditError (&err, &err_no, &err_file, &mach_dlerror_str);
|
|
|
|
|
|
|
|
return mach_dlerror_str;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void dl_startup (moo_t* moo)
|
|
|
|
{
|
|
|
|
#if defined(USE_LTDL)
|
|
|
|
lt_dlinit ();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dl_cleanup (moo_t* moo)
|
|
|
|
{
|
|
|
|
#if defined(USE_LTDL)
|
|
|
|
lt_dlexit ();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* dl_open (moo_t* moo, const moo_ooch_t* name, int flags)
|
|
|
|
{
|
|
|
|
#if defined(USE_LTDL) || defined(USE_DLFCN) || defined(USE_MACH_O_DYLD) || defined(USE_WIN_DLL)
|
|
|
|
moo_bch_t stabuf[128], * bufptr;
|
|
|
|
moo_oow_t ucslen, bcslen, bufcapa;
|
|
|
|
void* handle;
|
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
if (moo_convootobcstr(moo, name, &ucslen, MOO_NULL, &bufcapa) <= -1) return MOO_NULL;
|
|
|
|
/* +1 for terminating null. but it's not needed because MOO_COUNTOF(MOO_DEFAULT_PFMODPREFIX)
|
|
|
|
* and MOO_COUNTOF(MOO_DEFAULT_PFMODPOSTIFX) include the terminating nulls. Never mind about
|
|
|
|
* the extra 2 characters. */
|
|
|
|
#else
|
|
|
|
bufcapa = moo_count_bcstr(name);
|
|
|
|
#endif
|
|
|
|
bufcapa += MOO_COUNTOF(MOO_DEFAULT_PFMODDIR) + MOO_COUNTOF(MOO_DEFAULT_PFMODPREFIX) + MOO_COUNTOF(MOO_DEFAULT_PFMODPOSTFIX) + 1;
|
|
|
|
|
|
|
|
if (bufcapa <= MOO_COUNTOF(stabuf)) bufptr = stabuf;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bufptr = moo_allocmem(moo, bufcapa * MOO_SIZEOF(*bufptr));
|
|
|
|
if (!bufptr) return MOO_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & MOO_VMPRIM_DLOPEN_PFMOD)
|
|
|
|
{
|
|
|
|
moo_oow_t len, i, xlen, dlen;
|
|
|
|
|
|
|
|
/* opening a primitive function module - mostly libmoo-xxxx.
|
|
|
|
* if PFMODPREFIX is absolute, never use PFMODDIR */
|
|
|
|
dlen = IS_PATH_ABSOLUTE(MOO_DEFAULT_PFMODPREFIX)?
|
|
|
|
0: moo_copy_bcstr(bufptr, bufcapa, MOO_DEFAULT_PFMODDIR);
|
|
|
|
len = moo_copy_bcstr(&bufptr[dlen], bufcapa - dlen, MOO_DEFAULT_PFMODPREFIX);
|
|
|
|
len += dlen;
|
|
|
|
|
|
|
|
bcslen = bufcapa - len;
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
2019-05-14 15:54:16 +00:00
|
|
|
moo_convootobcstr (moo, name, &ucslen, &bufptr[len], &bcslen);
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
bcslen = moo_copy_bcstr(&bufptr[len], bcslen, name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* length including the directory, the prefix and the name. but excluding the postfix */
|
|
|
|
xlen = len + bcslen;
|
|
|
|
|
|
|
|
for (i = len; i < xlen; i++)
|
|
|
|
{
|
|
|
|
/* convert a period(.) to a dash(-) */
|
|
|
|
if (bufptr[i] == '.') bufptr[i] = '-';
|
|
|
|
}
|
|
|
|
|
|
|
|
retry:
|
|
|
|
moo_copy_bcstr (&bufptr[xlen], bufcapa - xlen, MOO_DEFAULT_PFMODPOSTFIX);
|
|
|
|
|
|
|
|
/* both prefix and postfix attached. for instance, libmoo-xxx */
|
|
|
|
handle = sys_dl_openext(&bufptr[dlen]);
|
|
|
|
if (!handle)
|
|
|
|
{
|
|
|
|
MOO_DEBUG3 (moo, "Unable to open(ext) PFMOD %hs[%js] - %hs\n", &bufptr[dlen], name, sys_dl_error());
|
|
|
|
|
|
|
|
if (dlen > 0)
|
|
|
|
{
|
|
|
|
handle = sys_dl_openext(&bufptr[0]);
|
|
|
|
if (handle) goto pfmod_open_ok;
|
|
|
|
MOO_DEBUG3 (moo, "Unable to open(ext) PFMOD %hs[%js] - %hs\n", &bufptr[0], name, sys_dl_error());
|
|
|
|
}
|
|
|
|
|
|
|
|
/* try without prefix and postfix */
|
|
|
|
bufptr[xlen] = '\0';
|
|
|
|
handle = sys_dl_openext(&bufptr[len]);
|
|
|
|
if (!handle)
|
|
|
|
{
|
|
|
|
moo_bch_t* dash;
|
|
|
|
const moo_bch_t* dl_errstr;
|
|
|
|
dl_errstr = sys_dl_error();
|
|
|
|
MOO_DEBUG3 (moo, "Unable to open(ext) PFMOD %hs[%js] - %hs\n", &bufptr[len], name, dl_errstr);
|
|
|
|
moo_seterrbfmt (moo, MOO_ESYSERR, "unable to open(ext) PFMOD %js - %hs", name, dl_errstr);
|
|
|
|
dash = moo_rfind_bchar(bufptr, moo_count_bcstr(bufptr), '-');
|
|
|
|
if (dash)
|
|
|
|
{
|
|
|
|
/* remove a segment at the back.
|
|
|
|
* [NOTE] a dash contained in the original name before
|
|
|
|
* period-to-dash transformation may cause extraneous/wrong
|
|
|
|
* loading reattempts. */
|
|
|
|
xlen = dash - bufptr;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
MOO_DEBUG3 (moo, "OPENED_HERE(ext) PFMOD %hs[%js] handle %p\n", &bufptr[len], name, handle);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pfmod_open_ok:
|
2018-11-13 06:54:30 +00:00
|
|
|
MOO_DEBUG3 (moo, "OPENED_HERE(ext) PFMOD %hs[%js] handle %p\n", &bufptr[dlen], name, handle);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* opening a raw shared object without a prefix and/or a postfix */
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
bcslen = bufcapa;
|
2019-05-14 15:54:16 +00:00
|
|
|
moo_convootobcstr (moo, name, &ucslen, bufptr, &bcslen);
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
bcslen = moo_copy_bcstr(bufptr, bufcapa, name);
|
|
|
|
#endif
|
|
|
|
|
2019-05-14 15:54:16 +00:00
|
|
|
if (moo_find_bchar(bufptr, bcslen, '.'))
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
handle = sys_dl_open(bufptr);
|
|
|
|
if (!handle)
|
|
|
|
{
|
|
|
|
const moo_bch_t* dl_errstr;
|
|
|
|
dl_errstr = sys_dl_error();
|
|
|
|
MOO_DEBUG2 (moo, "Unable to open DL %hs - %hs\n", bufptr, dl_errstr);
|
|
|
|
moo_seterrbfmt (moo, MOO_ESYSERR, "unable to open DL %js - %hs", name, dl_errstr);
|
|
|
|
}
|
2018-11-13 06:54:30 +00:00
|
|
|
else MOO_DEBUG2 (moo, "OPENED_HERE DL %hs handle %p\n", bufptr, handle);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
handle = sys_dl_openext(bufptr);
|
|
|
|
if (!handle)
|
|
|
|
{
|
|
|
|
const moo_bch_t* dl_errstr;
|
|
|
|
dl_errstr = sys_dl_error();
|
|
|
|
MOO_DEBUG2 (moo, "Unable to open(ext) DL %hs - %hs\n", bufptr, dl_errstr);
|
|
|
|
moo_seterrbfmt (moo, MOO_ESYSERR, "unable to open(ext) DL %js - %hs", name, dl_errstr);
|
|
|
|
}
|
2018-11-13 06:54:30 +00:00
|
|
|
else MOO_DEBUG2 (moo, "OPENED_HERE(ext) DL %hs handle %p\n", bufptr, handle);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bufptr != stabuf) moo_freemem (moo, bufptr);
|
|
|
|
return handle;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* TODO: support various platforms */
|
|
|
|
/* TODO: implemenent this */
|
|
|
|
MOO_DEBUG1 (moo, "Dynamic loading not implemented - cannot open %js\n", name);
|
|
|
|
moo_seterrbfmt (moo, MOO_ENOIMPL, "dynamic loading not implemented - cannot open %js", name);
|
|
|
|
return MOO_NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dl_close (moo_t* moo, void* handle)
|
|
|
|
{
|
|
|
|
#if defined(USE_LTDL) || defined(USE_DLFCN) || defined(USE_MACH_O_DYLD) || defined(USE_WIN_DLL)
|
|
|
|
MOO_DEBUG1 (moo, "Closed DL handle %p\n", handle);
|
|
|
|
sys_dl_close (handle);
|
|
|
|
|
|
|
|
#else
|
|
|
|
/* TODO: implemenent this */
|
|
|
|
MOO_DEBUG1 (moo, "Dynamic loading not implemented - cannot close handle %p\n", handle);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* dl_getsym (moo_t* moo, void* handle, const moo_ooch_t* name)
|
|
|
|
{
|
|
|
|
#if defined(USE_LTDL) || defined(USE_DLFCN) || defined(USE_MACH_O_DYLD) || defined(USE_WIN_DLL)
|
|
|
|
moo_bch_t stabuf[64], * bufptr;
|
|
|
|
moo_oow_t bufcapa, ucslen, bcslen, i;
|
|
|
|
const moo_bch_t* symname;
|
|
|
|
void* sym;
|
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
if (moo_convootobcstr(moo, name, &ucslen, MOO_NULL, &bcslen) <= -1) return MOO_NULL;
|
|
|
|
#else
|
|
|
|
bcslen = moo_count_bcstr (name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (bcslen >= MOO_COUNTOF(stabuf) - 2)
|
|
|
|
{
|
|
|
|
bufcapa = bcslen + 3;
|
|
|
|
bufptr = moo_allocmem(moo, bufcapa * MOO_SIZEOF(*bufptr));
|
|
|
|
if (!bufptr) return MOO_NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bufcapa = MOO_COUNTOF(stabuf);
|
|
|
|
bufptr = stabuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
bcslen = bufcapa - 1;
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
moo_convootobcstr (moo, name, &ucslen, &bufptr[1], &bcslen);
|
|
|
|
#else
|
|
|
|
bcslen = moo_copy_bcstr(&bufptr[1], bcslen, name);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* convert a period(.) to an underscore(_) */
|
|
|
|
for (i = 1; i <= bcslen; i++) if (bufptr[i] == '.') bufptr[i] = '_';
|
|
|
|
|
|
|
|
symname = &bufptr[1]; /* try the name as it is */
|
|
|
|
sym = sys_dl_getsym(handle, symname);
|
|
|
|
if (!sym)
|
|
|
|
{
|
|
|
|
bufptr[0] = '_';
|
|
|
|
symname = &bufptr[0]; /* try _name */
|
|
|
|
sym = sys_dl_getsym(handle, symname);
|
|
|
|
if (!sym)
|
|
|
|
{
|
|
|
|
bufptr[bcslen + 1] = '_';
|
|
|
|
bufptr[bcslen + 2] = '\0';
|
|
|
|
|
|
|
|
symname = &bufptr[1]; /* try name_ */
|
|
|
|
sym = sys_dl_getsym(handle, symname);
|
|
|
|
|
|
|
|
if (!sym)
|
|
|
|
{
|
|
|
|
symname = &bufptr[0]; /* try _name_ */
|
|
|
|
sym = sys_dl_getsym(handle, symname);
|
|
|
|
if (!sym)
|
|
|
|
{
|
|
|
|
const moo_bch_t* dl_errstr;
|
|
|
|
dl_errstr = sys_dl_error();
|
|
|
|
MOO_DEBUG3 (moo, "Unable to get module symbol %js from handle %p - %hs\n", name, handle, dl_errstr);
|
|
|
|
moo_seterrbfmt (moo, MOO_ENOENT, "unable to get module symbol %hs - %hs", symname, dl_errstr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym) MOO_DEBUG3 (moo, "Loaded module symbol %js from handle %p - %hs\n", name, handle, symname);
|
|
|
|
if (bufptr != stabuf) moo_freemem (moo, bufptr);
|
|
|
|
return sym;
|
|
|
|
|
|
|
|
#else
|
|
|
|
/* TODO: IMPLEMENT THIS */
|
|
|
|
MOO_DEBUG2 (moo, "Dynamic loading not implemented - Cannot load module symbol %js from handle %p\n", name, handle);
|
|
|
|
moo_seterrbfmt (moo, MOO_ENOIMPL, "dynamic loading not implemented - Cannot load module symbol %js from handle %p", name, handle);
|
|
|
|
return MOO_NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
static int _add_poll_fd (moo_t* moo, int fd, int event_mask)
|
|
|
|
{
|
|
|
|
#if defined(USE_DEVPOLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
struct pollfd ev;
|
|
|
|
|
|
|
|
MOO_ASSERT (moo, xtn->ep >= 0);
|
|
|
|
ev.fd = fd;
|
|
|
|
ev.events = event_mask;
|
|
|
|
ev.revents = 0;
|
|
|
|
if (write(xtn->ep, &ev, MOO_SIZEOF(ev)) != MOO_SIZEOF(ev))
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot add file descriptor %d to devpoll - %hs\n", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
struct kevent ev;
|
2019-09-25 10:05:39 +00:00
|
|
|
moo_oow_t rindex, roffset;
|
|
|
|
moo_oow_t rv = 0;
|
|
|
|
|
2019-09-25 14:34:43 +00:00
|
|
|
rindex = (moo_oow_t)fd / (MOO_BITSOF(moo_oow_t) >> 1);
|
|
|
|
roffset = ((moo_oow_t)fd << 1) % MOO_BITSOF(moo_oow_t);
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
if (rindex >= xtn->ev.reg.capa)
|
|
|
|
{
|
|
|
|
moo_oow_t* tmp;
|
|
|
|
moo_oow_t newcapa;
|
|
|
|
|
|
|
|
MOO_STATIC_ASSERT (MOO_SIZEOF(*tmp) == MOO_SIZEOF(*xtn->ev.reg.ptr));
|
|
|
|
|
|
|
|
newcapa = rindex + 1;
|
|
|
|
newcapa = MOO_ALIGN_POW2(newcapa, 16);
|
|
|
|
|
|
|
|
tmp = (moo_oow_t*)moo_reallocmem(moo, xtn->ev.reg.ptr, newcapa * MOO_SIZEOF(*tmp));
|
|
|
|
if (!tmp)
|
|
|
|
{
|
|
|
|
const moo_ooch_t* oldmsg = moo_backuperrmsg(moo);
|
|
|
|
moo_seterrbfmt (moo, MOO_ESYSERR, "unable to add file descriptor %d to kqueue - %js", fd, oldmsg);
|
|
|
|
MOO_DEBUG1 (moo, "%js", moo_geterrmsg(moo));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
MOO_MEMSET (&tmp[xtn->ev.reg.capa], 0, newcapa - xtn->ev.reg.capa);
|
|
|
|
xtn->ev.reg.ptr = tmp;
|
|
|
|
xtn->ev.reg.capa = newcapa;
|
|
|
|
}
|
2019-09-23 08:44:22 +00:00
|
|
|
|
|
|
|
if (event_mask & XPOLLIN)
|
|
|
|
{
|
|
|
|
/*EV_SET (&ev, fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);*/
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
2019-09-25 10:05:39 +00:00
|
|
|
ev.flags = EV_ADD;
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */
|
|
|
|
#endif
|
2019-09-23 08:44:22 +00:00
|
|
|
ev.filter = EVFILT_READ;
|
|
|
|
if (kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL) == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
2019-09-25 10:05:39 +00:00
|
|
|
MOO_DEBUG2 (moo, "Cannot add file descriptor %d to kqueue for read - %hs\n", fd, strerror(errno));
|
2019-09-23 08:44:22 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
rv |= 1;
|
2019-09-23 08:44:22 +00:00
|
|
|
}
|
|
|
|
if (event_mask & XPOLLOUT)
|
|
|
|
{
|
|
|
|
/*EV_SET (&ev, fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, 0, 0, 0);*/
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
2019-09-25 10:05:39 +00:00
|
|
|
ev.flags = EV_ADD;
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */
|
|
|
|
#endif
|
2019-09-23 08:44:22 +00:00
|
|
|
ev.filter = EVFILT_WRITE;
|
|
|
|
if (kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL) == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
2019-09-25 10:05:39 +00:00
|
|
|
MOO_DEBUG2 (moo, "Cannot add file descriptor %d to kqueue for write - %hs\n", fd, strerror(errno));
|
|
|
|
|
2019-09-23 08:44:22 +00:00
|
|
|
if (event_mask & XPOLLIN)
|
|
|
|
{
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_DELETE;
|
|
|
|
ev.filter = EVFILT_READ;
|
|
|
|
kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL);
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
rv |= 2;
|
2019-09-23 08:44:22 +00:00
|
|
|
}
|
|
|
|
|
2019-09-25 10:05:39 +00:00
|
|
|
MOO_SETBITS (moo_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2, rv);
|
2019-09-23 08:44:22 +00:00
|
|
|
return 0;
|
2019-09-25 10:05:39 +00:00
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
struct epoll_event ev;
|
|
|
|
|
|
|
|
MOO_ASSERT (moo, xtn->ep >= 0);
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
2018-11-07 15:26:30 +00:00
|
|
|
ev.events = event_mask;
|
|
|
|
#if defined(USE_THREAD) && defined(EPOLLET)
|
|
|
|
/* epoll_wait may return again if the worker thread consumes events.
|
|
|
|
* switch to level-trigger. */
|
|
|
|
/* TODO: verify if EPOLLLET is desired */
|
|
|
|
ev.events |= EPOLLET/* | EPOLLRDHUP | EPOLLHUP */;
|
|
|
|
#endif
|
|
|
|
/*ev.data.ptr = (void*)event_data;*/
|
|
|
|
ev.data.fd = fd;
|
|
|
|
if (epoll_ctl(xtn->ep, EPOLL_CTL_ADD, fd, &ev) == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot add file descriptor %d to epoll - %hs\n", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#elif defined(USE_POLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.pmtx);
|
|
|
|
if (xtn->ev.reg.len >= xtn->ev.reg.capa)
|
|
|
|
{
|
|
|
|
struct pollfd* tmp, * tmp2;
|
|
|
|
moo_oow_t newcapa;
|
|
|
|
|
|
|
|
newcapa = MOO_ALIGN_POW2 (xtn->ev.reg.len + 1, 256);
|
2019-07-08 07:51:53 +00:00
|
|
|
tmp = (struct pollfd*)moo_reallocmem(moo, xtn->ev.reg.ptr, newcapa * MOO_SIZEOF(*tmp));
|
|
|
|
tmp2 = (struct pollfd*)moo_reallocmem(moo, xtn->ev.buf, newcapa * MOO_SIZEOF(*tmp2));
|
2018-11-07 15:26:30 +00:00
|
|
|
if (!tmp || !tmp2)
|
|
|
|
{
|
|
|
|
MOO_DEBUG2 (moo, "Cannot add file descriptor %d to poll - %hs\n", fd, strerror(errno));
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
if (tmp) moo_freemem (moo, tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
xtn->ev.reg.ptr = tmp;
|
|
|
|
xtn->ev.reg.capa = newcapa;
|
|
|
|
|
|
|
|
xtn->ev.buf = tmp2;
|
|
|
|
}
|
|
|
|
|
|
|
|
xtn->ev.reg.ptr[xtn->ev.reg.len].fd = fd;
|
|
|
|
xtn->ev.reg.ptr[xtn->ev.reg.len].events = event_mask;
|
|
|
|
xtn->ev.reg.ptr[xtn->ev.reg.len].revents = 0;
|
|
|
|
xtn->ev.reg.len++;
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#elif defined(USE_SELECT)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.smtx);
|
|
|
|
if (event_mask & XPOLLIN)
|
|
|
|
{
|
|
|
|
FD_SET (fd, &xtn->ev.reg.rfds);
|
|
|
|
if (fd > xtn->ev.reg.maxfd) xtn->ev.reg.maxfd = fd;
|
|
|
|
}
|
|
|
|
if (event_mask & XPOLLOUT)
|
|
|
|
{
|
|
|
|
FD_SET (fd, &xtn->ev.reg.wfds);
|
|
|
|
if (fd > xtn->ev.reg.maxfd) xtn->ev.reg.maxfd = fd;
|
|
|
|
}
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.smtx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
MOO_DEBUG1 (moo, "Cannot add file descriptor %d to poll - not implemented\n", fd);
|
|
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int _del_poll_fd (moo_t* moo, int fd)
|
|
|
|
{
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
struct pollfd ev;
|
|
|
|
|
|
|
|
MOO_ASSERT (moo, xtn->ep >= 0);
|
|
|
|
ev.fd = fd;
|
|
|
|
ev.events = POLLREMOVE;
|
|
|
|
ev.revents = 0;
|
2019-09-23 08:44:22 +00:00
|
|
|
if (write(xtn->ep, &ev, MOO_SIZEOF(ev)) != MOO_SIZEOF(ev))
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot remove file descriptor %d from devpoll - %hs\n", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2019-09-25 10:05:39 +00:00
|
|
|
moo_oow_t rindex, roffset;
|
|
|
|
int rv;
|
2019-09-23 08:44:22 +00:00
|
|
|
struct kevent ev;
|
|
|
|
|
2019-09-25 14:34:43 +00:00
|
|
|
rindex = (moo_oow_t)fd / (MOO_BITSOF(moo_oow_t) >> 1);
|
|
|
|
roffset = ((moo_oow_t)fd << 1) % MOO_BITSOF(moo_oow_t);
|
2019-09-23 08:44:22 +00:00
|
|
|
|
2019-09-25 10:05:39 +00:00
|
|
|
if (rindex >= xtn->ev.reg.capa)
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unknown file descriptor %d", fd);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot remove file descriptor %d from kqueue - %js\n", fd, moo_geterrmsg(moo));
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
|
|
|
|
rv = MOO_GETBITS (moo_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2);
|
|
|
|
|
|
|
|
if (rv & 1)
|
|
|
|
{
|
|
|
|
/*EV_SET (&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);*/
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_DELETE;
|
|
|
|
ev.filter = EVFILT_READ;
|
|
|
|
kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL);
|
|
|
|
/* no error check for now */
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rv & 2)
|
|
|
|
{
|
|
|
|
/*EV_SET (&ev, fd, EVFILT_WRITE, EV_DELETE, 0, 0, 0);*/
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_DELETE;
|
|
|
|
ev.filter = EVFILT_WRITE;
|
|
|
|
kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL);
|
|
|
|
/* no error check for now */
|
|
|
|
}
|
2019-09-23 08:44:22 +00:00
|
|
|
|
2019-09-25 14:34:43 +00:00
|
|
|
MOO_SETBITS (moo_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2, 0);
|
2019-09-23 08:44:22 +00:00
|
|
|
return 0;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
struct epoll_event ev;
|
|
|
|
|
|
|
|
MOO_ASSERT (moo, xtn->ep >= 0);
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
2019-09-23 08:44:22 +00:00
|
|
|
if (epoll_ctl(xtn->ep, EPOLL_CTL_DEL, fd, &ev) == -1)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot remove file descriptor %d from epoll - %hs\n", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#elif defined(USE_POLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_oow_t i;
|
|
|
|
|
|
|
|
/* TODO: performance boost. no linear search */
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.pmtx);
|
|
|
|
for (i = 0; i < xtn->ev.reg.len; i++)
|
|
|
|
{
|
|
|
|
if (xtn->ev.reg.ptr[i].fd == fd)
|
|
|
|
{
|
|
|
|
xtn->ev.reg.len--;
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMMOVE (&xtn->ev.reg.ptr[i], &xtn->ev.reg.ptr[i+1], (xtn->ev.reg.len - i) * MOO_SIZEOF(*xtn->ev.reg.ptr));
|
2018-11-07 15:26:30 +00:00
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
|
|
|
|
|
|
|
|
MOO_DEBUG1 (moo, "Cannot remove file descriptor %d from poll - not found\n", fd);
|
|
|
|
moo_seterrnum (moo, MOO_ENOENT);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
#elif defined(USE_SELECT)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.smtx);
|
|
|
|
FD_CLR (fd, &xtn->ev.reg.rfds);
|
|
|
|
FD_CLR (fd, &xtn->ev.reg.wfds);
|
|
|
|
if (fd >= xtn->ev.reg.maxfd)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
/* TODO: any way to make this search faster or to do without the search like this */
|
|
|
|
for (i = fd - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (FD_ISSET(i, &xtn->ev.reg.rfds) || FD_ISSET(i, &xtn->ev.reg.wfds)) break;
|
|
|
|
}
|
|
|
|
xtn->ev.reg.maxfd = i;
|
|
|
|
}
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.smtx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
MOO_DEBUG1 (moo, "Cannot remove file descriptor %d from poll - not implemented\n", fd);
|
|
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int _mod_poll_fd (moo_t* moo, int fd, int event_mask)
|
|
|
|
{
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
|
|
|
|
if (_del_poll_fd (moo, fd) <= -1) return -1;
|
|
|
|
|
|
|
|
if (_add_poll_fd (moo, fd, event_mask) <= -1)
|
|
|
|
{
|
|
|
|
/* TODO: any good way to rollback successful deletion? */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-09-23 08:44:22 +00:00
|
|
|
return 0;
|
|
|
|
#elif defined(USE_KQUEUE)
|
2019-09-25 10:05:39 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
moo_oow_t rindex, roffset;
|
|
|
|
int rv, newrv = 0;
|
|
|
|
struct kevent ev;
|
2019-09-23 08:44:22 +00:00
|
|
|
|
2019-09-25 14:34:43 +00:00
|
|
|
rindex = (moo_oow_t)fd / (MOO_BITSOF(moo_oow_t) >> 1);
|
|
|
|
roffset = ((moo_oow_t)fd << 1) % MOO_BITSOF(moo_oow_t);
|
2019-09-23 08:44:22 +00:00
|
|
|
|
2019-09-25 10:05:39 +00:00
|
|
|
if (rindex >= xtn->ev.reg.capa)
|
2019-09-23 08:44:22 +00:00
|
|
|
{
|
2019-09-25 10:05:39 +00:00
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unknown file descriptor %d", fd);
|
2019-09-25 14:34:43 +00:00
|
|
|
MOO_DEBUG2 (moo, "Cannot modify file descriptor %d in kqueue - %js\n", fd, moo_geterrmsg(moo));
|
2019-09-23 08:44:22 +00:00
|
|
|
return -1;
|
2019-09-25 10:05:39 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
rv = MOO_GETBITS(moo_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2);
|
|
|
|
|
|
|
|
if (rv & 1)
|
|
|
|
{
|
|
|
|
if (!(event_mask & XPOLLIN))
|
|
|
|
{
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_DELETE;
|
|
|
|
ev.filter = EVFILT_READ;
|
2019-09-25 14:34:43 +00:00
|
|
|
if (kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL) == -1) goto kqueue_syserr;
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
newrv &= ~1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (event_mask & XPOLLIN)
|
|
|
|
{
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_ADD;
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */
|
|
|
|
#endif
|
|
|
|
ev.filter = EVFILT_READ;
|
2019-09-25 14:34:43 +00:00
|
|
|
if (kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL) == -1) goto kqueue_syserr;
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
newrv |= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rv & 2)
|
|
|
|
{
|
|
|
|
if (!(event_mask & XPOLLOUT))
|
|
|
|
{
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_DELETE;
|
|
|
|
ev.filter = EVFILT_WRITE;
|
2019-09-25 14:34:43 +00:00
|
|
|
/* there is no operation rollback for the (rv & 1) case.
|
|
|
|
* the rollback action may fail again even if i try it */
|
|
|
|
if (kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL) == -1) goto kqueue_syserr;
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
newrv &= ~2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (event_mask & XPOLLOUT)
|
|
|
|
{
|
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
|
|
|
ev.ident = fd;
|
|
|
|
ev.flags = EV_ADD;
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
ev.flags |= EV_CLEAR; /* EV_CLEAR for edge trigger? */
|
|
|
|
#endif
|
|
|
|
ev.filter = EVFILT_WRITE;
|
2019-09-25 14:34:43 +00:00
|
|
|
|
|
|
|
/* there is no operation rollback for the (rv & 1) case.
|
|
|
|
* the rollback action may fail again even if i try it */
|
|
|
|
if (kevent(xtn->ep, &ev, 1, MOO_NULL, 0, MOO_NULL) == -1) goto kqueue_syserr;
|
2019-09-25 10:05:39 +00:00
|
|
|
|
|
|
|
newrv |= 2;
|
|
|
|
}
|
2019-09-23 08:44:22 +00:00
|
|
|
}
|
|
|
|
|
2019-09-25 10:05:39 +00:00
|
|
|
MOO_SETBITS (moo_oow_t, xtn->ev.reg.ptr[rindex], roffset, 2, newrv);
|
2018-11-07 15:26:30 +00:00
|
|
|
return 0;
|
|
|
|
|
2019-09-25 14:34:43 +00:00
|
|
|
kqueue_syserr:
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot modify file descriptor %d in kqueue - %hs\n", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
struct epoll_event ev;
|
|
|
|
|
|
|
|
MOO_ASSERT (moo, xtn->ep >= 0);
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMSET (&ev, 0, MOO_SIZEOF(ev));
|
2018-11-07 15:26:30 +00:00
|
|
|
ev.events = event_mask;
|
|
|
|
#if defined(USE_THREAD) && defined(EPOLLET)
|
|
|
|
/* epoll_wait may return again if the worker thread consumes events.
|
|
|
|
* switch to level-trigger. */
|
|
|
|
/* TODO: verify if EPOLLLET is desired */
|
|
|
|
ev.events |= EPOLLET;
|
|
|
|
#endif
|
|
|
|
ev.data.fd = fd;
|
|
|
|
if (epoll_ctl(xtn->ep, EPOLL_CTL_MOD, fd, &ev) == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG2 (moo, "Cannot modify file descriptor %d in epoll - %hs\n", fd, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_oow_t i;
|
|
|
|
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.pmtx);
|
|
|
|
for (i = 0; i < xtn->ev.reg.len; i++)
|
|
|
|
{
|
|
|
|
if (xtn->ev.reg.ptr[i].fd == fd)
|
|
|
|
{
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMMOVE (&xtn->ev.reg.ptr[i], &xtn->ev.reg.ptr[i+1], (xtn->ev.reg.len - i - 1) * MOO_SIZEOF(*xtn->ev.reg.ptr));
|
2018-11-07 15:26:30 +00:00
|
|
|
xtn->ev.reg.ptr[i].fd = fd;
|
|
|
|
xtn->ev.reg.ptr[i].events = event_mask;
|
|
|
|
xtn->ev.reg.ptr[i].revents = 0;
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
|
|
|
|
MOO_DEBUG1 (moo, "Cannot modify file descriptor %d in poll - not found\n", fd);
|
|
|
|
moo_seterrnum (moo, MOO_ENOENT);
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.smtx);
|
|
|
|
MOO_ASSERT (moo, fd <= xtn->ev.reg.maxfd);
|
|
|
|
|
|
|
|
if (event_mask & XPOLLIN)
|
|
|
|
FD_SET (fd, &xtn->ev.reg.rfds);
|
|
|
|
else
|
|
|
|
FD_CLR (fd, &xtn->ev.reg.rfds);
|
|
|
|
|
|
|
|
if (event_mask & XPOLLOUT)
|
|
|
|
FD_SET (fd, &xtn->ev.reg.wfds);
|
|
|
|
else
|
|
|
|
FD_CLR (fd, &xtn->ev.reg.wfds);
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.smtx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#else
|
|
|
|
MOO_DEBUG1 (moo, "Cannot modify file descriptor %d in poll - not implemented\n", fd);
|
|
|
|
moo_seterrnum (moo, MOO_ENOIMPL);
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2019-10-10 06:30:04 +00:00
|
|
|
static int open_pipes (moo_t* moo, int p[2])
|
2019-08-15 15:55:06 +00:00
|
|
|
{
|
2021-03-30 06:11:20 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
u_long flags;
|
|
|
|
#else
|
2019-08-15 15:55:06 +00:00
|
|
|
int flags;
|
2021-03-30 06:11:20 +00:00
|
|
|
#endif
|
2019-08-15 15:55:06 +00:00
|
|
|
|
2019-10-10 06:30:04 +00:00
|
|
|
#if defined(_WIN32)
|
2019-10-11 03:30:00 +00:00
|
|
|
if (_pipe(p, 256, _O_BINARY | _O_NOINHERIT) == -1)
|
2021-03-30 06:11:20 +00:00
|
|
|
{
|
|
|
|
moo_seterrbfmtwithsyserr (moo, 0, errno, "unable to create pipes");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
#if defined(TCPV40HDRS)
|
|
|
|
/* neither pipe nor socketpair available */
|
|
|
|
if (os2_socket_pair(p) == -1)
|
|
|
|
#else
|
|
|
|
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, p) == -1)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
moo_seterrbfmtwithsyserr (moo, 2, sock_errno(), "unable to create pipes");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-10-10 06:30:04 +00:00
|
|
|
#elif defined(HAVE_PIPE2) && defined(O_CLOEXEC) && defined(O_NONBLOCK)
|
2019-08-15 15:55:06 +00:00
|
|
|
if (pipe2(p, O_CLOEXEC | O_NONBLOCK) == -1)
|
2021-03-30 06:11:20 +00:00
|
|
|
{
|
|
|
|
moo_seterrbfmtwithsyserr (moo, 0, errno, "unable to create pipes");
|
|
|
|
return -1;
|
|
|
|
}
|
2019-08-15 15:55:06 +00:00
|
|
|
#else
|
|
|
|
if (pipe(p) == -1)
|
|
|
|
{
|
2021-03-30 06:11:20 +00:00
|
|
|
moo_seterrbfmtwithsyserr (moo, 0, errno, "unable to create pipes");
|
2019-08-15 15:55:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
2021-03-30 06:11:20 +00:00
|
|
|
#endif
|
|
|
|
|
2019-08-15 15:55:06 +00:00
|
|
|
|
2021-03-30 06:11:20 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
flags = 1;
|
|
|
|
ioctl (p[0], FIONBIO, &flags);
|
|
|
|
ioctl (p[1], FIONBIO, &flags);
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
flags = 1; /* don't block */
|
|
|
|
ioctl (p[0], FIONBIO, (char*)&flags, moo_SIZEOF(flags));
|
|
|
|
ioctl (p[1], FIONBIO, (char*)&flags, moo_SIZEOF(flags));
|
|
|
|
#elif defined(HAVE_PIPE2) && defined(O_CLOEXEC) && defined(O_NONBLOCK)
|
2019-08-15 15:55:06 +00:00
|
|
|
/* do nothing */
|
|
|
|
#else
|
|
|
|
#if defined(FD_CLOEXEC)
|
|
|
|
flags = fcntl(p[0], F_GETFD);
|
|
|
|
if (flags >= 0) fcntl (p[0], F_SETFD, flags | FD_CLOEXEC);
|
|
|
|
flags = fcntl(p[1], F_GETFD);
|
|
|
|
if (flags >= 0) fcntl (p[1], F_SETFD, flags | FD_CLOEXEC);
|
|
|
|
#endif
|
|
|
|
#if defined(O_NONBLOCK)
|
|
|
|
flags = fcntl(p[0], F_GETFL);
|
|
|
|
if (flags >= 0) fcntl (p[0], F_SETFL, flags | O_NONBLOCK);
|
|
|
|
flags = fcntl(p[1], F_GETFL);
|
|
|
|
if (flags >= 0) fcntl (p[1], F_SETFL, flags | O_NONBLOCK);
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2021-03-30 06:11:20 +00:00
|
|
|
|
2019-10-10 15:09:44 +00:00
|
|
|
static void close_pipes (moo_t* moo, int p[2])
|
2019-10-10 06:30:04 +00:00
|
|
|
{
|
|
|
|
#if defined(_WIN32)
|
|
|
|
_close (p[0]);
|
|
|
|
_close (p[1]);
|
2021-03-30 06:11:20 +00:00
|
|
|
#elif defined(__OS2__)
|
|
|
|
soclose (p[0]);
|
|
|
|
soclose (p[1]);
|
2019-10-10 06:30:04 +00:00
|
|
|
#else
|
|
|
|
close (p[0]);
|
|
|
|
close (p[1]);
|
|
|
|
#endif
|
|
|
|
p[0] = -1;
|
|
|
|
p[1] = -1;
|
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
static int vm_startup (moo_t* moo)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2019-08-15 15:55:06 +00:00
|
|
|
int sigfd_pcount = 0;
|
|
|
|
int iothr_pcount = 0, flags;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
xtn->waitable_timer = CreateWaitableTimer(MOO_NULL, TRUE, MOO_NULL);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
xtn->ep = open("/dev/poll", O_RDWR);
|
|
|
|
if (xtn->ep == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG1 (moo, "Cannot create devpoll - %hs\n", strerror(errno));
|
|
|
|
goto oops;
|
|
|
|
}
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
#if defined(FD_CLOEXEC)
|
2019-08-15 15:55:06 +00:00
|
|
|
flags = fcntl(xtn->ep, F_GETFD);
|
|
|
|
if (flags >= 0) fcntl (xtn->ep, F_SETFD, flags | FD_CLOEXEC);
|
2018-11-13 07:40:30 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
#if defined(HAVE_KQUEUE1) && defined(O_CLOEXEC)
|
|
|
|
xtn->ep = kqueue1(O_CLOEXEC);
|
|
|
|
if (xtn->ep == -1) xtn->ep = kqueue();
|
|
|
|
#else
|
|
|
|
xtn->ep = kqueue();
|
|
|
|
#endif
|
|
|
|
if (xtn->ep == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG1 (moo, "Cannot create kqueue - %hs\n", strerror(errno));
|
|
|
|
goto oops;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(FD_CLOEXEC)
|
|
|
|
flags = fcntl(xtn->ep, F_GETFD);
|
|
|
|
if (flags >= 0 && !(flags & FD_CLOEXEC)) fcntl (xtn->ep, F_SETFD, flags | FD_CLOEXEC);
|
|
|
|
#endif
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
2018-11-13 07:40:30 +00:00
|
|
|
#if defined(HAVE_EPOLL_CREATE1) && defined(EPOLL_CLOEXEC)
|
2018-11-07 15:26:30 +00:00
|
|
|
xtn->ep = epoll_create1(EPOLL_CLOEXEC);
|
2019-07-11 15:58:16 +00:00
|
|
|
if (xtn->ep == -1) xtn->ep = epoll_create(1024);
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
xtn->ep = epoll_create(1024);
|
|
|
|
#endif
|
|
|
|
if (xtn->ep == -1)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
MOO_DEBUG1 (moo, "Cannot create epoll - %hs\n", strerror(errno));
|
|
|
|
goto oops;
|
|
|
|
}
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
#if defined(FD_CLOEXEC)
|
2019-08-15 15:55:06 +00:00
|
|
|
flags = fcntl(xtn->ep, F_GETFD);
|
|
|
|
if (flags >= 0 && !(flags & FD_CLOEXEC)) fcntl (xtn->ep, F_SETFD, flags | FD_CLOEXEC);
|
2018-11-13 07:40:30 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#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 */
|
|
|
|
|
2019-10-10 06:30:04 +00:00
|
|
|
if (open_pipes(moo, xtn->sigfd.p) <= -1) goto oops;
|
2019-08-15 15:55:06 +00:00
|
|
|
sigfd_pcount = 2;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-08-15 15:55:06 +00:00
|
|
|
#if defined(USE_THREAD)
|
2019-10-10 06:30:04 +00:00
|
|
|
if (open_pipes(moo, xtn->iothr.p) <= -1) goto oops;
|
2019-08-15 15:55:06 +00:00
|
|
|
iothr_pcount = 2;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
if (_add_poll_fd(moo, xtn->iothr.p[0], XPOLLIN) <= -1) goto oops;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
pthread_mutex_init (&xtn->ev.mtx, MOO_NULL);
|
|
|
|
pthread_cond_init (&xtn->ev.cnd, MOO_NULL);
|
|
|
|
pthread_cond_init (&xtn->ev.cnd2, MOO_NULL);
|
2019-09-02 16:23:03 +00:00
|
|
|
xtn->ev.halting = 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->iothr.abort = 0;
|
|
|
|
xtn->iothr.up = 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
/*pthread_create (&xtn->iothr, MOO_NULL, iothr_main, moo);*/
|
|
|
|
|
|
|
|
#endif /* USE_THREAD */
|
|
|
|
|
|
|
|
xtn->vm_running = 1;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
oops:
|
|
|
|
#if defined(USE_THREAD)
|
2019-08-15 15:55:06 +00:00
|
|
|
if (iothr_pcount > 0)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
close (xtn->iothr.p[0]);
|
|
|
|
close (xtn->iothr.p[1]);
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2019-08-15 15:55:06 +00:00
|
|
|
if (sigfd_pcount > 0)
|
|
|
|
{
|
|
|
|
close (xtn->sigfd.p[0]);
|
|
|
|
close (xtn->sigfd.p[1]);
|
|
|
|
}
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(USE_DEVPOLL) || defined(USE_EPOLL)
|
|
|
|
if (xtn->ep >= 0)
|
|
|
|
{
|
|
|
|
close (xtn->ep);
|
|
|
|
xtn->ep = -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vm_cleanup (moo_t* moo)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
xtn->vm_running = 0;
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
if (xtn->waitable_timer)
|
|
|
|
{
|
|
|
|
CloseHandle (xtn->waitable_timer);
|
|
|
|
xtn->waitable_timer = MOO_NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(USE_THREAD)
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->iothr.up)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->iothr.abort = 1;
|
|
|
|
write (xtn->iothr.p[1], "Q", 1);
|
2018-11-07 15:26:30 +00:00
|
|
|
pthread_cond_signal (&xtn->ev.cnd);
|
2018-11-13 07:40:30 +00:00
|
|
|
pthread_join (xtn->iothr.thr, MOO_NULL);
|
|
|
|
xtn->iothr.up = 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
pthread_cond_destroy (&xtn->ev.cnd);
|
|
|
|
pthread_cond_destroy (&xtn->ev.cnd2);
|
|
|
|
pthread_mutex_destroy (&xtn->ev.mtx);
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
_del_poll_fd (moo, xtn->iothr.p[0]);
|
2019-10-10 06:30:04 +00:00
|
|
|
close_pipes (moo, xtn->iothr.p);
|
2018-11-07 15:26:30 +00:00
|
|
|
#endif /* USE_THREAD */
|
|
|
|
|
2019-10-10 06:30:04 +00:00
|
|
|
close_pipes (moo, xtn->sigfd.p);
|
2019-08-15 15:55:06 +00:00
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
if (xtn->ep >= 0)
|
|
|
|
{
|
|
|
|
close (xtn->ep);
|
|
|
|
xtn->ep = -1;
|
|
|
|
}
|
|
|
|
/*destroy_poll_data_space (moo);*/
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
if (xtn->ep >= 0)
|
|
|
|
{
|
|
|
|
close (xtn->ep);
|
|
|
|
xtn->ep = -1;
|
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
if (xtn->ep >= 0)
|
|
|
|
{
|
|
|
|
close (xtn->ep);
|
|
|
|
xtn->ep = -1;
|
|
|
|
}
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
if (xtn->ev.reg.ptr)
|
|
|
|
{
|
|
|
|
moo_freemem (moo, xtn->ev.reg.ptr);
|
|
|
|
xtn->ev.reg.ptr = MOO_NULL;
|
|
|
|
xtn->ev.reg.len = 0;
|
|
|
|
xtn->ev.reg.capa = 0;
|
|
|
|
}
|
|
|
|
if (xtn->ev.buf)
|
|
|
|
{
|
|
|
|
moo_freemem (moo, xtn->ev.buf);
|
|
|
|
xtn->ev.buf = MOO_NULL;
|
|
|
|
}
|
|
|
|
/*destroy_poll_data_space (moo);*/
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
static void vm_gettime (moo_t* moo, moo_ntime_t* now)
|
|
|
|
{
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
|
|
|
#if defined(_WIN64) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600))
|
|
|
|
moo_uint64_t bigsec, bigmsec;
|
|
|
|
bigmsec = GetTickCount64();
|
|
|
|
#else
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_uint64_t bigsec, bigmsec;
|
|
|
|
DWORD msec;
|
|
|
|
|
|
|
|
msec = GetTickCount(); /* this can sustain for 49.7 days */
|
|
|
|
if (msec < xtn->tc_last)
|
|
|
|
{
|
|
|
|
/* i assume the difference is never bigger than 49.7 days */
|
|
|
|
/*diff = (MOO_TYPE_MAX(DWORD) - xtn->tc_last) + 1 + msec;*/
|
|
|
|
xtn->tc_overflow++;
|
|
|
|
bigmsec = ((moo_uint64_t)MOO_TYPE_MAX(DWORD) * xtn->tc_overflow) + msec;
|
|
|
|
}
|
|
|
|
else bigmsec = msec;
|
|
|
|
xtn->tc_last = msec;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bigsec = MOO_MSEC_TO_SEC(bigmsec);
|
|
|
|
bigmsec -= MOO_SEC_TO_MSEC(bigsec);
|
|
|
|
MOO_INIT_NTIME(now, bigsec, MOO_MSEC_TO_NSEC(bigmsec));
|
|
|
|
|
|
|
|
#elif defined(__OS2__)
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-12-01 14:52:24 +00:00
|
|
|
ULONG msec, elapsed;
|
|
|
|
moo_ntime_t et;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
/* TODO: use DosTmrQueryTime() and DosTmrQueryFreq()? */
|
|
|
|
DosQuerySysInfo (QSV_MS_COUNT, QSV_MS_COUNT, &msec, MOO_SIZEOF(msec)); /* milliseconds */
|
2018-12-01 14:52:24 +00:00
|
|
|
|
|
|
|
elapsed = (msec < xtn->tc_last)? (MOO_TYPE_MAX(ULONG) - xtn->tc_last + msec + 1): (msec - xtn->tc_last);
|
2018-11-07 15:26:30 +00:00
|
|
|
xtn->tc_last = msec;
|
|
|
|
|
2018-12-01 14:52:24 +00:00
|
|
|
et.sec = MOO_MSEC_TO_SEC(elapsed);
|
|
|
|
msec = elapsed - MOO_SEC_TO_MSEC(et.sec);
|
|
|
|
et.nsec = MOO_MSEC_TO_NSEC(msec);
|
|
|
|
|
|
|
|
MOO_ADD_NTIME (&xtn->tc_last_ret , &xtn->tc_last_ret, &et);
|
|
|
|
*now = xtn->tc_last_ret;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#elif defined(__DOS__) && (defined(_INTELC32_) || defined(__WATCOMC__))
|
2018-11-30 15:19:33 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-12-01 06:15:31 +00:00
|
|
|
clock_t c, elapsed;
|
|
|
|
moo_ntime_t et;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2018-11-30 15:19:33 +00:00
|
|
|
c = clock();
|
2018-12-01 14:52:24 +00:00
|
|
|
elapsed = (c < xtn->tc_last)? (MOO_TYPE_MAX(clock_t) - xtn->tc_last + c + 1): (c - xtn->tc_last);
|
|
|
|
xtn->tc_last = c;
|
2018-11-30 14:18:35 +00:00
|
|
|
|
2018-12-01 06:15:31 +00:00
|
|
|
et.sec = elapsed / CLOCKS_PER_SEC;
|
2018-11-07 15:26:30 +00:00
|
|
|
#if (CLOCKS_PER_SEC == 100)
|
2018-12-01 06:15:31 +00:00
|
|
|
et.nsec = MOO_MSEC_TO_NSEC((elapsed % CLOCKS_PER_SEC) * 10);
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif (CLOCKS_PER_SEC == 1000)
|
2018-12-01 06:15:31 +00:00
|
|
|
et.nsec = MOO_MSEC_TO_NSEC(elapsed % CLOCKS_PER_SEC);
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif (CLOCKS_PER_SEC == 1000000L)
|
2018-12-01 06:15:31 +00:00
|
|
|
et.nsec = MOO_USEC_TO_NSEC(elapsed % CLOCKS_PER_SEC);
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif (CLOCKS_PER_SEC == 1000000000L)
|
2018-12-01 06:15:31 +00:00
|
|
|
et.nsec = (elapsed % CLOCKS_PER_SEC);
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
# error UNSUPPORTED CLOCKS_PER_SEC
|
|
|
|
#endif
|
|
|
|
|
2018-12-01 06:15:31 +00:00
|
|
|
MOO_ADD_NTIME (&xtn->tc_last_ret , &xtn->tc_last_ret, &et);
|
|
|
|
*now = xtn->tc_last_ret;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(macintosh)
|
|
|
|
UnsignedWide tick;
|
|
|
|
moo_uint64_t tick64;
|
|
|
|
Microseconds (&tick);
|
|
|
|
tick64 = *(moo_uint64_t*)&tick;
|
|
|
|
MOO_INIT_NTIME (now, MOO_USEC_TO_SEC(tick64), MOO_USEC_TO_NSEC(tick64));
|
|
|
|
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
|
|
|
|
struct timespec ts;
|
|
|
|
clock_gettime (CLOCK_MONOTONIC, &ts);
|
|
|
|
MOO_INIT_NTIME(now, ts.tv_sec, ts.tv_nsec);
|
|
|
|
#elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
|
|
|
|
struct timespec ts;
|
|
|
|
clock_gettime (CLOCK_REALTIME, &ts);
|
|
|
|
MOO_INIT_NTIME(now, ts.tv_sec, ts.tv_nsec);
|
|
|
|
#else
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday (&tv, MOO_NULL);
|
|
|
|
MOO_INIT_NTIME(now, tv.tv_sec, MOO_USEC_TO_NSEC(tv.tv_usec));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vm_muxadd (moo_t* moo, moo_ooi_t io_handle, moo_ooi_t mask)
|
|
|
|
{
|
|
|
|
int event_mask;
|
|
|
|
|
|
|
|
event_mask = 0;
|
|
|
|
if (mask & MOO_SEMAPHORE_IO_MASK_INPUT) event_mask |= XPOLLIN;
|
|
|
|
if (mask & MOO_SEMAPHORE_IO_MASK_OUTPUT) event_mask |= XPOLLOUT;
|
|
|
|
|
|
|
|
if (event_mask == 0)
|
|
|
|
{
|
|
|
|
MOO_DEBUG2 (moo, "<vm_muxadd> Invalid semaphore mask %zd on handle %zd\n", mask, io_handle);
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "invalid semaphore mask %zd on handle %zd", mask, io_handle);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _add_poll_fd(moo, io_handle, event_mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vm_muxmod (moo_t* moo, moo_ooi_t io_handle, moo_ooi_t mask)
|
|
|
|
{
|
|
|
|
int event_mask;
|
|
|
|
|
|
|
|
event_mask = 0;
|
|
|
|
if (mask & MOO_SEMAPHORE_IO_MASK_INPUT) event_mask |= XPOLLIN;
|
|
|
|
if (mask & MOO_SEMAPHORE_IO_MASK_OUTPUT) event_mask |= XPOLLOUT;
|
|
|
|
|
|
|
|
if (event_mask == 0)
|
|
|
|
{
|
|
|
|
MOO_DEBUG2 (moo, "<vm_muxadd> Invalid semaphore mask %zd on handle %zd\n", mask, io_handle);
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "invalid semaphore mask %zd on handle %zd", mask, io_handle);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return _mod_poll_fd(moo, io_handle, event_mask);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vm_muxdel (moo_t* moo, moo_ooi_t io_handle)
|
|
|
|
{
|
|
|
|
return _del_poll_fd(moo, io_handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
static void* iothr_main (void* arg)
|
|
|
|
{
|
|
|
|
moo_t* moo = (moo_t*)arg;
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
/*while (!moo->abort_req)*/
|
2018-11-13 07:40:30 +00:00
|
|
|
while (!xtn->iothr.abort)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
if (xtn->ev.len <= 0) /* TODO: no mutex needed for this check? */
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
struct dvpoll dvp;
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
struct timespec ts;
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_POLL)
|
|
|
|
moo_oow_t nfds;
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
struct timeval tv;
|
|
|
|
fd_set rfds;
|
|
|
|
fd_set wfds;
|
|
|
|
int maxfd;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
poll_for_event:
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
dvp.dp_timeout = 10000; /* milliseconds */
|
|
|
|
dvp.dp_fds = xtn->ev.buf;
|
|
|
|
dvp.dp_nfds = MOO_COUNTOF(xtn->ev.buf);
|
|
|
|
n = ioctl (xtn->ep, DP_POLL, &dvp);
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
ts.tv_sec = 10;
|
|
|
|
ts.tv_nsec = 0;
|
|
|
|
n = kevent(xtn->ep, MOO_NULL, 0, xtn->ev.buf, MOO_COUNTOF(xtn->ev.buf), &ts);
|
|
|
|
/* n == 0: timeout
|
|
|
|
* n == -1: error */
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
2019-08-15 15:55:06 +00:00
|
|
|
n = epoll_wait(xtn->ep, xtn->ev.buf, MOO_COUNTOF(xtn->ev.buf), 10000); /* TODO: make this timeout value in the io thread */
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_POLL)
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.pmtx);
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMCPY (xtn->ev.buf, xtn->ev.reg.ptr, xtn->ev.reg.len * MOO_SIZEOF(*xtn->ev.buf));
|
2018-11-07 15:26:30 +00:00
|
|
|
nfds = xtn->ev.reg.len;
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.pmtx);
|
|
|
|
n = poll(xtn->ev.buf, nfds, 10000);
|
|
|
|
if (n > 0)
|
|
|
|
{
|
|
|
|
/* compact the return buffer as poll() doesn't */
|
|
|
|
moo_oow_t i, j;
|
|
|
|
for (i = 0, j = 0; i < nfds && j < n; i++)
|
|
|
|
{
|
|
|
|
if (xtn->ev.buf[i].revents)
|
|
|
|
{
|
|
|
|
if (j != i) xtn->ev.buf[j] = xtn->ev.buf[i];
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n = j;
|
|
|
|
}
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
tv.tv_sec = 10;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
MUTEX_LOCK (&xtn->ev.reg.smtx);
|
|
|
|
maxfd = xtn->ev.reg.maxfd;
|
|
|
|
MOO_MEMCPY (&rfds, &xtn->ev.reg.rfds, MOO_SIZEOF(rfds));
|
|
|
|
MOO_MEMCPY (&wfds, &xtn->ev.reg.wfds, MOO_SIZEOF(wfds));
|
|
|
|
MUTEX_UNLOCK (&xtn->ev.reg.smtx);
|
2018-11-21 13:37:27 +00:00
|
|
|
n = select (maxfd + 1, &rfds, &wfds, MOO_NULL, &tv);
|
2018-11-07 15:26:30 +00:00
|
|
|
if (n > 0)
|
|
|
|
{
|
|
|
|
int fd, count = 0;
|
|
|
|
for (fd = 0; fd <= maxfd; fd++)
|
|
|
|
{
|
|
|
|
int events = 0;
|
|
|
|
if (FD_ISSET(fd, &rfds)) events |= XPOLLIN;
|
|
|
|
if (FD_ISSET(fd, &wfds)) events |= XPOLLOUT;
|
|
|
|
|
|
|
|
if (events)
|
|
|
|
{
|
|
|
|
MOO_ASSERT (moo, count < MOO_COUNTOF(xtn->ev.buf));
|
|
|
|
xtn->ev.buf[count].fd = fd;
|
|
|
|
xtn->ev.buf[count].events = events;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n = count;
|
|
|
|
MOO_ASSERT (moo, n > 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
pthread_mutex_lock (&xtn->ev.mtx);
|
|
|
|
if (n <= -1)
|
|
|
|
{
|
|
|
|
/* TODO: don't use MOO_DEBUG2. it's not thread safe... */
|
|
|
|
/* the following call has a race-condition issue when called in this separate thread */
|
|
|
|
/*MOO_DEBUG2 (moo, "Warning: multiplexer wait failure - %d, %hs\n", errno, strerror(errno));*/
|
|
|
|
}
|
|
|
|
else if (n > 0)
|
|
|
|
{
|
|
|
|
xtn->ev.len = n;
|
|
|
|
}
|
|
|
|
pthread_cond_signal (&xtn->ev.cnd2);
|
|
|
|
pthread_mutex_unlock (&xtn->ev.mtx);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* the event buffer has not been emptied yet */
|
|
|
|
struct timespec ts;
|
|
|
|
|
|
|
|
pthread_mutex_lock (&xtn->ev.mtx);
|
|
|
|
if (xtn->ev.len <= 0)
|
|
|
|
{
|
|
|
|
/* it got emptied between the if check and pthread_mutex_lock() above */
|
|
|
|
pthread_mutex_unlock (&xtn->ev.mtx);
|
|
|
|
goto poll_for_event;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
|
|
|
|
clock_gettime (CLOCK_REALTIME, &ts);
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday (&tv, MOO_NULL);
|
|
|
|
ts.tv_sec = tv.tv_sec;
|
|
|
|
ts.tv_nsec = MOO_USEC_TO_NSEC(tv.tv_usec);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ts.tv_sec += 10;
|
|
|
|
pthread_cond_timedwait (&xtn->ev.cnd, &xtn->ev.mtx, &ts);
|
|
|
|
pthread_mutex_unlock (&xtn->ev.mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*sched_yield ();*/
|
|
|
|
}
|
|
|
|
|
|
|
|
return MOO_NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void vm_muxwait (moo_t* moo, const moo_ntime_t* dur, moo_vmprim_muxwait_cb_t muxwcb)
|
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
int n;
|
|
|
|
|
|
|
|
/* create a thread if mux wait is started at least once. */
|
2018-11-13 07:40:30 +00:00
|
|
|
if (!xtn->iothr.up)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->iothr.up = 1;
|
2019-09-03 06:33:58 +00:00
|
|
|
if (pthread_create(&xtn->iothr.thr, MOO_NULL, iothr_main, moo) != 0)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
MOO_LOG2 (moo, MOO_LOG_WARN, "Warning: pthread_create failure - %d, %hs\n", errno, strerror(errno));
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->iothr.up = 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
/* TODO: switch to the non-threaded mode? */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->iothr.abort) return;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
if (xtn->ev.len <= 0)
|
|
|
|
{
|
|
|
|
struct timespec ts;
|
|
|
|
moo_ntime_t ns;
|
|
|
|
|
|
|
|
if (!dur) return; /* immediate check is requested. and there is no event */
|
|
|
|
|
|
|
|
#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)
|
|
|
|
clock_gettime (CLOCK_REALTIME, &ts);
|
|
|
|
ns.sec = ts.tv_sec;
|
|
|
|
ns.nsec = ts.tv_nsec;
|
|
|
|
#else
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday (&tv, MOO_NULL);
|
|
|
|
ns.sec = tv.tv_sec;
|
|
|
|
ns.nsec = MOO_USEC_TO_NSEC(tv.tv_usec);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
MOO_ADD_NTIME (&ns, &ns, dur);
|
|
|
|
ts.tv_sec = ns.sec;
|
|
|
|
ts.tv_nsec = ns.nsec;
|
|
|
|
|
|
|
|
pthread_mutex_lock (&xtn->ev.mtx);
|
2019-09-03 06:33:58 +00:00
|
|
|
if (xtn->ev.len <= 0)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
/* the event buffer is still empty */
|
|
|
|
pthread_cond_timedwait (&xtn->ev.cnd2, &xtn->ev.mtx, &ts);
|
|
|
|
}
|
|
|
|
pthread_mutex_unlock (&xtn->ev.mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
n = xtn->ev.len;
|
|
|
|
|
|
|
|
if (n > 0)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
--n;
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->ev.buf[n].fd == xtn->iothr.p[0])
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
if (xtn->ev.buf[n].ident == xtn->iothr.p[0])
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
/*if (xtn->ev.buf[n].data.ptr == (void*)MOO_TYPE_MAX(moo_oow_t))*/
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->ev.buf[n].data.fd == xtn->iothr.p[0])
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_POLL)
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->ev.buf[n].fd == xtn->iothr.p[0])
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_SELECT)
|
2018-11-13 07:40:30 +00:00
|
|
|
if (xtn->ev.buf[n].fd == xtn->iothr.p[0])
|
2018-11-07 15:26:30 +00:00
|
|
|
#else
|
|
|
|
# error UNSUPPORTED
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
moo_uint8_t u8;
|
2018-11-13 07:40:30 +00:00
|
|
|
while (read(xtn->iothr.p[0], &u8, MOO_SIZEOF(u8)) > 0)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
/* consume as much as possible */;
|
2018-11-13 07:40:30 +00:00
|
|
|
if (u8 == 'Q') xtn->iothr.abort = 1;
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (muxwcb)
|
|
|
|
{
|
|
|
|
int revents;
|
|
|
|
moo_ooi_t mask;
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
revents = xtn->ev.buf[n].revents;
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
if (xtn->ev.buf[n].filter == EVFILT_READ) mask = MOO_SEMAPHORE_IO_MASK_INPUT;
|
|
|
|
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) mask = MOO_SEMAPHORE_IO_MASK_OUTPUT;
|
|
|
|
else mask = 0;
|
|
|
|
goto call_muxwcb_kqueue;
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
revents = xtn->ev.buf[n].events;
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
revents = xtn->ev.buf[n].revents;
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
revents = xtn->ev.buf[n].events;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mask = 0;
|
|
|
|
if (revents & XPOLLIN) mask |= MOO_SEMAPHORE_IO_MASK_INPUT;
|
|
|
|
if (revents & XPOLLOUT) mask |= MOO_SEMAPHORE_IO_MASK_OUTPUT;
|
|
|
|
if (revents & XPOLLERR) mask |= MOO_SEMAPHORE_IO_MASK_ERROR;
|
|
|
|
if (revents & XPOLLHUP) mask |= MOO_SEMAPHORE_IO_MASK_HANGUP;
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].fd, mask);
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
call_muxwcb_kqueue:
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].ident, mask);
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].data.fd, mask);
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].fd, mask);
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].fd, mask);
|
|
|
|
#else
|
|
|
|
# error UNSUPPORTED
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (n > 0);
|
|
|
|
|
|
|
|
pthread_mutex_lock (&xtn->ev.mtx);
|
|
|
|
xtn->ev.len = 0;
|
|
|
|
pthread_cond_signal (&xtn->ev.cnd);
|
|
|
|
pthread_mutex_unlock (&xtn->ev.mtx);
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* USE_THREAD */
|
2019-09-23 08:44:22 +00:00
|
|
|
int n;
|
2018-11-07 15:26:30 +00:00
|
|
|
#if defined(USE_DEVPOLL)
|
2019-09-23 08:44:22 +00:00
|
|
|
int tmout;
|
2018-11-07 15:26:30 +00:00
|
|
|
struct dvpoll dvp;
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
struct timespec ts;
|
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
int tmout;
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
int tmout;
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
struct timeval tv;
|
|
|
|
fd_set rfds, wfds;
|
|
|
|
int maxfd;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
2019-09-23 08:44:22 +00:00
|
|
|
tmout = dur? MOO_SECNSEC_TO_MSEC(dur->sec, dur->nsec): 0;
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
dvp.dp_timeout = tmout; /* milliseconds */
|
|
|
|
dvp.dp_fds = xtn->ev.buf;
|
|
|
|
dvp.dp_nfds = MOO_COUNTOF(xtn->ev.buf);
|
2019-08-15 15:55:06 +00:00
|
|
|
n = ioctl(xtn->ep, DP_POLL, &dvp);
|
2019-09-23 08:44:22 +00:00
|
|
|
|
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
|
|
|
|
if (dur)
|
|
|
|
{
|
|
|
|
ts.tv_sec = dur->sec;
|
|
|
|
ts.tv_nsec = dur->nsec;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ts.tv_sec = 0;
|
|
|
|
ts.tv_nsec = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = kevent(xtn->ep, MOO_NULL, 0, xtn->ev.buf, MOO_COUNTOF(xtn->ev.buf), &ts);
|
|
|
|
/* n == 0: timeout
|
|
|
|
* n == -1: error */
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
2019-09-23 08:44:22 +00:00
|
|
|
tmout = dur? MOO_SECNSEC_TO_MSEC(dur->sec, dur->nsec): 0;
|
2019-08-15 15:55:06 +00:00
|
|
|
n = epoll_wait(xtn->ep, xtn->ev.buf, MOO_COUNTOF(xtn->ev.buf), tmout);
|
2019-09-23 08:44:22 +00:00
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_POLL)
|
2019-09-23 08:44:22 +00:00
|
|
|
tmout = dur? MOO_SECNSEC_TO_MSEC(dur->sec, dur->nsec): 0;
|
2018-11-11 16:53:21 +00:00
|
|
|
MOO_MEMCPY (xtn->ev.buf, xtn->ev.reg.ptr, xtn->ev.reg.len * MOO_SIZEOF(*xtn->ev.buf));
|
2018-11-07 15:26:30 +00:00
|
|
|
n = poll(xtn->ev.buf, xtn->ev.reg.len, tmout);
|
|
|
|
if (n > 0)
|
|
|
|
{
|
|
|
|
/* compact the return buffer as poll() doesn't */
|
|
|
|
moo_oow_t i, j;
|
|
|
|
for (i = 0, j = 0; i < xtn->ev.reg.len && j < n; i++)
|
|
|
|
{
|
|
|
|
if (xtn->ev.buf[i].revents)
|
|
|
|
{
|
|
|
|
if (j != i) xtn->ev.buf[j] = xtn->ev.buf[i];
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
n = j;
|
|
|
|
}
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
if (dur)
|
|
|
|
{
|
|
|
|
tv.tv_sec = dur->sec;
|
|
|
|
tv.tv_usec = MOO_NSEC_TO_USEC(dur->nsec);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tv.tv_sec = 0;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
}
|
|
|
|
maxfd = xtn->ev.reg.maxfd;
|
|
|
|
MOO_MEMCPY (&rfds, &xtn->ev.reg.rfds, MOO_SIZEOF(rfds));
|
|
|
|
MOO_MEMCPY (&wfds, &xtn->ev.reg.wfds, MOO_SIZEOF(wfds));
|
2018-11-21 13:37:27 +00:00
|
|
|
n = select(maxfd + 1, &rfds, &wfds, MOO_NULL, &tv);
|
2018-11-07 15:26:30 +00:00
|
|
|
if (n > 0)
|
|
|
|
{
|
|
|
|
int fd, count = 0;
|
|
|
|
for (fd = 0; fd <= maxfd; fd++)
|
|
|
|
{
|
|
|
|
int events = 0;
|
|
|
|
if (FD_ISSET(fd, &rfds)) events |= XPOLLIN;
|
|
|
|
if (FD_ISSET(fd, &wfds)) events |= XPOLLOUT;
|
|
|
|
|
|
|
|
if (events)
|
|
|
|
{
|
|
|
|
MOO_ASSERT (moo, count < MOO_COUNTOF(xtn->ev.buf));
|
|
|
|
xtn->ev.buf[count].fd = fd;
|
|
|
|
xtn->ev.buf[count].events = events;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
n = count;
|
|
|
|
MOO_ASSERT (moo, n > 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (n <= -1)
|
|
|
|
{
|
2021-03-30 06:11:20 +00:00
|
|
|
#if defined(__OS2__)
|
|
|
|
moo_seterrwithsyserr (moo, 2, sock_errno());
|
|
|
|
MOO_DEBUG2 (moo, "Warning: multiplexer wait failure - %d, %js\n", sock_errno(), moo_geterrmsg(moo));
|
|
|
|
#else
|
2018-11-07 15:26:30 +00:00
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
2021-02-11 14:08:43 +00:00
|
|
|
MOO_DEBUG2 (moo, "Warning: multiplexer wait failure - %d, %js\n", errno, moo_geterrmsg(moo));
|
2021-03-30 06:11:20 +00:00
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
xtn->ev.len = n;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the muxwcb must be valid all the time in a non-threaded mode */
|
|
|
|
MOO_ASSERT (moo, muxwcb != MOO_NULL);
|
|
|
|
|
|
|
|
while (n > 0)
|
|
|
|
{
|
|
|
|
int revents;
|
|
|
|
moo_ooi_t mask;
|
|
|
|
|
|
|
|
--n;
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
revents = xtn->ev.buf[n].revents;
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
if (xtn->ev.buf[n].filter == EVFILT_READ) mask = MOO_SEMAPHORE_IO_MASK_INPUT;
|
|
|
|
else if (xtn->ev.buf[n].filter == EVFILT_WRITE) mask = MOO_SEMAPHORE_IO_MASK_OUTPUT;
|
|
|
|
else mask = 0;
|
|
|
|
goto call_muxwcb_kqueue;
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
revents = xtn->ev.buf[n].events;
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
revents = xtn->ev.buf[n].revents;
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
revents = xtn->ev.buf[n].events;
|
|
|
|
#else
|
|
|
|
revents = 0; /* TODO: fake. unsupported but to compile on such an unsupported system.*/
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mask = 0;
|
|
|
|
if (revents & XPOLLIN) mask |= MOO_SEMAPHORE_IO_MASK_INPUT;
|
|
|
|
if (revents & XPOLLOUT) mask |= MOO_SEMAPHORE_IO_MASK_OUTPUT;
|
|
|
|
if (revents & XPOLLERR) mask |= MOO_SEMAPHORE_IO_MASK_ERROR;
|
|
|
|
if (revents & XPOLLHUP) mask |= MOO_SEMAPHORE_IO_MASK_HANGUP;
|
|
|
|
|
|
|
|
#if defined(USE_DEVPOLL)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].fd, mask);
|
2019-09-23 08:44:22 +00:00
|
|
|
#elif defined(USE_KQUEUE)
|
|
|
|
call_muxwcb_kqueue:
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].ident, mask);
|
2018-11-07 15:26:30 +00:00
|
|
|
#elif defined(USE_EPOLL)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].data.fd, mask);
|
|
|
|
#elif defined(USE_POLL)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].fd, mask);
|
|
|
|
#elif defined(USE_SELECT)
|
|
|
|
muxwcb (moo, xtn->ev.buf[n].fd, mask);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
xtn->ev.len = 0;
|
|
|
|
#endif /* USE_THREAD */
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(__DOS__)
|
|
|
|
# if defined(_INTELC32_)
|
|
|
|
void _halt_cpu (void);
|
|
|
|
# elif defined(__WATCOMC__)
|
|
|
|
void _halt_cpu (void);
|
|
|
|
# pragma aux _halt_cpu = "hlt"
|
|
|
|
# endif
|
|
|
|
#endif
|
|
|
|
|
2019-09-03 06:33:58 +00:00
|
|
|
static int vm_sleep (moo_t* moo, const moo_ntime_t* dur)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2019-09-03 06:33:58 +00:00
|
|
|
|
|
|
|
if (MOO_UNLIKELY(xtn->ev.halting)) return xtn->ev.halting;
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
2018-11-07 15:26:30 +00:00
|
|
|
if (xtn->waitable_timer)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER li;
|
|
|
|
li.QuadPart = -(MOO_SECNSEC_TO_NSEC(dur->sec, dur->nsec) / 100); /* in 100 nanoseconds */
|
|
|
|
if(SetWaitableTimer(xtn->waitable_timer, &li, 0, MOO_NULL, MOO_NULL, FALSE) == FALSE) goto normal_sleep;
|
|
|
|
WaitForSingleObject(xtn->waitable_timer, INFINITE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
normal_sleep:
|
|
|
|
/* fallback to normal Sleep() */
|
|
|
|
Sleep (MOO_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 (MOO_SECNSEC_TO_MSEC(dur->sec,dur->nsec));
|
|
|
|
|
|
|
|
#elif defined(macintosh)
|
|
|
|
|
|
|
|
/* TODO: ... */
|
2019-09-03 06:33:58 +00:00
|
|
|
# error NOT IMPLEMENTED
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
#elif defined(__DOS__) && (defined(_INTELC32_) || defined(__WATCOMC__))
|
2019-09-03 06:33:58 +00:00
|
|
|
{
|
|
|
|
clock_t c;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-09-03 06:33:58 +00:00
|
|
|
c = clock ();
|
|
|
|
c += dur->sec * CLOCKS_PER_SEC;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-09-03 06:33:58 +00:00
|
|
|
#if (CLOCKS_PER_SEC == 100)
|
|
|
|
c += MOO_NSEC_TO_MSEC(dur->nsec) / 10;
|
|
|
|
#elif (CLOCKS_PER_SEC == 1000)
|
|
|
|
c += MOO_NSEC_TO_MSEC(dur->nsec);
|
|
|
|
#elif (CLOCKS_PER_SEC == 1000000L)
|
|
|
|
c += MOO_NSEC_TO_USEC(dur->nsec);
|
|
|
|
#elif (CLOCKS_PER_SEC == 1000000000L)
|
|
|
|
c += dur->nsec;
|
|
|
|
#else
|
|
|
|
# error UNSUPPORTED CLOCKS_PER_SEC
|
|
|
|
#endif
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2019-09-03 06:33:58 +00:00
|
|
|
/* TODO: handle clock overvlow */
|
|
|
|
/* TODO: check if there is abortion request or interrupt */
|
|
|
|
while (c > clock())
|
|
|
|
{
|
|
|
|
_halt_cpu();
|
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
2019-09-03 06:33:58 +00:00
|
|
|
#elif defined(USE_THREAD)
|
2018-11-07 15:26:30 +00:00
|
|
|
/* 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 */
|
2019-09-03 06:33:58 +00:00
|
|
|
vm_muxwait (moo, dur, MOO_NULL);
|
|
|
|
|
|
|
|
#elif defined(HAVE_NANOSLEEP)
|
|
|
|
{
|
2018-11-07 15:26:30 +00:00
|
|
|
struct timespec ts;
|
|
|
|
ts.tv_sec = dur->sec;
|
|
|
|
ts.tv_nsec = dur->nsec;
|
|
|
|
nanosleep (&ts, MOO_NULL);
|
2019-09-03 06:33:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(HAVE_USLEEP)
|
|
|
|
usleep (MOO_SECNSEC_TO_USEC(dur->sec, dur->nsec));
|
|
|
|
|
|
|
|
#else
|
|
|
|
# error UNSUPPORTED SLEEP
|
2018-11-07 15:26:30 +00:00
|
|
|
#endif
|
2019-09-03 06:33:58 +00:00
|
|
|
|
|
|
|
return 0;
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2019-08-15 15:55:06 +00:00
|
|
|
static moo_ooi_t vm_getsigfd (moo_t* moo)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
return xtn->sigfd.p[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vm_getsig (moo_t* moo, moo_uint8_t* u8)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2019-10-11 03:30:00 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
/* TODO: can i make the pipe non-block in win32? */
|
|
|
|
DWORD navail;
|
|
|
|
if (PeekNamedPipe(_get_osfhandle(xtn->sigfd.p[0]), MOO_NULL, 0, MOO_NULL, &navail, MOO_NULL) == 0)
|
|
|
|
{
|
|
|
|
moo_seterrwithsyserr (moo, 1, GetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (navail <= 0) return 0;
|
|
|
|
#endif
|
2019-08-15 15:55:06 +00:00
|
|
|
if (read(xtn->sigfd.p[0], u8, MOO_SIZEOF(*u8)) == -1)
|
|
|
|
{
|
|
|
|
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
return -1;
|
|
|
|
}
|
2019-10-11 03:30:00 +00:00
|
|
|
|
2019-08-15 15:55:06 +00:00
|
|
|
return 1;
|
|
|
|
}
|
2019-08-16 15:29:36 +00:00
|
|
|
|
|
|
|
static int vm_setsig (moo_t* moo, moo_uint8_t u8)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
if (write(xtn->sigfd.p[1], &u8, MOO_SIZEOF(u8)) == -1)
|
|
|
|
{
|
|
|
|
if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) return 0;
|
|
|
|
moo_seterrwithsyserr (moo, 0, errno);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2018-11-11 16:53:21 +00:00
|
|
|
/* ========================================================================= */
|
|
|
|
|
2018-11-19 15:52:26 +00:00
|
|
|
#if defined(HAVE_SIGACTION)
|
|
|
|
|
2018-11-18 15:38:59 +00:00
|
|
|
typedef struct sig_state_t sig_state_t;
|
|
|
|
struct sig_state_t
|
|
|
|
{
|
|
|
|
moo_oow_t handler;
|
|
|
|
moo_oow_t old_handler;
|
|
|
|
sigset_t old_sa_mask;
|
|
|
|
int old_sa_flags;
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef void (*sig_handler_t) (int sig);
|
|
|
|
|
2018-11-19 15:52:26 +00:00
|
|
|
static sig_state_t g_sig_state[MOO_NSIG];
|
2018-11-18 15:38:59 +00:00
|
|
|
|
|
|
|
static void dispatch_siginfo (int sig, siginfo_t* si, void* ctx)
|
|
|
|
{
|
2018-11-19 15:52:26 +00:00
|
|
|
if (g_sig_state[sig].handler != (moo_oow_t)SIG_IGN &&
|
|
|
|
g_sig_state[sig].handler != (moo_oow_t)SIG_DFL)
|
|
|
|
{
|
|
|
|
((sig_handler_t)g_sig_state[sig].handler) (sig);
|
|
|
|
}
|
|
|
|
|
2018-11-18 15:38:59 +00:00
|
|
|
if (g_sig_state[sig].old_handler &&
|
|
|
|
g_sig_state[sig].old_handler != (moo_oow_t)SIG_IGN &&
|
|
|
|
g_sig_state[sig].old_handler != (moo_oow_t)SIG_DFL)
|
|
|
|
{
|
|
|
|
((void(*)(int, siginfo_t*, void*))g_sig_state[sig].old_handler) (sig, si, ctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void dispatch_signal (int sig)
|
|
|
|
{
|
2018-11-19 15:52:26 +00:00
|
|
|
if (g_sig_state[sig].handler != (moo_oow_t)SIG_IGN &&
|
|
|
|
g_sig_state[sig].handler != (moo_oow_t)SIG_DFL)
|
|
|
|
{
|
|
|
|
((sig_handler_t)g_sig_state[sig].handler) (sig);
|
|
|
|
}
|
|
|
|
|
2018-11-18 15:38:59 +00:00
|
|
|
if (g_sig_state[sig].old_handler &&
|
|
|
|
g_sig_state[sig].old_handler != (moo_oow_t)SIG_IGN &&
|
|
|
|
g_sig_state[sig].old_handler != (moo_oow_t)SIG_DFL)
|
|
|
|
{
|
|
|
|
((sig_handler_t)g_sig_state[sig].old_handler) (sig);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int set_signal_handler (int sig, sig_handler_t handler, int extra_flags)
|
|
|
|
{
|
|
|
|
if (g_sig_state[sig].handler)
|
|
|
|
{
|
|
|
|
/* already set - allow handler change. ignore extra_flags. */
|
2018-11-19 15:52:26 +00:00
|
|
|
if (g_sig_state[sig].handler == (moo_oow_t)handler) return -1;
|
2018-11-18 15:38:59 +00:00
|
|
|
g_sig_state[sig].handler = (moo_oow_t)handler;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
struct sigaction sa, oldsa;
|
|
|
|
|
|
|
|
if (sigaction(sig, MOO_NULL, &oldsa) == -1) return -1;
|
|
|
|
|
|
|
|
MOO_MEMSET (&sa, 0, MOO_SIZEOF(sa));
|
|
|
|
if (oldsa.sa_flags & SA_SIGINFO)
|
|
|
|
{
|
|
|
|
sa.sa_sigaction = dispatch_siginfo;
|
|
|
|
sa.sa_flags = SA_SIGINFO;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sa.sa_handler = dispatch_signal;
|
|
|
|
sa.sa_flags = 0;
|
|
|
|
}
|
|
|
|
sa.sa_flags |= extra_flags;
|
|
|
|
/*sa.sa_flags |= SA_INTERUPT;
|
|
|
|
sa.sa_flags |= SA_RESTART;*/
|
|
|
|
sigfillset (&sa.sa_mask); /* block all signals while the handler is being executed */
|
|
|
|
|
|
|
|
if (sigaction(sig, &sa, MOO_NULL) == -1) return -1;
|
|
|
|
|
|
|
|
g_sig_state[sig].handler = (moo_oow_t)handler;
|
|
|
|
if (oldsa.sa_flags & SA_SIGINFO)
|
|
|
|
g_sig_state[sig].old_handler = (moo_oow_t)oldsa.sa_sigaction;
|
|
|
|
else
|
|
|
|
g_sig_state[sig].old_handler = (moo_oow_t)oldsa.sa_handler;
|
|
|
|
|
|
|
|
g_sig_state[sig].old_sa_mask = oldsa.sa_mask;
|
|
|
|
g_sig_state[sig].old_sa_flags = oldsa.sa_flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int unset_signal_handler (int sig)
|
|
|
|
{
|
|
|
|
struct sigaction sa;
|
|
|
|
|
|
|
|
if (!g_sig_state[sig].handler) return -1; /* not set */
|
|
|
|
|
|
|
|
MOO_MEMSET (&sa, 0, MOO_SIZEOF(sa));
|
|
|
|
sa.sa_mask = g_sig_state[sig].old_sa_mask;
|
|
|
|
sa.sa_flags = g_sig_state[sig].old_sa_flags;
|
|
|
|
|
|
|
|
if (sa.sa_flags & SA_SIGINFO)
|
|
|
|
{
|
|
|
|
sa.sa_sigaction = (void(*)(int,siginfo_t*,void*))g_sig_state[sig].old_handler;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sa.sa_handler = (sig_handler_t)g_sig_state[sig].old_handler;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sigaction(sig, &sa, MOO_NULL) == -1) return -1;
|
|
|
|
|
|
|
|
g_sig_state[sig].handler = 0;
|
|
|
|
/* keep other fields untouched */
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-10-12 14:55:37 +00:00
|
|
|
static int is_signal_handler_set (int sig)
|
|
|
|
{
|
|
|
|
return !!g_sig_state[sig].handler;
|
|
|
|
}
|
2018-11-19 15:52:26 +00:00
|
|
|
#endif
|
2018-11-18 15:38:59 +00:00
|
|
|
/* ========================================================================= */
|
|
|
|
|
2018-11-20 05:30:45 +00:00
|
|
|
|
2019-08-14 16:24:39 +00:00
|
|
|
static MOO_INLINE void abort_all_moos (int signo)
|
2018-11-26 09:49:03 +00:00
|
|
|
{
|
|
|
|
/* TODO: make this atomic */
|
|
|
|
if (g_moo)
|
|
|
|
{
|
|
|
|
moo_t* moo = g_moo;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2019-08-15 15:55:06 +00:00
|
|
|
moo_uint8_t u8;
|
2019-08-14 16:24:39 +00:00
|
|
|
/*moo_abortstd (moo);*/
|
2019-08-15 15:55:06 +00:00
|
|
|
u8 = signo & 0xFF;
|
|
|
|
write (xtn->sigfd.p[1], &u8, MOO_SIZEOF(u8));
|
2018-11-26 09:49:03 +00:00
|
|
|
moo = xtn->next;
|
|
|
|
}
|
|
|
|
while (moo);
|
|
|
|
}
|
|
|
|
/* TODO: make this atomic */
|
|
|
|
}
|
|
|
|
|
2019-07-11 06:43:47 +00:00
|
|
|
static MOO_INLINE void do_nothing (int unused)
|
|
|
|
{
|
|
|
|
}
|
2018-11-26 09:49:03 +00:00
|
|
|
|
2018-11-20 05:30:45 +00:00
|
|
|
/*#define MOO_TICKER_INTERVAL_USECS 10000*/ /* microseconds. 0.01 seconds */
|
|
|
|
#define MOO_TICKER_INTERVAL_USECS 20000 /* microseconds. 0.02 seconds. */
|
|
|
|
|
2018-11-26 09:49:03 +00:00
|
|
|
static MOO_INLINE void swproc_all_moos (int unused)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
|
|
|
/* TODO: make this atomic */
|
|
|
|
if (g_moo)
|
|
|
|
{
|
|
|
|
moo_t* moo = g_moo;
|
|
|
|
do
|
|
|
|
{
|
2018-11-19 15:52:26 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
if (xtn->rcv_tick) moo_switchprocess (moo);
|
|
|
|
moo = xtn->next;
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
while (moo);
|
|
|
|
}
|
|
|
|
/* TODO: make this atomic */
|
|
|
|
}
|
|
|
|
|
2018-11-20 05:30:45 +00:00
|
|
|
#if defined(_WIN32)
|
2018-11-16 08:38:05 +00:00
|
|
|
|
2018-11-21 13:19:07 +00:00
|
|
|
static HANDLE msw_tick_timer = MOO_NULL; /*INVALID_HANDLE_VALUE;*/
|
|
|
|
static int msw_tick_done = 0;
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-21 13:19:07 +00:00
|
|
|
static DWORD WINAPI msw_wait_for_timer_event (LPVOID ctx)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2018-11-26 07:43:04 +00:00
|
|
|
/* I don't think i need to use the waiting timer for this.
|
|
|
|
* a simple loop with sleep inside should also work as i don't do anything
|
|
|
|
* special except waiting for timer expiry.
|
|
|
|
* while (!msw_tick_done)
|
|
|
|
* {
|
|
|
|
* Sleep (...);
|
|
|
|
* swproc_all_moos();
|
|
|
|
* }
|
|
|
|
* but never mind for now. let's do it the hard way.
|
|
|
|
*/
|
|
|
|
|
2018-11-21 13:19:07 +00:00
|
|
|
msw_tick_timer = CreateWaitableTimer(MOO_NULL, FALSE, MOO_NULL);
|
|
|
|
if (msw_tick_timer)
|
|
|
|
{
|
|
|
|
LARGE_INTEGER li;
|
|
|
|
|
|
|
|
/* lpDueTime in 100 nanoseconds */
|
|
|
|
li.QuadPart = -MOO_USEC_TO_NSEC(MOO_TICKER_INTERVAL_USECS) / 100;
|
|
|
|
|
|
|
|
/*#define MSW_TICKER_MANUAL_RESET */
|
|
|
|
#if defined(MSW_TICKER_MANUAL_RESET)
|
|
|
|
/* if manual resetting is enabled, the reset is done after
|
|
|
|
* swproc_all_moos has been called. so the interval is the
|
|
|
|
* interval specified plus the time taken in swproc_all_moos. */
|
|
|
|
SetWaitableTimer (msw_tick_timer, &li, 0, MOO_NULL, MOO_NULL, FALSE);
|
|
|
|
#else
|
|
|
|
/* with auto reset, the interval is not affected by time taken
|
|
|
|
* in swproc_all_moos() */
|
|
|
|
SetWaitableTimer (msw_tick_timer, &li, MOO_USEC_TO_MSEC(MOO_TICKER_INTERVAL_USECS), MOO_NULL, MOO_NULL, FALSE);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
while (!msw_tick_done)
|
|
|
|
{
|
|
|
|
if (WaitForSingleObject(msw_tick_timer, 100000) == WAIT_OBJECT_0)
|
|
|
|
{
|
2018-11-26 09:49:03 +00:00
|
|
|
swproc_all_moos (0);
|
2018-11-21 13:19:07 +00:00
|
|
|
#if defined(MSW_TICKER_MANUAL_RESET)
|
|
|
|
SetWaitableTimer (msw_tick_timer, &li, 0, MOO_NULL, MOO_NULL, FALSE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CancelWaitableTimer (msw_tick_timer);
|
|
|
|
|
|
|
|
CloseHandle (msw_tick_timer);
|
|
|
|
msw_tick_timer = MOO_NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
msw_tick_done = 0;
|
|
|
|
/*ExitThread (0);*/
|
2018-11-22 08:13:30 +00:00
|
|
|
return 0;
|
2018-11-16 08:38:05 +00:00
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void start_ticker (void)
|
2018-11-16 08:38:05 +00:00
|
|
|
{
|
2018-11-21 13:19:07 +00:00
|
|
|
HANDLE thr;
|
|
|
|
|
|
|
|
msw_tick_done = 0;
|
|
|
|
|
|
|
|
thr = CreateThread(MOO_NULL, 0, msw_wait_for_timer_event, MOO_NULL, 0, MOO_NULL);
|
|
|
|
if (thr)
|
2018-11-16 08:38:05 +00:00
|
|
|
{
|
2018-11-26 04:12:55 +00:00
|
|
|
SetThreadPriority (thr, THREAD_PRIORITY_HIGHEST);
|
|
|
|
|
2018-11-21 13:19:07 +00:00
|
|
|
/* MSDN - The thread object remains in the system until the thread has terminated
|
|
|
|
* and all handles to it have been closed through a call to CloseHandle.
|
|
|
|
* it is safe to close the handle here */
|
|
|
|
CloseHandle (thr);
|
2018-11-16 08:38:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void stop_ticker (void)
|
2018-11-16 08:38:05 +00:00
|
|
|
{
|
2018-11-21 13:19:07 +00:00
|
|
|
if (msw_tick_timer) CancelWaitableTimer (msw_tick_timer);
|
|
|
|
msw_tick_done = 1;
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__OS2__)
|
2018-11-21 13:19:07 +00:00
|
|
|
|
2018-11-16 08:38:05 +00:00
|
|
|
static HEV os2_tick_sem;
|
|
|
|
static HTIMER os2_tick_timer;
|
|
|
|
static int os2_tick_done = 0;
|
2018-11-11 16:53:21 +00:00
|
|
|
|
|
|
|
static void EXPENTRY os2_wait_for_timer_event (ULONG x)
|
|
|
|
{
|
|
|
|
APIRET rc;
|
|
|
|
ULONG count;
|
|
|
|
|
2018-11-21 13:37:27 +00:00
|
|
|
rc = DosCreateEventSem(MOO_NULL, &os2_tick_sem, DC_SEM_SHARED, FALSE);
|
2018-11-11 16:53:21 +00:00
|
|
|
if (rc != NO_ERROR)
|
|
|
|
{
|
2018-11-21 13:19:07 +00:00
|
|
|
goto done;
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-21 13:37:27 +00:00
|
|
|
rc = DosStartTimer(MOO_USEC_TO_MSEC(MOO_TICKER_INTERVAL_USECS), (HSEM)os2_tick_sem, &os2_tick_timer);
|
2018-11-11 16:53:21 +00:00
|
|
|
if (rc != NO_ERROR)
|
|
|
|
{
|
2018-12-01 14:52:24 +00:00
|
|
|
DosCloseEventSem (os2_tick_sem);
|
2018-11-21 13:19:07 +00:00
|
|
|
goto done;
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-16 08:38:05 +00:00
|
|
|
while (!os2_tick_done)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2018-12-01 14:52:24 +00:00
|
|
|
rc = DosWaitEventSem(os2_tick_sem, 5000L);
|
2018-11-21 13:37:27 +00:00
|
|
|
#if 0
|
2018-11-26 09:49:03 +00:00
|
|
|
swproc_all_moos (0);
|
2018-12-01 14:52:24 +00:00
|
|
|
DosResetEventSem (os2_tick_sem, &count);
|
2018-11-21 13:37:27 +00:00
|
|
|
#else
|
2018-12-01 14:52:24 +00:00
|
|
|
DosResetEventSem (os2_tick_sem, &count);
|
2018-11-26 09:49:03 +00:00
|
|
|
swproc_all_moos (0);
|
2018-11-21 13:37:27 +00:00
|
|
|
#endif
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-16 08:38:05 +00:00
|
|
|
DosStopTimer (os2_tick_timer);
|
2018-12-01 14:52:24 +00:00
|
|
|
DosCloseEventSem (os2_tick_sem);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-21 13:19:07 +00:00
|
|
|
done:
|
2018-11-16 08:38:05 +00:00
|
|
|
os2_tick_timer = NULL;
|
|
|
|
os2_tick_sem = NULL;
|
2018-11-21 13:19:07 +00:00
|
|
|
os2_tick_done = 0;
|
2018-11-11 16:53:21 +00:00
|
|
|
DosExit (EXIT_THREAD, 0);
|
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void start_ticker (void)
|
2018-11-16 08:38:05 +00:00
|
|
|
{
|
2018-11-21 13:19:07 +00:00
|
|
|
static TID tid;
|
|
|
|
os2_tick_done = 0;
|
|
|
|
DosCreateThread (&tid, os2_wait_for_timer_event, 0, 0, 4096);
|
2018-11-19 16:00:55 +00:00
|
|
|
/* TODO: Error check */
|
2018-11-16 08:38:05 +00:00
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void stop_ticker (void)
|
2018-11-16 08:38:05 +00:00
|
|
|
{
|
2018-11-19 16:00:55 +00:00
|
|
|
if (os2_tick_sem) DosPostEventSem (os2_tick_sem);
|
|
|
|
os2_tick_done = 1;
|
2018-11-16 08:38:05 +00:00
|
|
|
}
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-20 05:30:45 +00:00
|
|
|
#elif defined(__DOS__) && (defined(_INTELC32_) || defined(__WATCOMC__))
|
|
|
|
|
|
|
|
#if defined(_INTELC32_)
|
|
|
|
static void (*dos_prev_timer_intr_handler) (void);
|
2018-12-01 05:22:53 +00:00
|
|
|
#pragma interrupt(dos_timer_intr_handler)
|
2018-11-20 05:30:45 +00:00
|
|
|
static void dos_timer_intr_handler (void)
|
|
|
|
#else
|
2018-12-02 05:57:10 +00:00
|
|
|
static void (__interrupt *dos_prev_timer_intr_handler) (void);
|
2018-11-20 05:30:45 +00:00
|
|
|
static void __interrupt dos_timer_intr_handler (void)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
/*
|
2018-12-02 05:57:10 +00:00
|
|
|
_XSTACK* stk = (_XSTACK *)_get_stk_frame();
|
|
|
|
r = (unsigned short)stk->eax;
|
2018-11-20 05:30:45 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* The timer interrupt (normally) occurs 18.2 times per second. */
|
2018-11-26 09:49:03 +00:00
|
|
|
swproc_all_moos (0);
|
2018-11-20 05:30:45 +00:00
|
|
|
_chain_intr (dos_prev_timer_intr_handler);
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE void start_ticker (void)
|
|
|
|
{
|
|
|
|
dos_prev_timer_intr_handler = _dos_getvect(0x1C);
|
|
|
|
_dos_setvect (0x1C, dos_timer_intr_handler);
|
|
|
|
}
|
|
|
|
|
2018-11-30 15:19:33 +00:00
|
|
|
static MOO_INLINE void stop_ticker (void)
|
2018-11-20 05:30:45 +00:00
|
|
|
{
|
|
|
|
_dos_setvect (0x1C, dos_prev_timer_intr_handler);
|
|
|
|
}
|
|
|
|
|
2018-11-11 16:53:21 +00:00
|
|
|
#elif defined(macintosh)
|
|
|
|
|
2018-11-16 08:38:05 +00:00
|
|
|
static TMTask mac_tmtask;
|
|
|
|
static ProcessSerialNumber mac_psn;
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-21 13:37:27 +00:00
|
|
|
/* milliseconds if positive, microseconds(after negation) if negative */
|
|
|
|
#define TMTASK_DELAY MOO_USEC_TO_MSEC(MOO_TICKER_INTERVAL_USECS)
|
2018-11-11 16:53:21 +00:00
|
|
|
|
|
|
|
static pascal void timer_intr_handler (TMTask* task)
|
|
|
|
{
|
2018-11-26 09:49:03 +00:00
|
|
|
swproc_all_moos (0);
|
2018-11-16 08:38:05 +00:00
|
|
|
WakeUpProcess (&mac_psn);
|
|
|
|
PrimeTime ((QElem*)&mac_tmtask, TMTASK_DELAY);
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void start_ticker (void)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2018-11-16 08:38:05 +00:00
|
|
|
GetCurrentProcess (&mac_psn);
|
2018-11-21 13:19:07 +00:00
|
|
|
MOO_MEMSET (&mac_tmtask, 0, MOO_SIZEOF(mac_tmtask));
|
2018-11-16 08:38:05 +00:00
|
|
|
mac_tmtask.tmAddr = NewTimerProc (timer_intr_handler);
|
|
|
|
InsXTime ((QElem*)&mac_tmtask);
|
|
|
|
PrimeTime ((QElem*)&mac_tmtask, TMTASK_DELAY);
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void stop_ticker (void)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2018-11-16 08:38:05 +00:00
|
|
|
RmvTime ((QElem*)&mac_tmtask);
|
|
|
|
/*DisposeTimerProc (mac_tmtask.tmAddr);*/
|
|
|
|
}
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-16 08:38:05 +00:00
|
|
|
#elif defined(HAVE_SETITIMER) && defined(SIGVTALRM) && defined(ITIMER_VIRTUAL)
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void start_ticker (void)
|
2018-11-19 15:52:26 +00:00
|
|
|
{
|
2018-11-26 09:49:03 +00:00
|
|
|
if (set_signal_handler(SIGVTALRM, swproc_all_moos, SA_RESTART) >= 0)
|
2018-11-19 15:52:26 +00:00
|
|
|
{
|
2018-11-19 16:00:55 +00:00
|
|
|
struct itimerval itv;
|
|
|
|
itv.it_interval.tv_sec = 0;
|
2018-11-20 05:31:36 +00:00
|
|
|
itv.it_interval.tv_usec = MOO_TICKER_INTERVAL_USECS;
|
2018-11-19 16:00:55 +00:00
|
|
|
itv.it_value.tv_sec = 0;
|
2018-11-20 05:30:45 +00:00
|
|
|
itv.it_value.tv_usec = MOO_TICKER_INTERVAL_USECS;
|
2019-10-12 14:55:37 +00:00
|
|
|
if (setitimer(ITIMER_VIRTUAL, &itv, MOO_NULL) == -1)
|
|
|
|
{
|
|
|
|
/* WSL supports ITIMER_VIRTUAL only as of windows 10.0.18362.413.
|
|
|
|
the following is a fallback which will get */
|
|
|
|
unset_signal_handler (SIGVTALRM);
|
|
|
|
|
2019-10-17 15:43:00 +00:00
|
|
|
#if defined(SIGALRM) && defined(ITIMER_REAL)
|
2019-10-12 14:55:37 +00:00
|
|
|
if (set_signal_handler(SIGALRM, swproc_all_moos, SA_RESTART) >= 0)
|
|
|
|
{
|
|
|
|
/* i double the interval as ITIMER_REAL is against the wall clock.
|
|
|
|
* if the underlying system is under heavy load, some signals
|
|
|
|
* will get lost */
|
|
|
|
itv.it_interval.tv_sec = 0;
|
|
|
|
itv.it_interval.tv_usec = MOO_TICKER_INTERVAL_USECS * 2;
|
|
|
|
itv.it_value.tv_sec = 0;
|
|
|
|
itv.it_value.tv_usec = MOO_TICKER_INTERVAL_USECS * 2;
|
|
|
|
setitimer(ITIMER_REAL, &itv, MOO_NULL);
|
|
|
|
}
|
2019-10-17 15:43:00 +00:00
|
|
|
#endif
|
2019-10-12 14:55:37 +00:00
|
|
|
}
|
2018-11-19 15:52:26 +00:00
|
|
|
}
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-19 16:00:55 +00:00
|
|
|
static MOO_INLINE void stop_ticker (void)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2018-11-19 16:00:55 +00:00
|
|
|
/* ignore the signal fired by the activated timer.
|
|
|
|
* unsetting the signal may cause the program to terminate(default action) */
|
2019-10-12 14:55:37 +00:00
|
|
|
if (is_signal_handler_set(SIGVTALRM) && set_signal_handler(SIGVTALRM, SIG_IGN, 0) >= 0)
|
2018-11-19 15:52:26 +00:00
|
|
|
{
|
2018-11-19 16:00:55 +00:00
|
|
|
struct itimerval itv;
|
|
|
|
itv.it_interval.tv_sec = 0;
|
|
|
|
itv.it_interval.tv_usec = 0;
|
|
|
|
itv.it_value.tv_sec = 0; /* make setitimer() one-shot only */
|
|
|
|
itv.it_value.tv_usec = 0;
|
|
|
|
setitimer (ITIMER_VIRTUAL, &itv, MOO_NULL);
|
2018-11-19 15:52:26 +00:00
|
|
|
}
|
2019-10-12 14:55:37 +00:00
|
|
|
|
2019-10-17 15:43:00 +00:00
|
|
|
#if defined(SIGALRM) && defined(ITIMER_REAL)
|
2019-10-12 14:55:37 +00:00
|
|
|
if (is_signal_handler_set(SIGALRM) && set_signal_handler(SIGALRM, SIG_IGN, 0) >= 0)
|
|
|
|
{
|
|
|
|
struct itimerval itv;
|
|
|
|
itv.it_interval.tv_sec = 0;
|
|
|
|
itv.it_interval.tv_usec = 0;
|
|
|
|
itv.it_value.tv_sec = 0; /* make setitimer() one-shot only */
|
|
|
|
itv.it_value.tv_usec = 0;
|
|
|
|
setitimer (ITIMER_REAL, &itv, MOO_NULL);
|
|
|
|
}
|
2019-10-17 15:43:00 +00:00
|
|
|
#endif
|
2018-11-16 08:38:05 +00:00
|
|
|
}
|
2018-11-19 15:52:26 +00:00
|
|
|
|
2018-11-11 16:53:21 +00:00
|
|
|
#else
|
2019-10-17 15:43:00 +00:00
|
|
|
|
|
|
|
static pid_t ticker_pid = -1;
|
|
|
|
|
|
|
|
static MOO_INLINE void start_ticker (void)
|
|
|
|
{
|
|
|
|
if (set_signal_handler(SIGALRM, swproc_all_moos, SA_RESTART) >= 0)
|
|
|
|
{
|
|
|
|
ticker_pid = fork();
|
|
|
|
|
|
|
|
if (ticker_pid <= -1)
|
|
|
|
{
|
|
|
|
unset_signal_handler (SIGALRM);
|
|
|
|
}
|
|
|
|
else if (ticker_pid == 0)
|
|
|
|
{
|
|
|
|
/* child process - actual ticker */
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
#if defined(HAVE_NANOSLEEP)
|
|
|
|
struct timespec ts;
|
|
|
|
ts.tv_sec = 0;
|
|
|
|
ts.tv_nsec = MOO_USEC_TO_NSEC(MOO_TICKER_INTERVAL_USECS) * 2;
|
|
|
|
nanosleep (&ts, MOO_NULL);
|
|
|
|
#elif defined(HAVE_USLEEP)
|
|
|
|
usleep (MOO_TICKER_INTERVAL_USECS * 2);
|
|
|
|
|
|
|
|
#else
|
|
|
|
# error UNDEFINED SLEEP
|
|
|
|
#endif
|
|
|
|
|
|
|
|
kill (getppid(), SIGALRM);
|
|
|
|
}
|
|
|
|
|
|
|
|
_exit (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* parent just carries on. */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE void stop_ticker (void)
|
|
|
|
{
|
|
|
|
if (ticker_pid >= 0)
|
|
|
|
{
|
|
|
|
int wstatus;
|
|
|
|
kill (ticker_pid, SIGKILL);
|
|
|
|
while (waitpid(ticker_pid, &wstatus, 0) != ticker_pid);
|
|
|
|
ticker_pid = -1;
|
|
|
|
|
|
|
|
unset_signal_handler (SIGALRM);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-11 16:53:21 +00:00
|
|
|
#endif
|
|
|
|
|
2018-11-26 07:43:04 +00:00
|
|
|
/* ========================================================================= */
|
|
|
|
#if defined(_WIN32)
|
|
|
|
|
|
|
|
static const wchar_t* msw_exception_name (DWORD excode)
|
|
|
|
{
|
|
|
|
switch (excode)
|
|
|
|
{
|
|
|
|
case EXCEPTION_ACCESS_VIOLATION: return L"Access violation exception";
|
|
|
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return L"Array bounds exceeded";
|
|
|
|
case EXCEPTION_BREAKPOINT: return L"Breakpoint";
|
|
|
|
case EXCEPTION_DATATYPE_MISALIGNMENT: return L"Float datatype misalignment";
|
|
|
|
case EXCEPTION_FLT_DENORMAL_OPERAND: return L"Float denormal operand";
|
|
|
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO: return L"Float divide by zero";
|
|
|
|
case EXCEPTION_FLT_INEXACT_RESULT: return L"Float inexact result";
|
|
|
|
case EXCEPTION_FLT_OVERFLOW: return L"Float overflow";
|
|
|
|
case EXCEPTION_FLT_STACK_CHECK: return L"Float stack check";
|
|
|
|
case EXCEPTION_FLT_UNDERFLOW: return L"Float underflow";
|
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION: return L"Illegal instruction";
|
|
|
|
case EXCEPTION_IN_PAGE_ERROR: return L"In page error";
|
|
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO: return L"Integer divide by zero";
|
|
|
|
case EXCEPTION_INT_OVERFLOW: return L"Integer overflow";
|
|
|
|
case EXCEPTION_INVALID_DISPOSITION: return L"Invalid disposition";
|
|
|
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION: return L"Noncontinuable exception";
|
|
|
|
case EXCEPTION_PRIV_INSTRUCTION: return L"Priv instruction";
|
|
|
|
case EXCEPTION_SINGLE_STEP: return L"Single step";
|
|
|
|
case EXCEPTION_STACK_OVERFLOW: return L"Stack overflow";
|
|
|
|
default: return L"Unknown exception";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const wchar_t* msw_exception_opname (const ULONG opcode)
|
|
|
|
{
|
|
|
|
switch (opcode)
|
|
|
|
{
|
|
|
|
case 0: return L"Read attempt from inaccessible data";
|
|
|
|
case 1: return L"Write attempt to inaccessible data";
|
|
|
|
case 8: return L"User-mode data execution prevention violation";
|
|
|
|
default: return L"Unknown exception operation";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static LONG WINAPI msw_exception_filter (struct _EXCEPTION_POINTERS* exinfo)
|
|
|
|
{
|
|
|
|
HMODULE mod;
|
2019-03-28 23:52:56 +00:00
|
|
|
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
2018-11-26 07:43:04 +00:00
|
|
|
MODULEINFO modinfo;
|
2019-03-28 23:52:56 +00:00
|
|
|
#endif
|
2018-11-26 07:43:04 +00:00
|
|
|
DWORD excode;
|
|
|
|
static wchar_t exmsg[256];
|
|
|
|
static wchar_t expath[128];
|
|
|
|
|
|
|
|
#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
|
|
|
|
GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, exinfo->ExceptionRecord->ExceptionAddress, &mod);
|
2019-07-11 15:58:16 +00:00
|
|
|
/*GetModuleInformation (GetCurrentProcess(), mod, &modinfo, MOO_SIZEOF(modinfo));*/
|
2018-11-26 07:43:04 +00:00
|
|
|
GetModuleFileNameExW (GetCurrentProcess(), mod, expath, MOO_SIZEOF(expath));
|
|
|
|
#else
|
|
|
|
GetModuleFileNameW (MOO_NULL, expath, MOO_SIZEOF(expath));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
excode = exinfo->ExceptionRecord->ExceptionCode;
|
|
|
|
if (excode == EXCEPTION_BREAKPOINT) return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
|
|
|
|
if (excode == EXCEPTION_ACCESS_VIOLATION || excode == EXCEPTION_IN_PAGE_ERROR)
|
|
|
|
{
|
|
|
|
_snwprintf (exmsg, MOO_COUNTOF(exmsg), L"Exception %s(%u) at 0x%p - Invalid operation at 0x%p - %s",
|
|
|
|
msw_exception_name(excode), (unsigned int)excode,
|
|
|
|
exinfo->ExceptionRecord->ExceptionAddress,
|
|
|
|
(PVOID)exinfo->ExceptionRecord->ExceptionInformation[1],
|
|
|
|
msw_exception_opname(exinfo->ExceptionRecord->ExceptionInformation[0])
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_snwprintf (exmsg, MOO_COUNTOF(exmsg), L"Exception %s(%u) at 0x%p",
|
|
|
|
msw_exception_name(excode), (unsigned int)excode,
|
|
|
|
exinfo->ExceptionRecord->ExceptionAddress
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: use a global output callback like vmprim.assertfail().
|
|
|
|
* vmprim.assertfail() requires 'moo'. so i need another global level callback for this */
|
|
|
|
MessageBoxW (NULL, exmsg, expath, MB_OK | MB_ICONERROR);
|
|
|
|
|
|
|
|
/*return EXCEPTION_CONTINUE_SEARCH;*/
|
|
|
|
/*return EXCEPTION_CONTINUE_EXECUTION;*/
|
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
}
|
|
|
|
#endif
|
2018-11-11 16:53:21 +00:00
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
const char* name;
|
2021-07-20 00:57:22 +00:00
|
|
|
int op;
|
2018-11-11 16:53:21 +00:00
|
|
|
moo_bitmask_t mask;
|
|
|
|
} log_mask_table[] =
|
|
|
|
{
|
2021-07-20 00:57:22 +00:00
|
|
|
{ "app", 0, MOO_LOG_APP },
|
|
|
|
{ "compiler", 0, MOO_LOG_COMPILER },
|
|
|
|
{ "vm", 0, MOO_LOG_VM },
|
|
|
|
{ "mnemonic", 0, MOO_LOG_MNEMONIC },
|
|
|
|
{ "gc", 0, MOO_LOG_GC },
|
|
|
|
{ "ic", 0, MOO_LOG_IC },
|
|
|
|
{ "primitive", 0, MOO_LOG_PRIMITIVE },
|
|
|
|
{ "all", 0, MOO_LOG_ALL_TYPES },
|
|
|
|
|
|
|
|
{ "fatal", 0, MOO_LOG_FATAL },
|
|
|
|
{ "error", 0, MOO_LOG_ERROR },
|
|
|
|
{ "warn", 0, MOO_LOG_WARN },
|
|
|
|
{ "info", 0, MOO_LOG_INFO },
|
|
|
|
{ "debug", 0, MOO_LOG_DEBUG },
|
|
|
|
|
|
|
|
{ "fatal+", 0, MOO_LOG_FATAL },
|
|
|
|
{ "error+", 0, MOO_LOG_FATAL | MOO_LOG_ERROR },
|
|
|
|
{ "warn+", 0, MOO_LOG_FATAL | MOO_LOG_ERROR | MOO_LOG_WARN },
|
|
|
|
{ "info+", 0, MOO_LOG_FATAL | MOO_LOG_ERROR | MOO_LOG_WARN | MOO_LOG_INFO },
|
|
|
|
{ "debug+", 0, MOO_LOG_FATAL | MOO_LOG_ERROR | MOO_LOG_WARN | MOO_LOG_INFO | MOO_LOG_DEBUG },
|
|
|
|
|
|
|
|
{ "fatal-", 0, MOO_LOG_FATAL | MOO_LOG_ERROR | MOO_LOG_WARN | MOO_LOG_INFO | MOO_LOG_DEBUG },
|
|
|
|
{ "error-", 0, MOO_LOG_ERROR | MOO_LOG_WARN | MOO_LOG_INFO | MOO_LOG_DEBUG },
|
|
|
|
{ "warn-", 0, MOO_LOG_WARN | MOO_LOG_INFO | MOO_LOG_DEBUG },
|
|
|
|
{ "info-", 0, MOO_LOG_INFO | MOO_LOG_DEBUG },
|
|
|
|
{ "debug-", 0, MOO_LOG_DEBUG },
|
|
|
|
|
|
|
|
{ "-fatal", 1, ~MOO_LOG_FATAL },
|
|
|
|
{ "-error", 1, ~MOO_LOG_ERROR },
|
|
|
|
{ "-warn", 1, ~MOO_LOG_WARN },
|
|
|
|
{ "-info", 1, ~MOO_LOG_INFO },
|
|
|
|
{ "-debug", 1, ~MOO_LOG_DEBUG },
|
2018-11-11 16:53:21 +00:00
|
|
|
};
|
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
static struct
|
|
|
|
{
|
|
|
|
const char* name;
|
|
|
|
moo_bitmask_t mask;
|
|
|
|
} dbg_mask_table[] =
|
|
|
|
{
|
2019-05-14 10:22:37 +00:00
|
|
|
{ "bigint", MOO_TRAIT_DEBUG_BIGINT },
|
|
|
|
{ "gc", MOO_TRAIT_DEBUG_GC }
|
2018-11-13 09:53:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int parse_logoptb (moo_t* moo, const moo_bch_t* str, moo_oow_t* xpathlen, moo_bitmask_t* xlogmask)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2021-02-09 17:37:45 +00:00
|
|
|
/*xtn_t* xtn = GET_XTN(moo);*/
|
2018-11-30 15:19:33 +00:00
|
|
|
const moo_bch_t* cm, * flt;
|
2018-11-11 16:53:21 +00:00
|
|
|
moo_bitmask_t logmask;
|
2018-11-13 09:53:48 +00:00
|
|
|
moo_oow_t i, len, pathlen;
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
cm = moo_find_bchar_in_bcstr(str, ',');
|
2018-11-11 16:53:21 +00:00
|
|
|
if (cm)
|
|
|
|
{
|
|
|
|
/* i duplicate this string for open() below as open() doesn't
|
|
|
|
* accept a length-bounded string */
|
2018-11-13 09:53:48 +00:00
|
|
|
cm = moo_find_bchar_in_bcstr(str, ',');
|
|
|
|
pathlen = cm - str;
|
|
|
|
|
2018-12-26 08:29:20 +00:00
|
|
|
logmask = 0;
|
2019-01-26 16:45:23 +00:00
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
do
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2018-11-13 09:53:48 +00:00
|
|
|
flt = cm + 1;
|
|
|
|
|
|
|
|
cm = moo_find_bchar_in_bcstr(flt, ',');
|
|
|
|
len = cm? (cm - flt): moo_count_bcstr(flt);
|
|
|
|
|
|
|
|
for (i = 0; i < MOO_COUNTOF(log_mask_table); i++)
|
|
|
|
{
|
|
|
|
if (moo_comp_bchars_bcstr(flt, len, log_mask_table[i].name) == 0)
|
|
|
|
{
|
2021-07-20 00:57:22 +00:00
|
|
|
if (log_mask_table[i].op)
|
|
|
|
logmask &= log_mask_table[i].mask;
|
|
|
|
else
|
|
|
|
logmask |= log_mask_table[i].mask;
|
2018-11-13 09:53:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= MOO_COUNTOF(log_mask_table))
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unknown log option value %.*hs", len, flt);
|
|
|
|
return -1;
|
|
|
|
}
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
2018-11-13 09:53:48 +00:00
|
|
|
while (cm);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-12-26 08:29:20 +00:00
|
|
|
if (!(logmask & MOO_LOG_ALL_TYPES)) logmask |= MOO_LOG_ALL_TYPES & ~(moo_bitmask_t)MOO_LOG_GC; /* no types specified. force to all types except gc */
|
2018-11-13 09:53:48 +00:00
|
|
|
if (!(logmask & MOO_LOG_ALL_LEVELS)) logmask |= MOO_LOG_ALL_LEVELS; /* no levels specified. force to all levels */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-12-26 08:29:20 +00:00
|
|
|
logmask = (MOO_LOG_ALL_LEVELS | MOO_LOG_ALL_TYPES) & ~(moo_bitmask_t)MOO_LOG_GC; /* all types except gc + all levels */
|
2018-11-13 09:53:48 +00:00
|
|
|
pathlen = moo_count_bcstr(str);
|
|
|
|
}
|
|
|
|
|
2018-12-26 08:29:20 +00:00
|
|
|
/* to have gc logs produced, you should specify 'all' or 'gc' */
|
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
*xlogmask = logmask;
|
|
|
|
*xpathlen = pathlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int parse_logoptu (moo_t* moo, const moo_uch_t* str, moo_oow_t* xpathlen, moo_bitmask_t* xlogmask)
|
|
|
|
{
|
2021-02-09 17:37:45 +00:00
|
|
|
/*xtn_t* xtn = GET_XTN(moo);*/
|
2018-11-30 15:19:33 +00:00
|
|
|
const moo_uch_t* cm, * flt;
|
2018-11-13 09:53:48 +00:00
|
|
|
moo_bitmask_t logmask;
|
|
|
|
moo_oow_t i, len, pathlen;
|
|
|
|
|
|
|
|
cm = moo_find_uchar_in_ucstr(str, ',');
|
|
|
|
if (cm)
|
|
|
|
{
|
|
|
|
cm = moo_find_uchar_in_ucstr(str, ',');
|
|
|
|
pathlen = cm - str;
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-12-26 08:29:20 +00:00
|
|
|
logmask = 0;
|
2018-11-11 16:53:21 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
flt = cm + 1;
|
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
cm = moo_find_uchar_in_ucstr(flt, ',');
|
|
|
|
len = cm? (cm - flt): moo_count_ucstr(flt);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
|
|
|
for (i = 0; i < MOO_COUNTOF(log_mask_table); i++)
|
|
|
|
{
|
2018-11-13 09:53:48 +00:00
|
|
|
if (moo_comp_uchars_bcstr(flt, len, log_mask_table[i].name) == 0)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
2021-07-20 00:57:22 +00:00
|
|
|
if (log_mask_table[i].op)
|
|
|
|
logmask &= log_mask_table[i].mask;
|
|
|
|
else
|
|
|
|
logmask |= log_mask_table[i].mask;
|
2018-11-11 16:53:21 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= MOO_COUNTOF(log_mask_table))
|
|
|
|
{
|
2018-11-13 09:53:48 +00:00
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unknown log option value %.*ls", len, flt);
|
2018-11-11 16:53:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (cm);
|
|
|
|
|
|
|
|
if (!(logmask & MOO_LOG_ALL_TYPES)) logmask |= MOO_LOG_ALL_TYPES; /* no types specified. force to all types */
|
|
|
|
if (!(logmask & MOO_LOG_ALL_LEVELS)) logmask |= MOO_LOG_ALL_LEVELS; /* no levels specified. force to all levels */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
logmask = MOO_LOG_ALL_LEVELS | MOO_LOG_ALL_TYPES;
|
2018-11-13 09:53:48 +00:00
|
|
|
pathlen = moo_count_ucstr(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
*xlogmask = logmask;
|
|
|
|
*xpathlen = pathlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_logoptb (moo_t* moo, const moo_bch_t* str)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
moo_bitmask_t logmask;
|
|
|
|
moo_oow_t pathlen;
|
|
|
|
moo_bch_t* xstr = (moo_bch_t*)str;
|
|
|
|
|
|
|
|
if (parse_logoptb(moo, str, &pathlen, &logmask) <= -1) return -1;
|
|
|
|
if (str[pathlen] != '\0')
|
|
|
|
{
|
|
|
|
xstr = moo_dupbchars(moo, str, pathlen);
|
|
|
|
if (!xstr) moo_seterrbfmt (moo, moo_geterrnum(moo), "out of memory in duplicating %hs", str);
|
2018-11-11 16:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->log.fd = open(xstr, O_CREAT | O_WRONLY | O_APPEND , 0644);
|
|
|
|
if (xtn->log.fd == -1)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_ESYSERR, "cannot open log file %hs", xstr); /* TODO: use syserrb/u??? */
|
|
|
|
if (str != xstr) moo_freemem (moo, xstr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->log.fd_flag |= LOGFD_OPENED_HERE;
|
2018-11-11 16:53:21 +00:00
|
|
|
#if defined(HAVE_ISATTY)
|
2018-11-13 07:40:30 +00:00
|
|
|
if (isatty(xtn->log.fd)) xtn->log.fd_flag |= LOGFD_TTY;
|
2018-11-11 16:53:21 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (str != xstr) moo_freemem (moo, xstr);
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_setoption (moo, MOO_OPTION_LOG_MASK, &logmask);
|
2018-11-11 16:53:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
static int handle_logoptu (moo_t* moo, const moo_uch_t* str)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
moo_bitmask_t logmask;
|
|
|
|
moo_oow_t pathlen;
|
|
|
|
moo_bch_t* xstr;
|
|
|
|
|
|
|
|
if (parse_logoptu(moo, str, &pathlen, &logmask) <= -1) return -1;
|
|
|
|
|
|
|
|
xstr = moo_duputobchars(moo, str, pathlen, MOO_NULL); /* moo_duputobchars() null-terminates xstr */
|
|
|
|
if (!xstr) moo_seterrbfmt (moo, moo_geterrnum(moo), "out of memory in duplicating %hs", str);
|
|
|
|
|
|
|
|
xtn->log.fd = open(xstr, O_CREAT | O_WRONLY | O_APPEND , 0644);
|
|
|
|
if (xtn->log.fd == -1)
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_ESYSERR, "cannot open log file %hs", xstr); /* TODO: use syserrb/u??? */
|
|
|
|
moo_freemem (moo, xstr);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
xtn->log.fd_flag |= LOGFD_OPENED_HERE;
|
|
|
|
#if defined(HAVE_ISATTY)
|
|
|
|
if (isatty(xtn->log.fd)) xtn->log.fd_flag |= LOGFD_TTY;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
moo_freemem (moo, xstr);
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_setoption (moo, MOO_OPTION_LOG_MASK, &logmask);
|
2018-11-13 09:53:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int handle_dbgoptb (moo_t* moo, const moo_bch_t* str)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
|
|
|
const moo_bch_t* cm, * flt;
|
2018-11-13 09:53:48 +00:00
|
|
|
moo_oow_t len, i;
|
2018-11-11 16:53:21 +00:00
|
|
|
moo_bitmask_t trait, dbgopt = 0;
|
|
|
|
|
|
|
|
cm = str - 1;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
flt = cm + 1;
|
|
|
|
|
|
|
|
cm = moo_find_bchar_in_bcstr(flt, ',');
|
|
|
|
len = cm? (cm - flt): moo_count_bcstr(flt);
|
2018-11-13 09:53:48 +00:00
|
|
|
|
|
|
|
for (i = 0; i < MOO_COUNTOF(dbg_mask_table); i++)
|
|
|
|
{
|
|
|
|
if (moo_comp_bchars_bcstr(flt, len, dbg_mask_table[i].name) == 0)
|
|
|
|
{
|
|
|
|
dbgopt |= dbg_mask_table[i].mask;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= MOO_COUNTOF(log_mask_table))
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unknown log option value %.*hs", len, flt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (cm);
|
|
|
|
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_getoption (moo, MOO_OPTION_TRAIT, &trait);
|
2018-11-11 16:53:21 +00:00
|
|
|
trait |= dbgopt;
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_setoption (moo, MOO_OPTION_TRAIT, &trait);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-11-13 09:53:48 +00:00
|
|
|
static int handle_dbgoptu (moo_t* moo, const moo_uch_t* str)
|
|
|
|
{
|
|
|
|
const moo_uch_t* cm, * flt;
|
|
|
|
moo_oow_t len, i;
|
|
|
|
moo_bitmask_t trait, dbgopt = 0;
|
|
|
|
|
|
|
|
cm = str - 1;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
flt = cm + 1;
|
|
|
|
|
|
|
|
cm = moo_find_uchar_in_ucstr(flt, ',');
|
|
|
|
len = cm? (cm - flt): moo_count_ucstr(flt);
|
|
|
|
|
|
|
|
for (i = 0; i < MOO_COUNTOF(dbg_mask_table); i++)
|
|
|
|
{
|
|
|
|
if (moo_comp_uchars_bcstr(flt, len, dbg_mask_table[i].name) == 0)
|
|
|
|
{
|
|
|
|
dbgopt |= dbg_mask_table[i].mask;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (i >= MOO_COUNTOF(log_mask_table))
|
|
|
|
{
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unknown log option value %.*ls", len, flt);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (cm);
|
|
|
|
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_getoption (moo, MOO_OPTION_TRAIT, &trait);
|
2018-11-13 09:53:48 +00:00
|
|
|
trait |= dbgopt;
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_setoption (moo, MOO_OPTION_TRAIT, &trait);
|
2018-11-13 09:53:48 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int handle_cfg_options (moo_t* moo, const moo_cfgstd_t* cfg)
|
|
|
|
{
|
|
|
|
switch (cfg->type)
|
|
|
|
{
|
|
|
|
#if defined(MOO_OOCH_IS_BCH)
|
|
|
|
case MOO_CFGSTD_OPT:
|
|
|
|
MOO_ASSERT (moo, &cfg->u.optb.log == &cfg->u.opt.log);
|
|
|
|
MOO_ASSERT (moo, &cfg->u.optb.dbg == &cfg->u.opt.dbg);
|
|
|
|
#endif
|
|
|
|
case MOO_CFGSTD_OPTB:
|
|
|
|
if ((cfg->u.optb.log && handle_logoptb(moo, cfg->u.optb.log) <= -1) ||
|
|
|
|
(cfg->u.optb.dbg && handle_dbgoptb(moo, cfg->u.optb.dbg) <= -1)) return -1;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
case MOO_CFGSTD_OPT:
|
|
|
|
MOO_ASSERT (moo, &cfg->u.optu.log == &cfg->u.opt.log);
|
|
|
|
MOO_ASSERT (moo, &cfg->u.optu.dbg == &cfg->u.opt.dbg);
|
|
|
|
#endif
|
|
|
|
case MOO_CFGSTD_OPTU:
|
|
|
|
if ((cfg->u.optu.log && handle_logoptu(moo, cfg->u.optu.log) <= -1) ||
|
|
|
|
(cfg->u.optu.dbg && handle_dbgoptu(moo, cfg->u.optu.dbg) <= -1)) return -1;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
default:
|
|
|
|
moo_seterrbfmt (moo, MOO_EINVAL, "unsupported configuration option type - %d", (int)cfg->type);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2018-11-07 15:26:30 +00:00
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
static MOO_INLINE void reset_log_to_default (xtn_t* xtn)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
#if defined(ENABLE_LOG_INITIALLY)
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->log.fd = 2;
|
|
|
|
xtn->log.fd_flag = 0;
|
2018-11-11 16:53:21 +00:00
|
|
|
#if defined(HAVE_ISATTY)
|
2018-11-13 07:40:30 +00:00
|
|
|
if (isatty(xtn->log.fd)) xtn->log.fd_flag |= LOGFD_TTY;
|
2018-11-11 16:53:21 +00:00
|
|
|
#endif
|
2018-11-13 06:54:30 +00:00
|
|
|
#else
|
2018-11-13 07:40:30 +00:00
|
|
|
xtn->log.fd = -1;
|
|
|
|
xtn->log.fd_flag = 0;
|
2018-11-13 06:54:30 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE void chain (moo_t* moo)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
/* TODO: make this atomic */
|
2018-11-19 15:52:26 +00:00
|
|
|
xtn->prev = MOO_NULL;
|
|
|
|
xtn->next = g_moo;
|
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
if (g_moo) GET_XTN(g_moo)->prev = moo;
|
|
|
|
else g_moo = moo;
|
|
|
|
/* TODO: make this atomic */
|
|
|
|
}
|
|
|
|
|
|
|
|
static MOO_INLINE void unchain (moo_t* moo)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
|
|
|
|
/* TODO: make this atomic */
|
2018-11-12 09:19:35 +00:00
|
|
|
if (xtn->prev) GET_XTN(xtn->prev)->next = xtn->next;
|
2018-11-11 16:53:21 +00:00
|
|
|
else g_moo = xtn->next;
|
2018-11-12 09:19:35 +00:00
|
|
|
if (xtn->next) GET_XTN(xtn->next)->prev = xtn->prev;
|
2018-11-13 06:54:30 +00:00
|
|
|
/* TODO: make this atomic */
|
2018-11-11 16:53:21 +00:00
|
|
|
xtn->prev = MOO_NULL;
|
|
|
|
xtn->prev = MOO_NULL;
|
2018-11-07 15:26:30 +00:00
|
|
|
}
|
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
static void fini_moo (moo_t* moo)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-13 07:40:30 +00:00
|
|
|
if ((xtn->log.fd_flag & LOGFD_OPENED_HERE) && xtn->log.fd >= 0) close (xtn->log.fd);
|
|
|
|
reset_log_to_default (xtn);
|
2018-11-13 06:54:30 +00:00
|
|
|
unchain (moo);
|
|
|
|
}
|
|
|
|
|
2019-09-02 16:23:03 +00:00
|
|
|
static void halting_moo (moo_t* moo)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2019-09-03 06:33:58 +00:00
|
|
|
xtn->ev.halting = 1; /* once set, vm_sleep() is supposed to return without waiting */
|
2019-09-02 16:23:03 +00:00
|
|
|
}
|
|
|
|
|
2019-09-03 06:33:58 +00:00
|
|
|
moo_t* moo_openstd (moo_oow_t xtnsize, const moo_cfgstd_t* cfg, moo_errinf_t* errinfo)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
moo_t* moo;
|
|
|
|
moo_vmprim_t vmprim;
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_evtcb_t evtcb;
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn_t* xtn;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
|
|
|
MOO_MEMSET(&vmprim, 0, MOO_SIZEOF(vmprim));
|
2019-05-28 08:55:13 +00:00
|
|
|
if (cfg && cfg->large_pages)
|
2018-11-07 15:26:30 +00:00
|
|
|
{
|
|
|
|
vmprim.alloc_heap = alloc_heap;
|
|
|
|
vmprim.free_heap = free_heap;
|
|
|
|
}
|
2019-05-28 08:55:13 +00:00
|
|
|
vmprim.log_write = ((cfg && cfg->log_write)? cfg->log_write: log_write);
|
2018-11-07 15:26:30 +00:00
|
|
|
vmprim.syserrstrb = syserrstrb;
|
|
|
|
vmprim.assertfail = assert_fail;
|
|
|
|
vmprim.dl_startup = dl_startup;
|
|
|
|
vmprim.dl_cleanup = dl_cleanup;
|
|
|
|
vmprim.dl_open = dl_open;
|
|
|
|
vmprim.dl_close = dl_close;
|
|
|
|
vmprim.dl_getsym = dl_getsym;
|
|
|
|
vmprim.vm_startup = vm_startup;
|
|
|
|
vmprim.vm_cleanup = vm_cleanup;
|
|
|
|
vmprim.vm_gettime = vm_gettime;
|
|
|
|
vmprim.vm_muxadd = vm_muxadd;
|
|
|
|
vmprim.vm_muxdel = vm_muxdel;
|
|
|
|
vmprim.vm_muxmod = vm_muxmod;
|
|
|
|
vmprim.vm_muxwait = vm_muxwait;
|
|
|
|
vmprim.vm_sleep = vm_sleep;
|
2019-08-15 15:55:06 +00:00
|
|
|
vmprim.vm_getsigfd = vm_getsigfd;
|
|
|
|
vmprim.vm_getsig = vm_getsig;
|
2019-08-16 15:29:36 +00:00
|
|
|
vmprim.vm_setsig = vm_setsig;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2020-12-01 15:04:30 +00:00
|
|
|
moo = moo_open(&sys_mmgr, MOO_SIZEOF(xtn_t) + xtnsize, ((cfg && cfg->cmgr)? cfg->cmgr: moo_get_utf8_cmgr()), &vmprim, (cfg? cfg->gc_type: MOO_GC_TYPE_DEFAULT), errinfo);
|
2020-11-25 14:48:26 +00:00
|
|
|
if (MOO_UNLIKELY(!moo)) return MOO_NULL;
|
2018-11-07 15:26:30 +00:00
|
|
|
|
2020-10-31 04:39:32 +00:00
|
|
|
/* adjust the object size by the sizeof xtn_t so that moo_getxtn() returns the right pointer. */
|
2019-06-21 07:21:58 +00:00
|
|
|
moo->_instsize += MOO_SIZEOF(xtn_t);
|
|
|
|
|
2018-11-12 09:19:35 +00:00
|
|
|
xtn = GET_XTN(moo);
|
2019-05-28 08:55:13 +00:00
|
|
|
if (cfg) xtn->input_cmgr = cfg->input_cmgr;
|
2019-05-18 18:01:02 +00:00
|
|
|
if (!xtn->input_cmgr) xtn->input_cmgr = moo_getcmgr(moo);
|
2019-05-28 08:55:13 +00:00
|
|
|
if (cfg) xtn->log_cmgr = cfg->log_cmgr;
|
2019-05-18 18:01:02 +00:00
|
|
|
if (!xtn->log_cmgr) xtn->log_cmgr = moo_getcmgr(moo);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
chain (moo); /* call chain() before moo_regevtcb() as fini_moo() calls unchain() */
|
|
|
|
reset_log_to_default (xtn);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2018-11-13 06:54:30 +00:00
|
|
|
MOO_MEMSET (&evtcb, 0, MOO_SIZEOF(evtcb));
|
|
|
|
evtcb.fini = fini_moo;
|
2019-09-02 16:23:03 +00:00
|
|
|
evtcb.halting = halting_moo;
|
2018-11-13 06:54:30 +00:00
|
|
|
moo_regevtcb (moo, &evtcb);
|
2018-11-11 16:53:21 +00:00
|
|
|
|
2019-11-03 09:15:24 +00:00
|
|
|
#if defined(EMSCRIPTEN)
|
|
|
|
{
|
2019-12-11 08:23:40 +00:00
|
|
|
/* TODO: this is experimental. make it proper */
|
2019-11-03 09:15:24 +00:00
|
|
|
moo_bitmask_t m = ~(moo_bitmask_t)0;
|
|
|
|
moo_setoption (moo, MOO_OPTION_LOG_MASK, &m);
|
|
|
|
}
|
|
|
|
#endif
|
2019-12-11 08:23:40 +00:00
|
|
|
|
2018-12-26 08:29:20 +00:00
|
|
|
{
|
|
|
|
moo_bitmask_t bm = 0;
|
|
|
|
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_getoption (moo, MOO_OPTION_TRAIT, &bm);
|
|
|
|
/*bm |= MOO_TRAIT_NOGC;*/
|
|
|
|
bm |= MOO_TRAIT_AWAIT_PROCS;
|
|
|
|
moo_setoption (moo, MOO_OPTION_TRAIT, &bm);
|
2018-12-26 08:29:20 +00:00
|
|
|
|
|
|
|
/* disable GC logs */
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_getoption (moo, MOO_OPTION_LOG_MASK, &bm);
|
2018-12-26 08:29:20 +00:00
|
|
|
bm = ~MOO_LOG_GC;
|
2019-05-14 10:22:37 +00:00
|
|
|
moo_setoption (moo, MOO_OPTION_LOG_MASK, &bm);
|
2018-12-26 08:29:20 +00:00
|
|
|
}
|
|
|
|
|
2019-10-16 09:04:09 +00:00
|
|
|
if (cfg && cfg->proc_stk_size > 0)
|
|
|
|
{
|
|
|
|
moo_setoption (moo, MOO_OPTION_PROCSTK_SIZE, &cfg->proc_stk_size);
|
|
|
|
}
|
|
|
|
|
2019-05-28 08:55:13 +00:00
|
|
|
if (cfg && handle_cfg_options(moo, cfg) <= -1)
|
2018-11-11 16:53:21 +00:00
|
|
|
{
|
|
|
|
if (errinfo) moo_geterrinf (moo, errinfo);
|
|
|
|
moo_close (moo);
|
|
|
|
return MOO_NULL;
|
|
|
|
}
|
|
|
|
|
2018-11-26 07:43:04 +00:00
|
|
|
#if defined(_WIN32)
|
|
|
|
SetUnhandledExceptionFilter (msw_exception_filter);
|
|
|
|
#endif
|
|
|
|
|
2018-11-07 15:26:30 +00:00
|
|
|
return moo;
|
|
|
|
}
|
|
|
|
|
2018-11-15 08:40:22 +00:00
|
|
|
void moo_abortstd (moo_t* moo)
|
|
|
|
{
|
|
|
|
#if defined(USE_THREAD)
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
write (xtn->iothr.p[1], "Q", 1);
|
|
|
|
#endif
|
|
|
|
moo_abort (moo);
|
|
|
|
}
|
|
|
|
|
2019-07-10 09:19:38 +00:00
|
|
|
#if defined(MOO_INCLUDE_COMPILER)
|
2018-11-19 15:52:26 +00:00
|
|
|
int moo_compilestd (moo_t* moo, const moo_iostd_t* in, moo_oow_t count)
|
2018-11-12 09:19:35 +00:00
|
|
|
{
|
2018-11-19 15:52:26 +00:00
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
2018-11-12 09:19:35 +00:00
|
|
|
moo_oow_t i;
|
|
|
|
|
|
|
|
for (i = 0; i < count; i++)
|
|
|
|
{
|
2018-11-13 06:54:30 +00:00
|
|
|
xtn->in = &in[i];
|
2018-11-12 09:19:35 +00:00
|
|
|
if (moo_compile(moo, input_handler) <= -1) return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2018-11-30 15:19:33 +00:00
|
|
|
}
|
2019-11-02 06:34:18 +00:00
|
|
|
|
|
|
|
int moo_compilefileb (moo_t* moo, const moo_bch_t* path)
|
|
|
|
{
|
|
|
|
moo_iostd_t in;
|
|
|
|
|
|
|
|
MOO_MEMSET (&in, 0, MOO_SIZEOF(in));
|
|
|
|
in.type = MOO_IOSTD_FILEB;
|
|
|
|
in.u.fileb.path = path;
|
|
|
|
|
|
|
|
return moo_compilestd(moo, &in, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
int moo_compilefileu (moo_t* moo, const moo_uch_t* path)
|
|
|
|
{
|
|
|
|
moo_iostd_t in;
|
|
|
|
|
|
|
|
MOO_MEMSET (&in, 0, MOO_SIZEOF(in));
|
|
|
|
in.type = MOO_IOSTD_FILEU;
|
|
|
|
in.u.fileu.path = path;
|
|
|
|
|
|
|
|
return moo_compilestd(moo, &in, 1);
|
|
|
|
}
|
|
|
|
|
2019-07-10 09:19:38 +00:00
|
|
|
#endif
|
2018-11-19 15:52:26 +00:00
|
|
|
|
2019-11-03 09:15:24 +00:00
|
|
|
int moo_invokebynameb (moo_t* moo, const moo_bch_t* objname, const moo_bch_t* mthname)
|
2019-11-02 06:34:18 +00:00
|
|
|
{
|
|
|
|
#if defined(MOO_OOCH_IS_UCH)
|
|
|
|
int n = -1;
|
|
|
|
moo_oocs_t o, m;
|
|
|
|
|
|
|
|
o.ptr = moo_dupbtooocstr(moo, objname, &o.len);
|
|
|
|
m.ptr = moo_dupbtooocstr(moo, mthname, &m.len);
|
|
|
|
if (!o.ptr || !m.ptr) goto done;
|
|
|
|
|
|
|
|
n = moo_invoke(moo, &o, &m);
|
|
|
|
|
|
|
|
done:
|
|
|
|
if (m.ptr) moo_freemem (moo, m.ptr);
|
|
|
|
if (o.ptr) moo_freemem (moo, o.ptr);
|
|
|
|
|
|
|
|
return n;
|
|
|
|
#else
|
|
|
|
moo_oocs_t o, m;
|
|
|
|
|
|
|
|
o.ptr = objname;
|
|
|
|
o.len = moo_count_bcstr(objname);
|
|
|
|
|
|
|
|
m.ptr = objname;
|
|
|
|
m.len = moo_count_bcstr(objname);
|
|
|
|
|
|
|
|
return moo_invoke(moo, &o, &m);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-11-19 15:52:26 +00:00
|
|
|
void moo_rcvtickstd (moo_t* moo, int v)
|
|
|
|
{
|
|
|
|
xtn_t* xtn = GET_XTN(moo);
|
|
|
|
xtn->rcv_tick = v;
|
|
|
|
}
|
2018-11-19 16:00:55 +00:00
|
|
|
|
|
|
|
/* ========================================================================= */
|
|
|
|
|
|
|
|
static moo_uint32_t ticker_started = 0;
|
|
|
|
|
|
|
|
void moo_start_ticker (void)
|
|
|
|
{
|
|
|
|
if (++ticker_started == 1)
|
|
|
|
{
|
|
|
|
start_ticker ();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void moo_stop_ticker (void)
|
|
|
|
{
|
|
|
|
if (ticker_started > 0 && --ticker_started == 0)
|
|
|
|
{
|
|
|
|
stop_ticker ();
|
|
|
|
}
|
|
|
|
}
|
2018-11-26 09:49:03 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* ========================================================================== */
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
static BOOL WINAPI handle_term (DWORD ctrl_type)
|
|
|
|
{
|
|
|
|
if (ctrl_type == CTRL_C_EVENT || ctrl_type == CTRL_CLOSE_EVENT)
|
|
|
|
{
|
2019-10-11 03:30:00 +00:00
|
|
|
abort_all_moos (SIGINT);
|
2018-11-26 09:49:03 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void moo_catch_termreq (void)
|
|
|
|
{
|
|
|
|
SetConsoleCtrlHandler (handle_term, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void moo_uncatch_termreq (void)
|
|
|
|
{
|
|
|
|
SetConsoleCtrlHandler (handle_term, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__OS2__)
|
|
|
|
|
|
|
|
static EXCEPTIONREGISTRATIONRECORD os2_excrr = { 0 };
|
|
|
|
|
2018-12-01 14:52:24 +00:00
|
|
|
static ULONG APIENTRY handle_term (
|
2018-11-26 09:49:03 +00:00
|
|
|
PEXCEPTIONREPORTRECORD p1,
|
|
|
|
PEXCEPTIONREGISTRATIONRECORD p2,
|
|
|
|
PCONTEXTRECORD p3,
|
|
|
|
PVOID pv)
|
|
|
|
{
|
|
|
|
if (p1->ExceptionNum == XCPT_SIGNAL)
|
|
|
|
{
|
|
|
|
if (p1->ExceptionInfo[0] == XCPT_SIGNAL_INTR ||
|
|
|
|
p1->ExceptionInfo[0] == XCPT_SIGNAL_KILLPROC ||
|
|
|
|
p1->ExceptionInfo[0] == XCPT_SIGNAL_BREAK)
|
|
|
|
{
|
2019-10-11 03:30:00 +00:00
|
|
|
abort_all_moos (SIGINT);
|
2018-11-26 09:49:03 +00:00
|
|
|
return (DosAcknowledgeSignalException(p1->ExceptionInfo[0]) != NO_ERROR)? 1: XCPT_CONTINUE_EXECUTION;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return XCPT_CONTINUE_SEARCH; /* exception not resolved */
|
|
|
|
}
|
|
|
|
|
|
|
|
void moo_catch_termreq (void)
|
|
|
|
{
|
|
|
|
os2_excrr.ExceptionHandler = (ERR)handle_term;
|
|
|
|
DosSetExceptionHandler (&os2_excrr); /* TODO: check if NO_ERROR is returned */
|
|
|
|
}
|
|
|
|
|
|
|
|
void moo_uncatch_termreq (void)
|
|
|
|
{
|
|
|
|
DosUnsetExceptionHandler (&os2_excrr);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__DOS__)
|
|
|
|
|
2018-12-04 08:40:59 +00:00
|
|
|
/*#define IRQ_TERM 0x23*/
|
|
|
|
/*#define IRQ_TERM 0x1B*/
|
|
|
|
#define IRQ_TERM 0x9
|
|
|
|
|
2018-12-02 05:57:10 +00:00
|
|
|
#if defined(_INTELC32_)
|
|
|
|
static void (*dos_prev_int23_handler) (void);
|
|
|
|
#pragma interrupt(dos_int23_handler)
|
|
|
|
static void dos_int23_handler (void)
|
|
|
|
#else
|
|
|
|
static void (__interrupt *dos_prev_int23_handler) (void);
|
|
|
|
static void __interrupt dos_int23_handler (void)
|
|
|
|
#endif
|
|
|
|
{
|
2018-12-04 08:40:59 +00:00
|
|
|
#if (IRQ_TERM == 0x23) && defined(_INTELC32_)
|
|
|
|
/* note this code for _INTELC32_ doesn't seem to work properly
|
|
|
|
* unless the program is waiting on getch() or something similar */
|
2018-12-02 05:57:10 +00:00
|
|
|
/* prevent the DOS interrupt handler from being called */
|
|
|
|
_XSTACK* stk = (_XSTACK*)_get_stk_frame();
|
|
|
|
stk->opts |= _STK_NOINT;
|
2019-10-11 03:30:00 +00:00
|
|
|
abort_all_moos (SIGINT);
|
2018-12-02 05:57:10 +00:00
|
|
|
/* if i call the previous handler, it's likely to kill the application.
|
|
|
|
* so i don't chain-call the previous handler. but another call could
|
|
|
|
* have changed the handler already to something else. then it would be
|
|
|
|
* better to chain-call it. TODO: find a way to chain-call it safely */
|
|
|
|
/*_chain_intr (dos_prev_int23_handler);*/
|
2018-12-04 08:40:59 +00:00
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
static int extended = 0;
|
|
|
|
static int keyboard[255] = { 0, };
|
|
|
|
moo_uint8_t sc, status;
|
|
|
|
/* TODO: determine if the key pressed is ctrl-C or ctrl-break ... */
|
|
|
|
|
|
|
|
sc = inp(0x60);
|
|
|
|
/*status = inp(0x61);*/
|
|
|
|
if (sc == 0xE0)
|
|
|
|
{
|
|
|
|
/* extended key prefix */
|
|
|
|
extended = 1;
|
|
|
|
}
|
|
|
|
else if (sc == 0xE1)
|
|
|
|
{
|
|
|
|
/* pause key */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (sc & 0x80)
|
|
|
|
{
|
|
|
|
/* key release */
|
|
|
|
sc = sc & 0x7F;
|
|
|
|
keyboard[sc] = 0;
|
2019-10-11 03:30:00 +00:00
|
|
|
/*printf ("%key released ... %x\n", sc);*/
|
2018-12-04 08:40:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
keyboard[sc] = 1;
|
2019-10-11 03:30:00 +00:00
|
|
|
/*printf ("%key pressed ... %x %c\n", sc, sc);*/
|
|
|
|
abort_all_moos (SIGINT);
|
2018-12-04 08:40:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
extended = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*_chain_intr (dos_prev_int23_handler);*/
|
|
|
|
outp (0x20, 0x20);
|
|
|
|
#else
|
2019-10-11 03:30:00 +00:00
|
|
|
abort_all_moos (SIGINT);
|
2018-12-04 08:40:59 +00:00
|
|
|
_chain_intr (dos_prev_int23_handler);
|
|
|
|
#endif
|
|
|
|
#endif
|
2018-12-02 05:57:10 +00:00
|
|
|
}
|
|
|
|
|
2018-11-26 09:49:03 +00:00
|
|
|
void moo_catch_termreq (void)
|
|
|
|
{
|
2018-12-04 08:40:59 +00:00
|
|
|
dos_prev_int23_handler = _dos_getvect(IRQ_TERM);
|
|
|
|
_dos_setvect (IRQ_TERM, dos_int23_handler);
|
2018-11-26 09:49:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void moo_uncatch_termreq (void)
|
|
|
|
{
|
2018-12-04 08:40:59 +00:00
|
|
|
_dos_setvect (IRQ_TERM, dos_prev_int23_handler);
|
|
|
|
dos_prev_int23_handler = MOO_NULL;
|
2018-11-26 09:49:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
void moo_catch_termreq (void)
|
|
|
|
{
|
2018-12-04 03:34:54 +00:00
|
|
|
set_signal_handler(SIGTERM, abort_all_moos, 0);
|
2019-07-11 06:43:47 +00:00
|
|
|
set_signal_handler(SIGHUP, abort_all_moos, 0);
|
2018-11-26 09:49:03 +00:00
|
|
|
set_signal_handler(SIGINT, abort_all_moos, 0);
|
2019-07-11 06:43:47 +00:00
|
|
|
set_signal_handler(SIGPIPE, do_nothing, 0);
|
2018-11-26 09:49:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void moo_uncatch_termreq (void)
|
|
|
|
{
|
|
|
|
unset_signal_handler(SIGTERM);
|
2019-07-11 06:43:47 +00:00
|
|
|
unset_signal_handler(SIGHUP);
|
2018-12-04 03:34:54 +00:00
|
|
|
unset_signal_handler(SIGINT);
|
2019-07-11 06:43:47 +00:00
|
|
|
unset_signal_handler(SIGPIPE);
|
2018-11-26 09:49:03 +00:00
|
|
|
}
|
|
|
|
|
2019-07-10 09:19:38 +00:00
|
|
|
#endif
|