aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/vxworks
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /erts/etc/vxworks
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'erts/etc/vxworks')
-rw-r--r--erts/etc/vxworks/README.VxWorks350
-rw-r--r--erts/etc/vxworks/erl.exec.c129
-rw-r--r--erts/etc/vxworks/erl_io.c108
-rw-r--r--erts/etc/vxworks/erl_script.sam.in100
-rw-r--r--erts/etc/vxworks/heart_config.c60
-rw-r--r--erts/etc/vxworks/heart_config.h35
-rw-r--r--erts/etc/vxworks/rdate.c87
-rw-r--r--erts/etc/vxworks/reclaim.c551
-rw-r--r--erts/etc/vxworks/reclaim.h150
-rw-r--r--erts/etc/vxworks/reclaim_private.h44
-rw-r--r--erts/etc/vxworks/resolv.conf6
-rw-r--r--erts/etc/vxworks/vxcall.c145
-rw-r--r--erts/etc/vxworks/wd_example.c141
13 files changed, 1906 insertions, 0 deletions
diff --git a/erts/etc/vxworks/README.VxWorks b/erts/etc/vxworks/README.VxWorks
new file mode 100644
index 0000000000..299e35b513
--- /dev/null
+++ b/erts/etc/vxworks/README.VxWorks
@@ -0,0 +1,350 @@
+
+ %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%
+
+-----------------------------------------------------------------------
+README, Erlang/OTP R11B for VxWorks on PPC860 and PPC603
+-----------------------------------------------------------------------
+20060515 -- Patrik Nyblom, [email protected]
+
+R11B is a libraries only release for VxWorks. Only the libraries of
+erl_interface (ei+erl_inteface) and ic are expected to be used. Still
+the whole erlang system is distributed, although no support will be
+given for anything else but the libraries. The information in this
+file still applies to the full erlang distribution and parts of it are
+therefore somewhat irrelevant to commercial users.
+
+
+Included OTP applications
+-------------------------
+
+appmon
+asn1
+compiler
+cosEvent
+cosNotification
+cosTime
+cosTransaction
+debugger
+erl_interface
+erts
+eva [1]
+ic
+inets [2]
+jinterface
+kernel
+mesh
+mnemosyne
+mnesia [1]
+mnesia_session
+orber
+os_mon
+pman
+runtime_tools
+sasl
+snmp
+stdlib
+tools
+tv
+
+[1] Only ram_copies work, The VxWorks filesystems are not
+ reliable enough for disk_copies to be fully supported.
+[2] CGI scripts do not work on VxWorks.
+
+Omitted applications
+--------------------
+
+crypto
+emacs
+etk
+gs
+odbc
+parsetools
+toolbar
+ssl
+megaco
+webtools
+
+As `crypto' and `ssl' provides cryptographic functionality to `inets'
+and `snmp', the latter applications will not handle cryptography on
+VxWorks.
+
+Graphical interfaces
+--------------------
+
+For applications using graphical interfaces, only the backend part works.
+
+Compilers
+---------
+
+All compilers are expected to be run on a cross host. The VxWorks
+systems memory capabilities are too restricting to allow native
+compiling. The expected host system is a Sun Solaris machine, although
+Erlang compilation may be done on most platforms.
+
+Supported boards and configuration (only libraries supported)
+----------------------------------
+The following boards and configurations are supported:
+
+* Force PowerCore 603 with Force pcore603 BSP and VxWorks 3.5.1 (no
+ SENS or SENS 1.1 + SPR23938) and a minimum of 32 Mb memory.
+
+* Force Powercore 750 with Force pcore750 BSP and VxWorks 3.5.1 (no
+ SENS or SENS 1.1 + SPR23938) and a minimum of 32 Mb memory.
+
+* PSS Core PPC860 processors, only erl_interface (too small main memory).
+
+Most PowerPC boards with FPU are expected to work, but will need to be
+tested by OTP to be fully supported.
+
+The PPC603 build has been compiled with Wind River's `-mlongcall'
+flag (SPR25893) to support arbitrary function calls across more
+than 32 MB of memory.
+
+The PPC860 (PowerQuicc) has no FPU and requires a separate build.
+
+For Erlang to run, the Wind kernel has to be configured with a minimum
+of these variables defined in config.h (or by the Tornado
+configuration tool):
+
+ INCLUDE_ANSI_ALL
+ INCLUDE_ENV_VARS
+ INCLUDE_EXC_HANDLING
+ INCLUDE_EXC_TASK
+ INCLUDE_FLOATING_POINT
+ INCLUDE_FORMATTED_IO
+ INCLUDE_IO_SYSTEM
+ INCLUDE_LOADER
+ INCLUDE_NETWORK
+ INCLUDE_NET_INIT
+ INCLUDE_NET_SHOW
+ INCLUDE_NET_SYM_TBL or INCLUDE_STANDALONE_SYM_TBL
+ INCLUDE_PIPES
+ INCLUDE_POSIX_FTRUNC
+ INCLUDE_RLOGIN or INCLUDE_TELNET (for pty's only)
+ INCLUDE_SELECT
+ INCLUDE_SEM_BINARY
+ INCLUDE_SEM_COUNTING
+ INCLUDE_SEM_MUTEX
+ INCLUDE_SHELL (*)
+ INCLUDE_SHOW_ROUTINES
+ INCLUDE_SIGNALS
+ INCLUDE_STARTUP_SCRIPT (*)
+ INCLUDE_STDIO
+ INCLUDE_SYM_TBL
+ INCLUDE_TASK_HOOKS
+ INCLUDE_TASK_VARS
+ INCLUDE_TTY_DEV
+ INCLUDE_UNLOADER
+ INCLUDE_NFS or INCLUDE_RAMDRV or INCLUDE_DOSFS (i.e. a file system,
+ possibly read-only) (**)
+
+(*) Needed for the example startup script, not actually needed in production if
+ erlang is set up by a c routine called from usrConfig.c.
+(**) INCLUDE_NFS usually requires the NFS_USER_ID and NFS_GROUP_ID variables
+ to be set in config.h
+
+As an erlang system may open a lot of files, it is recommended to raise the
+default NUM_FILES variable to something like 256 in config.h like this:
+ #ifdef NUM_FILES
+ #undef NUM_FILES
+ #endif
+ #define NUM_FILES 256
+
+The SENS stack *has* to be of version 1.1 or higher, 1.0 is *not*
+supported and will not work reliably. Upgrades as well as the patch
+for SPR23938 can be found at www.wrs.com (i.e. WindSurf). Also, the
+following constants in $WIND_BASE/target/h/netBufLib.h has to be
+raised to a value of at least four times the default:
+
+ NUM_NET_MBLKS
+ NUM_64
+ NUM_128
+ NUM_256
+ NUM_512
+ NUM_1024
+ NUM_2048
+
+ NUM_SYS_64
+ NUM_SYS_128
+ NUM_SYS_256
+ NUM_SYS_512
+
+Use the show routines mbufShow and netStackSysPoolShow to verify that
+these pools are not exhausted.
+
+Installation
+------------
+
+To install Erlang on a VxWorks card, the following knowledge is
+expected:
+
+* VxWorks installation and configuration.
+
+* Network (TCP/IP) configuration.
+
+* Erlang basic operation and configuration.
+
+There is no specific install script for erlang on the VxWorks
+platform. There is however an example VxWorks startup file named
+erts-5.0.1/bin/erl_script.sam under the root of an unpacked
+release. There may of course be other things to do in the start
+script, like using the rdate program in the erlang distribution to get
+a correct date and set the TIMEZONE variable.
+
+Please consult the "Embedded System" documentation for further
+information on installation.
+
+Known Bugs and problems
+-----------------------
+
+We have found the VxWorks/NFS client file system to be unreliable.
+Important file operations like rename, ftruncate, cd and unlink
+doesn't always work as expected. Therefore more complex file using
+parts of OTP, like DETS and disk based mnesia tables cannot be used
+reliably with NFS. Lowering the NFS cache size (global variable
+nfsCacheSize) to 512 gives a more reliable NFS client, but to disk
+base the mnesia tables over NFS is still not a good idea, especially
+as disk based mnesia tables are not supported on VxWorks. Another
+problem with VxWorks file systems is that the error codes they produce
+are not consistent. We have worked around this problem by mapping the
+codes to POSIX ones, by doing this we make the VxWorks Erlang platform
+behave similarly to the UNIX and Windows implementations.
+
+The rename and ftruncate operations over NFS are emulated using
+copying of files. This is mainly for our own test suites and it is not
+recommended to use file:rename and/or file:ftruncate on NFS file
+systems in production.
+
+Floating point operations is somewhat faulty. For instance, testing
+floating point numbers for equality should be done with care. This is
+actually not a bug, IEEE specifies no equality among floating point
+numbers.
+
+Memory handling
+---------------
+
+Please read the erl_set_memory_block(3) manual page in the ERTS
+documentation for information concerning memory handling in the erlang
+emulator. Also please observe that reclaim.o has to be loaded and
+reclaim_init() called before any other erlang routines are loaded and
+started. If one wish to use the resource reclamation routines in other
+programs, refer to the header file in `erts-5.0.1/include/reclaim.h'.
+Including that file in your C source makes malloc/realloc/free and
+open/fopen/socket/close etc be redefined to routines that makes the
+memory and files be free'd/closed when the task exits. Still,
+reclaim_init() *has* to be called before any program that uses this is
+started.
+
+Using heart
+-----------
+
+The default behavior of the heart object file that is part of the
+distribution is that it reboots the target when the Erlang process
+hasn't given it a heart beat in 60 seconds. The normal heart beat rate
+is one beat per five seconds. This makes an effective "software
+watchdog" but there is really no substitute for the real thing --- a
+hardware watchdog. If you want to add a hardware watchdog to the
+system please contact us for directions. If you want to disable the
+reboot you may set the environment variable HEART_DONT_REBOOT (see the
+example erlang start script, erl). Please note that if you DO want the
+card to reboot you mustn't define HEART_DONT_REBOOT at all. E.g. to
+disable heart reboot you may include the following line in the start
+script (as is indeed the case with the example start script).
+
+ putenv "HEART_DONT_REBOOT=1"
+
+A few words on writing port program and dynamically loaded drivers for VxWorks
+------------------------------------------------------------------------------
+
+VxWorks has one name-space for all symbols. This makes it harder to
+write C programs whose global symbols doesn't interfere with each
+other. It is a good rule to avoid all globally visible symbols that
+are not absolutely necessary. Due to these facts we use the following
+naming rules that are crucial to follow. (there are more issues
+involved but the issues described here is a good beginning).
+
+Port programs must have a function with the same name as the object
+file. E.g. if you have an object file named `port_test.o' it must
+contain a globally visible function named `port_test'. This is the
+function that will be called when you output data from Erlang to the
+port. (The object file, in this example, should be named
+`port_test.o', but `port_test' will also do).
+
+Also, in an embedded system, it is recommended to load the port
+program into the system before the port program is used. This is to
+avoid the real time degradation dynamical linking in runtime would
+introduce. Use VxWorks command ld < "port_prg" to accomplish this.
+
+Dynamically linked drivers must have a function with the same name as
+the object file with the added suffix `_init'. We recommend the use of
+the macro DRIVER_INIT in `driver.h'. E.g. if you have an object file
+named `echo_drv.eld' it must contain a globally visible function
+`echo_drv_init'. (The object file, in this example, should be named
+`echo_drv.eld' (`eld' is short for Erlang Loadable Driver), but
+`echo_drv.o' and `echo_drv' will both also do). It is also very
+important to initialize all unused function pointer in the
+`driver_entry' struct to NULL (see example below).
+
+Example of dynamically linked driver
+------------------------------------
+
+#include <stdio.h>
+#include "driver.h"
+
+static int erlang_port;
+static long echo_start();
+static int echo_stop(), echo_read();
+
+static struct driver_entry echo_driver_entry = {
+ null_func,
+ echo_start,
+ echo_stop,
+ echo_read,
+ null_func,
+ null_func,
+ "echo_drv",
+ null_func
+};
+
+int DRIVER_INIT(echo_drv)(void *handle)
+{
+ erlang_port = -1;
+
+ echo_driver_entry.handle = handle;
+ return (int) &echo_driver_entry;
+}
+
+static long echo_start(long port,char *buf)
+{
+ if (erlang_port != -1) {
+ return -1;
+ }
+
+ erlang_port = port;
+ return port;
+}
+
+static int echo_read(long port, char *buf, int count)
+{
+ return driver_output(erlang_port, buf, count);
+}
+
+static int echo_stop()
+{
+ return erlang_port = -1;
+}
diff --git a/erts/etc/vxworks/erl.exec.c b/erts/etc/vxworks/erl.exec.c
new file mode 100644
index 0000000000..6b45ebaa39
--- /dev/null
+++ b/erts/etc/vxworks/erl.exec.c
@@ -0,0 +1,129 @@
+/*
+ * %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%
+ */
+/*
+ A simpified version of the 'erl.exec' "startup script".
+ Called (e.g. from VxWorks shell) with all arguments in a
+ single string, e.g.: erl "-name thisnode -s mymod myfunc".
+ These arguments are handled as in 'erl.exec':
+ -name
+ -sname
+ -noshell
+ -noinput
+ anything else is just passed on to the emulator. Note that there
+ is no automatic start of epmd, that -oldshell is implicit, and
+ that you need to set current directory appropriately if you want
+ auto-load of port programs
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef DEFAULT_HOMEDIR /* used if environment HOME isn't set */
+#define DEFAULT_HOMEDIR "/"
+#endif
+
+#define ARGLEN 2048 /* Total length of args passed to erl_main */
+#define ARGMAX 64 /* Max no of "extra" args */
+
+static char *erl_cmd = "erl_main -n ";
+
+static toomuch()
+{
+ fprintf(stderr, "erl: Too many arguments\n");
+ return(-1);
+}
+
+static toolittle(arg)
+char *arg;
+{
+ fprintf(stderr, "erl.exec: Missing argument for %s\n", arg);
+ return(-1);
+}
+
+erl_exec(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
+int arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10;
+{
+ char *shell = "-oldshell ", *noshell = "",
+ *home, *rootdir, *bindir, *progname;
+ char cmd[ARGLEN], eargs[ARGLEN], iargs[ARGLEN];
+ char *args[ARGMAX], *arglast = NULL, *argp;
+ int nargs = 0, len, i;
+
+ if ((rootdir = getenv("ROOTDIR")) == NULL ||
+ (bindir = getenv("BINDIR")) == NULL ||
+ (progname = getenv("PROGNAME")) == NULL) {
+ fprintf(stderr, "erl.exec: ROOTDIR, BINDIR, and PROGNAME must be set.");
+ return -1;
+ }
+ eargs[0] = '\0';
+ iargs[0] = '\0';
+ if ((home = getenv("HOME")) == NULL)
+ home = DEFAULT_HOMEDIR;
+ argp = strtok_r((char *)arg1, " \t", &arglast);
+ while (argp != NULL) {
+ if (strcmp(argp, "-name") == 0) {
+ if ((argp = strtok_r((char *)NULL, " \t", &arglast)) == NULL)
+ return(toolittle("-name"));
+ strcat(iargs, "-name ");
+ strcat(iargs, argp);
+ strcat(iargs, " ");
+ } else if (strcmp(argp, "-sname") == 0) {
+ if ((argp = strtok_r((char *)NULL, " \t", &arglast)) == NULL)
+ return(toolittle("-sname"));
+ strcat(iargs, "-sname ");
+ strcat(iargs, argp);
+ strcat(iargs, " ");
+ } else if (strcmp(argp, "-noshell") == 0) {
+ strcat(iargs, "-noshell -noinp_shell ");
+ } else if (strcmp(argp, "-noinput") == 0) {
+ strcat(iargs, "-noshell -noinput ");
+ } else {
+ if (nargs > ARGMAX - 1)
+ return(toomuch());
+ args[nargs++] = argp;
+ }
+ argp = strtok_r((char *)NULL, " \t", &arglast);
+ }
+ strcpy(cmd, erl_cmd);
+ strcat(cmd, eargs);
+ strcat(cmd, " -- -root ");
+ strcat(cmd, rootdir);
+ strcat(cmd, " -progname ");
+ strcat(cmd, progname);
+ strcat(cmd, " -- ");
+ strcat(cmd, "-home ");
+ strcat(cmd, home);
+ strcat(cmd, " ");
+ strcat(cmd, iargs);
+
+ len = strlen(cmd);
+ for (i = 0; i < nargs; i++) {
+ if (len + strlen(args[i]) + 2 >= ARGLEN)
+ return(toomuch());
+ cmd[len++] = ' ';
+ strcpy(&cmd[len], args[i]);
+ len += strlen(args[i]);
+ }
+ argcall(cmd);
+}
+
diff --git a/erts/etc/vxworks/erl_io.c b/erts/etc/vxworks/erl_io.c
new file mode 100644
index 0000000000..0032b77079
--- /dev/null
+++ b/erts/etc/vxworks/erl_io.c
@@ -0,0 +1,108 @@
+/*
+ * %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%
+ */
+/* Some stuff to let the Erlang and VxWorks shells coexist peacefully.
+ Basically, run Erlang as a spawned task with input redirected to
+ the slave side of a pseudo-tty, and connect explicitly to the master
+ side of the pseudo-tty to send input to Erlang when desired. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <stdio.h>
+#include <ioLib.h>
+#include <taskLib.h>
+#include <ptyDrv.h>
+
+extern int spTaskPriority, spTaskOptions;
+
+#define TBUFSIZ 512
+
+#define DEFAULT_STACK_SIZE 100000
+
+static int slavefd = -1, masterfd = -1;
+static run_erl();
+
+/* Frontend to the Erlang startup function - callable from VxWorks shell
+ or script. 'arg' is actually a string passed to the real startup. */
+start_erl(arg)
+int arg;
+{
+ int stacksize;
+ char *stackenv;
+
+ /* create and open the pty - we want the master side to be open
+ all the time, since closing it probably generates EOF on the
+ slave side */
+ (void)ptyDevCreate("/pty/erlang.", TBUFSIZ, TBUFSIZ);
+ if (slavefd != -1)
+ (void)close(slavefd);
+ slavefd = open("/pty/erlang.S", O_RDONLY, 0);
+ if (masterfd != -1)
+ (void)close(masterfd);
+ masterfd = open("/pty/erlang.M", O_WRONLY, 0);
+
+ /* flush any old leftover garbage */
+ (void) ioctl(masterfd, FIOFLUSH, 0);
+ if ((stackenv = getenv("ERLSTACKSIZE")) == NULL)
+ stacksize = DEFAULT_STACK_SIZE;
+ else
+ stacksize = atoi(stackenv);
+ /* spawn Erlang, via stub below */
+ return(taskSpawn("erlang", spTaskPriority, spTaskOptions, stacksize,
+ run_erl, arg, 0,0,0,0,0,0,0,0,0));
+}
+
+/* Little stub that runs in the spawned task - we need this to redirect
+ stdin reliably (redirections aren't "inherited" in VxWorks) */
+static
+run_erl(arg)
+int arg;
+{
+ ioTaskStdSet(0, 0, slavefd); /* redirect stdin to slave side of pty */
+
+ /* We don't want to redirect stdout/err since no one will be reading
+ from the master side (to_erl - and the open()s above - could be
+ made bidirectional, but still the master side would only be read
+ when to_erl was running), and output can eventually fill the pty
+ buffer and cause the Erlang system to block. Not redirecting
+ stdout/err will have the effect that output from Erlang, e.g. the
+ shell prompt, will appear on console/rlogin/whatever even when
+ to_erl isn't running, which may be confusing - can't win 'em all... */
+
+ erl_exec(arg, 0,0,0,0,0,0,0,0); /* call the real startup */
+}
+
+/* Function callable from VxWorks shell to talk to Erlang - stop talking
+ and return to VxWorks shell through ^D (EOF) */
+to_erl()
+{
+ char buf[TBUFSIZ];
+ int cc;
+
+ if (masterfd == -1) { /* sanity check */
+ fprintf(stderr, "Must start_erl first!\n");
+ return(-1);
+ }
+ while ((cc = read(0, buf, TBUFSIZ)) > 0) /* just pass everything through */
+ if (write(masterfd, buf, cc) != cc) {
+ fprintf(stderr, "Write to Erlang failed!\n");
+ return(-1);
+ }
+ return(cc);
+}
diff --git a/erts/etc/vxworks/erl_script.sam.in b/erts/etc/vxworks/erl_script.sam.in
new file mode 100644
index 0000000000..81c2b0128d
--- /dev/null
+++ b/erts/etc/vxworks/erl_script.sam.in
@@ -0,0 +1,100 @@
+#
+# %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%
+#
+#
+# erl_script.sam
+# Sample VxWorks script to start Erlang
+#
+# Note! This is not a complete or ready to use VxWorks startup script,
+# rather an example of what You should add to Your existing startupscript
+# to execute the erlang emulator at boot.
+#
+# When writing Your own script to start erlang, the paths to
+# the binaries have to be changed to reflect your system.
+#
+# The ROOTDIR variable should not point to a ftp or rcp filesystem unless
+# the erlang machine is run in embedded mode. Loading of modules
+# is far to slow if the erlang binaries are not placed on a real filesystem
+# like NFS or any type of local filesystem.
+#
+
+#
+# Load modules
+#
+
+#
+# First load and initiate the reclaim facility
+#
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/reclaim.o
+reclaim_init()
+
+#
+# Now load the runtime system
+#
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/jam
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/erl.exec
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/erl_io
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/vxcall
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/heart
+ld </home/tornado/erlvxworks/erts-%VSN%/bin/epmd
+
+#
+# Stack sizes
+#
+putenv "ERLSTACKSIZE=100000"
+putenv "ERLPORTSTACKSIZE=100000"
+
+#
+# Activate Round robin scheduling
+#
+kernelTimeSlice 1
+
+#
+# Distribution
+# The VxWorks machines host name
+sethostname "sb001", 5
+# Erlangs internal resolver
+putenv "ERLRESCONF=/home/tornado/erlvxworks/erts-%VSN%/bin/resolv.conf"
+
+#
+# Start epmd (for distribution)
+#
+start_epmd "-daemon"
+
+#
+# Misc environment variables
+#
+putenv "ROOTDIR=/home/tornado/erlvxworks"
+putenv "BINDIR=/home/tornado/erlvxworks/erts-%VSN%/bin"
+putenv "PROGNAME=erl"
+putenv "HOME=/home/tornado/erlvxworks"
+
+#
+# Set heart no reboot mode (to make heart reboot -
+# don't define HEART_DONT_REBOOT at all)
+#
+putenv "HEART_DONT_REBOOT=1"
+
+# To get fullsweep garbage collection on systems with
+# very limited memory, set ERL_FULLSWEEP_AFTER to "0":
+# putenv "ERL_FULLSWEEP_AFTER=0"
+
+#
+# Start Erlang/OTP
+#
+start_erl "-oldshell -heart -sname vxnode -setcookie switch -boot start_sasl"
diff --git a/erts/etc/vxworks/heart_config.c b/erts/etc/vxworks/heart_config.c
new file mode 100644
index 0000000000..7e60e61fbb
--- /dev/null
+++ b/erts/etc/vxworks/heart_config.c
@@ -0,0 +1,60 @@
+/*
+ * %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%
+ */
+/*
+ * A basic heart configure module for VxWorks.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <vxWorks.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <rebootLib.h>
+#include <sysLib.h>
+
+/* wd_init is executed to initialize a watchdog (if one is used). */
+int wd_init(timeout, prio)
+ int timeout, prio;
+{
+
+}
+
+/* wd_reset should be called every 5th second from heart */
+void wd_reset()
+{
+
+}
+
+/* This routine is called when erlang has closed */
+void heart_reboot()
+{
+ if (getenv("HEART_DONT_REBOOT") != NULL) {
+ fprintf(stderr, "heart_config: HEART_DONT_REBOOT set, no reboot ...\n");
+ } else {
+ fprintf(stderr, "heart_config: rebooting ...\n");
+ taskDelay(sysClkRateGet() * 5);
+ reboot(BOOT_CLEAR);
+ }
+}
+
+
+
+
diff --git a/erts/etc/vxworks/heart_config.h b/erts/etc/vxworks/heart_config.h
new file mode 100644
index 0000000000..5ffaaa8c3f
--- /dev/null
+++ b/erts/etc/vxworks/heart_config.h
@@ -0,0 +1,35 @@
+/*
+ * %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%
+ */
+/*
+ * This is heart's watchdog interface for VxWorks.
+ */
+
+#ifndef _HW_WATCHDOG_H
+#define _HW_WATCHDOG_H
+
+extern void wd_init(int timeout, int prio); /* wd_init initializes the
+ watchdog, if one is used. */
+extern void wd_reset(void); /* wd_reset is used by heart to kick
+ the watchdog, if one is used. */
+extern void heart_reboot(void); /* reboot is called if heart discovers
+ that the Erlang task has stopped sending
+ heart beats. It can log system status
+ and should reboot VxWorks. */
+
+#endif
diff --git a/erts/etc/vxworks/rdate.c b/erts/etc/vxworks/rdate.c
new file mode 100644
index 0000000000..3e8cc644d0
--- /dev/null
+++ b/erts/etc/vxworks/rdate.c
@@ -0,0 +1,87 @@
+/*
+ * %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%
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vxWorks.h>
+#include <timers.h>
+#ifdef NETDB
+#include <netdb.h>
+#endif
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/*
+ rdate("host") - Set the time from "host".
+*/
+
+/* No getservbyname() available... */
+#define TIME_PORT 37
+
+rdate(host)
+char *host;
+{
+ u_long haddr;
+#ifdef NETDB
+ struct hostent *hp;
+#endif
+ struct sockaddr_in saddr;
+ int sock;
+ u_long net_time;
+ struct timespec t;
+
+ if ((haddr = inet_addr(host)) == ERROR) {
+#ifdef NETDB
+ if ((hp = gethostbyname(host)) == NULL) {
+#else
+ if ((haddr = hostGetByName(host)) == ERROR) {
+#endif
+ printf("Host not found.\n");
+ return(-1);
+ }
+#ifdef NETDB
+ memcpy(&haddr, hp->h_addr, sizeof(haddr));
+#endif
+ }
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.sin_family = AF_INET;
+ memcpy(&saddr.sin_addr, &haddr, sizeof(haddr));
+ saddr.sin_port = htons(TIME_PORT);
+ if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ perror("socket");
+ return(-1);
+ }
+ if (connect(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
+ perror("connect");
+ close(sock);
+ return(-1);
+ }
+ if (read(sock, &net_time, 4) != 4) {
+ perror("read");
+ close(sock);
+ return(-1);
+ }
+ t.tv_sec = ntohl(net_time);
+ t.tv_sec -= 2208988800; /* seconds 1900-01-01 -- 1970-01-01 */
+ t.tv_nsec = 0;
+ clock_settime(CLOCK_REALTIME, &t);
+ close(sock);
+ return(0);
+}
diff --git a/erts/etc/vxworks/reclaim.c b/erts/etc/vxworks/reclaim.c
new file mode 100644
index 0000000000..d8676b3750
--- /dev/null
+++ b/erts/etc/vxworks/reclaim.c
@@ -0,0 +1,551 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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 <vxWorks.h>
+#include <version.h>
+#include <string.h>
+#include <types.h>
+#include <sigLib.h>
+#include <ioLib.h>
+#include <iosLib.h>
+#include <fioLib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <symLib.h>
+#include <sysLib.h>
+#include <sysSymTbl.h>
+#include <loadLib.h>
+#include <taskLib.h>
+#include <taskVarLib.h>
+#include <taskHookLib.h>
+#include <tickLib.h>
+#include <time.h>
+#include <rngLib.h>
+#include <semLib.h>
+#include <selectLib.h>
+#include <sockLib.h>
+#include <a_out.h>
+#include <wdLib.h>
+#include <timers.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <stdarg.h>
+
+#include <stdio.h>
+#include <math.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+
+#define RECLAIM_NO_ALIAS /* No #defines for open/malloc/fopen etc */
+#include "reclaim.h"
+#include "reclaim_private.h"
+
+#undef open
+#undef creat
+#undef socket
+#undef accept
+#undef close
+#undef fopen
+#undef fdopen
+#undef freopen
+#undef fclose
+/* XXX Should do opendir/closedir too... */
+#undef malloc
+#undef calloc
+#undef realloc
+#undef free
+#undef cfree
+
+#ifdef _ARCH_PPC
+#define MAX_FILES_SYM_NAME "maxFiles"
+#else
+#define MAX_FILES_SYM_NAME "_maxFiles"
+#endif
+
+
+/*
+ * Use another free() function upon task deletion?
+ * Note! When changing free function, the new free function will have to
+ * be able to cope with ALL previously used malloced areas, that is
+ * it has to be able to find out how things are malloced
+ * to free them in the right way!
+ */
+static FreeFunction reclaim_free_function = NULL;
+
+/* delete hook handling (see below) */
+static int hook_added = 0; /* Initated at first reclaim_init, an extra
+ non MT-safe check that we only get
+ initialized once */
+
+/* Forward... */
+static void save_reclaim(WIND_TCB *tcbp);
+
+struct mall_data {
+ struct mall_data *next;
+ char *self;
+};
+
+struct task_data {
+ FUNCPTR version; /* To recognize when we have reloaded */
+ int max_files; /* It may change... */
+ struct fd_set open_fds;
+ struct mall_data *mall_data;
+ FUNCPTR delete_hook;
+ caddr_t hook_data;
+ FILE *open_fps[1]; /* Will be max_files long */
+} *task_data = NULL;
+
+static int max_files = 50; /* default configAll.h */
+
+int reclaim_max_files(void)
+{
+ return max_files;
+}
+
+#ifdef DEBUG
+#define check_hook() \
+((task_data != NULL || \
+ fdprintf(2,"check_hook() TID = 0x%08x, Called from line %d\n", \
+ (unsigned int)taskIdSelf(),\
+ __LINE__)) && \
+(task_data != NULL || \
+ (taskVarAdd(0, (int *)&task_data) == OK && \
+ (task_data = (struct task_data *)\
+ calloc(1, sizeof(struct task_data) + max_files*sizeof(FILE *))) != NULL && \
+ (task_data->version = (FUNCPTR)save_reclaim) != NULL && \
+ (task_data->max_files = max_files) != 0 && \
+ fdprintf(2,"taskVar Added for 0x%08x\n",(unsigned int)taskIdSelf()))))
+#else
+#define check_hook() \
+(task_data != NULL || \
+ (taskVarAdd(0, (int *)&task_data) == OK && \
+ (task_data = (struct task_data *)\
+ calloc(1, sizeof(struct task_data) + max_files*sizeof(FILE *))) != NULL && \
+ (task_data->version = (FUNCPTR)save_reclaim) != NULL && \
+ (task_data->max_files = max_files) != 0))
+#endif
+
+/*
+ * Global initialization of the reclaim data structures, mainly
+ * the max_files variable. This HAS to be called by some task before
+ * the first task that utilizes this exit's, preferrably before any
+ * task makes the first use of this library.
+ */
+STATUS reclaim_init(void)
+{
+ int *mp;
+ SYM_TYPE type;
+ struct task_data *tdp;
+ int i;
+
+ if (!hook_added) {
+ /* race condition */
+ ++hook_added;
+ /* Try to find the maxFiles value */
+ if (symFindByNameAndType(sysSymTbl, MAX_FILES_SYM_NAME, (char **)&mp,
+ &type,
+ N_EXT | N_BSS, N_EXT | N_BSS) == OK ||
+ symFindByNameAndType(sysSymTbl, MAX_FILES_SYM_NAME, (char **)&mp,
+ &type,
+ N_EXT | N_DATA, N_EXT | N_DATA) == OK) {
+
+#ifdef DEBUG
+ fdprintf(2, "Found maxFiles=%d\n", *mp);
+#endif
+ if (*mp <= FD_SETSIZE)
+ max_files = *mp;
+ else
+ max_files = FD_SETSIZE;
+ }
+ if (task_data != NULL && task_data->max_files != max_files) {
+ /* fix our own iff we have one */
+ if ((tdp = (struct task_data *)
+ realloc(task_data, sizeof(struct task_data) +
+ max_files*sizeof(FILE *))) != NULL) {
+ task_data = tdp;
+ for (i = task_data->max_files; i < max_files; i++)
+ task_data->open_fps[i] = NULL;
+ task_data->max_files = max_files;
+ }
+ }
+ /* Make sure taskVariables are deleted AFTER our hook is run. */
+ taskVarInit();
+ if(taskDeleteHookAdd((FUNCPTR)save_reclaim) != OK) {
+ fprintf(stderr,
+ "Panic: taskDeleteHook cannot be added for reclaim.\n");
+ return ERROR;
+ }
+ return OK;
+ } else
+ return ERROR;
+}
+
+/* N.B.!! We do *not* execute in the context of the dying task here,
+ but rather that of tExcTask - we do get a pointer to the task's
+ TCB though - this pointer is in fact also the task's ID. */
+static void save_reclaim(WIND_TCB *tcbp)
+{
+ int i, var, oldfd;
+ struct task_data *tdp;
+ struct mall_data *mdp, *mdnextp;
+
+ if ((var = taskVarGet((int)tcbp, (int *)&task_data)) != ERROR &&
+ var != 0) {
+ tdp = (struct task_data *)var;
+ if (tdp->version == (FUNCPTR)save_reclaim) { /* Only handle our own */
+#ifdef DEBUG
+ fdprintf(2, "Reclaiming for task id 0x%x:\nFiles: ", (int)tcbp);
+#endif
+ /* Ugh! VxWorks doesn't even flush stdout/err - we need to
+ get at those (which are task-private of course, i.e. we
+ can't just do fflush(stdout) here) - we could be really
+ pedantic and try to redefine stdout/err (which "are"
+ function calls) too, snarfing the values when they are
+ used - but besides the overhead this is problematic since
+ they are actually #defines already... We'll peek in the
+ TCB instead (no documentation of course). And of course,
+ we must also meddle with the *file descriptor* indirections,
+ or we'll just flush out on tExcTask's descriptors... */
+ for (i = 1; i <= 2; i++) {
+ if (tcbp->taskStdFp[i] != NULL) {
+#ifdef DEBUG
+ fdprintf(2, "fflush(%s) ", i == 1 ? "stdout" : "stderr");
+#endif
+ oldfd = ioTaskStdGet(0, i);
+ ioTaskStdSet(0, i, tcbp->taskStd[i]);
+ fflush(tcbp->taskStdFp[i]);
+ ioTaskStdSet(0, i, oldfd);
+ }
+ }
+ for (i = 3; i < tdp->max_files; i++) {
+ if (FD_ISSET(i, &tdp->open_fds)) {
+#ifdef DEBUG
+ fdprintf(2, "close(%d) ", i);
+#endif
+ (void) close(i);
+ }
+ if (tdp->open_fps[i] != NULL) {
+#ifdef DEBUG
+ fdprintf(2, "fclose(%0x%x) ", (int)tdp->open_fps[i]);
+#endif
+ (void) fclose(tdp->open_fps[i]);
+ }
+ }
+ i = 0;
+ mdp = tdp->mall_data;
+ while (mdp != NULL) {
+ mdnextp = mdp->next;
+ if(reclaim_free_function != NULL)
+ (*reclaim_free_function)(mdp->self);
+ else
+ free(mdp->self);
+ i++;
+ mdp = mdnextp;
+ }
+#ifdef DEBUG
+ fdprintf(2, "\nFreeing memory: total %d mallocs\n", i);
+#endif
+
+ if (tdp->delete_hook != NULL) {
+#ifdef DEBUG
+ fdprintf(2, "Calling delete hook at 0x%08x\n", tdp->delete_hook);
+#endif
+ (*tdp->delete_hook)(tdp->hook_data);
+#ifdef DEBUG
+ fdprintf(2, "Called delete hook at 0x%08x\n", tdp->delete_hook);
+#endif
+ }
+#ifdef DEBUG
+ fdprintf(2, "Freeing own mem at 0x%08x\n", tdp);
+#endif
+ (void) free((char *)tdp);
+#ifdef DEBUG
+ fdprintf(2, "Freed own mem at 0x%08x, done (0x%08x)\n**********\n", tdp,
+ taskIdSelf());
+ checkStack(0);
+#endif
+ }
+ }
+#ifdef DEBUG
+ else
+ fdprintf(2, "No task data found for id 0x%x, var = %d\n", (int)tcbp, var);
+#endif
+}
+
+/*
+ * This sets another free function to be used by the task deletion hook.
+ * The free function HAS to be able to free ANY type of dynamically allocated
+ * memory that can be in the task data list of allocated memory, that is
+ * also memory that's allocated before the free function was set.
+ * A "user-supplied" free function is GLOBAL to the system!!!
+ * A race condition is present, a task delete hook may be running when this
+ * function is called, that may not be especially funny...
+ */
+void set_reclaim_free_function(FreeFunction f){
+ reclaim_free_function = f;
+}
+
+void save_delete_hook(FUNCPTR func, caddr_t parm)
+{
+ if (check_hook()) {
+ task_data->delete_hook = func;
+ task_data->hook_data = parm;
+ }
+}
+
+/*
+ * plain_malloc is only used by spawn_start; plain_free by call_proc;
+ * save_fd is used by both.
+ */
+void *plain_malloc(size_t size){
+ return(malloc(size));
+}
+
+void *plain_realloc(void *ptr, size_t size){
+ return(realloc(ptr, size));
+}
+
+void plain_free(void *ptr){
+ free(ptr);
+}
+
+void save_fd(int fd){
+ if (fd >= 0 && check_hook() && fd < task_data->max_files)
+ FD_SET(fd, &task_data->open_fds);
+}
+
+int save_open(char *path, int flags, /*mode_t mode*/ ...){
+ int fd;
+ mode_t mode = 0;
+ if(flags & O_CREAT){
+ va_list pvar;
+ va_start(pvar,flags);
+#ifdef __GNUC__
+#warning save_open() gives three known alignment warnings.
+#endif
+ mode = va_arg(pvar, mode_t);
+ va_end(pvar);
+ }
+ if ((fd = open(path, flags, mode)) >= 0 && check_hook())
+ FD_SET(fd, &task_data->open_fds);
+ return(fd);
+}
+
+int save_creat(char *path, int mode){
+ int fd;
+ if ((fd = creat(path, mode)) >= 0 && check_hook())
+ FD_SET(fd, &task_data->open_fds);
+ return(fd);
+}
+
+int save_socket(int domain, int type, int protocol){
+ int fd;
+ if ((fd = socket(domain, type, protocol)) >= 0 && check_hook())
+ FD_SET(fd, &task_data->open_fds);
+ return(fd);
+}
+
+int save_accept(int s, struct sockaddr *addr, int *addrlen){
+ int fd;
+ if ((fd = accept(s, addr, addrlen)) >= 0 && check_hook())
+ FD_SET(fd, &task_data->open_fds);
+ return(fd);
+}
+
+int save_close(int fd){
+ if (fd >= 0 && fd <= FD_SETSIZE && check_hook())
+ FD_CLR(fd, &task_data->open_fds);
+ return(close(fd));
+}
+
+/* The dealing with FILE *'s below isn't strictly correct, we assume
+ that one never has several pointing to the same fd - in the unlikely
+ event that one does, all but the last one opened is forgotten */
+FILE *save_fopen(const char *filename, char *type){
+ FILE *fp;
+
+ if ((fp = fopen(filename, type)) != NULL &&
+ check_hook() && fileno(fp) < task_data->max_files)
+ task_data->open_fps[fileno(fp)] = fp;
+ return(fp);
+}
+
+FILE *save_fdopen(int fd, char *type){
+ FILE *fp;
+
+ if ((fp = fdopen(fd, type)) != NULL &&
+ check_hook() && fileno(fp) < task_data->max_files) {
+ task_data->open_fps[fileno(fp)] = fp;
+ FD_CLR(fd, &task_data->open_fds);
+ }
+ return(fp);
+}
+
+FILE *save_freopen(char *filename, char *type, FILE *stream){
+ FILE *fp;
+
+ if (check_hook()) {
+ if(fileno(stream) < task_data->max_files &&
+ task_data->open_fps[fileno(stream)] == stream)
+ task_data->open_fps[fileno(stream)] = NULL;
+ if ((fp = freopen(filename, type, stream)) != NULL &&
+ fileno(fp) < task_data->max_files)
+ task_data->open_fps[fileno(fp)] = fp;
+ } else
+ fp = freopen(filename, type, stream);
+ return(fp);
+}
+
+int save_fclose(FILE *stream){
+ if (check_hook() && fileno(stream) < task_data->max_files &&
+ task_data->open_fps[fileno(stream)] == stream)
+ task_data->open_fps[fileno(stream)] = NULL;
+ return(fclose(stream));
+}
+
+/* We link all malloc'ed segments by adding a couple of pointers
+ at the *end* - that way we can return the address malloc gave
+ (need to make sure we align those pointers) */
+
+/*
+ #define MALL_MARGIN 32
+ #define save_mall_size(size) save_mall_size1((size) + 2 * MALL_MARGIN)
+ #define save_mall_size1(size) \
+ (((size) + sizeof(char *) - 1) & (unsigned long)(-sizeof(char*)))
+
+ #define save_mall_enq(ptr, mdp) save_mall_enq1((ptr), (mdp) - MALL_MARGIN)
+ #define save_mall_enq1(ptr, mdp) \
+ (((struct mall_data *)(mdp))->self = (ptr), \
+ ((struct mall_data *)(mdp))->next = task_data->mall_data, \
+ task_data->mall_data = (struct mall_data *)(mdp))
+*/
+#define save_mall_size(size) \
+(((size) + sizeof(char *) - 1) & (unsigned long)(-sizeof(char*)))
+#define save_mall_enq(ptr, mdp) \
+(((struct mall_data *)(mdp))->self = (ptr), \
+ ((struct mall_data *)(mdp))->next = task_data->mall_data, \
+ task_data->mall_data = (struct mall_data *)(mdp))
+
+
+#define save_mall_deq(ptr) { \
+ struct mall_data *mdp = task_data->mall_data, \
+ **prevnext = &task_data->mall_data; \
+ while (mdp != NULL && mdp->self != (ptr)) { \
+ prevnext = &mdp->next; \
+ mdp = mdp->next; \
+ } \
+ if (mdp != NULL) *prevnext = mdp->next; \
+}
+
+void *save_malloc2(size_t size, MallocFunction mf){
+ unsigned msize = save_mall_size(size);
+ char *ptr;
+
+ if ((ptr = (*mf)(msize + sizeof(struct mall_data))) != NULL &&
+ check_hook())
+ save_mall_enq((void *) ptr, (void *) (ptr + msize));
+ return((void *) ptr);
+}
+
+void *save_malloc(size_t size){
+ return save_malloc2(size, &malloc);
+}
+
+void *save_calloc2(size_t nelem, size_t elsize, CallocFunction cf){
+ unsigned msize = save_mall_size(nelem * elsize);
+ char *ptr;
+
+ if ((ptr = (*cf)(1, msize + sizeof(struct mall_data))) != NULL &&
+ check_hook())
+ save_mall_enq((void *) ptr, (void *) (ptr + msize));
+ return((void *) ptr);
+}
+
+void *save_calloc(size_t nelem, size_t elsize){
+ return save_calloc2(nelem,elsize,&calloc);
+}
+
+void *save_realloc2(void *optr, size_t size, ReallocFunction rf){
+ unsigned msize = save_mall_size(size);
+ char *ptr;
+
+ /* First we must dequeue the old save block, after that
+ we try to realloc, if that succeeds we enqueue the new
+ block, if it fails we have to enqueue the old one anew
+ so we must deduce the size of that old block first. */
+
+ struct mall_data *mdp0 = task_data->mall_data,
+ **prevnext0 = &task_data->mall_data;
+ while (mdp0 != NULL && mdp0->self != (((char *) optr))) {
+ prevnext0 = &mdp0->next;
+ mdp0 = mdp0->next;
+ }
+ /* mdp0 == NULL (can) mean that the block that is realloced
+ have been malloced with an (for example) ordinary malloc
+ (that is not a save_malloc). This is handled like: no dequeing
+ is done of that block, the new block is enqueued */
+ if (mdp0 != NULL)
+ save_mall_deq(((char *) optr));
+
+ if ((ptr = (*rf)(optr, msize + sizeof(struct mall_data))) != NULL &&
+ check_hook())
+ save_mall_enq((void *) ptr, (void *) (ptr + msize));
+ else if (mdp0 != NULL)
+ /* re-enqueue the old block that has just been dequeued */
+ save_mall_enq(((char *) optr), mdp0);
+
+ return((void *) ptr);
+}
+
+void *save_realloc(void *optr, size_t size){
+ return save_realloc2(optr,size,&realloc);
+}
+
+void save_free2(void *ptr, FreeFunction ff)
+{
+ if (check_hook())
+ save_mall_deq(((char *) ptr));
+ (*ff)(ptr);
+}
+
+void save_free(void *ptr){
+ save_free2(ptr,&free);
+}
+
+void save_cfree2(void *ptr, CfreeFunction cf)
+{
+ if (check_hook())
+ save_mall_deq(((char *)ptr));
+ (*cf)(ptr);
+}
+
+void save_cfree(void *ptr){
+ save_cfree2(ptr,&cfree);
+}
+
diff --git a/erts/etc/vxworks/reclaim.h b/erts/etc/vxworks/reclaim.h
new file mode 100644
index 0000000000..ca9aa8f6be
--- /dev/null
+++ b/erts/etc/vxworks/reclaim.h
@@ -0,0 +1,150 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#ifndef _RECLAIM_H
+#define _RECLAIM_H
+
+
+/* The Erlang release for VxWorks includes a simple mechanism for
+ "resource reclamation" at task exit - it allows replacement of the
+ functions that open/close "files" and malloc/free memory with versions
+ that keep track, to be able to "reclaim" file descriptors and memory
+ when a task exits (regardless of *how* it exits).
+
+ The interface to this mechanism is made available via this file,
+ with the following caveats:
+
+ - The interface may change (or perhaps even be removed, though that
+ isn't likely until VxWorks itself provides similar functionality)
+ in future releases - i.e. you must always use the version of this
+ file that comes with the Erlang release you are using.
+
+ - Disaster is guaranteed if you use the mechanism incorrectly (see
+ below for the correct way), e.g. allocate memory with the "tracking"
+ version of malloc() and free it with the "standard" version of free().
+
+ - The mechanism (of course) incurs some performance penalty - thus
+ for a simple program you may be better off with careful programming,
+ making sure that you do whatever close()/free()/etc calls that are
+ appropriate at all exit points (though if you need to guard against
+ taskDelete() etc, things get messy...).
+
+ To use the mechanism, simply program your application normally, i.e.
+ use open()/close()/malloc()/free() etc as usual, but #include this
+ file before any usage of the relevant functions. NOTE: To avoid the
+ "disaster" mentioned above, you *must* #include it in *all* (or none)
+ of the files that manipulate a particular file descriptor, allocated
+ memory area, etc.
+
+ Before any task that uses this utility is loaded (which includes the
+ erlang emulator), the reclaim.o object file has to be loaded and
+ the function reclaim_init() has to be called. reclaim_init should be called
+ only _ONCE_ in a systems lifetime and has only a primitive guard
+ against multiple calls (i.e. a global variable is checked). Therefore
+ the initialization should occur either in the start script of the system
+ or (even better) in the usrInit() part of system initialization. The
+ object file itself should be loaded only once, so linking it with the
+ kernel is a good idea, linking with each application is an extremely bad
+ dito. Make really sure that it's loaded _before_ any application that
+ uses it if You want to load it in the startup script.
+
+ If You dont want to have #define's for the posix/stdio names
+ of the file/memory operations (i.e. no #define malloc save_malloc etc),
+ #define RECLAIM_NO_ALIAS in Your source before reclaim.h is included.
+*/
+
+#include <vxWorks.h> /* STATUS, size_t */
+#include <sockLib.h> /* struct sockaddr */
+#include <memLib.h>
+#include <stdio.h> /* FILE */
+
+#if defined(__STDC__)
+#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \
+extern RetType FunName ParamList
+#define _RECLAIM_VOID_PTR void *
+#define _RECLAIM_VOID_PARAM void
+#define _RECLAIM_VOID_RETURN void
+#elif defined(__cplusplus)
+#define _RECLAIM_DECL_FUN(RetType, FunName, ParamList) \
+extern "C" RetType FunName ParamList
+#define _RECLAIM_VOID_PTR void *
+#define _RECLAIM_VOID_PARAM
+#define _RECLAIM_VOID_RETURN void
+#else
+#define _RECLAIM_DECL_FUN(RetType, FunName, Ignore) extern RetType FunName()
+#define DECLARE_FUNCTION_TYPE(RetType, Type, PList) typedef RetType (* Type)()
+#define _RECLAIM_VOID_PTR char *
+#define _RECLAIM_VOID_PARAM
+#define _RECLAIM_VOID_RETURN
+#endif /* __STDC__ / __cplusplus */
+
+/* Initialize the facility, on a per system basis. */
+_RECLAIM_DECL_FUN(STATUS, reclaim_init, (_RECLAIM_VOID_PARAM));
+
+/* File descriptor operations */
+_RECLAIM_DECL_FUN(int,save_open,(char *, int, ...));
+_RECLAIM_DECL_FUN(int,save_creat,(char *, int));
+_RECLAIM_DECL_FUN(int,save_socket,(int, int, int));
+_RECLAIM_DECL_FUN(int,save_accept,(int, struct sockaddr *, int *));
+_RECLAIM_DECL_FUN(int,save_close,(int));
+/* Interface to add an fd to what's reclaimed even though it's not open with
+ one of the above functions */
+_RECLAIM_DECL_FUN(_RECLAIM_VOID_RETURN, save_fd, (int fd));
+#ifndef RECLAIM_NO_ALIAS
+#define open save_open
+#define creat save_creat
+#define socket save_socket
+#define accept save_accept
+#define close save_close
+#endif
+/* Stdio file operations */
+_RECLAIM_DECL_FUN(FILE *, save_fopen, (const char *, char *));
+_RECLAIM_DECL_FUN(FILE *, save_fdopen, (int, char *));
+_RECLAIM_DECL_FUN(FILE *, save_freopen, (char *, char *, FILE *));
+_RECLAIM_DECL_FUN(int, save_fclose, (FILE *));
+/* XXX Should do opendir/closedir too... */
+#ifndef RECLAIM_NO_ALIAS
+#define fopen save_fopen
+#define fdopen save_fdopen
+#define freopen save_freopen
+#define fclose save_fclose
+#endif
+/* Memory allocation */
+_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_malloc, (size_t));
+_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_calloc, (size_t, size_t));
+_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, save_realloc,
+ (_RECLAIM_VOID_PTR, size_t));
+_RECLAIM_DECL_FUN(void, save_free, (_RECLAIM_VOID_PTR));
+_RECLAIM_DECL_FUN(void, save_cfree, (_RECLAIM_VOID_PTR));
+#ifndef RECLAIM_NO_ALIAS
+#define malloc save_malloc
+#define calloc save_calloc
+#define realloc save_realloc
+#define free save_free
+#define cfree save_cfree
+#endif
+/* Generic interfaces to malloc etc... */
+_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_malloc, (size_t));
+_RECLAIM_DECL_FUN(_RECLAIM_VOID_PTR, plain_realloc,
+ (_RECLAIM_VOID_PTR, size_t));
+_RECLAIM_DECL_FUN(void, plain_free, (_RECLAIM_VOID_PTR));
+#endif /* _RECLAIM_H */
+
+
+
+
diff --git a/erts/etc/vxworks/reclaim_private.h b/erts/etc/vxworks/reclaim_private.h
new file mode 100644
index 0000000000..4ed935bee2
--- /dev/null
+++ b/erts/etc/vxworks/reclaim_private.h
@@ -0,0 +1,44 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1998-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%
+ */
+#ifndef _RECLAIM_PRIVATE_H
+#define _RECLAIM_PRIVATE_H
+/*
+ * Private header for the reclaim facility, also included in the emulator.
+ */
+
+#include "reclaim.h"
+
+/* Typedefs for ANSI memory allocation function pointers */
+typedef void *(*MallocFunction)(size_t);
+typedef void *(*ReallocFunction)(void *, size_t);
+typedef void *(*CallocFunction)(size_t, size_t);
+typedef void (*FreeFunction)(void *);
+typedef STATUS (*CfreeFunction)(char *);
+
+/* Functions for internal use and use by the emulator */
+extern int reclaim_max_files(void);
+extern void set_reclaim_free_function(FreeFunction f);
+extern void save_delete_hook(FUNCPTR func, caddr_t parm);
+extern void *save_malloc2(size_t size, MallocFunction mf);
+extern void *save_calloc2(size_t nelem, size_t elsize, CallocFunction cf);
+extern void *save_realloc2(void *optr, size_t size, ReallocFunction rf);
+extern void save_free2(void *ptr, FreeFunction ff);
+extern void save_cfree2(void *ptr, CfreeFunction ff);
+
+#endif /* _RECLAIM_PRIVATE_H */
diff --git a/erts/etc/vxworks/resolv.conf b/erts/etc/vxworks/resolv.conf
new file mode 100644
index 0000000000..85c89d64c4
--- /dev/null
+++ b/erts/etc/vxworks/resolv.conf
@@ -0,0 +1,6 @@
+domain du.uab.ericsson.se
+nameserver 134.138.176.16
+nameserver 136.225.254.224
+nameserver 134.138.128.25
+search du.uab.ericsson.se uab.ericsson.se ericsson.se
+lookup bind file
diff --git a/erts/etc/vxworks/vxcall.c b/erts/etc/vxworks/vxcall.c
new file mode 100644
index 0000000000..3362d05fc5
--- /dev/null
+++ b/erts/etc/vxworks/vxcall.c
@@ -0,0 +1,145 @@
+/*
+ * %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%
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vxWorks.h>
+#include <symLib.h>
+#include <sysSymTbl.h>
+#include <a_out.h>
+
+extern char *malloc();
+static STATUS lookup();
+
+/*
+ Little utility to convert from Unix' argv,argv calling conventions to
+ VxWorks' arg0,arg1,arg2,...
+ Will do limited argument parsing - no parenthesis around nor commas
+ between the args, which may be "-enclosed strings (without \ escapes),
+ '-enclosed characters (also no \ escapes), integers, or symbols.
+*/
+
+int vxcall(argc, argv)
+int argc;
+char **argv;
+{
+ int vxarg[10]; /* Max 10 args can be passed */
+ FUNCPTR entry;
+ SYM_TYPE type;
+ int i, l;
+
+#ifdef DEBUG
+ fdprintf(2, "vxcall:");
+ for (i = 1; i < argc; i++)
+ fdprintf(2, " %s", argv[i]);
+ fdprintf(2, "\n");
+#endif
+ if (lookup(argv[1], N_EXT | N_TEXT, (char **)&entry) != OK)
+ return(ERROR);
+ /* Do limited "C" parsing of the args */
+ for (i = 0; i < 10; i++) {
+ if (i < argc - 2) {
+ switch (argv[i+2][0]) {
+ case '"':
+ l = strlen(argv[i+2]) - 1;
+ if (argv[i+2][l] != '"')
+ return(ERROR);
+ /* just strip the quotes - should do \escapes within... */
+ vxarg[i] = (int)&argv[i+2][1];
+ argv[i+2][l] = '\0';
+ break;
+ case '\'':
+ if (argv[i+2][2] != '\'')
+ return(ERROR);
+ vxarg[i] = argv[i+2][1]; /* should do \escapes... */
+ break;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ vxarg[i] = atoi(argv[i+2]); /* should do octal, hex, float.. */
+ break;
+ default:
+ if (lookup(argv[i+2], 0, (char **)&vxarg[i]) != OK)
+ return(ERROR);
+ }
+ } else
+ vxarg[i] = 0;
+ }
+#ifdef DEBUG
+ fdprintf(2, "calling 0x%x(0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x)\n",
+ entry, vxarg[0], vxarg[1], vxarg[2], vxarg[3], vxarg[4],
+ vxarg[5], vxarg[6], vxarg[7], vxarg[8], vxarg[9]);
+#endif
+ return((*entry)(vxarg[0], vxarg[1], vxarg[2], vxarg[3], vxarg[4],
+ vxarg[5], vxarg[6], vxarg[7], vxarg[8], vxarg[9]));
+}
+
+/* Entry point for unix:cmd in post-4.1 erlang - uses "sh -c 'cmd...'" */
+int sh(argc, argv)
+int argc;
+char **argv;
+{
+ int ll = strlen(argv[argc-1]) - 1;
+
+#ifdef DEBUG
+ int i;
+ fdprintf(2, "sh:");
+ for (i = 1; i < argc; i++)
+ fdprintf(2, " %s", argv[i]);
+ fdprintf(2, "\n");
+#endif
+ if (strcmp(argv[1], "-c") != 0 ||
+ argv[2][0] != '\'' || argv[argc-1][ll] != '\'')
+ return(ERROR);
+ argv[argc-1][ll] = '\0'; /* delete trailing ' */
+ argv[2]++; /* skip leading ' (*after* the above!) */
+ return(vxcall(argc-1, argv+1));
+}
+
+/* Lookup symbol; get address for text symbols, value (assuming int)
+ otherwise; return OK or ERROR on failure
+ Symbol name is null-terminated and without the leading '_' */
+STATUS
+lookup(sym, stype, value)
+char *sym, **value;
+int stype;
+{
+ char buf[256];
+ char *symname = buf;
+ int len, ret;
+ SYM_TYPE type;
+
+ len = strlen(sym);
+ if (len > 254 && (symname = malloc(len+2)) == NULL)
+ return(ERROR);
+#if defined _ARCH_PPC || defined SIMSPARCSOLARIS
+ /* GCC for PPC or SIMSPARC doesn't add a leading _ to symbols */
+ strcpy(symname, sym);
+#else
+ sprintf(symname, "_%s", sym);
+#endif
+ ret = (stype != 0) ?
+ symFindByNameAndType(sysSymTbl, symname, value, &type, stype, stype) :
+ symFindByName(sysSymTbl, symname, value, &type);
+ if (symname != buf)
+ free(symname);
+ if (ret == OK && (type & N_TEXT) == 0) /* get value */
+ *value = (char *)*((int *)*value);
+ return(ret);
+}
diff --git a/erts/etc/vxworks/wd_example.c b/erts/etc/vxworks/wd_example.c
new file mode 100644
index 0000000000..0e3a6a1cb2
--- /dev/null
+++ b/erts/etc/vxworks/wd_example.c
@@ -0,0 +1,141 @@
+/*
+ * %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%
+ */
+/*
+ * File: frc5te_wd.c
+ * Purpose: Watchdog NMI handling for FORCE 5TE
+ *
+ * Description:
+ * The watchdog handler routines are system specific. A program that
+ * wants to utilize a hardware watchdog should call wd_init and test
+ * the return value. If wd_init returns true (!0); there is a hardware
+ * watchdog, and that watchdog has been activated. If no watchdog exists,
+ * wd_init returns false (0).
+ *
+ * To keep the watchdog happy, call wd_reset at least every X seconds,
+ * where X is the number of seconds specified in the call to wd_init.
+ *
+ * The watchdog can be disarmed by setting the variable wd_disarmed to 1,
+ * and armed again by setting the same variable to 0. Watchdog status
+ * information can be retrieved using the function wd_status.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include <frc5e.h>
+#include <logLib.h>
+#include <taskLib.h>
+#include <sysLib.h>
+#include <stdio.h>
+#include "hw_watchdog.h"
+
+/* prototypes */
+extern sysNMIConnect();
+#ifdef __STDC__
+void wd_keeper(int);
+void wd_nmi_int(UINT8);
+void wd_status(void);
+#else
+void wd_keeper();
+void wd_nmi_int();
+void wd_status();
+#endif
+
+#define WD_NMI_MIN_DELAY 0.830 /* Min time before watchdog NMI (in seconds) */
+#define WD_RESET_FREQUENCY (WD_NMI_MIN_DELAY / 2) /* how often the timer is reset */
+
+#define WD_KEEPER_STACK_SIZE 10000
+
+/* global variables */
+extern int spTaskOptions;
+static volatile int wd_count_startval; /* start value set by wd_init */
+static volatile int wd_count; /* counter for wd_keeper */
+volatile int wd_disarmed = 0; /* debug feature */
+
+/* wd_init is executed to initialize the watchdog. It spawns the task */
+/* wd_keeper and returns true (non-zero) if a hardware watchdog exists, */
+/* or returns false (zero) otherwise. */
+int wd_init(timeout, prio)
+ int timeout, prio;
+{
+ taskSpawn("wd_keeper", prio, spTaskOptions, WD_KEEPER_STACK_SIZE,
+ (FUNCPTR)wd_keeper, timeout,0,0,0,0,0,0,0,0,0);
+ return !0; /* watchdog exists */
+}
+
+
+/* wd_reset is called as an alive-signal from the supervisor process. */
+/* If there is no call to this function within a certain time, the */
+/* watchdog will reboot the system. */
+void wd_reset()
+{
+ wd_count = wd_count_startval;
+}
+
+
+/* wd_keeper runs as a separate task and resets the watchdog timer */
+/* before an NMI is generated. This task uses the counter wd_count to */
+/* decide if it should exit or keep resetting the timer. */
+/* Note! This task must run with higher priority than the application! */
+void wd_keeper(timeout)
+ int timeout;
+{
+ int wd_delay = sysClkRateGet() * WD_RESET_FREQUENCY;
+ wd_count_startval = (int)(timeout / WD_RESET_FREQUENCY);
+ wd_count = wd_count_startval;
+
+ /* Connect and enable level 15 interrupts */
+ sysNMIConnect((VOIDFUNCPTR) wd_nmi_int, WD_NMI, WD_NMI);
+ *(char *)FRC5CE_GEN_PURPOSE2_REG |= FRC5CE_NMI_ENABLE;
+
+ while ((wd_count > 0) || wd_disarmed) {
+ *(char *)FRC5CE_VME_A32MAP_REG |= FRC5CE_WATCHDOG_ENABLE;
+ taskDelay(wd_delay);
+ if (!wd_disarmed) wd_count--;
+ else wd_count = wd_count_startval;
+ }
+ logMsg("Watchdog keeper exits. No alive signal from application in %d seconds.\n",wd_count_startval * WD_RESET_FREQUENCY,0,0,0,0,0);
+}
+
+
+/* wd_nmi_int is the function connected to the watchdog interrupt. */
+/* It will report the failure to reset the watchdog timer. */
+void wd_nmi_int(type)
+ UINT8 type;
+{
+ switch(type) {
+ case WD_NMI:
+ logMsg("Watchdog interrupt! System will reboot.\n",0,0,0,0,0,0);
+ break;
+ default:
+ logMsg("Bad type (%d) in call to watchdog interrupt handler.\n",type,0,0,0,0,0);
+ break;
+ }
+}
+
+
+/* wd_status displays the current value of the counter. */
+void wd_status()
+{
+ fprintf(stderr, "Watchdog is %sarmed.\n", wd_disarmed ? "dis" : "");
+ fprintf(stderr, "Counter value: %d\n", wd_count);
+ fprintf(stderr, "Start value is: %d (%d seconds)\n",
+ wd_count_startval, (int)(wd_count_startval * WD_RESET_FREQUENCY));
+}