aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/sys')
-rw-r--r--erts/emulator/sys/common/erl_check_io.c43
-rw-r--r--erts/emulator/sys/common/erl_poll.h25
-rw-r--r--erts/emulator/sys/common/erl_sys_common_misc.c2
-rw-r--r--erts/emulator/sys/ose/beam.lmconf26
-rw-r--r--erts/emulator/sys/ose/driver_int.h41
-rw-r--r--erts/emulator/sys/ose/erl_main.c53
-rw-r--r--erts/emulator/sys/ose/erl_ose_sys.h353
-rw-r--r--erts/emulator/sys/ose/erl_ose_sys_ddll.c126
-rw-r--r--erts/emulator/sys/ose/erl_poll.c780
-rw-r--r--erts/emulator/sys/ose/erts.sig17
-rw-r--r--erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf182
-rw-r--r--erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf242
-rw-r--r--erts/emulator/sys/ose/sys.c1846
-rw-r--r--erts/emulator/sys/ose/sys_float.c844
-rw-r--r--erts/emulator/sys/ose/sys_time.c56
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c46
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h5
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys_ddll.c6
-rw-r--r--erts/emulator/sys/unix/sys.c38
-rw-r--r--erts/emulator/sys/unix/sys_float.c2
-rw-r--r--erts/emulator/sys/win32/erl_win32_sys_ddll.c32
-rw-r--r--erts/emulator/sys/win32/erl_win_dyn_driver.h4
-rw-r--r--erts/emulator/sys/win32/erl_win_sys.h24
-rwxr-xr-xerts/emulator/sys/win32/sys.c422
24 files changed, 4888 insertions, 327 deletions
diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c
index 7035dc77df..1db673e7f3 100644
--- a/erts/emulator/sys/common/erl_check_io.c
+++ b/erts/emulator/sys/common/erl_check_io.c
@@ -34,6 +34,7 @@
#endif
#include "sys.h"
#include "global.h"
+#include "erl_port.h"
#include "erl_check_io.h"
#include "erl_thr_progress.h"
#include "dtrace-wrapper.h"
@@ -78,6 +79,8 @@ typedef char EventStateFlags;
#define ERTS_CIO_POLL_INIT ERTS_POLL_EXPORT(erts_poll_init)
#define ERTS_CIO_POLL_INFO ERTS_POLL_EXPORT(erts_poll_info)
+#define GET_FD(fd) fd
+
static struct pollset_info
{
ErtsPollSet ps;
@@ -524,7 +527,8 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix,
/* fast track to stop_select callback */
stop_select_fn = prt->drv_ptr->stop_select;
#ifdef USE_VM_PROBES
- strncpy(name, prt->drv_ptr->name, sizeof(name)-1);
+ strncpy(name, prt->drv_ptr->name,
+ sizeof(DTRACE_CHARBUF_NAME(name))-1);
name[sizeof(name)-1] = '\0';
#endif
ret = 0;
@@ -894,7 +898,7 @@ print_driver_name(erts_dsprintf_buf_t *dsbufp, Eterm id)
static void
steal(erts_dsprintf_buf_t *dsbufp, ErtsDrvEventState *state, int mode)
{
- erts_dsprintf(dsbufp, "stealing control of fd=%d from ", (int) state->fd);
+ erts_dsprintf(dsbufp, "stealing control of fd=%d from ", (int) GET_FD(state->fd));
switch (state->type) {
case ERTS_EV_TYPE_DRV_SEL: {
int deselect_mode = 0;
@@ -918,7 +922,7 @@ steal(erts_dsprintf_buf_t *dsbufp, ErtsDrvEventState *state, int mode)
if (deselect_mode)
deselect(state, deselect_mode);
else {
- erts_dsprintf(dsbufp, "no one", (int) state->fd);
+ erts_dsprintf(dsbufp, "no one", (int) GET_FD(state->fd));
ASSERT(0);
}
erts_dsprintf(dsbufp, "\n");
@@ -946,7 +950,7 @@ steal(erts_dsprintf_buf_t *dsbufp, ErtsDrvEventState *state, int mode)
break;
}
default:
- erts_dsprintf(dsbufp, "no one\n", (int) state->fd);
+ erts_dsprintf(dsbufp, "no one\n", (int) GET_FD(state->fd));
ASSERT(0);
}
}
@@ -957,10 +961,14 @@ print_select_op(erts_dsprintf_buf_t *dsbufp,
{
Port *pp = erts_drvport2port(ix);
erts_dsprintf(dsbufp,
+#ifdef __OSE__
+ "driver_select(%p, %d,%s%s%s%s | %d, %d) "
+#else
"driver_select(%p, %d,%s%s%s%s, %d) "
+#endif
"by ",
ix,
- (int) fd,
+ (int) GET_FD(fd),
mode & ERL_DRV_READ ? " ERL_DRV_READ" : "",
mode & ERL_DRV_WRITE ? " ERL_DRV_WRITE" : "",
mode & ERL_DRV_USE ? " ERL_DRV_USE" : "",
@@ -1010,7 +1018,7 @@ steal_pending_stop_select(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix,
ASSERT(state->type == ERTS_EV_TYPE_STOP_USE);
erts_dsprintf(dsbufp, "failed: fd=%d (re)selected before stop_select "
"was called for driver %s\n",
- (int) state->fd, state->driver.drv_ptr->name);
+ (int) GET_FD(state->fd), state->driver.drv_ptr->name);
erts_send_error_to_logger_nogl(dsbufp);
if (on) {
@@ -1395,6 +1403,26 @@ stale_drv_select(Eterm id, ErtsDrvEventState *state, int mode)
}
#ifndef ERTS_SYS_CONTINOUS_FD_NUMBERS
+
+#ifdef __OSE__
+static SafeHashValue drv_ev_state_hash(void *des)
+{
+ ErtsSysFdType fd = ((ErtsDrvEventState *) des)->fd;
+ /* We use hash on signo ^ id in order for steal to happen when the
+ same signo + fd is selected on by two different ports */
+ SafeHashValue val = (SafeHashValue)(fd->signo ^ fd->id);
+ return val ^ (val >> 8);
+}
+
+static int drv_ev_state_cmp(void *des1, void *des2)
+{
+ ErtsSysFdType fd1 = ((ErtsDrvEventState *) des1)->fd;
+ ErtsSysFdType fd2 = ((ErtsDrvEventState *) des2)->fd;
+ if (fd1->signo == fd2->signo && fd1->id == fd2->id)
+ return 0;
+ return 1;
+}
+#else /* !__OSE__ && !ERTS_SYS_CONTINOUS_FD_NUMBERS i.e. probably windows */
static SafeHashValue drv_ev_state_hash(void *des)
{
SafeHashValue val = (SafeHashValue) ((ErtsDrvEventState *) des)->fd;
@@ -1406,6 +1434,7 @@ static int drv_ev_state_cmp(void *des1, void *des2)
return ( ((ErtsDrvEventState *) des1)->fd == ((ErtsDrvEventState *) des2)->fd
? 0 : 1);
}
+#endif
static void *drv_ev_state_alloc(void *des_tmpl)
{
@@ -1882,12 +1911,14 @@ ERTS_CIO_EXPORT(erts_check_io_debug)(void)
int fd, len;
#endif
IterDebugCounters counters;
+#ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS
ErtsDrvEventState null_des;
null_des.driver.select = NULL;
null_des.events = 0;
null_des.remove_cnt = 0;
null_des.type = ERTS_EV_TYPE_NONE;
+#endif
erts_printf("--- fds in pollset --------------------------------------\n");
diff --git a/erts/emulator/sys/common/erl_poll.h b/erts/emulator/sys/common/erl_poll.h
index 09ed9f41af..2f1c05f401 100644
--- a/erts/emulator/sys/common/erl_poll.h
+++ b/erts/emulator/sys/common/erl_poll.h
@@ -90,7 +90,7 @@
# if defined(ERTS_USE_POLL)
# undef ERTS_POLL_USE_POLL
# define ERTS_POLL_USE_POLL 1
-# elif !defined(__WIN32__)
+# elif !defined(__WIN32__) && !defined(__OSE__)
# undef ERTS_POLL_USE_SELECT
# define ERTS_POLL_USE_SELECT 1
# endif
@@ -99,13 +99,31 @@
typedef Uint32 ErtsPollEvents;
#undef ERTS_POLL_EV_E2N
-#if defined(__WIN32__) /* --- win32 ------------------------------- */
+#if defined(__WIN32__) || defined(__OSE__) /* --- win32 or ose -------- */
#define ERTS_POLL_EV_IN 1
#define ERTS_POLL_EV_OUT 2
#define ERTS_POLL_EV_ERR 4
#define ERTS_POLL_EV_NVAL 8
+#ifdef __OSE__
+
+typedef struct ErtsPollOseMsgList_ {
+ struct ErtsPollOseMsgList_ *next;
+ union SIGNAL *data;
+} ErtsPollOseMsgList;
+
+struct erts_sys_fd_type {
+ SIGSELECT signo;
+ ErlDrvOseEventId id;
+ ErtsPollOseMsgList *msgs;
+ ErlDrvOseEventId (*resolve_signal)(union SIGNAL *sig);
+ ethr_mutex mtx;
+ void *extra;
+};
+
+#endif
+
#elif ERTS_POLL_USE_EPOLL /* --- epoll ------------------------------- */
#include <sys/epoll.h>
@@ -228,7 +246,8 @@ ErtsPollEvents ERTS_POLL_EXPORT(erts_poll_control)(ErtsPollSet,
ErtsSysFdType,
ErtsPollEvents,
int on,
- int* wake_poller);
+ int* wake_poller
+ );
void ERTS_POLL_EXPORT(erts_poll_controlv)(ErtsPollSet,
ErtsPollControlEntry [],
int on);
diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c
index 31ad3b82d5..e3ba741058 100644
--- a/erts/emulator/sys/common/erl_sys_common_misc.c
+++ b/erts/emulator/sys/common/erl_sys_common_misc.c
@@ -52,7 +52,7 @@ static int filename_warning = ERL_FILENAME_WARNING_WARNING;
/* Default unicode on windows and MacOS X */
static int user_filename_encoding = ERL_FILENAME_UTF8;
#else
-static int user_filename_encoding = ERL_FILENAME_LATIN1;
+static int user_filename_encoding = ERL_FILENAME_UNKNOWN;
#endif
/* This controls the heuristic in printing characters in shell and w/
io:format("~tp", ...) etc. */
diff --git a/erts/emulator/sys/ose/beam.lmconf b/erts/emulator/sys/ose/beam.lmconf
new file mode 100644
index 0000000000..4ad46b01d9
--- /dev/null
+++ b/erts/emulator/sys/ose/beam.lmconf
@@ -0,0 +1,26 @@
+OSE_LM_STACK_SIZES=256,512,1024,2048,4096,8192,16384,65536
+OSE_LM_SIGNAL_SIZES=31,63,127,255,1023,4095,16383,65535
+OSE_LM_POOL_SIZE=0x200000
+OSE_LM_MAIN_NAME=main
+OSE_LM_MAIN_STACK_SIZE=0xF000
+OSE_LM_MAIN_PRIORITY=20
+## Has to be of a type that allows MAM
+OSE_LM_PROGRAM_TYPE=APP_RAM
+OSE_LM_DATA_INIT=YES
+OSE_LM_BSS_INIT=YES
+OSE_LM_EXEC_MODEL=SHARED
+HEAP_MAX_SIZE=1000000000
+HEAP_SMALL_BUF_INIT_SIZE=20971520
+HEAP_LARGE_BUF_THRESHOLD=16000000
+HEAP_LOCK_TYPE=2
+
+ERTS_DEFAULT_PRIO=24
+ERTS_SCHEDULER_PRIO=24
+ERTS_ASYNC_PRIO=22
+ERTS_AUX_PRIO=24
+ERTS_SYS_MSG_DISPATCHER_PRIO=21
+
+# Setting the environment variable EFS_RESOLVE_TMO on the block to 0.
+# This will eliminiate delays when trying to open files on not mounted
+# volumes.
+EFS_RESOLVE_TMO=0
diff --git a/erts/emulator/sys/ose/driver_int.h b/erts/emulator/sys/ose/driver_int.h
new file mode 100644
index 0000000000..2c9ac955d8
--- /dev/null
+++ b/erts/emulator/sys/ose/driver_int.h
@@ -0,0 +1,41 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1997-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * System dependant driver declarations
+ */
+
+#ifndef __DRIVER_INT_H__
+#define __DRIVER_INT_H__
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/types.h>
+#include <sys/uio.h>
+
+typedef struct iovec SysIOVec;
+
+#else
+
+typedef struct {
+ char* iov_base;
+ int iov_len;
+} SysIOVec;
+
+#endif
+
+#endif
diff --git a/erts/emulator/sys/ose/erl_main.c b/erts/emulator/sys/ose/erl_main.c
new file mode 100644
index 0000000000..23a9bc93a4
--- /dev/null
+++ b/erts/emulator/sys/ose/erl_main.c
@@ -0,0 +1,53 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2000-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdlib.h>
+
+#include "sys.h"
+#include "erl_vm.h"
+#include "global.h"
+#include "ose.h"
+
+int
+main(int argc, char **argv) {
+
+ (void)stdin;(void)stdout;(void)stderr;
+
+ /* When starting using pm_create -c ARGV="-- -root ..", argv[0] is the first
+ part of ARGV and not the name of the executable. So we shuffle some
+ pointers here to make erl_start happy. */
+ if (argv[0][0] == '-') {
+ int i;
+ char **tmp_argv = malloc(sizeof(char*)*(argc+1));
+ for (i = 0; i < argc; i++)
+ tmp_argv[i+1] = argv[i];
+ tmp_argv[0] = "beam";
+ erl_start(argc+1,tmp_argv);
+ free(tmp_argv);
+ } else {
+ erl_start(argc,argv);
+ }
+
+ stop(current_process());
+
+ return 0;
+}
diff --git a/erts/emulator/sys/ose/erl_ose_sys.h b/erts/emulator/sys/ose/erl_ose_sys.h
new file mode 100644
index 0000000000..cd66d95c26
--- /dev/null
+++ b/erts/emulator/sys/ose/erl_ose_sys.h
@@ -0,0 +1,353 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1997-2011. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+ * This file handles differences between different Unix systems.
+ * This should be the only place with conditional compilation
+ * depending on the type of OS.
+ */
+
+#ifndef _ERL_OSE_SYS_H
+#define _ERL_OSE_SYS_H
+
+#include "ose.h"
+#undef NIL
+#include "ramlog.h"
+#include "erts.sig"
+
+#include "fcntl.h"
+#include "math.h"
+#include "stdio.h"
+#include "stdlib.h"
+#include "string.h"
+#include "sys/param.h"
+#include "sys/time.h"
+#include "time.h"
+#include "dirent.h"
+#include "ethread.h"
+
+/* FIXME: configuration options */
+#define ERTS_SCHED_MIN_SPIN 1
+#define ERTS_SCHED_ONLY_POLL_SCHED_1 1
+#define ERTS_SCHED_FAIR 1
+#define NO_SYSCONF 1
+#define OPEN_MAX FOPEN_MAX
+
+#define MAP_ANON MAP_ANONYMOUS
+
+#ifndef HAVE_MMAP
+# define HAVE_MMAP 0
+#endif
+
+#if HAVE_MMAP
+# include "sys/mman.h"
+#endif
+
+/*
+ * Min number of async threads
+ */
+#define ERTS_MIN_NO_OF_ASYNC_THREADS 1
+
+/*
+ * Our own type of "FD's"
+ */
+#define ERTS_SYS_FD_TYPE struct erts_sys_fd_type*
+#define NO_FSTAT_ON_SYS_FD_TYPE 1 /* They are signals, not files */
+
+#include "sys/stat.h"
+
+/* FIXME mremap is not defined in OSE - POSIX issue */
+extern void *mremap (void *__addr, size_t __old_len, size_t __new_len,
+ int __flags, ...);
+
+/* FIXME: mremap constants */
+#define MREMAP_MAYMOVE 1
+#define MREMAP_FIXED 2
+
+typedef void *GETENV_STATE;
+
+/*
+** For the erl_timer_sup module.
+*/
+#define HAVE_GETHRTIME
+
+typedef long long SysHrTime;
+extern SysHrTime sys_gethrtime(void);
+
+void sys_init_hrtime(void);
+
+typedef time_t erts_time_t;
+
+typedef struct timeval SysTimeval;
+
+#define sys_gettimeofday(Arg) ((void) gettimeofday((Arg), NULL))
+
+typedef struct {
+ clock_t tms_utime;
+ clock_t tms_stime;
+ clock_t tms_cutime;
+ clock_t tms_cstime;
+} SysTimes;
+
+extern int erts_ticks_per_sec;
+
+#define SYS_CLK_TCK (erts_ticks_per_sec)
+
+extern clock_t sys_times(SysTimes *buffer);
+
+/* No use in having other resolutions than 1 Ms. */
+#define SYS_CLOCK_RESOLUTION 1
+
+#ifdef NO_FPE_SIGNALS
+
+#define erts_get_current_fp_exception() NULL
+#ifdef ERTS_SMP
+#define erts_thread_init_fp_exception() do{}while(0)
+#endif
+# define __ERTS_FP_CHECK_INIT(fpexnp) do {} while (0)
+# define __ERTS_FP_ERROR(fpexnp, f, Action) if (!finite(f)) { Action; } else {}
+# define __ERTS_FP_ERROR_THOROUGH(fpexnp, f, Action) __ERTS_FP_ERROR(fpexnp, f, Action)
+# define __ERTS_SAVE_FP_EXCEPTION(fpexnp)
+# define __ERTS_RESTORE_FP_EXCEPTION(fpexnp)
+
+#define erts_sys_block_fpe() 0
+#define erts_sys_unblock_fpe(x) do{}while(0)
+
+#else /* !NO_FPE_SIGNALS */
+
+extern volatile unsigned long *erts_get_current_fp_exception(void);
+#ifdef ERTS_SMP
+extern void erts_thread_init_fp_exception(void);
+#endif
+# if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
+# define erts_fwait(fpexnp,f) \
+ __asm__ __volatile__("fwait" : "=m"(*(fpexnp)) : "m"(f))
+# elif (defined(__powerpc__) || defined(__ppc__)) && defined(__GNUC__)
+# define erts_fwait(fpexnp,f) \
+ __asm__ __volatile__("" : "=m"(*(fpexnp)) : "fm"(f))
+# elif defined(__sparc__) && defined(__linux__) && defined(__GNUC__)
+# define erts_fwait(fpexnp,f) \
+ __asm__ __volatile__("" : "=m"(*(fpexnp)) : "em"(f))
+# else
+# define erts_fwait(fpexnp,f) \
+ __asm__ __volatile__("" : "=m"(*(fpexnp)) : "g"(f))
+# endif
+# if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
+ extern void erts_restore_fpu(void);
+# else
+# define erts_restore_fpu() /*empty*/
+# endif
+# if (!defined(__GNUC__) || \
+ (__GNUC__ < 2) || \
+ (__GNUC__ == 2 && __GNUC_MINOR < 96)) && \
+ !defined(__builtin_expect)
+# define __builtin_expect(x, expected_value) (x)
+# endif
+static __inline__ int erts_check_fpe(volatile unsigned long *fp_exception, double f)
+{
+ erts_fwait(fp_exception, f);
+ if (__builtin_expect(*fp_exception == 0, 1))
+ return 0;
+ *fp_exception = 0;
+ erts_restore_fpu();
+ return 1;
+}
+# undef erts_fwait
+# undef erts_restore_fpu
+extern void erts_fp_check_init_error(volatile unsigned long *fp_exception);
+static __inline__ void __ERTS_FP_CHECK_INIT(volatile unsigned long *fp_exception)
+{
+ if (__builtin_expect(*fp_exception == 0, 1))
+ return;
+ erts_fp_check_init_error(fp_exception);
+}
+# define __ERTS_FP_ERROR(fpexnp, f, Action) do { if (erts_check_fpe((fpexnp),(f))) { Action; } } while (0)
+# define __ERTS_SAVE_FP_EXCEPTION(fpexnp) unsigned long old_erl_fp_exception = *(fpexnp)
+# define __ERTS_RESTORE_FP_EXCEPTION(fpexnp) \
+ do { *(fpexnp) = old_erl_fp_exception; } while (0)
+ /* This is for library calls where we don't trust the external
+ code to always throw floating-point exceptions on errors. */
+static __inline__ int erts_check_fpe_thorough(volatile unsigned long *fp_exception, double f)
+{
+ return erts_check_fpe(fp_exception, f) || !finite(f);
+}
+# define __ERTS_FP_ERROR_THOROUGH(fpexnp, f, Action) \
+ do { if (erts_check_fpe_thorough((fpexnp),(f))) { Action; } } while (0)
+
+int erts_sys_block_fpe(void);
+void erts_sys_unblock_fpe(int);
+
+#endif /* !NO_FPE_SIGNALS */
+
+#define ERTS_FP_CHECK_INIT(p) __ERTS_FP_CHECK_INIT(&(p)->fp_exception)
+#define ERTS_FP_ERROR(p, f, A) __ERTS_FP_ERROR(&(p)->fp_exception, f, A)
+#define ERTS_FP_ERROR_THOROUGH(p, f, A) __ERTS_FP_ERROR_THOROUGH(&(p)->fp_exception, f, A)
+
+/* FIXME: force HAVE_GETPAGESIZE and stub getpagesize */
+#ifndef HAVE_GETPAGESIZE
+#define HAVE_GETPAGESIZE 1
+#endif
+
+extern int getpagesize(void);
+
+#ifndef HZ
+#define HZ 60
+#endif
+
+/* OSE5 doesn't provide limits.h so a number of macros should be
+ * added manually */
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+/* Minimum and maximum values a `signed int' can hold. */
+#ifndef INT_MAX
+#define INT_MAX 2147483647
+#endif
+
+#ifndef INT_MIN
+#define INT_MIN (-INT_MAX - 1)
+#endif
+
+#ifndef UINT_MAX
+# define UINT_MAX 4294967295U
+#endif
+
+/*
+static void erts_ose_sys_send(union SIGNAL **signal,PROCESS dst,
+ char* file,int line) {
+ SIGSELECT **ziggy = (SIGSELECT**)signal;
+ printf("%s:%d 0x%x Send signal 0x%x(0x%x) to 0x%x\r\n",
+ file,line,current_process(),ziggy[0][0],*ziggy,dst);
+ send(signal,dst);
+}
+#define send(signal,dst) erts_ose_sys_send(signal,dst,__FILE__,__LINE__)
+
+static void erts_ose_sys_send_w_sender(union SIGNAL **signal,
+ PROCESS sender,PROCESS dst,
+ char* file,int line) {
+ SIGSELECT **ziggy = (SIGSELECT**)signal;
+ printf("%s:%d 0x%x Send signal 0x%x(0x%x) to 0x%x as 0x%x\r\n",
+ file,line,current_process(),ziggy[0][0],*ziggy,dst,sender);
+ send_w_sender(signal,sender,dst);
+}
+#define send_w_sender(signal,sender,dst) \
+ erts_ose_sys_send_w_sender(signal,sender,dst,__FILE__,__LINE__)
+
+
+static union SIGNAL *erts_ose_sys_receive(SIGSELECT *sigsel,
+ char *file,
+ int line) {
+ SIGSELECT *sig;
+ int i;
+
+ printf("%s:%d 0x%x receive({%d,",file,line,current_process(),sigsel[0]);
+ for (i = 1; i < sigsel[0]; i++)
+ printf("0x%x, ",sigsel[i]);
+ if (sigsel[0] != 0)
+ printf("0x%x",sigsel[i]);
+ printf("})\n");
+ sig = (SIGSELECT*)receive(sigsel);
+ printf("%s:%d 0x%x got 0x%x from 0x%x\n",file,line,current_process(),
+ *sig,sender((union SIGNAL**)(&sig)));
+ return (union SIGNAL*)sig;
+}
+#define receive(SIGSEL) erts_ose_sys_receive(SIGSEL,__FILE__,__LINE__)
+
+static union SIGNAL *erts_ose_sys_receive_w_tmo(OSTIME tmo,SIGSELECT *sigsel,
+ char *file,int line) {
+ SIGSELECT *sig;
+ int i;
+ if (tmo == 0) {
+ sig = (SIGSELECT*)receive_w_tmo(tmo,sigsel);
+ if (sig != NULL) {
+ printf("%s:%d 0x%x receive_w_tmo(0,{%d,",file,line,current_process(),
+ sigsel[0]);
+ for (i = 1; i < sigsel[0]; i++)
+ printf("0x%x, ",sigsel[i]);
+ if (sigsel[0] != 0)
+ printf("0x%x",sigsel[i]);
+ printf("})\n");
+ printf("%s:%d 0x%x got 0x%x from 0x%x\n",file,line,current_process(),
+ *sig,sender((union SIGNAL**)(&sig)));
+ }
+ } else {
+ printf("%s:%d 0x%x receive_w_tmo(%u,{%d,",file,line,current_process(),tmo,
+ sigsel[0]);
+ for (i = 1; i < sigsel[0]; i++)
+ printf("0x%x, ",sigsel[i]);
+ if (sigsel[0] != 0)
+ printf("0x%x",sigsel[i]);
+ printf("})\n");
+ sig = (SIGSELECT*)receive_w_tmo(tmo,sigsel);
+ printf("%s:%d 0x%x got ",file,line,current_process());
+ if (sig == NULL)
+ printf("TIMEOUT\n");
+ else
+ printf("0x%x from 0x%x\n",*sig,sender((union SIGNAL**)(&sig)));
+ }
+
+ return (union SIGNAL*)sig;
+}
+
+#define receive_w_tmo(tmo,sigsel) erts_ose_sys_receive_w_tmo(tmo,sigsel, \
+ __FILE__,__LINE__)
+
+static union SIGNAL *erts_ose_sys_receive_fsem(OSTIME tmo,SIGSELECT *sigsel,
+ OSFSEMVAL fsem,
+ char *file,int line) {
+ SIGSELECT *sig;
+ int i;
+ if (tmo == 0) {
+ sig = (SIGSELECT*)receive_fsem(tmo,sigsel,fsem);
+ if (sig != NULL && sig != OS_RCV_FSEM) {
+ printf("%s:%d 0x%x receive_fsem(0,{%d,",file,line,current_process(),
+ sigsel[0]);
+ for (i = 1; i < sigsel[0]; i++)
+ printf("0x%x, ",sigsel[i]);
+ if (sigsel[0] != 0)
+ printf("0x%x",sigsel[i]);
+ printf("},%d)\n",fsem);
+ printf("%s:%d 0x%x got 0x%x from 0x%x\n",file,line,current_process(),
+ *sig,sender((union SIGNAL**)(&sig)));
+ }
+ } else {
+ printf("%s:%d 0x%x receive_fsem(%u,{%d,",file,line,current_process(),tmo,
+ sigsel[0]);
+ for (i = 1; i < sigsel[0]; i++)
+ printf("0x%x, ",sigsel[i]);
+ if (sigsel[0] != 0)
+ printf("0x%x",sigsel[i]);
+ printf("},%d)\n",fsem);
+ sig = (SIGSELECT*)receive_fsem(tmo,sigsel,fsem);
+ printf("%s:%d 0x%x got ",file,line,current_process());
+ if (sig == NULL)
+ printf("TIMEOUT\n");
+ else if (sig == OS_RCV_FSEM)
+ printf("FSEM\n");
+ else
+ printf("0x%x from 0x%x\n",*sig,sender((union SIGNAL**)(&sig)));
+ }
+
+ return (union SIGNAL*)sig;
+}
+
+#define receive_fsem(tmo,sigsel,fsem) \
+ erts_ose_sys_receive_fsem(tmo,sigsel,fsem,__FILE__,__LINE__)
+*/
+#endif /* _ERL_OSE_SYS_H */
diff --git a/erts/emulator/sys/ose/erl_ose_sys_ddll.c b/erts/emulator/sys/ose/erl_ose_sys_ddll.c
new file mode 100644
index 0000000000..ebd80deeaf
--- /dev/null
+++ b/erts/emulator/sys/ose/erl_ose_sys_ddll.c
@@ -0,0 +1,126 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2006-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Interface functions to the dynamic linker using dl* functions.
+ * (No support in OSE, we use static linkage instead)
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "erl_vm.h"
+#include "global.h"
+
+
+void erl_sys_ddll_init(void) {
+}
+
+/*
+ * Open a shared object
+ */
+int erts_sys_ddll_open(const char *full_name, void **handle, ErtsSysDdllError* err)
+{
+ return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY;
+}
+
+int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
+{
+ return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY;
+}
+
+/*
+ * Find a symbol in the shared object
+ */
+int erts_sys_ddll_sym2(void *handle, const char *func_name, void **function,
+ ErtsSysDdllError* err)
+{
+ return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY;
+}
+
+/* XXX:PaN These two will be changed with new driver interface! */
+
+/*
+ * Load the driver init function, might appear under different names depending on object arch...
+ */
+
+int erts_sys_ddll_load_driver_init(void *handle, void **function)
+{
+ void *fn;
+ int res;
+ if ((res = erts_sys_ddll_sym2(handle, "driver_init", &fn, NULL)) != ERL_DE_NO_ERROR) {
+ res = erts_sys_ddll_sym2(handle, "_driver_init", &fn, NULL);
+ }
+ if (res == ERL_DE_NO_ERROR) {
+ *function = fn;
+ }
+ return res;
+}
+
+int erts_sys_ddll_load_nif_init(void *handle, void **function, ErtsSysDdllError* err)
+{
+ void *fn;
+ int res;
+ if ((res = erts_sys_ddll_sym2(handle, "nif_init", &fn, err)) != ERL_DE_NO_ERROR) {
+ res = erts_sys_ddll_sym2(handle, "_nif_init", &fn, err);
+ }
+ if (res == ERL_DE_NO_ERROR) {
+ *function = fn;
+ }
+ return res;
+}
+
+/*
+ * Call the driver_init function, whatever it's really called, simple on unix...
+*/
+void *erts_sys_ddll_call_init(void *function) {
+ void *(*initfn)(void) = function;
+ return (*initfn)();
+}
+void *erts_sys_ddll_call_nif_init(void *function) {
+ return erts_sys_ddll_call_init(function);
+}
+
+
+
+/*
+ * Close a chared object
+ */
+int erts_sys_ddll_close2(void *handle, ErtsSysDdllError* err)
+{
+ return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY;
+}
+
+
+/*
+ * Return string that describes the (current) error
+ */
+char *erts_sys_ddll_error(int code)
+{
+ return "Unspecified error";
+}
+
+void erts_sys_ddll_free_error(ErtsSysDdllError* err)
+{
+ if (err->str != NULL) {
+ erts_free(ERTS_ALC_T_DDLL_TMP_BUF, err->str);
+ }
+}
diff --git a/erts/emulator/sys/ose/erl_poll.c b/erts/emulator/sys/ose/erl_poll.c
new file mode 100644
index 0000000000..7d2a3d1e0b
--- /dev/null
+++ b/erts/emulator/sys/ose/erl_poll.c
@@ -0,0 +1,780 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2006-2012. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * Description: Poll interface suitable for ERTS on OSE with or without
+ * SMP support.
+ *
+ * The interface is currently implemented using:
+ * - receive + receive_fsem
+ *
+ * Author: Lukas Larsson
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "erl_thr_progress.h"
+#include "erl_driver.h"
+#include "erl_alloc.h"
+#include "erl_poll.h"
+
+#define NOFILE 4096
+
+/*
+ * Some debug macros
+ */
+
+/* #define HARDDEBUG
+#define HARDTRACE*/
+#ifdef HARDDEBUG
+#ifdef HARDTRACE
+#define HARDTRACEF(X, ...) { fprintf(stderr, X, __VA_ARGS__); fprintf(stderr,"\r\n"); }
+#else
+#define HARDTRACEF(...)
+#endif
+
+#else
+#define HARDTRACEF(X,...)
+#define HARDDEBUGF(...)
+#endif
+
+#if 0
+#define ERTS_POLL_DEBUG_PRINT
+#endif
+
+#if defined(DEBUG) && 0
+#define HARD_DEBUG
+#endif
+
+# define SEL_ALLOC erts_alloc
+# define SEL_REALLOC realloc_wrap
+# define SEL_FREE erts_free
+
+#ifdef ERTS_SMP
+
+#define ERTS_POLLSET_LOCK(PS) \
+ erts_smp_mtx_lock(&(PS)->mtx)
+#define ERTS_POLLSET_UNLOCK(PS) \
+ erts_smp_mtx_unlock(&(PS)->mtx)
+
+#else
+
+#define ERTS_POLLSET_LOCK(PS)
+#define ERTS_POLLSET_UNLOCK(PS)
+
+#endif
+
+/*
+ * --- Data types ------------------------------------------------------------
+ */
+
+union SIGNAL {
+ SIGSELECT sig_no;
+};
+
+typedef struct erts_sigsel_item_ ErtsSigSelItem;
+
+struct erts_sigsel_item_ {
+ ErtsSigSelItem *next;
+ ErtsSysFdType fd;
+ ErtsPollEvents events;
+};
+
+typedef struct erts_sigsel_info_ ErtsSigSelInfo;
+
+struct erts_sigsel_info_ {
+ ErtsSigSelInfo *next;
+ SIGSELECT signo;
+ ErlDrvOseEventId (*decode)(union SIGNAL* sig);
+ ErtsSigSelItem *fds;
+};
+
+struct ErtsPollSet_ {
+ SIGSELECT *sigs;
+ ErtsSigSelInfo *info;
+ Uint sig_count;
+ Uint item_count;
+ PROCESS interrupt;
+ erts_atomic32_t wakeup_state;
+ erts_smp_atomic32_t timeout;
+#ifdef ERTS_SMP
+ erts_smp_mtx_t mtx;
+#endif
+};
+
+static int max_fds = -1;
+
+#define ERTS_POLL_NOT_WOKEN ((erts_aint32_t) (1 << 0))
+#define ERTS_POLL_WOKEN_INTR ((erts_aint32_t) (1 << 1))
+#define ERTS_POLL_WOKEN_TIMEDOUT ((erts_aint32_t) (1 << 2))
+#define ERTS_POLL_WOKEN_IO_READY ((erts_aint32_t) (1 << 3))
+#define ERTS_POLL_SLEEPING ((erts_aint32_t) (1 << 4))
+
+/* signal list prototypes */
+static ErtsSigSelInfo *get_sigsel_info(ErtsPollSet ps, SIGSELECT signo);
+static ErtsSigSelItem *get_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd);
+static ErtsSigSelInfo *add_sigsel_info(ErtsPollSet ps, ErtsSysFdType fd,
+ ErlDrvOseEventId (*decode)(union SIGNAL* sig));
+static ErtsSigSelItem *add_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd,
+ ErlDrvOseEventId (*decode)(union SIGNAL* sig));
+static int del_sigsel_info(ErtsPollSet ps, ErtsSigSelInfo *info);
+static int del_sigsel_item(ErtsPollSet ps, ErtsSigSelItem *item);
+static int update_sigsel(ErtsPollSet ps);
+
+static ErtsSigSelInfo *
+get_sigsel_info(ErtsPollSet ps, SIGSELECT signo) {
+ ErtsSigSelInfo *curr = ps->info;
+ while (curr != NULL) {
+ if (curr->signo == signo)
+ return curr;
+ curr = curr->next;
+ }
+ return NULL;
+}
+
+static ErtsSigSelItem *
+get_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd) {
+ ErtsSigSelInfo *info = get_sigsel_info(ps,fd->signo);
+ ErtsSigSelItem *curr;
+
+ if (info == NULL)
+ return NULL;
+
+ curr = info->fds;
+
+ while (curr != NULL) {
+ if (curr->fd->id == fd->id) {
+ ASSERT(curr->fd->signo == fd->signo);
+ return curr;
+ }
+ curr = curr->next;
+ }
+ return NULL;
+}
+
+static ErtsSigSelInfo *
+add_sigsel_info(ErtsPollSet ps, ErtsSysFdType fd,
+ ErlDrvOseEventId (*decode)(union SIGNAL* sig)) {
+ ErtsSigSelInfo *info = SEL_ALLOC(ERTS_ALC_T_POLLSET,
+ sizeof(ErtsSigSelInfo));
+ info->next = ps->info;
+ info->fds = NULL;
+ info->signo = fd->signo;
+ info->decode = decode;
+ ps->info = info;
+ ps->sig_count++;
+ return info;
+}
+
+static ErtsSigSelItem *
+add_sigsel_item(ErtsPollSet ps, ErtsSysFdType fd,
+ ErlDrvOseEventId (*decode)(union SIGNAL* sig)) {
+ ErtsSigSelInfo *info = get_sigsel_info(ps,fd->signo);
+ ErtsSigSelItem *item = SEL_ALLOC(ERTS_ALC_T_POLLSET,
+ sizeof(ErtsSigSelItem));
+ if (info == NULL)
+ info = add_sigsel_info(ps, fd, decode);
+ if (info->decode != decode) {
+ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
+ erts_dsprintf(dsbufp, "erts_poll_control() inconsistency: multiple resolve_signal functions for same signal (%d)\n",
+ fd->signo);
+ erts_send_error_to_logger_nogl(dsbufp);
+ }
+ ASSERT(info->decode == decode);
+ item->next = info->fds;
+ item->fd = fd;
+ item->events = 0;
+ info->fds = item;
+ ps->item_count++;
+ return item;
+}
+
+static int del_sigsel_info(ErtsPollSet ps, ErtsSigSelInfo *info) {
+ ErtsSigSelInfo *curr, *prev;
+
+ if (ps->info == info) {
+ ps->info = ps->info->next;
+ } else {
+ curr = ps->info->next;
+ prev = ps->info;
+
+ while (curr != info) {
+ if (curr == NULL)
+ return 1;
+ prev = curr;
+ curr = curr->next;
+ }
+ prev->next = curr->next;
+ }
+
+ ps->sig_count--;
+ SEL_FREE(ERTS_ALC_T_POLLSET, info);
+ return 0;
+}
+
+static int del_sigsel_item(ErtsPollSet ps, ErtsSigSelItem *item) {
+ ErtsSigSelInfo *info = get_sigsel_info(ps,item->fd->signo);
+ ErtsSigSelItem *curr, *prev;
+
+ ps->item_count--;
+ ASSERT(ps->item_count >= 0);
+
+ if (info->fds == item) {
+ info->fds = info->fds->next;
+ SEL_FREE(ERTS_ALC_T_POLLSET,item);
+ if (info->fds == NULL)
+ return del_sigsel_info(ps,info);
+ return 0;
+ }
+
+ curr = info->fds->next;
+ prev = info->fds;
+
+ while (curr != item) {
+ if (curr == NULL) {
+ /* We did not find an item to delete so we have to
+ * increment item count again.
+ */
+ ps->item_count++;
+ return 1;
+ }
+ prev = curr;
+ curr = curr->next;
+ }
+ prev->next = curr->next;
+ SEL_FREE(ERTS_ALC_T_POLLSET,item);
+ return 0;
+}
+
+#ifdef ERTS_SMP
+
+static void update_redir_tables(ErtsPollSet ps) {
+ struct OS_redir_entry *redir_table;
+ PROCESS sched_1 = ERTS_SCHEDULER_IX(0)->tid.id;
+ int i;
+ redir_table = SEL_ALLOC(ERTS_ALC_T_POLLSET,
+ sizeof(struct OS_redir_entry)*(ps->sig_count+1));
+
+ redir_table[0].sig = ps->sig_count+1;
+ redir_table[0].pid = 0;
+
+ for (i = 1; i < ps->sig_count+1; i++) {
+ redir_table[i].sig = ps->sigs[i];
+ redir_table[i].pid = sched_1;
+ }
+
+ for (i = 1; i < erts_no_schedulers; i++) {
+ ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(i);
+ set_redirection(esdp->tid.id,redir_table);
+ }
+
+ SEL_FREE(ERTS_ALC_T_POLLSET,redir_table);
+}
+
+#endif
+
+static int update_sigsel(ErtsPollSet ps) {
+ ErtsSigSelInfo *info = ps->info;
+
+ int i;
+
+ if (ps->sigs != NULL)
+ SEL_FREE(ERTS_ALC_T_POLLSET,ps->sigs);
+
+ if (ps->sig_count == 0) {
+ /* If there are no signals we place a non-valid signal to make sure that
+ * we do not trigger on a any unrelated signals which are sent to the
+ * process.
+ */
+ ps->sigs = SEL_ALLOC(ERTS_ALC_T_POLLSET,sizeof(SIGSELECT)*(2));
+ ps->sigs[0] = 1;
+ ps->sigs[1] = ERTS_SIGNAL_INVALID;
+ return 0;
+ }
+
+ ps->sigs = SEL_ALLOC(ERTS_ALC_T_POLLSET,sizeof(SIGSELECT)*(ps->sig_count+1));
+ ps->sigs[0] = ps->sig_count;
+
+ for (i = 1; info != NULL; i++, info = info->next)
+ ps->sigs[i] = info->signo;
+
+#ifdef ERTS_SMP
+ update_redir_tables(ps);
+#endif
+
+ return 0;
+}
+
+static ERTS_INLINE void
+wake_poller(ErtsPollSet ps)
+{
+ erts_aint32_t wakeup_state;
+
+ ERTS_THR_MEMORY_BARRIER;
+ wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state);
+ while (wakeup_state != ERTS_POLL_WOKEN_IO_READY
+ && wakeup_state != ERTS_POLL_WOKEN_INTR) {
+ erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_WOKEN_INTR,
+ wakeup_state);
+ if (act == wakeup_state) {
+ wakeup_state = act;
+ break;
+ }
+ wakeup_state = act;
+ }
+ if (wakeup_state == ERTS_POLL_SLEEPING) {
+ /*
+ * Since we don't know the internals of signal_fsem() we issue
+ * a memory barrier as a safety precaution ensuring that
+ * the store we just made to wakeup_state wont be reordered
+ * with loads in signal_fsem().
+ */
+ ERTS_THR_MEMORY_BARRIER;
+ signal_fsem(ps->interrupt);
+ }
+}
+
+static ERTS_INLINE void
+reset_interrupt(ErtsPollSet ps)
+{
+ /* We need to keep io-ready if set */
+ erts_aint32_t wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state);
+ while (wakeup_state != ERTS_POLL_NOT_WOKEN &&
+ wakeup_state != ERTS_POLL_SLEEPING) {
+ erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_NOT_WOKEN,
+ wakeup_state);
+ if (wakeup_state == act)
+ break;
+ wakeup_state = act;
+ }
+ ERTS_THR_MEMORY_BARRIER;
+}
+
+static ERTS_INLINE void
+set_interrupt(ErtsPollSet ps)
+{
+ wake_poller(ps);
+}
+
+void erts_poll_interrupt(ErtsPollSet ps,int set) {
+ HARDTRACEF("erts_poll_interrupt called!\n");
+
+ if (!set)
+ reset_interrupt(ps);
+ else
+ set_interrupt(ps);
+
+}
+
+void erts_poll_interrupt_timed(ErtsPollSet ps,int set,erts_short_time_t msec) {
+ HARDTRACEF("erts_poll_interrupt_timed called!\n");
+
+ if (!set)
+ reset_interrupt(ps);
+ else if (erts_smp_atomic32_read_acqb(&ps->timeout) > (erts_aint32_t) msec)
+ set_interrupt(ps);
+}
+
+ErtsPollEvents erts_poll_control(ErtsPollSet ps, ErtsSysFdType fd,
+ ErtsPollEvents pe, int on, int* do_wake) {
+ ErtsSigSelItem *curr;
+ ErtsPollEvents new_events;
+ int old_sig_count;
+
+ HARDTRACEF(
+ "%ux: In erts_poll_control, fd = %d, pe = %d, on = %d, *do_wake = %d, curr = 0x%xu",
+ ps, fd, pe, on, do_wake, curr);
+
+ ERTS_POLLSET_LOCK(ps);
+
+ if (on && (pe & ERTS_POLL_EV_IN) && (pe & ERTS_POLL_EV_OUT)) {
+ /* Check to make sure both in and out are not used at the same time */
+ new_events = ERTS_POLL_EV_NVAL;
+ goto done;
+ }
+
+ curr = get_sigsel_item(ps, fd);
+ old_sig_count = ps->sig_count;
+
+ if (curr == NULL && on) {
+ curr = add_sigsel_item(ps, fd, fd->resolve_signal);
+ } else if (curr == NULL && !on) {
+ new_events = ERTS_POLL_EV_NVAL;
+ goto done;
+ }
+
+ new_events = curr->events;
+
+ if (pe == 0) {
+ *do_wake = 0;
+ goto done;
+ }
+
+ if (on) {
+ new_events |= pe;
+ curr->events = new_events;
+ } else {
+ new_events &= ~pe;
+ curr->events = new_events;
+ if (new_events == 0 && del_sigsel_item(ps, curr)) {
+ new_events = ERTS_POLL_EV_NVAL;
+ goto done;
+ }
+ }
+
+ if (ps->sig_count != old_sig_count) {
+ if (update_sigsel(ps))
+ new_events = ERTS_POLL_EV_NVAL;
+ }
+done:
+ ERTS_POLLSET_UNLOCK(ps);
+ HARDTRACEF("%ux: Out erts_poll_control", ps);
+ return new_events;
+}
+
+int erts_poll_wait(ErtsPollSet ps,
+ ErtsPollResFd pr[],
+ int *len,
+ SysTimeval *utvp) {
+ int res = ETIMEDOUT, no_fds, currid = 0;
+ OSTIME timeout;
+ union SIGNAL *sig;
+ // HARDTRACEF("%ux: In erts_poll_wait",ps);
+ if (ps->interrupt == (PROCESS)0)
+ ps->interrupt = current_process();
+
+ ASSERT(current_process() == ps->interrupt);
+ ASSERT(get_fsem(current_process()) == 0);
+ ASSERT(erts_atomic32_read_nob(&ps->wakeup_state) &
+ (ERTS_POLL_NOT_WOKEN | ERTS_POLL_WOKEN_INTR));
+ /* Max no of spots avable in pr */
+ no_fds = *len;
+
+ *len = 0;
+
+ ASSERT(utvp);
+
+ /* erts_printf("Entering erts_poll_wait(), timeout=%d\n",
+ (int) utvp->tv_sec*1000 + utvp->tv_usec/1000); */
+
+ timeout = utvp->tv_sec*1000 + utvp->tv_usec/1000;
+
+ if (timeout > ((time_t) ERTS_AINT32_T_MAX))
+ timeout = ERTS_AINT32_T_MAX;
+ erts_smp_atomic32_set_relb(&ps->timeout, (erts_aint32_t) timeout);
+
+ while (currid < no_fds) {
+ if (timeout > 0) {
+ erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_SLEEPING,
+ ERTS_POLL_NOT_WOKEN);
+ if (act == ERTS_POLL_NOT_WOKEN) {
+#ifdef ERTS_SMP
+ erts_thr_progress_prepare_wait(NULL);
+#endif
+ sig = receive_fsem(timeout, ps->sigs, 1);
+#ifdef ERTS_SMP
+ erts_thr_progress_finalize_wait(NULL);
+#endif
+ } else {
+ ASSERT(act == ERTS_POLL_WOKEN_INTR);
+ sig = OS_RCV_FSEM;
+ }
+ } else
+ sig = receive_w_tmo(0, ps->sigs);
+
+ if (sig == NULL) {
+ if (timeout > 0) {
+ erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_WOKEN_TIMEDOUT,
+ ERTS_POLL_SLEEPING);
+ if (act == ERTS_POLL_WOKEN_INTR)
+ /* Restore fsem as it was signaled but we got a timeout */
+ wait_fsem(1);
+ } else
+ erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_WOKEN_TIMEDOUT,
+ ERTS_POLL_NOT_WOKEN);
+ break;
+ } else if (sig == OS_RCV_FSEM) {
+ ASSERT(erts_atomic32_read_nob(&ps->wakeup_state) == ERTS_POLL_WOKEN_INTR);
+ break;
+ }
+ {
+ ErtsSigSelInfo *info = get_sigsel_info(ps, sig->sig_no);
+ struct erts_sys_fd_type fd = { sig->sig_no, info->decode(sig) };
+ ErtsSigSelItem *item = get_sigsel_item(ps, &fd);
+
+ ASSERT(sig);
+ if (currid == 0 && timeout > 0) {
+ erts_aint32_t act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_WOKEN_IO_READY,
+ ERTS_POLL_SLEEPING);
+ if (act == ERTS_POLL_WOKEN_INTR) {
+ /* Restore fsem as it was signaled but we got a msg */
+ wait_fsem(1);
+ act = erts_atomic32_cmpxchg_nob(&ps->wakeup_state,
+ ERTS_POLL_WOKEN_IO_READY,
+ ERTS_POLL_WOKEN_INTR);
+ }
+ } else if (currid == 0) {
+ erts_atomic32_set_nob(&ps->wakeup_state,
+ ERTS_POLL_WOKEN_IO_READY);
+ }
+
+ if (item == NULL) {
+ erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
+ erts_dsprintf(
+ dsbufp,
+ "erts_poll_wait() failed: found unkown signal id %d (signo %u) "
+ "(curr_proc 0x%x)\n",
+ fd.id, fd.signo, current_process());
+ erts_send_error_to_logger_nogl(dsbufp);
+ timeout = 0;
+ /* Under normal circumstances the signal is deallocated by the
+ * driver that issued the select operation. But in this case
+ * there's no driver waiting for such signal so we have to
+ * deallocate it here */
+ if (sig)
+ free_buf(&sig);
+ } else {
+ int i;
+ struct erts_sys_fd_type *fd = NULL;
+ ErtsPollOseMsgList *tl,*new;
+
+ /* Check if this fd has already been triggered by a previous signal */
+ for (i = 0; i < currid;i++) {
+ if (pr[i].fd == item->fd) {
+ fd = pr[i].fd;
+ pr[i].events |= item->events;
+ break;
+ }
+ }
+
+ /* First time this fd is triggered */
+ if (fd == NULL) {
+ pr[currid].fd = item->fd;
+ pr[currid].events = item->events;
+ fd = item->fd;
+ timeout = 0;
+ currid++;
+ }
+
+ /* Insert new signal in approriate list */
+ new = erts_alloc(ERTS_ALC_T_FD_SIG_LIST,sizeof(ErtsPollOseMsgList));
+ new->next = NULL;
+ new->data = sig;
+
+ ethr_mutex_lock(&fd->mtx);
+ tl = fd->msgs;
+
+ if (tl == NULL) {
+ fd->msgs = new;
+ } else {
+ while (tl->next != NULL)
+ tl = tl->next;
+ tl->next = new;
+ }
+ ethr_mutex_unlock(&fd->mtx);
+ }
+
+ }
+ }
+
+ {
+ erts_aint32_t wakeup_state = erts_atomic32_read_nob(&ps->wakeup_state);
+
+ switch (wakeup_state) {
+ case ERTS_POLL_WOKEN_IO_READY:
+ res = 0;
+ break;
+ case ERTS_POLL_WOKEN_INTR:
+ res = EINTR;
+ break;
+ case ERTS_POLL_WOKEN_TIMEDOUT:
+ res = ETIMEDOUT;
+ break;
+ case ERTS_POLL_NOT_WOKEN:
+ /* This happens when we get an invalid signal only */
+ res = EINVAL;
+ break;
+ default:
+ res = 0;
+ erl_exit(ERTS_ABORT_EXIT,
+ "%s:%d: Internal error: Invalid wakeup_state=%d\n",
+ __FILE__, __LINE__, (int) wakeup_state);
+ }
+ }
+
+ erts_atomic32_set_nob(&ps->wakeup_state, ERTS_POLL_NOT_WOKEN);
+ erts_smp_atomic32_set_nob(&ps->timeout, ERTS_AINT32_T_MAX);
+
+ *len = currid;
+
+ // HARDTRACEF("%ux: Out erts_poll_wait",ps);
+ return res;
+}
+
+int erts_poll_max_fds(void)
+{
+
+ HARDTRACEF("In/Out erts_poll_max_fds -> %d",max_fds);
+ return max_fds;
+}
+
+void erts_poll_info(ErtsPollSet ps,
+ ErtsPollInfo *pip)
+{
+ Uint size = 0;
+ Uint num_events = 0;
+
+ size += sizeof(struct ErtsPollSet_);
+ size += sizeof(ErtsSigSelInfo)*ps->sig_count;
+ size += sizeof(ErtsSigSelItem)*ps->item_count;
+ size += sizeof(SIGSELECT)*(ps->sig_count+1);
+
+ pip->primary = "receive_fsem";
+
+ pip->fallback = NULL;
+
+ pip->kernel_poll = NULL;
+
+ pip->memory_size = size;
+
+ pip->poll_set_size = num_events;
+
+ pip->fallback_poll_set_size = 0;
+
+ pip->lazy_updates = 0;
+
+ pip->pending_updates = 0;
+
+ pip->batch_updates = 0;
+
+ pip->concurrent_updates = 0;
+
+
+ pip->max_fds = erts_poll_max_fds();
+ HARDTRACEF("%ux: Out erts_poll_info",ps);
+
+}
+
+ErtsPollSet erts_poll_create_pollset(void)
+{
+ ErtsPollSet ps = SEL_ALLOC(ERTS_ALC_T_POLLSET,
+ sizeof(struct ErtsPollSet_));
+
+ ps->sigs = NULL;
+ ps->sig_count = 0;
+ ps->item_count = 0;
+ ps->info = NULL;
+ ps->interrupt = (PROCESS)0;
+ erts_atomic32_init_nob(&ps->wakeup_state, ERTS_POLL_NOT_WOKEN);
+ erts_smp_atomic32_init_nob(&ps->timeout, ERTS_AINT32_T_MAX);
+#ifdef ERTS_SMP
+ erts_smp_mtx_init(&ps->mtx, "pollset");
+#endif
+ update_sigsel(ps);
+ HARDTRACEF("%ux: Out erts_poll_create_pollset",ps);
+ return ps;
+}
+
+void erts_poll_destroy_pollset(ErtsPollSet ps)
+{
+ ErtsSigSelInfo *info;
+ for (info = ps->info; ps->info != NULL; info = ps->info, ps->info = ps->info->next) {
+ ErtsSigSelItem *item;
+ for (item = info->fds; info->fds != NULL; item = info->fds, info->fds = info->fds->next)
+ SEL_FREE(ERTS_ALC_T_POLLSET, item);
+ SEL_FREE(ERTS_ALC_T_POLLSET, info);
+ }
+
+ SEL_FREE(ERTS_ALC_T_POLLSET,ps->sigs);
+
+#ifdef ERTS_SMP
+ erts_smp_mtx_destroy(&ps->mtx);
+#endif
+
+ SEL_FREE(ERTS_ALC_T_POLLSET,ps);
+}
+
+void erts_poll_init(void)
+{
+ HARDTRACEF("In %s", __FUNCTION__);
+ max_fds = 256;
+
+ HARDTRACEF("Out %s", __FUNCTION__);
+}
+
+
+/* OSE driver functions */
+
+union SIGNAL *erl_drv_ose_get_signal(ErlDrvEvent drv_ev) {
+ struct erts_sys_fd_type *ev = (struct erts_sys_fd_type *)drv_ev;
+ ethr_mutex_lock(&ev->mtx);
+ if (ev->msgs == NULL) {
+ ethr_mutex_unlock(&ev->mtx);
+ return NULL;
+ } else {
+ ErtsPollOseMsgList *msg = ev->msgs;
+ union SIGNAL *sig = (union SIGNAL*)msg->data;
+ ASSERT(msg->data);
+ ev->msgs = msg->next;
+ ethr_mutex_unlock(&ev->mtx);
+ erts_free(ERTS_ALC_T_FD_SIG_LIST,msg);
+ restore(sig);
+ return sig;
+ }
+}
+
+ErlDrvEvent
+erl_drv_ose_event_alloc(SIGSELECT signo, ErlDrvOseEventId id,
+ ErlDrvOseEventId (*resolve_signal)(union SIGNAL *sig), void *extra) {
+ struct erts_sys_fd_type *ev = erts_alloc(ERTS_ALC_T_DRV_EV,
+ sizeof(struct erts_sys_fd_type));
+ ev->signo = signo;
+ ev->extra = extra;
+ ev->id = id;
+ ev->msgs = NULL;
+ ev->resolve_signal = resolve_signal;
+ ethr_mutex_init(&ev->mtx);
+ return (ErlDrvEvent)ev;
+}
+
+void erl_drv_ose_event_free(ErlDrvEvent drv_ev) {
+ struct erts_sys_fd_type *ev = (struct erts_sys_fd_type *)drv_ev;
+ ASSERT(ev->msgs == NULL);
+ ethr_mutex_destroy(&ev->mtx);
+ erts_free(ERTS_ALC_T_DRV_EV,ev);
+}
+
+void erl_drv_ose_event_fetch(ErlDrvEvent drv_ev, SIGSELECT *signo,
+ ErlDrvOseEventId *id, void **extra) {
+ struct erts_sys_fd_type *ev = (struct erts_sys_fd_type *)drv_ev;
+ if (signo)
+ *signo = ev->signo;
+ if (extra)
+ *extra = ev->extra;
+ if (id)
+ *id = ev->id;
+}
diff --git a/erts/emulator/sys/ose/erts.sig b/erts/emulator/sys/ose/erts.sig
new file mode 100644
index 0000000000..78b883ee6c
--- /dev/null
+++ b/erts/emulator/sys/ose/erts.sig
@@ -0,0 +1,17 @@
+#ifndef ERTS_OSE_SIGNALS
+#define ERTS_OSE_SIGNALS
+
+#ifndef ERTS_OSE_SIGNAL_BASE
+#define ERTS_OSE_SIGNAL_BASE 0x01900280
+#endif
+
+#define ERTS_SIGNAL_INVALID ERTS_OSE_SIGNAL_BASE
+#define ERTS_SIGNAL_FD_DRV_CONFIG ERTS_OSE_SIGNAL_BASE+1
+#define ERTS_SIGNAL_FD_DRV_ASYNC ERTS_OSE_SIGNAL_BASE+2
+#define ERTS_SIGNAL_OSE_DRV_ATTACH ERTS_OSE_SIGNAL_BASE+3
+#define ERTS_SIGNAL_OSE_DRV_HUNT ERTS_OSE_SIGNAL_BASE+4
+
+#define ERTS_SIGNAL_RUN_ERL_SETUP ERTS_OSE_SIGNAL_BASE+100
+#define ERTS_SIGNAL_RUN_ERL_DAEMON ERTS_OSE_SIGNAL_BASE+101
+
+#endif
diff --git a/erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf b/erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf
new file mode 100644
index 0000000000..a19d23facf
--- /dev/null
+++ b/erts/emulator/sys/ose/gcc_4.4.3_lm_ppc.lcf
@@ -0,0 +1,182 @@
+/*******************************************************************************
+ * Copyright (C) 2013-2014 by Enea Software AB,
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ ******************************************************************************/
+
+OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
+OUTPUT_ARCH("powerpc")
+ENTRY("crt0_lm")
+MEMORY
+{
+ rom : ORIGIN = 0x01000000, LENGTH = 0x01000000
+ ram : ORIGIN = 0x02000000, LENGTH = 0x01000000
+}
+PHDRS
+{
+ ph_conf PT_LOAD ;
+ ph_rom PT_LOAD ;
+ ph_ram PT_LOAD ;
+}
+SECTIONS
+{
+ .text :
+ {
+ *(.text_first)
+ *(.text)
+ *(.text.*)
+ *(.stub)
+ *(oscode)
+ *(.init*)
+ *(.fini*)
+ *(.gnu.warning)
+ *(.gnu.linkonce.t.*)
+ *(.glue_7t)
+ *(.glue_7)
+ } > rom :ph_rom = 0
+ .ose_sfk_biosentry :
+ {
+ *(.ose_sfk_biosentry)
+ } > rom :ph_rom
+ .ctors :
+ {
+ __CTOR_LIST__ = .;
+ *(.ctors)
+ *(SORT(.ctors.*))
+ __CTOR_END__ = .;
+ } > rom :ph_rom
+ .dtors :
+ {
+ __DTOR_LIST__ = .;
+ *(.dtors)
+ *(SORT(.dtors.*))
+ __DTOR_END__ = .;
+ } > rom :ph_rom
+ OSESYMS :
+ {
+ *(.osesyms)
+ } > rom :ph_rom
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r.*)
+ } > rom :ph_rom
+ .eh_frame_hdr :
+ {
+ *(.eh_frame_hdr)
+ } > rom :ph_rom
+ .eh_frame :
+ {
+ __EH_FRAME_BEGIN__ = .;
+ *(.eh_frame)
+ LONG(0)
+ __EH_FRAME_END__ = .;
+ } > rom :ph_rom
+ .gcc_except_table :
+ {
+ *(.gcc_except_table .gcc_except_table.*)
+ } > rom :ph_rom
+ .sdata2 :
+ {
+ PROVIDE (_SDA2_BASE_ = .);
+ *(.sdata2)
+ *(.sdata2.*)
+ *(.gnu.linkonce.s2.*)
+ } > rom :ph_rom
+ .sbss2 :
+ {
+ *(.sbss2)
+ *(.sbss2.*)
+ *(.gnu.linkonce.sb2.*)
+ } > rom :ph_rom
+ LMCONF :
+ {
+ obj/?*?/ose_confd.o(.rodata)
+ *(LMCONF)
+ } > rom :ph_conf
+ .data :
+ {
+ LONG(0xDEADBABE)
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ . = ALIGN(0x10);
+ } > ram :ph_ram = 0
+ .sdata2 :
+ {
+ _SDA2_BASE_ = .;
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ }> ram :ph_ram
+ .sdata :
+ {
+ PROVIDE (_SDA_BASE_ = .);
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s.*)
+ } > ram :ph_ram
+ .sbss :
+ {
+ *(.sbss)
+ *(.sbss.*)
+ *(.scommon)
+ *(.gnu.linkonce.sb.*)
+ } > ram :ph_ram
+ .bss (NOLOAD) :
+ {
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ *(.gnu.linkonce.b.*)
+ *(.osvars)
+ } > ram :ph_ram
+ .ignore (NOLOAD) :
+ {
+ *(.rel.dyn)
+ } > ram :ph_ram
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+}
+__OSESYMS_START = ADDR(OSESYMS);
+__OSESYMS_END = ADDR(OSESYMS) + SIZEOF(OSESYMS);
diff --git a/erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf b/erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf
new file mode 100644
index 0000000000..3440c2961b
--- /dev/null
+++ b/erts/emulator/sys/ose/gcc_4.6.3_lm_ppc.lcf
@@ -0,0 +1,242 @@
+/*******************************************************************************
+ * Copyright (C) 2013-2014 by Enea Software AB,
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR CONTRIBUTORS 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.
+ ******************************************************************************/
+
+OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
+OUTPUT_ARCH("powerpc")
+
+ENTRY("crt0_lm")
+
+/* Note:
+ * You may have to increase the length of the "rom" memory region and the
+ * origin and length of the "ram" memory region below depending on the size
+ * of the code and data in your load module.
+ */
+
+MEMORY
+{
+ conf : ORIGIN = 0x00100000, LENGTH = 0x00030000
+ rom : ORIGIN = 0x01000000, LENGTH = 0x01000000
+ ram : ORIGIN = 0x03000000, LENGTH = 0x01000000
+}
+
+PHDRS
+{
+ ph_conf PT_LOAD ;
+ ph_rom PT_LOAD ;
+ ph_ram PT_LOAD ;
+}
+
+SECTIONS
+{
+/*---------------------------------------------------------------------------
+ * Load module configuration area
+ *-------------------------------------------------------------------------*/
+
+ /* Load module configuration section. */
+ LMCONF :
+ {
+ obj/?*?/ose_confd.o(.rodata)
+ *(LMCONF)
+ } > conf :ph_conf
+
+/*---------------------------------------------------------------------------
+ * Read-only area
+ *-------------------------------------------------------------------------*/
+
+ /* Code section. */
+ .text :
+ {
+ *(.text)
+ *(.text.*)
+ *(.stub)
+ *(oscode)
+ *(.init*)
+ *(.fini*)
+ *(.gnu.warning)
+ *(.gnu.linkonce.t.*)
+ } > rom :ph_rom = 0
+
+ /* OSE symbols section. */
+ OSESYMS :
+ {
+ *(.osesyms)
+ } > rom :ph_rom
+
+ /* Read-only data section. */
+ .rodata :
+ {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r.*)
+ } > rom :ph_rom
+
+ /* C++ exception handling section. */
+ .eh_frame :
+ {
+ __EH_FRAME_BEGIN__ = .;
+ *(.eh_frame)
+ LONG(0)
+ __EH_FRAME_END__ = .;
+ } > rom :ph_rom
+
+ /* C++ exception handling section. */
+ .gcc_except_table :
+ {
+ *(.gcc_except_table .gcc_except_table.*)
+ } > rom :ph_rom
+
+ /* PowerPC EABI initialized read-only data section. */
+ .sdata2 :
+ {
+ PROVIDE (_SDA2_BASE_ = .);
+ *(.sdata2)
+ *(.sdata2.*)
+ *(.gnu.linkonce.s2.*)
+ } > rom :ph_rom
+
+ /* PowerPC EABI uninitialized read-only data section. */
+ .sbss2 :
+ {
+ *(.sbss2)
+ *(.sbss2.*)
+ *(.gnu.linkonce.sb2.*)
+ } > rom :ph_rom
+
+/*---------------------------------------------------------------------------
+ * Read-write area
+ *-------------------------------------------------------------------------*/
+
+ /*-------------------------------------------------------------------
+ * Initialized data (copied by PM)
+ *-----------------------------------------------------------------*/
+
+ /* Data section. */
+ .data :
+ {
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ } > ram :ph_ram
+
+ /* C++ constructor section. */
+ .ctors :
+ {
+ __CTOR_LIST__ = .;
+ *(.ctors)
+ *(SORT(.ctors.*))
+ __CTOR_END__ = .;
+ } > ram :ph_ram
+
+ /* C++ destructor section. */
+ .dtors :
+ {
+ __DTOR_LIST__ = .;
+ *(.dtors)
+ *(SORT(.dtors.*))
+ __DTOR_END__ = .;
+ } > ram :ph_ram
+
+
+ /* Small data section. */
+ .sdata ALIGN(0x10) :
+ {
+ PROVIDE (_SDA_BASE_ = .);
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s.*)
+ } > ram :ph_ram
+
+ /*-------------------------------------------------------------------
+ * Uninitialized data (cleared by PM)
+ *-----------------------------------------------------------------*/
+
+ /* Small bss section. */
+ .sbss :
+ {
+ *(.sbss)
+ *(.sbss.*)
+ *(.scommon)
+ *(.gnu.linkonce.sb.*)
+ } > ram :ph_ram
+
+ /* Bss section. */
+ .bss :
+ {
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ *(.gnu.linkonce.b.*)
+ } > ram :ph_ram
+
+/*---------------------------------------------------------------------------
+ * Debug information
+ *-------------------------------------------------------------------------*/
+
+ /*
+ * Stabs debug sections.
+ */
+
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+
+ /*
+ * DWARF debug sections.
+ */
+
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+}
diff --git a/erts/emulator/sys/ose/sys.c b/erts/emulator/sys/ose/sys.c
new file mode 100644
index 0000000000..5b950a7dae
--- /dev/null
+++ b/erts/emulator/sys/ose/sys.c
@@ -0,0 +1,1846 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "sys/time.h"
+#include "time.h"
+#include "sys/uio.h"
+#include "termios.h"
+#include "ctype.h"
+#include "termios.h"
+
+#ifdef HAVE_FCNTL_H
+#include "fcntl.h"
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+#include "sys/ioctl.h"
+#endif
+
+#define ERTS_WANT_BREAK_HANDLING
+#define WANT_NONBLOCKING
+#include "sys.h"
+#include "erl_thr_progress.h"
+
+#ifdef USE_THREADS
+#include "erl_threads.h"
+#endif
+
+#include "erl_mseg.h"
+
+#include "unistd.h"
+#include "efs.h"
+#include "erl_printf.h"
+#include "aio.h"
+#include "pm.h"
+#include "fcntl.h"
+
+/* Set the define to 1 to get some logging */
+#if 0
+#include "ramlog.h"
+#define LOG(output) ramlog_printf output
+#else
+#define LOG(output)
+#endif
+
+extern char **environ;
+static erts_smp_rwmtx_t environ_rwmtx;
+static PROCESS sig_proxy_pid = 0;
+
+#define MAX_VSIZE 16 /* Max number of entries allowed in an I/O
+ * vector sock_sendv().
+ */
+/*
+ * Don't need global.h, but bif_table.h (included by bif.h),
+ * won't compile otherwise
+ */
+#include "global.h"
+#include "bif.h"
+
+#include "erl_sys_driver.h"
+#include "erl_check_io.h"
+#include "erl_cpu_topology.h"
+
+/* The priority for reader/writer processes */
+#define FD_PROC_PRI get_pri(current_process())
+
+typedef struct ErtsSysReportExit_ ErtsSysReportExit;
+struct ErtsSysReportExit_ {
+ ErtsSysReportExit *next;
+ Eterm port;
+ int pid;
+ int ifd;
+ int ofd;
+ ErlDrvEvent attach_event;
+ ErlDrvEvent input_event;
+ ErlDrvEvent output_event;
+};
+
+/* This data is shared by these drivers - initialized by spawn_init() */
+static struct driver_data {
+ ErlDrvPort port_num;
+ int ofd;
+ int ifd;
+ int packet_bytes;
+ ErtsSysReportExit *report_exit;
+ int pid;
+ int alive;
+ int status;
+ ErlDrvEvent input_event;
+ ErlDrvEvent output_event;
+ struct aiocb aiocb;
+ FmHandle handle;
+ char *install_handle;
+} *driver_data; /* indexed by fd */
+
+struct async {
+ SIGSELECT signo;
+ ErlDrvTermData port;
+ ErlDrvTermData proc;
+ PROCESS spid;
+ PROCESS target;
+ Uint32 ref;
+};
+
+static ErtsSysReportExit *report_exit_list;
+static ERTS_INLINE void report_exit_status(ErtsSysReportExit *rep, int status);
+
+extern int driver_interrupt(int, int);
+extern void do_break(void);
+
+extern void erl_sys_args(int*, char**);
+
+/* The following two defs should probably be moved somewhere else */
+
+extern void erts_sys_init_float(void);
+
+extern void erl_crash_dump(char* file, int line, char* fmt, ...);
+
+#define DIR_SEPARATOR_CHAR '/'
+
+#if defined(DEBUG)
+#define ERL_BUILD_TYPE_MARKER ".debug"
+#else /* opt */
+#define ERL_BUILD_TYPE_MARKER
+#endif
+
+#define CHILD_SETUP_PROG_NAME "child_setup" ERL_BUILD_TYPE_MARKER
+
+#ifdef DEBUG
+static int debug_log = 0;
+#endif
+
+#ifdef ERTS_SMP
+static erts_smp_atomic32_t have_prepared_crash_dump;
+#define ERTS_PREPARED_CRASH_DUMP \
+ ((int) erts_smp_atomic32_xchg_nob(&have_prepared_crash_dump, 1))
+#else
+static volatile int have_prepared_crash_dump;
+#define ERTS_PREPARED_CRASH_DUMP \
+ (have_prepared_crash_dump++)
+#endif
+
+static erts_smp_atomic_t sys_misc_mem_sz;
+
+#if defined(ERTS_SMP)
+erts_mtx_t chld_stat_mtx;
+#endif
+
+#if defined(ERTS_SMP) /* ------------------------------------------------- */
+#define CHLD_STAT_LOCK erts_mtx_lock(&chld_stat_mtx)
+#define CHLD_STAT_UNLOCK erts_mtx_unlock(&chld_stat_mtx)
+
+#else /* ------------------------------------------------------------------- */
+#define CHLD_STAT_LOCK
+#define CHLD_STAT_UNLOCK
+static volatile int children_died;
+#endif
+
+#define SET_AIO(REQ,FD,SIZE,BUFF) \
+ memset(&(REQ),0,sizeof(REQ)); \
+ (REQ).aio_fildes = FD; \
+ (REQ).aio_offset = FM_POSITION_CURRENT; \
+ (REQ).aio_nbytes = SIZE; \
+ (REQ).aio_buf = BUFF; \
+ (REQ).aio_sigevent.sigev_notify = SIGEV_NONE
+
+/* the first sizeof(struct aiocb *) bytes of the write buffer
+ * will contain the pointer to the aiocb struct, this needs
+ * to be freed between asynchronous writes.
+ * A write of 0 bytes is ignored. */
+#define WRITE_AIO(FD,SIZE,BUFF) do { \
+ if (SIZE > 0) { \
+ struct aiocb *write_req = driver_alloc(sizeof(struct aiocb)); \
+ char *write_buff = driver_alloc((sizeof(char)*SIZE)+1+ \
+ (sizeof(struct aiocb *))); \
+ *(struct aiocb **)write_buff = (struct aiocb *)write_req; \
+ write_buff += sizeof(struct aiocb *); \
+ memcpy(write_buff,BUFF,SIZE+1); \
+ SET_AIO(*write_req,FD,SIZE,write_buff); \
+ if (aio_write(write_req)) \
+ ramlog_printf("%s:%d: write failed with %d\n", \
+ __FILE__,__LINE__,errno); \
+ } \
+} while(0)
+
+/* free the write_buffer and write_req
+ * created in the WRITE_AIO() request macro */
+#define FREE_AIO(ptr) do { \
+ struct aiocb *aiocb_ptr; \
+ char *buffer_ptr; \
+ aiocb_ptr = *(struct aiocb **)((ptr)-sizeof(struct aiocb *)); \
+ buffer_ptr = (((char*)ptr)-sizeof(struct aiocb *)); \
+ driver_free(aiocb_ptr); \
+ driver_free(buffer_ptr); \
+} while(0)
+
+#define DISPATCH_AIO(sig) do { \
+ if (aio_dispatch(sig)) \
+ ramlog_printf("%s:%d: dispatch failed with %d\n", \
+ __FILE__,__LINE__,errno); \
+ } while(0)
+
+#define AIO_PIPE_SIZE 1024
+
+/* debug print macros */
+#define DEBUG_RES 0
+
+#ifdef DEBUG_RES
+#define DEBUG_CHECK_RES(actual, expected) \
+ do { \
+ if (actual != expected ) { \
+ ramlog_printf("Result check failed" \
+ " got: 0x%08x expected:0x%08x\nat: %s:%d\n", \
+ actual, expected, __FILE__, __LINE__); \
+ abort(); /* This might perhaps be too harsh? */ \
+ } \
+ } while(0)
+#else
+#define DEBUG_CHECK_RES
+#endif
+
+static struct fd_data {
+ char pbuf[4]; /* hold partial packet bytes */
+ int psz; /* size of pbuf */
+ char *buf;
+ char *cpos;
+ int sz;
+ int remain; /* for input on fd */
+} *fd_data; /* indexed by fd */
+
+/********************* General functions ****************************/
+
+/* This is used by both the drivers and general I/O, must be set early */
+static int max_files = -1;
+
+/*
+ * a few variables used by the break handler
+ */
+#ifdef ERTS_SMP
+erts_smp_atomic32_t erts_break_requested;
+#define ERTS_SET_BREAK_REQUESTED \
+ erts_smp_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 1)
+#define ERTS_UNSET_BREAK_REQUESTED \
+ erts_smp_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 0)
+#else
+volatile int erts_break_requested = 0;
+#define ERTS_SET_BREAK_REQUESTED (erts_break_requested = 1)
+#define ERTS_UNSET_BREAK_REQUESTED (erts_break_requested = 0)
+#endif
+/* set early so the break handler has access to initial mode */
+static struct termios initial_tty_mode;
+static int replace_intr = 0;
+/* assume yes initially, ttsl_init will clear it */
+int using_oldshell = 1;
+static PROCESS get_signal_proxy_pid(void);
+
+static void
+init_check_io(void)
+{
+ erts_init_check_io();
+ max_files = erts_check_io_max_files();
+}
+
+#ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
+#define ERTS_CHK_IO_AS_INTR() erts_check_io_async_sig_interrupt()
+#else
+#define ERTS_CHK_IO_AS_INTR() erts_check_io_interrupt(1)
+#endif
+#define ERTS_CHK_IO_INTR erts_check_io_interrupt
+#define ERTS_CHK_IO_INTR_TMD erts_check_io_interrupt_timed
+#define ERTS_CHK_IO erts_check_io
+#define ERTS_CHK_IO_SZ erts_check_io_size
+
+
+void
+erts_sys_schedule_interrupt(int set)
+{
+ ERTS_CHK_IO_INTR(set);
+}
+
+#ifdef ERTS_SMP
+void
+erts_sys_schedule_interrupt_timed(int set, erts_short_time_t msec)
+{
+ ERTS_CHK_IO_INTR_TMD(set, msec);
+}
+#endif
+
+Uint
+erts_sys_misc_mem_sz(void)
+{
+ Uint res = ERTS_CHK_IO_SZ();
+ res += erts_smp_atomic_read_mb(&sys_misc_mem_sz);
+ return res;
+}
+
+/*
+ * reset the terminal to the original settings on exit
+ */
+void sys_tty_reset(int exit_code)
+{
+ if (using_oldshell && !replace_intr) {
+ SET_BLOCKING(0);
+ }
+ else if (isatty(0)) {
+ tcsetattr(0,TCSANOW,&initial_tty_mode);
+ }
+}
+
+#ifdef USE_THREADS
+
+typedef struct {
+ int sched_bind_data;
+} erts_thr_create_data_t;
+
+/*
+ * thr_create_prepare() is called in parent thread before thread creation.
+ * Returned value is passed as argument to thr_create_cleanup().
+ */
+static void *
+thr_create_prepare(void)
+{
+ erts_thr_create_data_t *tcdp;
+
+ tcdp = erts_alloc(ERTS_ALC_T_TMP, sizeof(erts_thr_create_data_t));
+
+ tcdp->sched_bind_data = erts_sched_bind_atthrcreate_prepare();
+
+ return (void *) tcdp;
+}
+
+
+/* thr_create_cleanup() is called in parent thread after thread creation. */
+static void
+thr_create_cleanup(void *vtcdp)
+{
+ erts_thr_create_data_t *tcdp = (erts_thr_create_data_t *) vtcdp;
+
+ erts_sched_bind_atthrcreate_parent(tcdp->sched_bind_data);
+
+ erts_free(ERTS_ALC_T_TMP, tcdp);
+}
+
+static void
+thr_create_prepare_child(void *vtcdp)
+{
+ erts_thr_create_data_t *tcdp = (erts_thr_create_data_t *) vtcdp;
+
+#ifdef ERTS_ENABLE_LOCK_COUNT
+ erts_lcnt_thread_setup();
+#endif
+
+ erts_sched_bind_atthrcreate_child(tcdp->sched_bind_data);
+}
+
+#endif /* #ifdef USE_THREADS */
+
+/* The two functions below are stolen from win_con.c
+ They have to use malloc/free/realloc directly becasue
+ we want to do able to do erts_printf very early on.
+ */
+#define VPRINTF_BUF_INC_SIZE 128
+static erts_dsprintf_buf_t *
+grow_vprintf_buf(erts_dsprintf_buf_t *dsbufp, size_t need)
+{
+ char *buf;
+ size_t size;
+
+ ASSERT(dsbufp);
+
+ if (!dsbufp->str) {
+ size = (((need + VPRINTF_BUF_INC_SIZE - 1)
+ / VPRINTF_BUF_INC_SIZE)
+ * VPRINTF_BUF_INC_SIZE);
+ buf = (char *) malloc(size * sizeof(char));
+ }
+ else {
+ size_t free_size = dsbufp->size - dsbufp->str_len;
+
+ if (need <= free_size)
+ return dsbufp;
+
+ size = need - free_size + VPRINTF_BUF_INC_SIZE;
+ size = (((size + VPRINTF_BUF_INC_SIZE - 1)
+ / VPRINTF_BUF_INC_SIZE)
+ * VPRINTF_BUF_INC_SIZE);
+ size += dsbufp->size;
+ buf = (char *) realloc((void *) dsbufp->str,
+ size * sizeof(char));
+ }
+ if (!buf)
+ return NULL;
+ if (buf != dsbufp->str)
+ dsbufp->str = buf;
+ dsbufp->size = size;
+ return dsbufp;
+}
+
+static int erts_sys_ramlog_printf(char *format, va_list arg_list)
+{
+ int res,i;
+ erts_dsprintf_buf_t dsbuf = ERTS_DSPRINTF_BUF_INITER(grow_vprintf_buf);
+ res = erts_vdsprintf(&dsbuf, format, arg_list);
+ if (res >= 0) {
+ for (i = 0; i < dsbuf.str_len; i+= 50)
+ /* We print 50 characters at a time because otherwise
+ the ramlog looks broken */
+ ramlog_printf("%.*s",dsbuf.str_len-50 < 0?dsbuf.str_len:50,dsbuf.str+i);
+ }
+ if (dsbuf.str)
+ free((void *) dsbuf.str);
+ return res;
+}
+
+void
+erts_sys_pre_init(void)
+{
+ erts_printf_add_cr_to_stdout = 1;
+ erts_printf_add_cr_to_stderr = 1;
+#ifdef USE_THREADS
+ {
+ erts_thr_init_data_t eid = ERTS_THR_INIT_DATA_DEF_INITER;
+
+ eid.thread_create_child_func = thr_create_prepare_child;
+ /* Before creation in parent */
+ eid.thread_create_prepare_func = thr_create_prepare;
+ /* After creation in parent */
+ eid.thread_create_parent_func = thr_create_cleanup,
+
+ erts_thr_init(&eid);
+
+ report_exit_list = NULL;
+
+#ifdef ERTS_ENABLE_LOCK_COUNT
+ erts_lcnt_init();
+#endif
+
+#if defined(ERTS_SMP)
+ erts_mtx_init(&chld_stat_mtx, "child_status");
+#endif
+ }
+#ifdef ERTS_SMP
+ erts_smp_atomic32_init_nob(&erts_break_requested, 0);
+ erts_smp_atomic32_init_nob(&have_prepared_crash_dump, 0);
+#else
+ erts_break_requested = 0;
+ have_prepared_crash_dump = 0;
+#endif
+#if !defined(ERTS_SMP)
+ children_died = 0;
+#endif
+#endif /* USE_THREADS */
+
+ erts_printf_stdout_func = erts_sys_ramlog_printf;
+
+ erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0);
+}
+
+void
+erl_sys_init(void)
+{
+
+#ifdef USE_SETLINEBUF
+ setlinebuf(stdout);
+#else
+ setvbuf(stdout, (char *)NULL, _IOLBF, BUFSIZ);
+#endif
+
+ erts_sys_init_float();
+
+ /* we save this so the break handler can set and reset it properly */
+ /* also so that we can reset on exit (break handler or not) */
+ if (isatty(0)) {
+ tcgetattr(0,&initial_tty_mode);
+ }
+ tzset(); /* Required at least for NetBSD with localtime_r() */
+}
+
+static ERTS_INLINE int
+prepare_crash_dump(int secs)
+{
+#define NUFBUF (3)
+ int i, max;
+ char env[21]; /* enough to hold any 64-bit integer */
+ size_t envsz;
+ /*DeclareTmpHeapNoproc(heap,NUFBUF);*/
+ /*Eterm *hp = heap;*/
+ /*Eterm list = NIL;*/
+ int has_heart = 0;
+
+ UseTmpHeapNoproc(NUFBUF);
+
+ if (ERTS_PREPARED_CRASH_DUMP)
+ return 0; /* We have already been called */
+
+
+ /* Positive secs means an alarm must be set
+ * 0 or negative means no alarm
+ *
+ * Set alarm before we try to write to a port
+ * we don't want to hang on a port write with
+ * no alarm.
+ *
+ */
+
+#if 0 /*ose TBD!!!*/
+ if (secs >= 0) {
+ alarm((unsigned int)secs);
+ }
+#endif
+
+ /* Make sure we unregister at epmd (unknown fd) and get at least
+ one free filedescriptor (for erl_crash.dump) */
+
+ max = max_files;
+ if (max < 1024)
+ max = 1024;
+ for (i = 3; i < max; i++) {
+ close(i);
+ }
+
+ envsz = sizeof(env);
+ i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz);
+ if (i >= 0) {
+ int nice_val;
+ nice_val = i != 0 ? 0 : atoi(env);
+ if (nice_val > 39) {
+ nice_val = 39;
+ }
+ set_pri(nice_val);
+ }
+
+ UnUseTmpHeapNoproc(NUFBUF);
+#undef NUFBUF
+ return has_heart;
+}
+
+int erts_sys_prepare_crash_dump(int secs)
+{
+ return prepare_crash_dump(secs);
+}
+
+static ERTS_INLINE void
+break_requested(void)
+{
+ /*
+ * just set a flag - checked for and handled by
+ * scheduler threads erts_check_io() (not signal handler).
+ */
+#ifdef DEBUG
+ fprintf(stderr,"break!\n");
+#endif
+ if (ERTS_BREAK_REQUESTED)
+ erl_exit(ERTS_INTR_EXIT, "");
+
+ ERTS_SET_BREAK_REQUESTED;
+ ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */
+}
+
+/* Disable break */
+void erts_set_ignore_break(void) {
+
+}
+
+/* Don't use ctrl-c for break handler but let it be
+ used by the shell instead (see user_drv.erl) */
+void erts_replace_intr(void) {
+ struct termios mode;
+
+ if (isatty(0)) {
+ tcgetattr(0, &mode);
+
+ /* here's an example of how to replace ctrl-c with ctrl-u */
+ /* mode.c_cc[VKILL] = 0;
+ mode.c_cc[VINTR] = CKILL; */
+
+ mode.c_cc[VINTR] = 0; /* disable ctrl-c */
+ tcsetattr(0, TCSANOW, &mode);
+ replace_intr = 1;
+ }
+}
+
+void init_break_handler(void)
+{
+
+}
+
+int sys_max_files(void)
+{
+ return(max_files);
+}
+
+
+/************************** OS info *******************************/
+
+/* Used by erlang:info/1. */
+/* (This code was formerly in drv.XXX/XXX_os_drv.c) */
+
+char os_type[] = "ose";
+
+void
+os_flavor(char* namebuf, /* Where to return the name. */
+ unsigned size) /* Size of name buffer. */
+{
+#if 0
+ struct utsname uts; /* Information about the system. */
+ char* s;
+
+ (void) uname(&uts);
+ for (s = uts.sysname; *s; s++) {
+ if (isupper((int) *s)) {
+ *s = tolower((int) *s);
+ }
+ }
+ strcpy(namebuf, uts.sysname);
+#else
+ strncpy(namebuf, "release", size);
+#endif
+}
+
+void
+os_version(pMajor, pMinor, pBuild)
+int* pMajor; /* Pointer to major version. */
+int* pMinor; /* Pointer to minor version. */
+int* pBuild; /* Pointer to build number. */
+{
+ *pMajor = 5;
+ *pMinor = 7;
+ *pBuild = 0;
+}
+
+void init_getenv_state(GETENV_STATE *state)
+{
+ erts_smp_rwmtx_rlock(&environ_rwmtx);
+ *state = NULL;
+}
+
+char **environ; /*ose - needs replacement*/
+
+char *getenv_string(GETENV_STATE *state0)
+{
+ char **state = (char **) *state0;
+ char *cp;
+
+ ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rlocked(&environ_rwmtx));
+
+ if (state == NULL)
+ state = environ;
+
+ cp = *state++;
+ *state0 = (GETENV_STATE) state;
+
+ return cp;
+}
+
+void fini_getenv_state(GETENV_STATE *state)
+{
+ *state = NULL;
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+}
+
+
+/************************** Port I/O *******************************/
+
+/* I. Common stuff */
+
+union SIGNAL {
+ SIGSELECT sig_no;
+ struct FmReadPtr fm_read_reply;
+ struct FmWritePtr fm_write_reply;
+ struct async async;
+};
+
+/* II. The spawn/fd drivers */
+
+/*
+ * Decreasing the size of it below 16384 is not allowed.
+ */
+#define ERTS_SYS_READ_BUF_SZ (64*1024)
+
+/* Driver interfaces */
+static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*);
+static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*);
+static ErlDrvSSizeT fd_control(ErlDrvData, unsigned int, char *, ErlDrvSizeT,
+ char **, ErlDrvSizeT);
+static int spawn_init(void);
+static void fd_stop(ErlDrvData);
+static void erl_stop(ErlDrvData);
+static void ready_input(ErlDrvData, ErlDrvEvent);
+static void ready_output(ErlDrvData, ErlDrvEvent);
+static void output(ErlDrvData, char*, ErlDrvSizeT);
+static void stop_select(ErlDrvEvent, void*);
+
+static PROCESS
+get_signal_proxy_pid(void) {
+ union SIGNAL *sig;
+ SIGSELECT any_sig[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH};
+
+ if (!sig_proxy_pid) {
+ sig = alloc(sizeof(union SIGNAL), ERTS_SIGNAL_OSE_DRV_ATTACH);
+ hunt("ose_signal_driver_proxy", 0, NULL, &sig);
+ sig = receive(any_sig);
+ sig_proxy_pid = sender(&sig);
+ free_buf(&sig);
+ }
+ ASSERT(sig_proxy_pid);
+ return sig_proxy_pid;
+}
+
+static ErlDrvOseEventId
+resolve_signal(union SIGNAL* sig) {
+ switch(sig->sig_no) {
+
+ case FM_READ_PTR_REPLY:
+ return (ErlDrvOseEventId)sig->fm_read_reply.handle;
+
+ case FM_WRITE_PTR_REPLY:
+ return (ErlDrvOseEventId)sig->fm_write_reply.handle;
+
+ case ERTS_SIGNAL_OSE_DRV_ATTACH:
+ return (ErlDrvOseEventId)sig->async.target;
+
+ default:
+ break;
+ }
+ return (ErlDrvOseEventId)-1;
+}
+
+struct erl_drv_entry spawn_driver_entry = {
+ spawn_init,
+ spawn_start,
+ NULL, /* erl_stop, */
+ output,
+ ready_input,
+ ready_output,
+ "spawn",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ ERL_DRV_FLAG_USE_PORT_LOCKING,
+ NULL, NULL,
+ stop_select
+};
+struct erl_drv_entry fd_driver_entry = {
+ NULL,
+ fd_start,
+ fd_stop,
+ output,
+ ready_input,
+ ready_output,
+ "fd",
+ NULL,
+ NULL,
+ fd_control,
+ NULL,
+ NULL,
+ NULL, /* ready_async */
+ NULL, /* flush */
+ NULL, /* call */
+ NULL, /* event */
+ ERL_DRV_EXTENDED_MARKER,
+ ERL_DRV_EXTENDED_MAJOR_VERSION,
+ ERL_DRV_EXTENDED_MINOR_VERSION,
+ 0, /* ERL_DRV_FLAGs */
+ NULL, /* handle2 */
+ NULL, /* process_exit */
+ stop_select
+};
+
+static void
+set_spawn_fd(int local_fd, int remote_fd, PROCESS remote_pid) {
+ PROCESS vm_pid;
+ FmHandle handle;
+ char env_val[55];
+ char env_name[10];
+ EfsStatus efs_res;
+
+ /* get pid of pipevm and handle of chosen fd */
+ efs_res = efs_examine_fd(local_fd, FLIB_FD_VMPID, &vm_pid, 0);
+ DEBUG_CHECK_RES(efs_res, EFS_SUCCESS);
+
+ /* setup the file descriptor to buffer per line */
+ efs_res = efs_config_fd(local_fd, FLIB_FD_BUFMODE, FM_BUFF_LINE,
+ FLIB_FD_BUFSIZE, 80, 0);
+ DEBUG_CHECK_RES(efs_res, EFS_SUCCESS);
+
+ /* duplicate handle and set spawn pid owner */
+ efs_res = efs_dup_to(local_fd, remote_pid, &handle);
+ DEBUG_CHECK_RES(efs_res, EFS_SUCCESS);
+
+ sprintf(env_name, "FD%d", remote_fd);
+
+ /* Syntax of the environment variable:
+ * "FD#" "<pid of pipevm>,<handle>,<buffer mode>,<buff size>,<omode>" */
+ sprintf(env_val, "0x%lx,0x%lx,%lu,%lu,0x%x",
+ vm_pid, handle,
+ FM_BUFF_LINE, 80,
+ O_APPEND);
+
+ set_env(remote_pid, env_name, env_val);
+}
+
+static ErlDrvData
+set_driver_data(ErlDrvPort port_num,
+ int ifd,
+ int ofd,
+ int packet_bytes,
+ int read_write,
+ int exit_status,
+ PROCESS pid)
+{
+ Port *prt;
+ ErtsSysReportExit *report_exit;
+
+ prt = erts_drvport2port(port_num);
+ if (prt != ERTS_INVALID_ERL_DRV_PORT) {
+ prt->os_pid = pid;
+ }
+
+ /* READ */
+ if (read_write & DO_READ) {
+ EfsStatus res = efs_examine_fd(ifd, FLIB_FD_HANDLE,
+ &driver_data[ifd].handle, 0);
+ if (res != EFS_SUCCESS)
+ ramlog_printf("%s:%d: efs_examine_fd(%d) failed with %d\n",
+ __FILE__,__LINE__,ifd,errno);
+ driver_data[ifd].ifd = ifd;
+ driver_data[ifd].packet_bytes = packet_bytes;
+ driver_data[ifd].port_num = port_num;
+ driver_data[ifd].pid = pid;
+
+ /* async read struct */
+ memset(&driver_data[ifd].aiocb, 0, sizeof(struct aiocb));
+ driver_data[ifd].aiocb.aio_buf = driver_alloc(AIO_PIPE_SIZE);
+ driver_data[ifd].aiocb.aio_fildes = ifd;
+ driver_data[ifd].aiocb.aio_nbytes = (packet_bytes?packet_bytes:AIO_PIPE_SIZE);
+ driver_data[ifd].alive = 1;
+ driver_data[ifd].status = 0;
+ driver_data[ifd].input_event =
+ erl_drv_ose_event_alloc(FM_READ_PTR_REPLY,
+ driver_data[ifd].handle, resolve_signal,
+ &driver_data[ifd].ifd);
+
+ /* READ & WRITE */
+ if (read_write & DO_WRITE) {
+ driver_data[ifd].ofd = ofd;
+ efs_examine_fd(ofd, FLIB_FD_HANDLE, &driver_data[ofd].handle, 0);
+
+ driver_data[ifd].output_event =
+ erl_drv_ose_event_alloc(FM_WRITE_PTR_REPLY,
+ driver_data[ofd].handle, resolve_signal,
+ &driver_data[ofd].ofd);
+ driver_data[ofd].pid = pid;
+ if (ifd != ofd) {
+ driver_data[ofd] = driver_data[ifd];
+ driver_data[ofd].aiocb.aio_buf = NULL;
+ }
+ }
+ else { /* READ ONLY */
+ driver_data[ifd].ofd = -1;
+ }
+
+ /* enable input event */
+ (void) driver_select(port_num, driver_data[ifd].input_event,
+ (ERL_DRV_READ | ERL_DRV_USE), 1);
+
+ if (aio_read(&driver_data[ifd].aiocb))
+ ramlog_printf("%s:%d: aio_read(%d) failed with %d\n",
+ __FILE__,__LINE__,ifd,errno);
+ }
+ else { /* WRITE ONLY */
+ efs_examine_fd(ofd, FLIB_FD_HANDLE, &driver_data[ofd].handle, 0);
+ driver_data[ofd].packet_bytes = packet_bytes;
+ driver_data[ofd].port_num = port_num;
+ driver_data[ofd].ofd = ofd;
+ driver_data[ofd].pid = pid;
+ driver_data[ofd].alive = 1;
+ driver_data[ofd].status = 0;
+ driver_data[ofd].output_event =
+ erl_drv_ose_event_alloc(FM_WRITE_PTR_REPLY, driver_data[ofd].handle,
+ resolve_signal, &driver_data[ofd].ofd);
+ driver_data[ofd].input_event = driver_data[ofd].output_event;
+ }
+
+ /* this is used for spawned load modules, and is needed
+ * to properly uninstall them */
+ if (exit_status) {
+ struct PmProgramInfo *info;
+ int install_handle_size;
+ union SIGNAL *sig;
+ PmStatus pm_status;
+ report_exit = erts_alloc(ERTS_ALC_T_PRT_REP_EXIT,
+ sizeof(ErtsSysReportExit));
+ report_exit->next = report_exit_list;
+ report_exit->port = erts_drvport2id(port_num);
+ report_exit->pid = pid;
+ report_exit->ifd = (read_write & DO_READ) ? ifd : -1;
+ report_exit->ofd = (read_write & DO_WRITE) ? ofd : -1;
+ report_exit_list = report_exit;
+ report_exit->attach_event =
+ erl_drv_ose_event_alloc(ERTS_SIGNAL_OSE_DRV_ATTACH, pid,
+ resolve_signal, &driver_data[ifd].ifd);
+
+ /* setup ifd and ofd report exit */
+ driver_data[ifd].report_exit = report_exit;
+ driver_data[ofd].report_exit = report_exit;
+
+ pm_status = ose_pm_program_info(pid, &info);
+ DEBUG_CHECK_RES(pm_status, PM_SUCCESS);
+
+ install_handle_size = strlen(info->install_handle)+1;
+ driver_data[ifd].install_handle = driver_alloc(install_handle_size);
+ strcpy(driver_data[ifd].install_handle,
+ info->install_handle);
+
+ free_buf((union SIGNAL **)&info);
+
+ sig = alloc(sizeof(struct async), ERTS_SIGNAL_OSE_DRV_ATTACH);
+ sig->async.target = pid;
+ send(&sig, get_signal_proxy_pid());
+
+ /* this event will trigger when we receive an attach signal
+ * from the recently dead load module */
+ (void)driver_select(port_num,report_exit->attach_event, DO_READ, 1);
+ }
+ else {
+ report_exit = NULL;
+ }
+
+ /* the return value is the pointer to the driver_data struct we created
+ * in this function, it will be used in the drivers input
+ * and output functions */
+ return (ErlDrvData)((!(read_write & DO_READ) && read_write & DO_WRITE)
+ ? &driver_data[ofd]
+ : &driver_data[ifd]);
+}
+
+static int spawn_init()
+{
+ int i;
+
+ driver_data = (struct driver_data *)
+ erts_alloc(ERTS_ALC_T_DRV_TAB, max_files * sizeof(struct driver_data));
+ erts_smp_atomic_add_nob(&sys_misc_mem_sz,
+ max_files * sizeof(struct driver_data));
+
+ for (i = 0; i < max_files; i++)
+ driver_data[i].pid = -1;
+
+ return 1;
+}
+
+static void
+init_fd_data(int fd, ErlDrvPort port_num)
+{
+ fd_data[fd].buf = NULL;
+ fd_data[fd].cpos = NULL;
+ fd_data[fd].remain = 0;
+ fd_data[fd].sz = 0;
+ fd_data[fd].psz = 0;
+}
+
+/* FIXME write a decent text on pipes on ose */
+static ErlDrvData
+spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
+{
+ int ifd[2];
+ int ofd[2];
+ static uint32_t ticker = 1;
+ PmStatus pm_status;
+ OSDOMAIN domain = PM_NEW_DOMAIN;
+ PROCESS progpid, mainbid, mainpid;
+ char *handle = NULL;
+ struct PmProgramInfo *info;
+ char *args = NULL;
+ char *tmp_handle;
+ ErlDrvData res = (ErlDrvData)-1;
+ int handle_size;
+ char *ptr;
+
+
+ args = driver_alloc(strlen(name)+1);
+ strcpy(args, name);
+ /* We need to handle name in three parts
+ * - install handle (must be unique)
+ * - install binary (needed for ose_pm_install_load_module())
+ * - full path (as argument to the spawned applications env.var
+ */
+
+ /* full path including arguments */
+ args = driver_alloc(strlen(name)+1);
+ strcpy(args, name);
+
+ /* handle path */
+ tmp_handle = strrchr(name, '/');
+ if (tmp_handle == NULL) {
+ tmp_handle = name;
+ }
+ else {
+ tmp_handle++;
+ }
+
+ /* handle args */
+ ptr = strchr(tmp_handle, ' ');
+ if (ptr != NULL) {
+ *ptr = '\0';
+ handle_size = ptr - tmp_handle;
+ }
+ else {
+ handle_size = strlen(name)+1;
+ }
+
+ /* make room for ticker */
+ handle_size += (ticker<10)?3:((ticker<100)?4:5);
+ handle = driver_alloc(handle_size);
+
+ do {
+ snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker);
+ pm_status = ose_pm_install_load_module(0, "ELF", name, handle,
+ 0, 0, NULL);
+ ticker++;
+ } while (pm_status == PM_EINSTALL_HANDLE_ALREADY_INSTALLED);
+
+ if (pm_status != PM_SUCCESS) {
+ errno = ENOSYS; /* FIXME add comment */
+ return ERL_DRV_ERROR_ERRNO;
+ }
+
+ /* Create Program */
+ pm_status = ose_pm_create_program(&domain, handle, 0, 0,
+ NULL, &progpid, &mainbid);
+ DEBUG_CHECK_RES(pm_status, PM_SUCCESS);
+
+ /* Get the mainpid from the newly created program */
+ pm_status = ose_pm_program_info(progpid, &info);
+ DEBUG_CHECK_RES(pm_status, PM_SUCCESS);
+
+ mainpid = info->main_process;
+ free_buf ((union SIGNAL **)&info);
+
+ /* pipevm needs to be started
+ * pipe will return 0 if success, -1 if not,
+ * errno will be set */
+ if (pipe(ifd) != 0 || pipe(ofd) != 0) {
+ DEBUG_CHECK_RES(0, -1);
+ ASSERT(0);
+ }
+
+ /* setup driver data */
+ res = set_driver_data(port_num, ofd[0], ifd[1], opts->packet_bytes,
+ opts->read_write, 1 /* opts->exit_status */, progpid);
+
+ /* init the fd_data array for read/write */
+ init_fd_data(ofd[0], port_num);
+ init_fd_data(ifd[1], port_num);
+
+ /* setup additional configurations
+ * for the spawned applications environment */
+ if (args != NULL) {
+ set_env(progpid, "ARGV", args);
+ }
+ set_env(mainbid, "EFS_RESOLVE_TMO", 0);
+ set_spawn_fd(ifd[0], 0, mainpid);
+ set_spawn_fd(ofd[1], 1, mainpid);
+ set_spawn_fd(ofd[1], 2, mainpid);
+
+ /* start the spawned program */
+ pm_status = ose_pm_start_program(mainbid);
+ DEBUG_CHECK_RES(pm_status, PM_SUCCESS);
+
+ /* close unused fd's */
+ close(ifd[0]);
+ close(ofd[1]);
+
+ if (handle) {
+ driver_free(handle);
+ }
+
+ return (ErlDrvData)res;
+}
+
+#define FD_DEF_HEIGHT 24
+#define FD_DEF_WIDTH 80
+/* Control op */
+#define FD_CTRL_OP_GET_WINSIZE 100
+
+static int fd_get_window_size(int fd, Uint32 *width, Uint32 *height)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ if (ioctl(fd,TIOCGWINSZ,&ws) == 0) {
+ *width = (Uint32) ws.ws_col;
+ *height = (Uint32) ws.ws_row;
+ return 0;
+ }
+#endif
+ return -1;
+}
+
+static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
+ unsigned int command,
+ char *buf, ErlDrvSizeT len,
+ char **rbuf, ErlDrvSizeT rlen)
+{
+ struct driver_data *data = (struct driver_data *)drv_data;
+ char resbuff[2*sizeof(Uint32)];
+ switch (command) {
+ case FD_CTRL_OP_GET_WINSIZE:
+ {
+ Uint32 w,h;
+ if (fd_get_window_size(data->ifd,&w,&h))
+ return 0;
+ memcpy(resbuff,&w,sizeof(Uint32));
+ memcpy(resbuff+sizeof(Uint32),&h,sizeof(Uint32));
+ }
+ break;
+ default:
+ return 0;
+ }
+ if (rlen < 2*sizeof(Uint32)) {
+ *rbuf = driver_alloc(2*sizeof(Uint32));
+ }
+ memcpy(*rbuf,resbuff,2*sizeof(Uint32));
+ return 2*sizeof(Uint32);
+}
+
+static ErlDrvData fd_start(ErlDrvPort port_num, char* name,
+ SysDriverOpts* opts)
+{
+ ErlDrvData res;
+
+ CHLD_STAT_LOCK;
+ if (opts->read_write & DO_READ) {
+ init_fd_data(opts->ifd, port_num);
+ }
+ if (opts->read_write & DO_WRITE) {
+ init_fd_data(opts->ofd, port_num);
+ }
+ res = set_driver_data(port_num, opts->ifd, opts->ofd,
+ opts->packet_bytes,
+ opts->read_write, 0, -1);
+ CHLD_STAT_UNLOCK;
+ return res;
+}
+
+static void clear_fd_data(int fd)
+{
+ if (fd_data[fd].sz > 0) {
+ erts_free(ERTS_ALC_T_FD_ENTRY_BUF, (void *) fd_data[fd].buf);
+ ASSERT(erts_smp_atomic_read_nob(&sys_misc_mem_sz) >= fd_data[fd].sz);
+ erts_smp_atomic_add_nob(&sys_misc_mem_sz, -1*fd_data[fd].sz);
+ }
+ fd_data[fd].buf = NULL;
+ fd_data[fd].sz = 0;
+ fd_data[fd].remain = 0;
+ fd_data[fd].cpos = NULL;
+ fd_data[fd].psz = 0;
+}
+
+static void nbio_stop_fd(ErlDrvPort prt, ErlDrvEvent ev)
+{
+ int *fd;
+ driver_select(prt,ev,DO_READ|DO_WRITE,0);
+ erl_drv_ose_event_fetch(ev, NULL, NULL, (void **)&fd);
+ clear_fd_data(*fd);
+ SET_BLOCKING(*fd);
+}
+
+static void fd_stop(ErlDrvData drv_data) /* Does not close the fds */
+{
+ struct driver_data *data = (struct driver_data *)drv_data;
+
+ if (data->ofd != -1) {
+ if (data->ifd != data->ofd) { /* read and write */
+ nbio_stop_fd(data->port_num, data->input_event);
+ nbio_stop_fd(data->port_num, data->output_event);
+ }
+ else { /* write only */
+ nbio_stop_fd(data->port_num, data->output_event);
+ }
+ }
+ else { /* read only */
+ nbio_stop_fd(data->port_num, data->input_event);
+ }
+}
+
+
+static void erl_stop(ErlDrvData drv_data)
+{
+ struct driver_data *data = (struct driver_data *)drv_data;
+
+ CHLD_STAT_LOCK;
+ data->pid = -1;
+ CHLD_STAT_UNLOCK;
+
+ if (data->ofd != -1) {
+ if (data->ifd != data->ofd) { /* read and write */
+ nbio_stop_fd(data->port_num, data->input_event);
+ nbio_stop_fd(data->port_num, data->output_event);
+ }
+ else { /* write only */
+ nbio_stop_fd(data->port_num, data->output_event);
+ }
+ }
+ else { /* read only */
+ nbio_stop_fd(data->port_num, data->input_event);
+ }
+ close(data->ifd);
+ close(data->ofd);
+}
+
+/* The parameter e is a pointer to the driver_data structure
+ * related to the fd to be used as output */
+static void output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
+{
+ ErlDrvSizeT sz;
+ char lb[4];
+ char* lbp;
+ struct driver_data *data = (struct driver_data *)drv_data;
+
+ if (((data->packet_bytes == 2) &&
+ (len > 0xffff)) || (data->packet_bytes == 1 && len > 0xff)) {
+ driver_failure_posix(data->port_num, EINVAL);
+ return; /* -1; */
+ }
+ put_int32(len, lb);
+ lbp = lb + (4-(data->packet_bytes));
+
+ if ((sz = driver_sizeq(data->port_num)) > 0) {
+ if (data->packet_bytes != 0) {
+ driver_enq(data->port_num, lbp, data->packet_bytes);
+ }
+ driver_enq(data->port_num, buf, len);
+
+ if (sz + len + data->packet_bytes >= (1 << 13))
+ set_busy_port(data->port_num, 1);
+ }
+ else {
+ char *pbbuf;
+ if (data->packet_bytes != 0) {
+ pbbuf = malloc(len + data->packet_bytes);
+ int i;
+ for (i = 0; i < data->packet_bytes; i++) {
+ *pbbuf++ = *lbp++;
+ }
+ strncpy(pbbuf, buf, len);
+ pbbuf -= data->packet_bytes;
+ }
+ driver_select(data->port_num, data->output_event,
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+ WRITE_AIO(data->ofd,
+ (data->packet_bytes ? len+data->packet_bytes : len),
+ (data->packet_bytes ? pbbuf : buf));
+ if (data->packet_bytes != 0) free(pbbuf);
+ }
+ return; /* 0; */
+}
+
+/* This function is being run when we in recieve
+ * either a read of 0 bytes, or the attach signal from a dying
+ * spawned load module */
+static int port_inp_failure(ErlDrvPort port_num, ErlDrvEvent ready_fd, int res)
+ /* Result: 0 (eof) or -1 (error) */
+{
+ int *fd;
+ SIGSELECT sig_no;
+ ASSERT(res <= 0);
+
+ erl_drv_ose_event_fetch(ready_fd,&sig_no, NULL, (void **)&fd);
+ /* As we need to handle two signals, we do this in two steps */
+ if (driver_data[*fd].alive) {
+ report_exit_status(driver_data[*fd].report_exit, 0); /* status? */
+ }
+ else {
+ driver_select(port_num,ready_fd,DO_READ|DO_WRITE,0);
+ clear_fd_data(*fd);
+ driver_report_exit(driver_data[*fd].port_num, driver_data[*fd].status);
+ /* As we do not really know if the spawn has crashed or exited nicely
+ * we do not check the result status of the following call.. FIXME
+ * can we handle this in a better way? */
+ ose_pm_uninstall_load_module(driver_data[*fd].install_handle);
+ driver_free(driver_data[*fd].install_handle);
+ driver_free((void *)driver_data[*fd].aiocb.aio_buf);
+
+ close(*fd);
+ }
+
+ return 0;
+}
+
+/* The parameter e is a pointer to the driver_data structure
+ * related to the fd to be used as output.
+ * ready_fd is the event that triggered this call to ready_input */
+static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd)
+{
+ int res;
+ Uint h;
+ char *buf;
+ union SIGNAL *sig;
+ struct driver_data *data = (struct driver_data *)drv_data;
+
+ sig = erl_drv_ose_get_signal(ready_fd);
+ ASSERT(sig);
+
+
+ while (sig) {
+ /* If we've recieved an attach signal, we need to handle
+ * it in port_inp_failure */
+ if (sig->sig_no == ERTS_SIGNAL_OSE_DRV_ATTACH) {
+ port_inp_failure(data->port_num, ready_fd, 0);
+ }
+ else {
+ res = sig->fm_read_reply.actual;
+ if (res == 0) {
+ port_inp_failure(data->port_num, ready_fd, res);
+ break;
+ }
+
+ if (data->packet_bytes == 0) {
+ if (res < 0) {
+ if ((errno != EINTR) && (errno != ERRNO_BLOCK)) {
+ port_inp_failure(data->port_num, ready_fd, res);
+ }
+ }
+ else if (res == 0) {
+ /* read of 0 bytes, eof, otherside of pipe is assumed dead */
+ port_inp_failure(data->port_num, ready_fd, res);
+ break;
+ }
+ else {
+ buf = driver_alloc(res);
+ memcpy(buf, (void *)data->aiocb.aio_buf, res);
+ driver_select(data->port_num, data->output_event,
+ ERL_DRV_WRITE|ERL_DRV_USE, 1);
+ driver_output(data->port_num, (char*) buf, res);
+ driver_free(buf);
+ }
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, res);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ aio_read(&data->aiocb);
+ }
+ else if (data->packet_bytes && fd_data[data->ifd].remain > 0) {
+ /* we've read a partial package, or a header */
+
+ if (res == fd_data[data->ifd].remain) { /* we are done! */
+ char *buf = data->aiocb.aio_buf;
+ int i;
+
+ /* do we have anything buffered? */
+ if (fd_data[data->ifd].buf != NULL) {
+ memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz,
+ buf, res);
+ buf = fd_data[data->ifd].buf;
+ }
+
+ fd_data[data->ifd].sz += res;
+ driver_output(data->port_num, buf, (fd_data[data->ifd].sz>0?fd_data[data->ifd].sz:res));
+ clear_fd_data(data->ifd);
+
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, res);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ data->aiocb.aio_nbytes = data->packet_bytes;
+
+ if (data->aiocb.aio_buf == NULL) {
+ port_inp_failure(data->port_num, ready_fd, -1);
+ }
+ aio_read(&data->aiocb);
+ }
+ else if(res < fd_data[data->ifd].remain) { /* received part of a package */
+ if (fd_data[data->ifd].sz == 0) {
+
+ fd_data[data->ifd].sz += res;
+ memcpy(fd_data[data->ifd].buf, data->aiocb.aio_buf, res);
+ fd_data[data->ifd].remain -= res;
+ }
+ else {
+ memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz,
+ data->aiocb.aio_buf, res);
+ fd_data[data->ifd].sz += res;
+ fd_data[data->ifd].remain -= res;
+ }
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, res);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ data->aiocb.aio_nbytes = fd_data[data->ifd].remain;
+
+ if (data->aiocb.aio_buf == NULL) {
+ port_inp_failure(data->port_num, ready_fd, -1);
+ }
+ aio_read(&data->aiocb);
+ }
+ }
+ else if (data->packet_bytes && fd_data[data->ifd].remain == 0) { /* we've recieved a header */
+
+ /* analyze the header FIXME */
+ switch (data->packet_bytes) {
+ case 1: h = get_int8(data->aiocb.aio_buf); break;
+ case 2: h = get_int16(data->aiocb.aio_buf); break;
+ case 4: h = get_int32(data->aiocb.aio_buf); break;
+ }
+
+ fd_data[data->ifd].buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h + data->packet_bytes);
+ fd_data[data->ifd].remain = ((h + data->packet_bytes) - res);
+
+ /* clear the previous read */
+ memset(data->aiocb.aio_buf, 0, data->packet_bytes);
+
+ /* issue a new read */
+ DISPATCH_AIO(sig);
+ data->aiocb.aio_nbytes = h;
+
+ if (data->aiocb.aio_buf == NULL) {
+ port_inp_failure(data->port_num, ready_fd, -1);
+ }
+ aio_read(&data->aiocb);
+ }
+ }
+ sig = erl_drv_ose_get_signal(ready_fd);
+ }
+}
+
+
+/* The parameter e is a pointer to the driver_data structure
+ * related to the fd to be used as output.
+ * ready_fd is the event that triggered this call to ready_input */
+static void ready_output(ErlDrvData drv_data, ErlDrvEvent ready_fd)
+{
+ SysIOVec *iov;
+ int vlen;
+ int res;
+ union SIGNAL *sig;
+ struct driver_data *data = (struct driver_data *)drv_data;
+
+ sig = erl_drv_ose_get_signal(ready_fd);
+ ASSERT(sig);
+
+ while (sig != NULL) {
+ if (sig->fm_write_reply.actual <= 0) {
+ int status;
+
+ status = efs_status_to_errno(sig->fm_write_reply.status);
+ driver_select(data->port_num, ready_fd, ERL_DRV_WRITE, 0);
+ DISPATCH_AIO(sig);
+ FREE_AIO(sig->fm_write_reply.buffer);
+
+ driver_failure_posix(data->port_num, status);
+ }
+ else { /* written bytes > 0 */
+ iov = driver_peekq(data->port_num, &vlen);
+ if (vlen > 0) {
+ DISPATCH_AIO(sig);
+ FREE_AIO(sig->fm_write_reply.buffer);
+ res = driver_deq(data->port_num, iov[0].iov_len);
+ if (res > 0) {
+ iov = driver_peekq(data->port_num, &vlen);
+ WRITE_AIO(data->ofd, iov[0].iov_len, iov[0].iov_base);
+ }
+ }
+ else if (vlen == 0) {
+ DISPATCH_AIO(sig);
+ FREE_AIO(sig->fm_write_reply.buffer);
+ }
+
+ }
+ sig = erl_drv_ose_get_signal(ready_fd);
+ }
+}
+
+static void stop_select(ErlDrvEvent ready_fd, void* _)
+{
+ int *fd;
+ erl_drv_ose_event_fetch(ready_fd, NULL, NULL, (void **)&fd);
+ erl_drv_ose_event_free(ready_fd);
+ close(*fd);
+}
+
+
+void erts_do_break_handling(void)
+{
+ struct termios temp_mode;
+ int saved = 0;
+
+ /*
+ * Most functions that do_break() calls are intentionally not thread safe;
+ * therefore, make sure that all threads but this one are blocked before
+ * proceeding!
+ */
+ erts_smp_thr_progress_block();
+
+ /* during break we revert to initial settings */
+ /* this is done differently for oldshell */
+ if (using_oldshell && !replace_intr) {
+ SET_BLOCKING(1);
+ }
+ else if (isatty(0)) {
+ tcgetattr(0,&temp_mode);
+ tcsetattr(0,TCSANOW,&initial_tty_mode);
+ saved = 1;
+ }
+
+ /* call the break handling function, reset the flag */
+ do_break();
+
+ fflush(stdout);
+
+ /* after break we go back to saved settings */
+ if (using_oldshell && !replace_intr) {
+ SET_NONBLOCKING(1);
+ }
+ else if (saved) {
+ tcsetattr(0,TCSANOW,&temp_mode);
+ }
+
+ erts_smp_thr_progress_unblock();
+}
+
+static pid_t
+getpid(void)
+{
+ return get_bid(current_process());
+}
+
+int getpagesize(void)
+{
+ return 1024;
+}
+
+
+/* Fills in the systems representation of the jam/beam process identifier.
+** The Pid is put in STRING representation in the supplied buffer,
+** no interpretatione of this should be done by the rest of the
+** emulator. The buffer should be at least 21 bytes long.
+*/
+void sys_get_pid(char *buffer, size_t buffer_size){
+ pid_t p = getpid();
+ /* Assume the pid is scalar and can rest in an unsigned long... */
+ erts_snprintf(buffer, buffer_size, "%lu",(unsigned long) p);
+}
+
+int
+erts_sys_putenv_raw(char *key, char *value) {
+ return erts_sys_putenv(key, value);
+}
+int
+erts_sys_putenv(char *key, char *value)
+{
+ int res;
+
+ erts_smp_rwmtx_rwlock(&environ_rwmtx);
+ res = set_env(get_bid(current_process()), key,
+ value);
+ erts_smp_rwmtx_rwunlock(&environ_rwmtx);
+ return res;
+}
+
+
+int
+erts_sys_unsetenv(char *key)
+{
+ int res;
+
+ erts_smp_rwmtx_rwlock(&environ_rwmtx);
+ res = set_env(get_bid(current_process()),key,NULL);
+ erts_smp_rwmtx_rwunlock(&environ_rwmtx);
+
+ return res;
+}
+
+int
+erts_sys_getenv__(char *key, char *value, size_t *size)
+{
+ int res;
+ char *orig_value = get_env(get_bid(current_process()), key);
+ if (!orig_value)
+ res = -1;
+ else {
+ size_t len = sys_strlen(orig_value);
+ if (len >= *size) {
+ *size = len + 1;
+ res = 1;
+ }
+ else {
+ *size = len;
+ sys_memcpy((void *) value, (void *) orig_value, len+1);
+ res = 0;
+ }
+ free_buf((union SIGNAL **)&orig_value);
+ }
+ return res;
+}
+
+int
+erts_sys_getenv_raw(char *key, char *value, size_t *size) {
+ return erts_sys_getenv(key, value, size);
+}
+
+/*
+ * erts_sys_getenv
+ * returns:
+ * -1, if environment key is not set with a value
+ * 0, if environment key is set and value fits into buffer res
+ * 1, if environment key is set but does not fit into buffer res
+ * res is set with the needed buffer res value
+ */
+
+int
+erts_sys_getenv(char *key, char *value, size_t *size)
+{
+ int res;
+ erts_smp_rwmtx_rlock(&environ_rwmtx);
+ res = erts_sys_getenv__(key, value, size);
+ erts_smp_rwmtx_runlock(&environ_rwmtx);
+ return res;
+}
+
+void
+sys_init_io(void)
+{
+ fd_data = (struct fd_data *)
+ erts_alloc(ERTS_ALC_T_FD_TAB, max_files * sizeof(struct fd_data));
+ erts_smp_atomic_add_nob(&sys_misc_mem_sz,
+ max_files * sizeof(struct fd_data));
+}
+
+extern const char pre_loaded_code[];
+extern Preload pre_loaded[];
+
+void erts_sys_alloc_init(void)
+{
+}
+
+void *erts_sys_alloc(ErtsAlcType_t t, void *x, Uint sz)
+{
+ void *res = malloc((size_t) sz);
+#if HAVE_ERTS_MSEG
+ if (!res) {
+ erts_mseg_clear_cache();
+ return malloc((size_t) sz);
+ }
+#endif
+ return res;
+}
+
+void *erts_sys_realloc(ErtsAlcType_t t, void *x, void *p, Uint sz)
+{
+ void *res = realloc(p, (size_t) sz);
+#if HAVE_ERTS_MSEG
+ if (!res) {
+ erts_mseg_clear_cache();
+ return realloc(p, (size_t) sz);
+ }
+#endif
+ return res;
+}
+
+void erts_sys_free(ErtsAlcType_t t, void *x, void *p)
+{
+ free(p);
+}
+
+/* Return a pointer to a vector of names of preloaded modules */
+
+Preload*
+sys_preloaded(void)
+{
+ return pre_loaded;
+}
+
+/* Return a pointer to preloaded code for module "module" */
+unsigned char*
+sys_preload_begin(Preload* p)
+{
+ return p->code;
+}
+
+/* Clean up if allocated */
+void sys_preload_end(Preload* p)
+{
+ /* Nothing */
+}
+
+/* Read a key from console (?) */
+
+int sys_get_key(fd)
+int fd;
+{
+ int c;
+ unsigned char rbuf[64];
+
+ fflush(stdout); /* Flush query ??? */
+
+ if ((c = read(fd,rbuf,64)) <= 0) {
+ return c;
+ }
+
+ return rbuf[0];
+}
+
+
+#ifdef DEBUG
+
+extern int erts_initialized;
+void
+erl_assert_error(const char* expr, const char* func,
+ const char* file, int line)
+{
+ fflush(stdout);
+ fprintf(stderr, "%s:%d:%s() Assertion failed: %s\n",
+ file, line, func, expr);
+ fflush(stderr);
+ ramlog_printf("%s:%d:%s() Assertion failed: %s\n",
+ file, line, func, expr);
+
+ abort();
+}
+
+void
+erl_debug(char* fmt, ...)
+{
+ char sbuf[1024]; /* Temporary buffer. */
+ va_list va;
+
+ if (debug_log) {
+ va_start(va, fmt);
+ vsprintf(sbuf, fmt, va);
+ va_end(va);
+ fprintf(stderr, "%s", sbuf);
+ }
+}
+
+#endif /* DEBUG */
+
+static ERTS_INLINE void
+report_exit_status(ErtsSysReportExit *rep, int status)
+{
+ if (rep->ifd >= 0) {
+ driver_data[rep->ifd].alive = 0;
+ driver_data[rep->ifd].status = status;
+ }
+ if (rep->ofd >= 0) {
+ driver_data[rep->ofd].alive = 0;
+ driver_data[rep->ofd].status = status;
+ }
+
+ erts_free(ERTS_ALC_T_PRT_REP_EXIT, rep);
+}
+
+#define ERTS_REPORT_EXIT_STATUS report_exit_status
+
+/*
+ * Called from schedule() when it runs out of runnable processes,
+ * or when Erlang code has performed INPUT_REDUCTIONS reduction
+ * steps. runnable == 0 iff there are no runnable Erlang processes.
+ */
+void
+erl_sys_schedule(int runnable)
+{
+ ASSERT(get_fsem(current_process()) == 0);
+#ifdef ERTS_SMP
+ ASSERT(erts_get_scheduler_data()->no == 1);
+ ERTS_CHK_IO(!runnable);
+#else
+ ERTS_CHK_IO( 1 );
+#endif
+ ASSERT(get_fsem(current_process()) == 0);
+ ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking());
+}
+
+
+#ifdef ERTS_SMP
+
+void
+erts_sys_main_thread(void)
+{
+ erts_thread_disable_fpe();
+
+ /* Become signal receiver thread... */
+#ifdef ERTS_ENABLE_LOCK_CHECK
+ erts_lc_set_thread_name("signal_receiver");
+#endif
+
+ while (1) {
+ static const SIGSELECT sigsel[] = {0};
+ union SIGNAL *msg = receive(sigsel);
+
+ fprintf(stderr,"Main thread got message %d from 0x%x!!\r\n",
+ msg->sig_no, sender(&msg));
+ free_buf(&msg);
+ }
+}
+
+#endif /* ERTS_SMP */
+
+void
+erl_sys_args(int* argc, char** argv)
+{
+ int i, j;
+
+ erts_smp_rwmtx_init(&environ_rwmtx, "environ");
+
+ init_check_io();
+
+ /* Handled arguments have been marked with NULL. Slide arguments
+ not handled towards the beginning of argv. */
+ for (i = 0, j = 0; i < *argc; i++) {
+ if (argv[i])
+ argv[j++] = argv[i];
+ }
+ *argc = j;
+
+}
diff --git a/erts/emulator/sys/ose/sys_float.c b/erts/emulator/sys/ose/sys_float.c
new file mode 100644
index 0000000000..d9d6bb7c04
--- /dev/null
+++ b/erts/emulator/sys/ose/sys_float.c
@@ -0,0 +1,844 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "global.h"
+#include "erl_process.h"
+
+
+#ifdef NO_FPE_SIGNALS
+
+void
+erts_sys_init_float(void)
+{
+# ifdef SIGFPE
+ sys_sigset(SIGFPE, SIG_IGN); /* Ignore so we can test for NaN and Inf */
+# endif
+}
+
+#else /* !NO_FPE_SIGNALS */
+
+#ifdef ERTS_SMP
+static erts_tsd_key_t fpe_key;
+
+/* once-only initialisation early in the main thread (via erts_sys_init_float()) */
+static void erts_init_fp_exception(void)
+{
+ /* XXX: the wrappers prevent using a pthread destructor to
+ deallocate the key's value; so when/where do we do that? */
+ erts_tsd_key_create(&fpe_key);
+}
+
+void erts_thread_init_fp_exception(void)
+{
+ unsigned long *fpe = erts_alloc(ERTS_ALC_T_FP_EXCEPTION, sizeof(*fpe));
+ *fpe = 0L;
+ erts_tsd_set(fpe_key, fpe);
+}
+
+static ERTS_INLINE volatile unsigned long *erts_thread_get_fp_exception(void)
+{
+ return (volatile unsigned long*)erts_tsd_get(fpe_key);
+}
+#else /* !SMP */
+#define erts_init_fp_exception() /*empty*/
+static volatile unsigned long fp_exception;
+#define erts_thread_get_fp_exception() (&fp_exception)
+#endif /* SMP */
+
+volatile unsigned long *erts_get_current_fp_exception(void)
+{
+ Process *c_p;
+
+ c_p = erts_get_current_process();
+ if (c_p)
+ return &c_p->fp_exception;
+ return erts_thread_get_fp_exception();
+}
+
+static void set_current_fp_exception(unsigned long pc)
+{
+ volatile unsigned long *fpexnp = erts_get_current_fp_exception();
+ ASSERT(fpexnp != NULL);
+ *fpexnp = pc;
+}
+
+void erts_fp_check_init_error(volatile unsigned long *fpexnp)
+{
+ char buf[64];
+ snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n",
+ __builtin_return_address(0), (void*)*fpexnp);
+ if (write(2, buf, strlen(buf)) <= 0)
+ erl_exit(ERTS_ABORT_EXIT, "%s", buf);
+ *fpexnp = 0;
+#if defined(__i386__) || defined(__x86_64__)
+ erts_restore_fpu();
+#endif
+}
+
+/* Is there no standard identifier for Darwin/MacOSX ? */
+#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
+#define __DARWIN__ 1
+#endif
+
+#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
+
+static void unmask_x87(void)
+{
+ unsigned short cw;
+
+ __asm__ __volatile__("fstcw %0" : "=m"(cw));
+ cw &= ~(0x01|0x04|0x08); /* unmask IM, ZM, OM */
+ __asm__ __volatile__("fldcw %0" : : "m"(cw));
+}
+
+/* mask x87 FPE, return true if the previous state was unmasked */
+static int mask_x87(void)
+{
+ unsigned short cw;
+ int unmasked;
+
+ __asm__ __volatile__("fstcw %0" : "=m"(cw));
+ unmasked = (cw & (0x01|0x04|0x08)) == 0;
+ /* or just set cw = 0x37f */
+ cw |= (0x01|0x04|0x08); /* mask IM, ZM, OM */
+ __asm__ __volatile__("fldcw %0" : : "m"(cw));
+ return unmasked;
+}
+
+static void unmask_sse2(void)
+{
+ unsigned int mxcsr;
+
+ __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));
+ mxcsr &= ~(0x003F|0x0680); /* clear exn flags, unmask OM, ZM, IM (not PM, UM, DM) */
+ __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
+}
+
+/* mask SSE2 FPE, return true if the previous state was unmasked */
+static int mask_sse2(void)
+{
+ unsigned int mxcsr;
+ int unmasked;
+
+ __asm__ __volatile__("stmxcsr %0" : "=m"(mxcsr));
+ unmasked = (mxcsr & 0x0680) == 0;
+ /* or just set mxcsr = 0x1f80 */
+ mxcsr &= ~0x003F; /* clear exn flags */
+ mxcsr |= 0x0680; /* mask OM, ZM, IM (not PM, UM, DM) */
+ __asm__ __volatile__("ldmxcsr %0" : : "m"(mxcsr));
+ return unmasked;
+}
+
+#if defined(__x86_64__)
+
+static inline int cpu_has_sse2(void) { return 1; }
+
+#else /* !__x86_64__ */
+
+/*
+ * Check if an x86-32 processor has SSE2.
+ */
+static unsigned int xor_eflags(unsigned int mask)
+{
+ unsigned int eax, edx;
+
+ eax = mask; /* eax = mask */
+ __asm__("pushfl\n\t"
+ "popl %0\n\t" /* edx = original EFLAGS */
+ "xorl %0, %1\n\t" /* eax = mask ^ EFLAGS */
+ "pushl %1\n\t"
+ "popfl\n\t" /* new EFLAGS = mask ^ original EFLAGS */
+ "pushfl\n\t"
+ "popl %1\n\t" /* eax = new EFLAGS */
+ "xorl %0, %1\n\t" /* eax = new EFLAGS ^ old EFLAGS */
+ "pushl %0\n\t"
+ "popfl" /* restore original EFLAGS */
+ : "=d"(edx), "=a"(eax)
+ : "1"(eax));
+ return eax;
+}
+
+static __inline__ unsigned int cpuid_eax(unsigned int op)
+{
+ unsigned int eax, save_ebx;
+
+ /* In PIC mode i386 reserves EBX. So we must save
+ and restore it ourselves to not upset gcc. */
+ __asm__(
+ "movl %%ebx, %1\n\t"
+ "cpuid\n\t"
+ "movl %1, %%ebx"
+ : "=a"(eax), "=m"(save_ebx)
+ : "0"(op)
+ : "cx", "dx");
+ return eax;
+}
+
+static __inline__ unsigned int cpuid_edx(unsigned int op)
+{
+ unsigned int eax, edx, save_ebx;
+
+ /* In PIC mode i386 reserves EBX. So we must save
+ and restore it ourselves to not upset gcc. */
+ __asm__(
+ "movl %%ebx, %2\n\t"
+ "cpuid\n\t"
+ "movl %2, %%ebx"
+ : "=a"(eax), "=d"(edx), "=m"(save_ebx)
+ : "0"(op)
+ : "cx");
+ return edx;
+}
+
+/* The AC bit, bit #18, is a new bit introduced in the EFLAGS
+ * register on the Intel486 processor to generate alignment
+ * faults. This bit cannot be set on the Intel386 processor.
+ */
+static __inline__ int is_386(void)
+{
+ return ((xor_eflags(1<<18) >> 18) & 1) == 0;
+}
+
+/* Newer x86 processors have a CPUID instruction, as indicated by
+ * the ID bit (#21) in EFLAGS being modifiable.
+ */
+static __inline__ int has_CPUID(void)
+{
+ return (xor_eflags(1<<21) >> 21) & 1;
+}
+
+static int cpu_has_sse2(void)
+{
+ unsigned int maxlev, features;
+ static int has_sse2 = -1;
+
+ if (has_sse2 >= 0)
+ return has_sse2;
+ has_sse2 = 0;
+
+ if (is_386())
+ return 0;
+ if (!has_CPUID())
+ return 0;
+ maxlev = cpuid_eax(0);
+ /* Intel A-step Pentium had a preliminary version of CPUID.
+ It also didn't have SSE2. */
+ if ((maxlev & 0xFFFFFF00) == 0x0500)
+ return 0;
+ /* If max level is zero then CPUID cannot report any features. */
+ if (maxlev == 0)
+ return 0;
+ features = cpuid_edx(1);
+ has_sse2 = (features & (1 << 26)) != 0;
+
+ return has_sse2;
+}
+#endif /* !__x86_64__ */
+
+static void unmask_fpe(void)
+{
+ __asm__ __volatile__("fnclex");
+ unmask_x87();
+ if (cpu_has_sse2())
+ unmask_sse2();
+}
+
+static void unmask_fpe_conditional(int unmasked)
+{
+ if (unmasked)
+ unmask_fpe();
+}
+
+/* mask x86 FPE, return true if the previous state was unmasked */
+static int mask_fpe(void)
+{
+ int unmasked;
+
+ unmasked = mask_x87();
+ if (cpu_has_sse2())
+ unmasked |= mask_sse2();
+ return unmasked;
+}
+
+void erts_restore_fpu(void)
+{
+ __asm__ __volatile__("fninit");
+ unmask_x87();
+ if (cpu_has_sse2())
+ unmask_sse2();
+}
+
+#elif defined(__sparc__) && defined(__linux__)
+
+#if defined(__arch64__)
+#define LDX "ldx"
+#define STX "stx"
+#else
+#define LDX "ld"
+#define STX "st"
+#endif
+
+static void unmask_fpe(void)
+{
+ unsigned long fsr;
+
+ __asm__(STX " %%fsr, %0" : "=m"(fsr));
+ fsr &= ~(0x1FUL << 23); /* clear FSR[TEM] field */
+ fsr |= (0x1AUL << 23); /* enable NV, OF, DZ exceptions */
+ __asm__ __volatile__(LDX " %0, %%fsr" : : "m"(fsr));
+}
+
+static void unmask_fpe_conditional(int unmasked)
+{
+ if (unmasked)
+ unmask_fpe();
+}
+
+/* mask SPARC FPE, return true if the previous state was unmasked */
+static int mask_fpe(void)
+{
+ unsigned long fsr;
+ int unmasked;
+
+ __asm__(STX " %%fsr, %0" : "=m"(fsr));
+ unmasked = ((fsr >> 23) & 0x1A) == 0x1A;
+ fsr &= ~(0x1FUL << 23); /* clear FSR[TEM] field */
+ __asm__ __volatile__(LDX " %0, %%fsr" : : "m"(fsr));
+ return unmasked;
+}
+
+#elif (defined(__powerpc__) && defined(__linux__)) || (defined(__ppc__) && defined(__DARWIN__))
+
+#if defined(__linux__)
+#include <sys/prctl.h>
+
+static void set_fpexc_precise(void)
+{
+ if (prctl(PR_SET_FPEXC, PR_FP_EXC_PRECISE) < 0) {
+ perror("PR_SET_FPEXC");
+ exit(1);
+ }
+}
+
+#elif defined(__DARWIN__)
+
+#include <mach/mach.h>
+#include <pthread.h>
+
+/*
+ * FE0 FE1 MSR bits
+ * 0 0 floating-point exceptions disabled
+ * 0 1 floating-point imprecise nonrecoverable
+ * 1 0 floating-point imprecise recoverable
+ * 1 1 floating-point precise mode
+ *
+ * Apparently:
+ * - Darwin 5.5 (MacOS X <= 10.1) starts with FE0 == FE1 == 0,
+ * and resets FE0 and FE1 to 0 after each SIGFPE.
+ * - Darwin 6.0 (MacOS X 10.2) starts with FE0 == FE1 == 1,
+ * and does not reset FE0 or FE1 after a SIGFPE.
+ */
+#define FE0_MASK (1<<11)
+#define FE1_MASK (1<<8)
+
+/* a thread cannot get or set its own MSR bits */
+static void *fpu_fpe_enable(void *arg)
+{
+ thread_t t = *(thread_t*)arg;
+ struct ppc_thread_state state;
+ unsigned int state_size = PPC_THREAD_STATE_COUNT;
+
+ if (thread_get_state(t, PPC_THREAD_STATE, (natural_t*)&state, &state_size) != KERN_SUCCESS) {
+ perror("thread_get_state");
+ exit(1);
+ }
+ if ((state.srr1 & (FE1_MASK|FE0_MASK)) != (FE1_MASK|FE0_MASK)) {
+#if 1
+ /* This would also have to be performed in the SIGFPE handler
+ to work around the MSR reset older Darwin releases do. */
+ state.srr1 |= (FE1_MASK|FE0_MASK);
+ thread_set_state(t, PPC_THREAD_STATE, (natural_t*)&state, state_size);
+#else
+ fprintf(stderr, "srr1 == 0x%08x, your Darwin is too old\n", state.srr1);
+ exit(1);
+#endif
+ }
+ return NULL; /* Ok, we appear to be on Darwin 6.0 or later */
+}
+
+static void set_fpexc_precise(void)
+{
+ thread_t self = mach_thread_self();
+ pthread_t enabler;
+
+ if (pthread_create(&enabler, NULL, fpu_fpe_enable, &self)) {
+ perror("pthread_create");
+ } else if (pthread_join(enabler, NULL)) {
+ perror("pthread_join");
+ }
+}
+
+#endif
+
+static void set_fpscr(unsigned int fpscr)
+{
+ union {
+ double d;
+ unsigned int fpscr[2];
+ } u;
+
+ u.fpscr[0] = 0xFFF80000;
+ u.fpscr[1] = fpscr;
+ __asm__ __volatile__("mtfsf 255,%0" : : "f"(u.d));
+}
+
+static unsigned int get_fpscr(void)
+{
+ union {
+ double d;
+ unsigned int fpscr[2];
+ } u;
+
+ __asm__("mffs %0" : "=f"(u.d));
+ return u.fpscr[1];
+}
+
+static void unmask_fpe(void)
+{
+ set_fpexc_precise();
+ set_fpscr(0x80|0x40|0x10); /* VE, OE, ZE; not UE or XE */
+}
+
+static void unmask_fpe_conditional(int unmasked)
+{
+ if (unmasked)
+ unmask_fpe();
+}
+
+/* mask PowerPC FPE, return true if the previous state was unmasked */
+static int mask_fpe(void)
+{
+ int unmasked;
+
+ unmasked = (get_fpscr() & (0x80|0x40|0x10)) == (0x80|0x40|0x10);
+ set_fpscr(0x00);
+ return unmasked;
+}
+
+#else
+
+static void unmask_fpe(void)
+{
+ fpsetmask(FP_X_INV | FP_X_OFL | FP_X_DZ);
+}
+
+static void unmask_fpe_conditional(int unmasked)
+{
+ if (unmasked)
+ unmask_fpe();
+}
+
+/* mask IEEE FPE, return true if previous state was unmasked */
+static int mask_fpe(void)
+{
+ const fp_except unmasked_mask = FP_X_INV | FP_X_OFL | FP_X_DZ;
+ fp_except old_mask;
+
+ old_mask = fpsetmask(0);
+ return (old_mask & unmasked_mask) == unmasked_mask;
+}
+
+#endif
+
+#if (defined(__linux__) && (defined(__i386__) || defined(__x86_64__) || defined(__sparc__) || defined(__powerpc__))) || (defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__) || defined(__ppc__))) || (defined(__FreeBSD__) && (defined(__x86_64__) || defined(__i386__))) || ((defined(__NetBSD__) || defined(__OpenBSD__)) && defined(__x86_64__)) || (defined(__sun__) && defined(__x86_64__))
+
+#if defined(__linux__) && defined(__i386__)
+#if !defined(X86_FXSR_MAGIC)
+#define X86_FXSR_MAGIC 0x0000
+#endif
+#elif defined(__FreeBSD__) && defined(__x86_64__)
+#include <sys/types.h>
+#include <machine/fpu.h>
+#elif defined(__FreeBSD__) && defined(__i386__)
+#include <sys/types.h>
+#include <machine/npx.h>
+#elif defined(__DARWIN__)
+#include <machine/signal.h>
+#elif defined(__OpenBSD__) && defined(__x86_64__)
+#include <sys/types.h>
+#include <machine/fpu.h>
+#endif
+#if !(defined(__OpenBSD__) && defined(__x86_64__))
+#include <ucontext.h>
+#endif
+#include <string.h>
+
+#if defined(__linux__) && defined(__x86_64__)
+#define mc_pc(mc) ((mc)->gregs[REG_RIP])
+#elif defined(__linux__) && defined(__i386__)
+#define mc_pc(mc) ((mc)->gregs[REG_EIP])
+#elif defined(__DARWIN__) && defined(__i386__)
+#ifdef DARWIN_MODERN_MCONTEXT
+#define mc_pc(mc) ((mc)->__ss.__eip)
+#else
+#define mc_pc(mc) ((mc)->ss.eip)
+#endif
+#elif defined(__DARWIN__) && defined(__x86_64__)
+#ifdef DARWIN_MODERN_MCONTEXT
+#define mc_pc(mc) ((mc)->__ss.__rip)
+#else
+#define mc_pc(mc) ((mc)->ss.rip)
+#endif
+#elif defined(__FreeBSD__) && defined(__x86_64__)
+#define mc_pc(mc) ((mc)->mc_rip)
+#elif defined(__FreeBSD__) && defined(__i386__)
+#define mc_pc(mc) ((mc)->mc_eip)
+#elif defined(__NetBSD__) && defined(__x86_64__)
+#define mc_pc(mc) ((mc)->__gregs[_REG_RIP])
+#elif defined(__NetBSD__) && defined(__i386__)
+#define mc_pc(mc) ((mc)->__gregs[_REG_EIP])
+#elif defined(__OpenBSD__) && defined(__x86_64__)
+#define mc_pc(mc) ((mc)->sc_rip)
+#elif defined(__sun__) && defined(__x86_64__)
+#define mc_pc(mc) ((mc)->gregs[REG_RIP])
+#endif
+
+static void fpe_sig_action(int sig, siginfo_t *si, void *puc)
+{
+ ucontext_t *uc = puc;
+ unsigned long pc;
+
+#if defined(__linux__)
+#if defined(__x86_64__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ fpregset_t fpstate = mc->fpregs;
+ pc = mc_pc(mc);
+ /* A failed SSE2 instruction will restart. To avoid
+ looping we mask SSE2 exceptions now and unmask them
+ again later in erts_check_fpe()/erts_restore_fpu().
+ On RISCs we update PC to skip the failed instruction,
+ but the ever increasing complexity of the x86 instruction
+ set encoding makes that a poor solution here. */
+ fpstate->mxcsr = 0x1F80;
+ fpstate->swd &= ~0xFF;
+#elif defined(__i386__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ fpregset_t fpstate = mc->fpregs;
+ pc = mc_pc(mc);
+ if ((fpstate->status >> 16) == X86_FXSR_MAGIC)
+ ((struct _fpstate*)fpstate)->mxcsr = 0x1F80;
+ fpstate->sw &= ~0xFF;
+#elif defined(__sparc__) && defined(__arch64__)
+ /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */
+ struct sigcontext *sc = (struct sigcontext*)puc;
+ pc = sc->sigc_regs.tpc;
+ sc->sigc_regs.tpc = sc->sigc_regs.tnpc;
+ sc->sigc_regs.tnpc += 4;
+#elif defined(__sparc__)
+ /* on SPARC the 3rd parameter points to a sigcontext not a ucontext */
+ struct sigcontext *sc = (struct sigcontext*)puc;
+ pc = sc->si_regs.pc;
+ sc->si_regs.pc = sc->si_regs.npc;
+ sc->si_regs.npc = (unsigned long)sc->si_regs.npc + 4;
+#elif defined(__powerpc__)
+#if defined(__powerpc64__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ unsigned long *regs = &mc->gp_regs[0];
+#else
+ mcontext_t *mc = uc->uc_mcontext.uc_regs;
+ unsigned long *regs = &mc->gregs[0];
+#endif
+ pc = regs[PT_NIP];
+ regs[PT_NIP] += 4;
+ regs[PT_FPSCR] = 0x80|0x40|0x10; /* VE, OE, ZE; not UE or XE */
+#endif
+#elif defined(__DARWIN__) && (defined(__i386__) || defined(__x86_64__))
+#ifdef DARWIN_MODERN_MCONTEXT
+ mcontext_t mc = uc->uc_mcontext;
+ pc = mc_pc(mc);
+ mc->__fs.__fpu_mxcsr = 0x1F80;
+ *(unsigned short *)&mc->__fs.__fpu_fsw &= ~0xFF;
+#else
+ mcontext_t mc = uc->uc_mcontext;
+ pc = mc_pc(mc);
+ mc->fs.fpu_mxcsr = 0x1F80;
+ *(unsigned short *)&mc->fs.fpu_fsw &= ~0xFF;
+#endif /* DARWIN_MODERN_MCONTEXT */
+#elif defined(__DARWIN__) && defined(__ppc__)
+ mcontext_t mc = uc->uc_mcontext;
+ pc = mc->ss.srr0;
+ mc->ss.srr0 += 4;
+ mc->fs.fpscr = 0x80|0x40|0x10;
+#elif defined(__FreeBSD__) && defined(__x86_64__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ struct savefpu *savefpu = (struct savefpu*)&mc->mc_fpstate;
+ struct envxmm *envxmm = &savefpu->sv_env;
+ pc = mc_pc(mc);
+ envxmm->en_mxcsr = 0x1F80;
+ envxmm->en_sw &= ~0xFF;
+#elif defined(__FreeBSD__) && defined(__i386__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ union savefpu *savefpu = (union savefpu*)&mc->mc_fpstate;
+ pc = mc_pc(mc);
+ if (mc->mc_fpformat == _MC_FPFMT_XMM) {
+ struct envxmm *envxmm = &savefpu->sv_xmm.sv_env;
+ envxmm->en_mxcsr = 0x1F80;
+ envxmm->en_sw &= ~0xFF;
+ } else {
+ struct env87 *env87 = &savefpu->sv_87.sv_env;
+ env87->en_sw &= ~0xFF;
+ }
+#elif defined(__NetBSD__) && defined(__x86_64__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ struct fxsave64 *fxsave = (struct fxsave64 *)&mc->__fpregs;
+ pc = mc_pc(mc);
+ fxsave->fx_mxcsr = 0x1F80;
+ fxsave->fx_fsw &= ~0xFF;
+#elif defined(__NetBSD__) && defined(__i386__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ pc = mc_pc(mc);
+ if (uc->uc_flags & _UC_FXSAVE) {
+ struct envxmm *envxmm = (struct envxmm *)&mc->__fpregs;
+ envxmm->en_mxcsr = 0x1F80;
+ envxmm->en_sw &= ~0xFF;
+ } else {
+ struct env87 *env87 = (struct env87 *)&mc->__fpregs;
+ env87->en_sw &= ~0xFF;
+ }
+#elif defined(__OpenBSD__) && defined(__x86_64__)
+ struct fxsave64 *fxsave = uc->sc_fpstate;
+ pc = mc_pc(uc);
+ fxsave->fx_mxcsr = 0x1F80;
+ fxsave->fx_fsw &= ~0xFF;
+#elif defined(__sun__) && defined(__x86_64__)
+ mcontext_t *mc = &uc->uc_mcontext;
+ struct fpchip_state *fpstate = &mc->fpregs.fp_reg_set.fpchip_state;
+ pc = mc_pc(mc);
+ fpstate->mxcsr = 0x1F80;
+ fpstate->sw &= ~0xFF;
+#endif
+#if 0
+ {
+ char buf[64];
+ snprintf(buf, sizeof buf, "%s: FPE at %p\r\n", __FUNCTION__, (void*)pc);
+ write(2, buf, strlen(buf));
+ }
+#endif
+ set_current_fp_exception(pc);
+}
+
+static void erts_thread_catch_fp_exceptions(void)
+{
+ struct sigaction act;
+ memset(&act, 0, sizeof act);
+ act.sa_sigaction = fpe_sig_action;
+ act.sa_flags = SA_SIGINFO;
+ sigaction(SIGFPE, &act, NULL);
+ unmask_fpe();
+}
+
+#else /* !((__linux__ && (__i386__ || __x86_64__ || __powerpc__)) || (__DARWIN__ && (__i386__ || __x86_64__ || __ppc__))) */
+
+static void fpe_sig_handler(int sig)
+{
+ set_current_fp_exception(1); /* XXX: convert to sigaction so we can get the trap PC */
+}
+
+static void erts_thread_catch_fp_exceptions(void)
+{
+ sys_sigset(SIGFPE, fpe_sig_handler);
+ unmask_fpe();
+}
+
+#endif /* (__linux__ && (__i386__ || __x86_64__ || __powerpc__)) || (__DARWIN__ && (__i386__ || __x86_64__ || __ppc__))) */
+
+/* once-only initialisation early in the main thread */
+void erts_sys_init_float(void)
+{
+ erts_init_fp_exception();
+ erts_thread_catch_fp_exceptions();
+ erts_printf_block_fpe = erts_sys_block_fpe;
+ erts_printf_unblock_fpe = erts_sys_unblock_fpe;
+}
+
+#endif /* NO_FPE_SIGNALS */
+
+void erts_thread_init_float(void)
+{
+#ifdef ERTS_SMP
+ /* This allows Erlang schedulers to leave Erlang-process context
+ and still have working FP exceptions. XXX: is this needed? */
+ erts_thread_init_fp_exception();
+#endif
+
+#ifndef NO_FPE_SIGNALS
+ /* NOTE:
+ * erts_thread_disable_fpe() is called in all threads at
+ * creation. We at least need to call unmask_fpe()
+ */
+#if defined(__DARWIN__) || defined(__FreeBSD__)
+ /* Darwin (7.9.0) does not appear to propagate FP exception settings
+ to a new thread from its parent. So if we want FP exceptions, we
+ must manually re-enable them in each new thread.
+ FreeBSD 6.1 appears to suffer from a similar issue. */
+ erts_thread_catch_fp_exceptions();
+#else
+ unmask_fpe();
+#endif
+
+#endif
+}
+
+void erts_thread_disable_fpe(void)
+{
+#if !defined(NO_FPE_SIGNALS)
+ (void)mask_fpe();
+#endif
+}
+
+#if !defined(NO_FPE_SIGNALS)
+int erts_sys_block_fpe(void)
+{
+ return mask_fpe();
+}
+
+void erts_sys_unblock_fpe(int unmasked)
+{
+ unmask_fpe_conditional(unmasked);
+}
+#endif
+
+/* The following check is incorporated from the Vee machine */
+
+#define ISDIGIT(d) ((d) >= '0' && (d) <= '9')
+
+/*
+ ** Convert a double to ascii format 0.dddde[+|-]ddd
+ ** return number of characters converted or -1 if error.
+ **
+ ** These two functions should maybe use localeconv() to pick up
+ ** the current radix character, but since it is uncertain how
+ ** expensive such a system call is, and since no-one has heard
+ ** of other radix characters than '.' and ',' an ad-hoc
+ ** low execution time solution is used instead.
+ */
+
+int
+sys_double_to_chars_ext(double fp, char *buffer, size_t buffer_size, size_t decimals)
+{
+ char *s = buffer;
+
+ if (erts_snprintf(buffer, buffer_size, "%.*e", decimals, fp) >= buffer_size)
+ return -1;
+ /* Search upto decimal point */
+ if (*s == '+' || *s == '-') s++;
+ while (ISDIGIT(*s)) s++;
+ if (*s == ',') *s++ = '.'; /* Replace ',' with '.' */
+ /* Scan to end of string */
+ while (*s) s++;
+ return s-buffer; /* i.e strlen(buffer) */
+}
+
+/* Float conversion */
+
+int
+sys_chars_to_double(char* buf, double* fp)
+{
+#ifndef NO_FPE_SIGNALS
+ volatile unsigned long *fpexnp = erts_get_current_fp_exception();
+#endif
+ char *s = buf, *t, *dp;
+
+ /* Robert says that something like this is what he really wanted:
+ * (The [.,] radix test is NOT what Robert wanted - it was added later)
+ *
+ * 7 == sscanf(Tbuf, "%[+-]%[0-9][.,]%[0-9]%[eE]%[+-]%[0-9]%s", ....);
+ * if (*s2 == 0 || *s3 == 0 || *s4 == 0 || *s6 == 0 || *s7)
+ * break;
+ */
+
+ /* Scan string to check syntax. */
+ if (*s == '+' || *s == '-') s++;
+ if (!ISDIGIT(*s)) /* Leading digits. */
+ return -1;
+ while (ISDIGIT(*s)) s++;
+ if (*s != '.' && *s != ',') /* Decimal part. */
+ return -1;
+ dp = s++; /* Remember decimal point pos just in case */
+ if (!ISDIGIT(*s))
+ return -1;
+ while (ISDIGIT(*s)) s++;
+ if (*s == 'e' || *s == 'E') {
+ /* There is an exponent. */
+ s++;
+ if (*s == '+' || *s == '-') s++;
+ if (!ISDIGIT(*s))
+ return -1;
+ while (ISDIGIT(*s)) s++;
+ }
+ if (*s) /* That should be it */
+ return -1;
+
+#ifdef NO_FPE_SIGNALS
+ errno = 0;
+#endif
+ __ERTS_FP_CHECK_INIT(fpexnp);
+ *fp = strtod(buf, &t);
+ __ERTS_FP_ERROR_THOROUGH(fpexnp, *fp, return -1);
+ if (t != s) { /* Whole string not scanned */
+ /* Try again with other radix char */
+ *dp = (*dp == '.') ? ',' : '.';
+ errno = 0;
+ __ERTS_FP_CHECK_INIT(fpexnp);
+ *fp = strtod(buf, &t);
+ __ERTS_FP_ERROR_THOROUGH(fpexnp, *fp, return -1);
+ }
+
+#ifdef NO_FPE_SIGNALS
+ if (errno == ERANGE) {
+ if (*fp == HUGE_VAL || *fp == -HUGE_VAL) {
+ /* overflow, should give error */
+ return -1;
+ } else if (t == s && *fp == 0.0) {
+ /* This should give 0.0 - OTP-7178 */
+ errno = 0;
+
+ } else if (*fp == 0.0) {
+ return -1;
+ }
+ }
+#endif
+ return 0;
+}
+
+int
+matherr(struct exception *exc)
+{
+#if !defined(NO_FPE_SIGNALS)
+ volatile unsigned long *fpexnp = erts_get_current_fp_exception();
+ if (fpexnp != NULL)
+ *fpexnp = (unsigned long)__builtin_return_address(0);
+#endif
+ return 1;
+}
diff --git a/erts/emulator/sys/ose/sys_time.c b/erts/emulator/sys/ose/sys_time.c
new file mode 100644
index 0000000000..7e96f68424
--- /dev/null
+++ b/erts/emulator/sys/ose/sys_time.c
@@ -0,0 +1,56 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2005-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "global.h"
+
+/******************* Routines for time measurement *********************/
+
+int erts_ticks_per_sec = 0; /* Will be SYS_CLK_TCK in erl_unix_sys.h */
+
+int sys_init_time(void)
+{
+ return SYS_CLOCK_RESOLUTION;
+}
+
+clock_t sys_times(SysTimes *now) {
+ now->tms_utime = now->tms_stime = now->tms_cutime = now->tms_cstime = 0;
+ return 0;
+}
+
+static OSTICK last_tick_count = 0;
+static SysHrTime wrap = 0;
+static OSTICK us_per_tick;
+
+void sys_init_hrtime() {
+ us_per_tick = system_tick();
+}
+
+SysHrTime sys_gethrtime() {
+ OSTICK ticks = get_ticks();
+ if (ticks < (SysHrTime) last_tick_count) {
+ wrap += 1ULL << 32;
+ }
+ last_tick_count = ticks;
+ return ((((SysHrTime) ticks) + wrap) * 1000*us_per_tick);
+}
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 7c6e4a2f37..94eb6b1547 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -54,6 +54,17 @@ void sys_sigrelease(int sig)
#endif /* !SIG_SIGNAL */
#endif /* !SIG_SIGSET */
+#if defined(__ANDROID__)
+int __system_properties_fd(void);
+#endif /* __ANDROID__ */
+
+#if defined(__ANDROID__)
+#define SHELL "/system/bin/sh"
+#else
+#define SHELL "/bin/sh"
+#endif /* __ANDROID__ */
+
+
int
main(int argc, char *argv[])
{
@@ -89,8 +100,23 @@ main(int argc, char *argv[])
if (sscanf(argv[CS_ARGV_FD_CR_IX], "%d:%d", &from, &to) != 2)
return 1;
+
+#if defined(__ANDROID__)
+ for (i = from; i <= to; i++) {
+ if (i!=__system_properties_fd)
+ (void) close(i);
+ }
+#else
for (i = from; i <= to; i++)
(void) close(i);
+#endif /* __ANDROID__ */
+
+#if defined(HAVE_CLOSEFROM)
+ closefrom(from);
+#else
+ for (i = from; i <= to; i++)
+ (void) close(i);
+#endif
if (!(argv[CS_ARGV_WD_IX][0] == '.' && argv[CS_ARGV_WD_IX][1] == '\0')
&& chdir(argv[CS_ARGV_WD_IX]) < 0)
@@ -116,7 +142,25 @@ main(int argc, char *argv[])
execv(argv[CS_ARGV_NO_OF_ARGS],&(argv[CS_ARGV_NO_OF_ARGS + 1]));
}
} else {
- execl("/bin/sh", "sh", "-c", argv[CS_ARGV_CMD_IX], (char *) NULL);
+ execl(SHELL, "sh", "-c", argv[CS_ARGV_CMD_IX], (char *) NULL);
}
return 1;
}
+
+
+
+#if defined(__ANDROID__)
+int __system_properties_fd(void)
+{
+ int s, fd;
+ char *env;
+
+ env = getenv("ANDROID_PROPERTY_WORKSPACE");
+ if (!env) {
+ return -1;
+ }
+ fd = atoi(env);
+ return fd;
+}
+#endif /* __ANDROID__ */
+
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index 2c47aa06c2..176fc049a7 100644
--- a/erts/emulator/sys/unix/erl_unix_sys.h
+++ b/erts/emulator/sys/unix/erl_unix_sys.h
@@ -127,6 +127,11 @@
# endif
#endif
+/*
+ * Min number of async threads
+ */
+#define ERTS_MIN_NO_OF_ASYNC_THREADS 0
+
/* File descriptors are numbers anc consecutively allocated on Unix */
#define ERTS_SYS_CONTINOUS_FD_NUMBERS
diff --git a/erts/emulator/sys/unix/erl_unix_sys_ddll.c b/erts/emulator/sys/unix/erl_unix_sys_ddll.c
index 12c47d0088..2659d623c7 100644
--- a/erts/emulator/sys/unix/erl_unix_sys_ddll.c
+++ b/erts/emulator/sys/unix/erl_unix_sys_ddll.c
@@ -101,7 +101,7 @@ void erl_sys_ddll_init(void) {
/*
* Open a shared object
*/
-int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError* err)
+int erts_sys_ddll_open(const char *full_name, void **handle, ErtsSysDdllError* err)
{
#if defined(HAVE_DLOPEN)
char* dlname;
@@ -123,6 +123,7 @@ int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError*
int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
{
+#if defined(HAVE_DLOPEN)
int ret = ERL_DE_NO_ERROR;
char *str;
dlerror();
@@ -148,6 +149,9 @@ int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
ret = ERL_DE_DYNAMIC_ERROR_OFFSET - find_errcode(str, err);
}
return ret;
+#else
+ return ERL_DE_ERROR_NO_DDLL_FUNCTIONALITY;
+#endif
}
/*
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 61f9f6a59a..c3d7440409 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -149,6 +149,13 @@ extern void erl_crash_dump(char* file, int line, char* fmt, ...);
#define DIR_SEPARATOR_CHAR '/'
+#if defined(__ANDROID__)
+#define SHELL "/system/bin/sh"
+#else
+#define SHELL "/bin/sh"
+#endif /* __ANDROID__ */
+
+
#if defined(DEBUG)
#define ERL_BUILD_TYPE_MARKER ".debug"
#elif defined(PURIFY)
@@ -409,8 +416,10 @@ void sys_tty_reset(int exit_code)
#ifdef __tile__
/* Direct malloc to spread memory around the caches of multiple tiles. */
#include <malloc.h>
+#if defined(MALLOC_USE_HASH)
MALLOC_USE_HASH(1);
#endif
+#endif
#ifdef USE_THREADS
@@ -547,6 +556,25 @@ erts_sys_pre_init(void)
#endif
#endif /* USE_THREADS */
erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0);
+
+ {
+ /*
+ * Unfortunately we depend on fd 0,1,2 in the old shell code.
+ * So if for some reason we do not have those open when we start
+ * we have to open them here. Not doing this can cause the emulator
+ * to deadlock when reaping the fd_driver ports :(
+ */
+ int fd;
+ /* Make sure fd 0 is open */
+ if ((fd = open("/dev/null", O_RDONLY)) != 0)
+ close(fd);
+ /* Make sure fds 1 and 2 are open */
+ while (fd < 3) {
+ fd = open("/dev/null", O_WRONLY);
+ }
+ close(fd);
+ }
+
}
void
@@ -1575,7 +1603,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op
}
}
} else {
- execle("/bin/sh", "sh", "-c", cmd_line, (char *) NULL, new_environ);
+ execle(SHELL, "sh", "-c", cmd_line, (char *) NULL, new_environ);
}
child_error:
_exit(1);
@@ -1696,7 +1724,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* op
fcntl(i, F_SETFD, 1);
qnx_spawn_options.flags = _SPAWN_SETSID;
- if ((pid = spawnl(P_NOWAIT, "/bin/sh", "/bin/sh", "-c", cmd_line,
+ if ((pid = spawnl(P_NOWAIT, SHELL, SHELL, "-c", cmd_line,
(char *) 0)) < 0) {
erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
reset_qnx_spawn();
@@ -2540,7 +2568,7 @@ void *erts_sys_aligned_alloc(UWord alignment, UWord size)
#ifdef HAVE_POSIX_MEMALIGN
void *ptr = NULL;
int error;
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
error = posix_memalign(&ptr, (size_t) alignment, (size_t) size);
#if HAVE_ERTS_MSEG
if (error || !ptr) {
@@ -2563,7 +2591,7 @@ void *erts_sys_aligned_alloc(UWord alignment, UWord size)
void erts_sys_aligned_free(UWord alignment, void *ptr)
{
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
free(ptr);
}
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index 689be98969..cafeab547e 100644
--- a/erts/emulator/sys/unix/sys_float.c
+++ b/erts/emulator/sys/unix/sys_float.c
@@ -46,7 +46,7 @@ static void erts_init_fp_exception(void)
{
/* XXX: the wrappers prevent using a pthread destructor to
deallocate the key's value; so when/where do we do that? */
- erts_tsd_key_create(&fpe_key);
+ erts_tsd_key_create(&fpe_key,"fp_exception");
}
void erts_thread_init_fp_exception(void)
diff --git a/erts/emulator/sys/win32/erl_win32_sys_ddll.c b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
index 4c8d83ab16..338f0d7386 100644
--- a/erts/emulator/sys/win32/erl_win32_sys_ddll.c
+++ b/erts/emulator/sys/win32/erl_win32_sys_ddll.c
@@ -38,7 +38,7 @@
#include "erl_nif.h"
#define EXT_LEN 4
-#define FILE_EXT ".dll"
+#define FILE_EXT_WCHAR L".dll"
static DWORD tls_index = 0;
static TWinDynDriverCallbacks wddc;
@@ -57,11 +57,15 @@ void erl_sys_ddll_init(void) {
/*
* Open a shared object
+ * Expecting 'full_name' as an UTF-8 string.
*/
-int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError* err)
+int erts_sys_ddll_open(const char *full_name, void **handle, ErtsSysDdllError* err)
{
+ HINSTANCE hinstance;
int len;
- char dlname[MAXPATHLEN + 1];
+ wchar_t* wcp;
+ Sint used;
+ int code;
if ((len = sys_strlen(full_name)) >= MAXPATHLEN - EXT_LEN) {
if (err != NULL) {
@@ -69,10 +73,26 @@ int erts_sys_ddll_open2(const char *full_name, void **handle, ErtsSysDdllError*
}
return ERL_DE_LOAD_ERROR_NAME_TO_LONG;
}
- sys_strcpy(dlname, full_name);
- sys_strcpy(dlname+len, FILE_EXT);
- return erts_sys_ddll_open_noext(dlname, handle, err);
+
+ wcp = (wchar_t*)erts_convert_filename_to_wchar((byte*)full_name, len,
+ NULL, 0,
+ ERTS_ALC_T_TMP, &used, EXT_LEN);
+ wcscpy(&wcp[used/2 - 1], FILE_EXT_WCHAR);
+
+ if ((hinstance = LoadLibraryW(wcp)) == NULL) {
+ code = ERL_DE_DYNAMIC_ERROR_OFFSET - GetLastError();
+ if (err != NULL) {
+ err->str = erts_sys_ddll_error(code);
+ }
+ }
+ else {
+ code = ERL_DE_NO_ERROR;
+ *handle = (void *) hinstance;
+ }
+ erts_free(ERTS_ALC_T_TMP, wcp);
+ return code;
}
+
int erts_sys_ddll_open_noext(char *dlname, void **handle, ErtsSysDdllError* err)
{
HINSTANCE hinstance;
diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h
index b9a9838a36..4010d939e5 100644
--- a/erts/emulator/sys/win32/erl_win_dyn_driver.h
+++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h
@@ -82,7 +82,6 @@ WDD_TYPEDEF(int, erl_drv_send_term, (ErlDrvTermData, ErlDrvTermData, ErlDrvTermD
WDD_TYPEDEF(int, driver_send_term, (ErlDrvPort, ErlDrvTermData, ErlDrvTermData*, int));
WDD_TYPEDEF(unsigned int, driver_async_port_key, (ErlDrvPort));
WDD_TYPEDEF(long, driver_async, (ErlDrvPort,unsigned int*,void (*)(void*),void*,void (*)(void*)));
-WDD_TYPEDEF(int, driver_async_cancel, (unsigned int));
WDD_TYPEDEF(int, driver_lock_driver, (ErlDrvPort));
WDD_TYPEDEF(void *, driver_dl_open, (char *));
WDD_TYPEDEF(void *, driver_dl_sym, (void *, char *));
@@ -200,7 +199,6 @@ typedef struct {
WDD_FTYPE(driver_send_term) *driver_send_term;
WDD_FTYPE(driver_async_port_key) *driver_async_port_key;
WDD_FTYPE(driver_async) *driver_async;
- WDD_FTYPE(driver_async_cancel) *driver_async_cancel;
WDD_FTYPE(driver_lock_driver) *driver_lock_driver;
WDD_FTYPE(driver_dl_open) *driver_dl_open;
WDD_FTYPE(driver_dl_sym) *driver_dl_sym;
@@ -312,7 +310,6 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks;
#define driver_send_term (WinDynDriverCallbacks.driver_send_term)
#define driver_async_port_key (WinDynDriverCallbacks.driver_async_port_key)
#define driver_async (WinDynDriverCallbacks.driver_async)
-#define driver_async_cancel (WinDynDriverCallbacks.driver_async_cancel)
#define driver_lock_driver (WinDynDriverCallbacks.driver_lock_driver)
#define driver_dl_open (WinDynDriverCallbacks.driver_dl_open)
#define driver_dl_sym (WinDynDriverCallbacks.driver_dl_sym)
@@ -448,7 +445,6 @@ do { \
((W).driver_send_term) = driver_send_term; \
((W).driver_async_port_key) = driver_async_port_key; \
((W).driver_async) = driver_async; \
-((W).driver_async_cancel) = driver_async_cancel; \
((W).driver_lock_driver) = driver_lock_driver; \
((W).driver_dl_open) = driver_dl_open; \
((W).driver_dl_sym) = driver_dl_sym; \
diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h
index 0deb097b1a..a78dbf64af 100644
--- a/erts/emulator/sys/win32/erl_win_sys.h
+++ b/erts/emulator/sys/win32/erl_win_sys.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -60,16 +60,18 @@
#include <windows.h>
#undef WIN32_LEAN_AND_MEAN
-/*
- * Define MAXPATHLEN in terms of MAXPATH if available.
- */
-
-#ifndef MAXPATH
-#define MAXPATH MAX_PATH
-#endif /* MAXPATH */
#ifndef MAXPATHLEN
-#define MAXPATHLEN MAXPATH
+#define MAXPATHLEN 4096
+/*
+ erts-6.0 (OTP 17.0):
+ We now accept windows paths longer than 260 (MAX_PATH) by conversion to
+ UNC path format. In order to also return long paths from the driver we
+ increased MAXPATHLEN from 260 to larger (but arbitrary) value 4096.
+ It would of course be nicer to instead dynamically allocate large enough
+ tmp buffers when efile_drv needs to return really long paths, and do that
+ for unix as well.
+ */
#endif /* MAXPATHLEN */
/*
@@ -103,6 +105,10 @@
#define CreateAutoEvent(state) CreateEvent(NULL, FALSE, state, NULL)
#define CreateManualEvent(state) CreateEvent(NULL, TRUE, state, NULL)
+/*
+ * Min number of async threads
+ */
+#define ERTS_MIN_NO_OF_ASYNC_THREADS 0
/*
* Our own type of "FD's"
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index 99951bb45e..0ded6b274e 100755
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -69,17 +69,14 @@ static void async_read_file(struct async_io* aio, LPVOID buf, DWORD numToRead);
static int async_write_file(struct async_io* aio, LPVOID buf, DWORD numToWrite);
static int get_overlapped_result(struct async_io* aio,
LPDWORD pBytesRead, BOOL wait);
-static BOOL create_child_process(char *, HANDLE, HANDLE,
+static BOOL create_child_process(wchar_t *, HANDLE, HANDLE,
HANDLE, LPHANDLE, LPDWORD, BOOL,
- LPVOID, LPTSTR, unsigned,
- char **, int *);
+ LPVOID, wchar_t*, unsigned,
+ wchar_t **, int *);
static int create_pipe(LPHANDLE, LPHANDLE, BOOL, BOOL);
-static int application_type(const char* originalName, char fullPath[MAX_PATH],
+static int application_type(const wchar_t* originalName, wchar_t fullPath[MAX_PATH],
BOOL search_in_path, BOOL handle_quotes,
int *error_return);
-static int application_type_w(const WCHAR *originalName, WCHAR fullPath[MAX_PATH],
- BOOL search_in_path, BOOL handle_quotes,
- int *error_return);
HANDLE erts_service_event;
@@ -1173,7 +1170,7 @@ spawn_init(void)
}
static ErlDrvData
-spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
+spawn_start(ErlDrvPort port_num, char* utf8_name, SysDriverOpts* opts)
{
HANDLE hToChild = INVALID_HANDLE_VALUE; /* Write handle to child. */
HANDLE hFromChild = INVALID_HANDLE_VALUE; /* Read handle from child. */
@@ -1189,7 +1186,9 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
char* envir = opts->envir;
int errno_return = -1;
-
+ wchar_t *name;
+ int len;
+
if (opts->read_write & DO_READ)
neededSelects++;
if (opts->read_write & DO_WRITE)
@@ -1247,26 +1246,40 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
* Spawn the port program.
*/
- DEBUGF(("Spawning \"%s\"\n", name));
+ if ((len = MultiByteToWideChar(CP_UTF8, 0, utf8_name, -1, NULL, 0)) > 0) {
+ name = erts_alloc(ERTS_ALC_T_TMP, len*sizeof(wchar_t));
+ MultiByteToWideChar(CP_UTF8, 0, utf8_name, -1, name, len);
+ } else { /* Not valid utf-8, just convert byte to wchar */
+ int i;
+ len = strlen(utf8_name);
+ name = erts_alloc(ERTS_ALC_T_TMP, (1+len)*sizeof(wchar_t));
+ for(i=0; i<len; i++) {
+ name[i] = (wchar_t) utf8_name[i];
+ }
+ name[i] = L'\0';
+ }
+ DEBUGF(("Spawning \"%S\"\n", name));
envir = win_build_environment(envir); /* Always a unicode environment */
- ok = create_child_process(name,
- hChildStdin,
- hChildStdout,
- hChildStderr,
- &dp->port_pid,
- &pid,
- opts->hide_window,
- (LPVOID) envir,
- (LPTSTR) opts->wd,
- opts->spawn_type,
- opts->argv,
- &errno_return);
+ ok = create_child_process(name,
+ hChildStdin,
+ hChildStdout,
+ hChildStderr,
+ &dp->port_pid,
+ &pid,
+ opts->hide_window,
+ (LPVOID) envir,
+ (wchar_t *) opts->wd,
+ opts->spawn_type,
+ (wchar_t **) opts->argv,
+ &errno_return);
CloseHandle(hChildStdin);
CloseHandle(hChildStdout);
if (close_child_stderr && hChildStderr != INVALID_HANDLE_VALUE &&
hChildStderr != 0) {
CloseHandle(hChildStderr);
}
+ erts_free(ERTS_ALC_T_TMP, name);
+
if (envir != NULL) {
erts_free(ERTS_ALC_T_ENVIRONMENT, envir);
}
@@ -1344,9 +1357,9 @@ create_file_thread(AsyncIo* aio, int mode)
* Example: input = "\"Program Files\"\\erl arg1 arg2"
* gives 19 as result.
* The length returned is equivalent with length(argv[0]) if the
- * comman line should have been prepared by _setargv for the main function
+ * command line should have been prepared by _setargv for the main function
*/
-int parse_command(char* cmd){
+int parse_command(wchar_t* cmd){
#define NORMAL 2
#define STRING 1
#define STOP 0
@@ -1354,17 +1367,17 @@ int parse_command(char* cmd){
int state = NORMAL;
while (cmd[i]) {
switch (cmd[i]) {
- case '"':
+ case L'"':
if (state == NORMAL)
state = STRING;
else
state = NORMAL;
break;
- case '\\':
- if ((state == STRING) && (cmd[i+1]=='"'))
+ case L'\\':
+ if ((state == STRING) && (cmd[i+1]==L'"'))
i++;
break;
- case ' ':
+ case L' ':
if (state == NORMAL)
state = STOP;
break;
@@ -1379,7 +1392,7 @@ int parse_command(char* cmd){
return i;
}
-static BOOL need_quotes(WCHAR *str)
+static BOOL need_quotes(wchar_t *str)
{
int in_quote = 0;
int backslashed = 0;
@@ -1443,7 +1456,7 @@ static BOOL need_quotes(WCHAR *str)
static BOOL
create_child_process
(
- char *origcmd, /* Command line for child process (including
+ wchar_t *origcmd, /* Command line for child process (including
* name of executable). Or whole executable if st is
* ERTS_SPAWN_EXECUTABLE
*/
@@ -1454,57 +1467,53 @@ create_child_process
LPDWORD pdwID, /* Pointer to variable to received Process ID */
BOOL hide, /* Hide the window unconditionally. */
LPVOID env, /* Environment for the child */
- LPTSTR wd, /* Working dir for the child */
+ wchar_t *wd, /* Working dir for the child */
unsigned st, /* Flags for spawn, tells us how to interpret origcmd */
- char **argv, /* Argument vector if given. */
+ wchar_t **argv, /* Argument vector if given. */
int *errno_return /* Place to put an errno in in case of failure */
)
-{
+{
PROCESS_INFORMATION piProcInfo = {0};
BOOL ok = FALSE;
int applType;
/* Not to be changed for different types of executables */
int staticCreateFlags = GetPriorityClass(GetCurrentProcess());
int createFlags = DETACHED_PROCESS;
- char *newcmdline = NULL;
+ wchar_t *newcmdline = NULL;
int cmdlength;
- char* thecommand;
- LPTSTR appname = NULL;
+ wchar_t* thecommand;
+ wchar_t* appname = NULL;
HANDLE hProcess = GetCurrentProcess();
-
- *errno_return = -1;
+ STARTUPINFOW siStartInfo = {0};
+ wchar_t execPath[MAX_PATH];
+ *errno_return = -1;
+ siStartInfo.cb = sizeof(STARTUPINFOW);
+ siStartInfo.dwFlags = STARTF_USESTDHANDLES;
+ siStartInfo.hStdInput = hStdin;
+ siStartInfo.hStdOutput = hStdout;
+ siStartInfo.hStdError = hStderr;
if (st != ERTS_SPAWN_EXECUTABLE) {
- STARTUPINFO siStartInfo = {0};
- char execPath[MAX_PATH];
-
- siStartInfo.cb = sizeof(STARTUPINFO);
- siStartInfo.dwFlags = STARTF_USESTDHANDLES;
- siStartInfo.hStdInput = hStdin;
- siStartInfo.hStdOutput = hStdout;
- siStartInfo.hStdError = hStderr;
-
/*
* Parse out the program name from the command line (it can be quoted and
* contain spaces).
*/
- newcmdline = erts_alloc(ERTS_ALC_T_TMP, 2048);
+ newcmdline = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, 2048*sizeof(wchar_t));
cmdlength = parse_command(origcmd);
- thecommand = (char *) erts_alloc(ERTS_ALC_T_TMP, cmdlength+1);
- strncpy(thecommand, origcmd, cmdlength);
- thecommand[cmdlength] = '\0';
- DEBUGF(("spawn command: %s\n", thecommand));
-
- applType = application_type(thecommand, execPath, TRUE,
- TRUE, errno_return);
- DEBUGF(("application_type returned for (%s) is %d\n", thecommand, applType));
+ thecommand = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, (cmdlength+1)*sizeof(wchar_t));
+ wcsncpy(thecommand, origcmd, cmdlength);
+ thecommand[cmdlength] = L'\0';
+ DEBUGF(("spawn command: %S\n", thecommand));
+
+ applType = application_type(thecommand, execPath, TRUE, TRUE, errno_return);
+ DEBUGF(("application_type returned for (%S) is %d\n", thecommand, applType));
erts_free(ERTS_ALC_T_TMP, (void *) thecommand);
if (applType == APPL_NONE) {
erts_free(ERTS_ALC_T_TMP,newcmdline);
return FALSE;
}
- newcmdline[0] = '\0';
+ newcmdline[0] = L'\0';
if (applType == APPL_DOS) {
/*
@@ -1513,11 +1522,11 @@ create_child_process
* a normal process inside of a hidden console application,
* and then run that hidden console as a detached process.
*/
-
+
siStartInfo.wShowWindow = SW_HIDE;
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
createFlags = CREATE_NEW_CONSOLE;
- strcat(newcmdline, "cmd.exe /c ");
+ wcscat(newcmdline, L"cmd.exe /c ");
} else if (hide) {
DEBUGF(("hiding window\n"));
siStartInfo.wShowWindow = SW_HIDE;
@@ -1525,35 +1534,25 @@ create_child_process
createFlags = 0;
}
- strcat(newcmdline, execPath);
- strcat(newcmdline, origcmd+cmdlength);
- DEBUGF(("Creating child process: %s, createFlags = %d\n", newcmdline, createFlags));
- ok = CreateProcessA(appname,
- newcmdline,
- NULL,
- NULL,
- TRUE,
- createFlags | staticCreateFlags |
- CREATE_UNICODE_ENVIRONMENT,
- env,
- wd,
- &siStartInfo,
+ wcscat(newcmdline, execPath);
+ wcscat(newcmdline, origcmd+cmdlength);
+ DEBUGF(("Creating child process: %S, createFlags = %d\n", newcmdline, createFlags));
+ ok = CreateProcessW(appname,
+ newcmdline,
+ NULL,
+ NULL,
+ TRUE,
+ createFlags | staticCreateFlags |
+ CREATE_UNICODE_ENVIRONMENT,
+ env,
+ wd,
+ &siStartInfo,
&piProcInfo);
} else { /* ERTS_SPAWN_EXECUTABLE, filename and args are in unicode ({utf16,little}) */
int run_cmd = 0;
- STARTUPINFOW siStartInfo = {0};
- WCHAR execPath[MAX_PATH];
-
- siStartInfo.cb = sizeof(STARTUPINFOW);
- siStartInfo.dwFlags = STARTF_USESTDHANDLES;
- siStartInfo.hStdInput = hStdin;
- siStartInfo.hStdOutput = hStdout;
- siStartInfo.hStdError = hStderr;
-
- applType = application_type_w((WCHAR *) origcmd, execPath, FALSE, FALSE,
- errno_return);
+ applType = application_type(origcmd, execPath, FALSE, FALSE, errno_return);
if (applType == APPL_NONE) {
return FALSE;
}
@@ -1573,37 +1572,37 @@ create_child_process
createFlags = 0;
}
if (run_cmd) {
- WCHAR cmdPath[MAX_PATH];
+ wchar_t cmdPath[MAX_PATH];
int cmdType;
- cmdType = application_type_w(L"cmd.exe", cmdPath, TRUE, FALSE, errno_return);
+ cmdType = application_type(L"cmd.exe", cmdPath, TRUE, FALSE, errno_return);
if (cmdType == APPL_NONE || cmdType == APPL_DOS) {
return FALSE;
}
- appname = (char *) erts_alloc(ERTS_ALC_T_TMP, (wcslen(cmdPath)+1)*sizeof(WCHAR));
- wcscpy((WCHAR *) appname,cmdPath);
+ appname = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, (wcslen(cmdPath)+1)*sizeof(wchar_t));
+ wcscpy(appname,cmdPath);
} else {
- appname = (char *) erts_alloc(ERTS_ALC_T_TMP, (wcslen(execPath)+1)*sizeof(WCHAR));
- wcscpy((WCHAR *) appname, execPath);
+ appname = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, (wcslen(execPath)+1)*sizeof(wchar_t));
+ wcscpy(appname, execPath);
}
if (argv == NULL) {
BOOL orig_need_q = need_quotes(execPath);
- WCHAR *ptr;
+ wchar_t *ptr;
int ocl = wcslen(execPath);
if (run_cmd) {
- newcmdline = (char *) erts_alloc(ERTS_ALC_T_TMP,
- (ocl + ((orig_need_q) ? 3 : 1)
- + 11)*sizeof(WCHAR));
- memcpy(newcmdline,L"cmd.exe /c ",11*sizeof(WCHAR));
- ptr = (WCHAR *) (newcmdline + (11*sizeof(WCHAR)));
+ newcmdline = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP,
+ (ocl + ((orig_need_q) ? 3 : 1)
+ + 11)*sizeof(wchar_t));
+ memcpy(newcmdline,L"cmd.exe /c ",11*sizeof(wchar_t));
+ ptr = newcmdline + 11;
} else {
- newcmdline = (char *) erts_alloc(ERTS_ALC_T_TMP,
- (ocl + ((orig_need_q) ? 3 : 1))*sizeof(WCHAR));
- ptr = (WCHAR *) newcmdline;
+ newcmdline = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP,
+ (ocl + ((orig_need_q) ? 3 : 1))*sizeof(wchar_t));
+ ptr = (wchar_t *) newcmdline;
}
if (orig_need_q) {
*ptr++ = L'"';
}
- memcpy(ptr,execPath,ocl*sizeof(WCHAR));
+ memcpy(ptr,execPath,ocl*sizeof(wchar_t));
ptr += ocl;
if (orig_need_q) {
*ptr++ = L'"';
@@ -1611,12 +1610,12 @@ create_child_process
*ptr = L'\0';
} else {
int sum = 1; /* '\0' */
- WCHAR **ar = (WCHAR **) argv;
- WCHAR *n;
- char *save_arg0 = NULL;
- if (argv[0] == erts_default_arg0 || run_cmd) {
+ wchar_t **ar = argv;
+ wchar_t *n;
+ wchar_t *save_arg0 = NULL;
+ if (argv[0] == (wchar_t *) erts_default_arg0 || run_cmd) {
save_arg0 = argv[0];
- argv[0] = (char *) execPath;
+ argv[0] = execPath;
}
if (run_cmd) {
sum += 11; /* cmd.exe /c */
@@ -1629,11 +1628,11 @@ create_child_process
sum++; /* space */
++ar;
}
- ar = (WCHAR **) argv;
- newcmdline = erts_alloc(ERTS_ALC_T_TMP, sum*sizeof(WCHAR));
- n = (WCHAR *) newcmdline;
+ ar = argv;
+ newcmdline = (wchar_t *) erts_alloc(ERTS_ALC_T_TMP, sum*sizeof(wchar_t));
+ n = newcmdline;
if (run_cmd) {
- memcpy(n,L"cmd.exe /c ",11*sizeof(WCHAR));
+ memcpy(n,L"cmd.exe /c ",11*sizeof(wchar_t));
n += 11;
}
while (*ar != NULL) {
@@ -1642,7 +1641,7 @@ create_child_process
if (q) {
*n++ = L'"';
}
- memcpy(n,*ar,sum*sizeof(WCHAR));
+ memcpy(n,*ar,sum*sizeof(wchar_t));
n += sum;
if (q) {
*n++ = L'"';
@@ -1657,16 +1656,16 @@ create_child_process
}
DEBUGF(("Creating child process: %s, createFlags = %d\n", newcmdline, createFlags));
- ok = CreateProcessW((WCHAR *) appname,
- (WCHAR *) newcmdline,
- NULL,
- NULL,
- TRUE,
- createFlags | staticCreateFlags |
- CREATE_UNICODE_ENVIRONMENT,
- env,
- (WCHAR *) wd,
- &siStartInfo,
+ ok = CreateProcessW((wchar_t *) appname,
+ (wchar_t *) newcmdline,
+ NULL,
+ NULL,
+ TRUE,
+ createFlags | staticCreateFlags |
+ CREATE_UNICODE_ENVIRONMENT,
+ env,
+ wd,
+ &siStartInfo,
&piProcInfo);
} /* end SPAWN_EXECUTABLE */
@@ -1775,180 +1774,23 @@ static int create_pipe(HANDLE *phRead, HANDLE *phWrite, BOOL inheritRead, BOOL o
return TRUE;
}
-
-
-
-static int application_type
-(
- const char *originalName, /* Name of the application to find. */
- char fullPath[MAX_PATH], /* Filled with complete path to
- * application. */
- BOOL search_in_path, /* If we should search the system wide path */
- BOOL handle_quotes, /* If we should handle quotes around executable */
- int *error_return /* A place to put an error code */
- )
-{
- int applType, i;
- HANDLE hFile;
- char *ext, *rest;
- char buf[2];
- DWORD read;
- IMAGE_DOS_HEADER header;
- static char extensions[][5] = {"", ".com", ".exe", ".bat"};
- int is_quoted;
- int len;
-
- /* Look for the program as an external program. First try the name
- * as it is, then try adding .com, .exe, and .bat, in that order, to
- * the name, looking for an executable.
- * NOTE! that we does not support execution of .com programs on Windows NT
- *
- *
- * Using the raw SearchPath() procedure doesn't do quite what is
- * necessary. If the name of the executable already contains a '.'
- * character, it will not try appending the specified extension when
- * searching (in other words, SearchPath will not find the program
- * "a.b.exe" if the arguments specified "a.b" and ".exe").
- * So, first look for the file as it is named. Then manually append
- * the extensions, looking for a match. (')
- */
-
- len = strlen(originalName);
- is_quoted = handle_quotes && len > 0 && originalName[0] == '"' &&
- originalName[len-1] == '"';
-
- applType = APPL_NONE;
- *error_return = ENOENT;
- for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
- if(is_quoted) {
- lstrcpyn(fullPath, originalName+1, MAX_PATH - 7);
- len = strlen(fullPath);
- if(len > 0) {
- fullPath[len-1] = '\0';
- }
- } else {
- lstrcpyn(fullPath, originalName, MAX_PATH - 5);
- }
- lstrcat(fullPath, extensions[i]);
- SearchPath((search_in_path) ? NULL : ".", fullPath, NULL, MAX_PATH, fullPath, &rest);
-
- /*
- * Ignore matches on directories or data files, return if identified
- * a known type.
- */
-
- if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
- continue;
- }
-
- ext = strrchr(fullPath, '.');
- if ((ext != NULL) && (strcmpi(ext, ".bat") == 0)) {
- *error_return = EACCES;
- applType = APPL_DOS;
- break;
- }
-
- hFile = CreateFile(fullPath, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hFile == INVALID_HANDLE_VALUE) {
- continue;
- }
-
- *error_return = EACCES; /* If considered an error,
- it's an access error */
- header.e_magic = 0;
- ReadFile(hFile, (void *) &header, sizeof(header), &read, NULL);
- if (header.e_magic != IMAGE_DOS_SIGNATURE) {
- /*
- * Doesn't have the magic number for relocatable executables. If
- * filename ends with .com, assume it's a DOS application anyhow.
- * Note that we didn't make this assumption at first, because some
- * supposed .com files are really 32-bit executables with all the
- * magic numbers and everything.
- */
-
- CloseHandle(hFile);
- if ((ext != NULL) && (strcmpi(ext, ".com") == 0)) {
- applType = APPL_DOS;
- break;
- }
- continue;
- }
- if (header.e_lfarlc != sizeof(header)) {
- /*
- * All Windows 3.X and Win32 and some DOS programs have this value
- * set here. If it doesn't, assume that since it already had the
- * other magic number it was a DOS application.
- */
-
- CloseHandle(hFile);
- applType = APPL_DOS;
- break;
- }
-
- /*
- * The DWORD at header.e_lfanew points to yet another magic number.
- */
-
- buf[0] = '\0';
- SetFilePointer(hFile, header.e_lfanew, NULL, FILE_BEGIN);
- ReadFile(hFile, (void *) buf, 2, &read, NULL);
- CloseHandle(hFile);
-
- if ((buf[0] == 'L') && (buf[1] == 'E')) {
- applType = APPL_DOS;
- } else if ((buf[0] == 'N') && (buf[1] == 'E')) {
- applType = APPL_WIN3X;
- } else if ((buf[0] == 'P') && (buf[1] == 'E')) {
- applType = APPL_WIN32;
- } else {
- continue;
- }
- break;
- }
-
- if (applType == APPL_NONE) {
- return APPL_NONE;
- }
-
- if ((applType == APPL_DOS) || (applType == APPL_WIN3X)) {
- /*
- * Replace long path name of executable with short path name for
- * 16-bit applications. Otherwise the application may not be able
- * to correctly parse its own command line to separate off the
- * application name from the arguments.
- */
-
- GetShortPathName(fullPath, fullPath, MAX_PATH);
- }
- if (is_quoted) {
- /* restore quotes on quoted program name */
- len = strlen(fullPath);
- memmove(fullPath+1,fullPath,len);
- fullPath[0]='"';
- fullPath[len+1]='"';
- fullPath[len+2]='\0';
- }
- return applType;
-}
-
-static int application_type_w (const WCHAR *originalName, /* Name of the application to find. */
- WCHAR wfullpath[MAX_PATH],/* Filled with complete path to
+static int application_type (const wchar_t *originalName, /* Name of the application to find. */
+ wchar_t wfullpath[MAX_PATH],/* Filled with complete path to
* application. */
- BOOL search_in_path, /* If we should search the system wide path */
- BOOL handle_quotes, /* If we should handle quotes around executable */
- int *error_return) /* A place to put an error code */
+ BOOL search_in_path, /* If we should search the system wide path */
+ BOOL handle_quotes, /* If we should handle quotes around executable */
+ int *error_return) /* A place to put an error code */
{
int applType, i;
HANDLE hFile;
- WCHAR *ext, *rest;
+ wchar_t *ext, *rest;
char buf[2];
DWORD read;
IMAGE_DOS_HEADER header;
- static WCHAR extensions[][5] = {L"", L".com", L".exe", L".bat"};
+ static wchar_t extensions[][5] = {L"", L".com", L".exe", L".bat"};
int is_quoted;
int len;
- WCHAR xfullpath[MAX_PATH];
+ wchar_t xfullpath[MAX_PATH];
len = wcslen(originalName);
is_quoted = handle_quotes && len > 0 && originalName[0] == L'"' &&
@@ -2063,7 +1905,7 @@ static int application_type_w (const WCHAR *originalName, /* Name of the applica
if (is_quoted) {
/* restore quotes on quoted program name */
len = wcslen(wfullpath);
- memmove(wfullpath+1,wfullpath,len*sizeof(WCHAR));
+ memmove(wfullpath+1,wfullpath,len*sizeof(wchar_t));
wfullpath[0]=L'"';
wfullpath[len+1]=L'"';
wfullpath[len+2]=L'\0';
@@ -2915,7 +2757,7 @@ void erts_sys_free(ErtsAlcType_t t, void *x, void *p)
void *erts_sys_aligned_alloc(UWord alignment, UWord size)
{
void *ptr;
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
ptr = _aligned_malloc((size_t) size, (size_t) alignment);
ASSERT(!ptr || (((UWord) ptr) & (alignment - 1)) == 0);
return ptr;
@@ -2923,14 +2765,14 @@ void *erts_sys_aligned_alloc(UWord alignment, UWord size)
void erts_sys_aligned_free(UWord alignment, void *ptr)
{
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
_aligned_free(ptr);
}
void *erts_sys_aligned_realloc(UWord alignment, void *ptr, UWord size, UWord old_size)
{
void *new_ptr;
- ASSERT(alignment && (alignment & ~alignment) == 0); /* power of 2 */
+ ASSERT(alignment && (alignment & (alignment-1)) == 0); /* power of 2 */
new_ptr = _aligned_realloc(ptr, (size_t) size, (size_t) alignment);
ASSERT(!new_ptr || (((UWord) new_ptr) & (alignment - 1)) == 0);
return new_ptr;
@@ -3355,7 +3197,7 @@ void erl_sys_init(void)
noinherit_std_handle(STD_ERROR_HANDLE);
#ifdef ERTS_SMP
- erts_smp_tsd_key_create(&win32_errstr_key);
+ erts_smp_tsd_key_create(&win32_errstr_key,"win32_errstr_key");
InitializeCriticalSection(&htbc_lock);
#endif
erts_smp_atomic_init_nob(&pipe_creation_counter,0);