aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/port_SUITE_data
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/port_SUITE_data')
-rw-r--r--erts/emulator/test/port_SUITE_data/Makefile.src26
-rw-r--r--erts/emulator/test/port_SUITE_data/dir/dummy1
-rw-r--r--erts/emulator/test/port_SUITE_data/echo_args.c12
-rw-r--r--erts/emulator/test/port_SUITE_data/echo_drv.c85
-rw-r--r--erts/emulator/test/port_SUITE_data/exit_drv.c68
-rw-r--r--erts/emulator/test/port_SUITE_data/failure_drv.c63
-rw-r--r--erts/emulator/test/port_SUITE_data/port_test.c605
-rw-r--r--erts/emulator/test/port_SUITE_data/port_test.erl36
-rw-r--r--erts/emulator/test/port_SUITE_data/reclaim.h60
9 files changed, 956 insertions, 0 deletions
diff --git a/erts/emulator/test/port_SUITE_data/Makefile.src b/erts/emulator/test/port_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..d97b37c9ae
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/Makefile.src
@@ -0,0 +1,26 @@
+CC = @CC@
+LD = @LD@
+CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
+CROSSLDFLAGS = @CROSSLDFLAGS@
+
+PROGS = port_test@exe@ echo_args@exe@
+DRIVERS = echo_drv@dll@ exit_drv@dll@ failure_drv@dll@
+
+all: $(PROGS) $(DRIVERS) port_test.@EMULATOR@
+
+port_test@exe@: port_test@obj@
+ $(LD) $(CROSSLDFLAGS) -o port_test port_test@obj@ @LIBS@
+
+port_test@obj@: port_test.c
+ $(CC) -c -o port_test@obj@ $(CFLAGS) port_test.c
+
+echo_args@exe@: echo_args@obj@
+ $(LD) $(CROSSLDFLAGS) -o echo_args echo_args@obj@ @LIBS@
+
+echo_args@obj@: echo_args.c
+ $(CC) -c -o echo_args@obj@ $(CFLAGS) echo_args.c
+
+port_test.@EMULATOR@: port_test.erl
+ @erl_name@ -compile port_test
+
+@SHLIB_RULES@
diff --git a/erts/emulator/test/port_SUITE_data/dir/dummy b/erts/emulator/test/port_SUITE_data/dir/dummy
new file mode 100644
index 0000000000..442071915b
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/dir/dummy
@@ -0,0 +1 @@
+Dumma WinZip!!
diff --git a/erts/emulator/test/port_SUITE_data/echo_args.c b/erts/emulator/test/port_SUITE_data/echo_args.c
new file mode 100644
index 0000000000..91dca8993f
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/echo_args.c
@@ -0,0 +1,12 @@
+#include <stdio.h>
+
+int main(int argc, char **argv)
+{
+ int i;
+
+ for(i = 0; i < argc; ++i) {
+ printf("argv[%d]:|%s|\n",i,argv[i]);
+ }
+ return 0;
+}
+
diff --git a/erts/emulator/test/port_SUITE_data/echo_drv.c b/erts/emulator/test/port_SUITE_data/echo_drv.c
new file mode 100644
index 0000000000..25eda116fe
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/echo_drv.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include "erl_driver.h"
+
+
+
+/* -------------------------------------------------------------------------
+** Data types
+**/
+
+typedef struct _erl_drv_data EchoDrvData;
+
+
+
+/* -------------------------------------------------------------------------
+** Entry struct
+**/
+
+static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command);
+static void echo_drv_stop(EchoDrvData *data_p);
+static void echo_drv_output(EchoDrvData *data_p, char *buf, int len);
+static void echo_drv_finish(void);
+static int echo_drv_control(EchoDrvData *data_p, unsigned int command,
+ char *buf, int len,
+ char **rbuf, int rlen);
+
+static ErlDrvEntry echo_drv_entry = {
+ NULL, /* init */
+ echo_drv_start,
+ echo_drv_stop,
+ echo_drv_output,
+ NULL, /* ready_input */
+ NULL, /* ready_output */
+ "echo_drv",
+ echo_drv_finish,
+ NULL, /* handle */
+ echo_drv_control,
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL /* ready_async */
+};
+
+
+
+/* -------------------------------------------------------------------------
+** Entry functions
+**/
+
+DRIVER_INIT(echo_drv)
+{
+ return &echo_drv_entry;
+}
+
+static EchoDrvData *echo_drv_start(ErlDrvPort port, char *command) {
+ void *void_ptr;
+ int res = -4711;
+ if (command) {
+ while(*command != '\0' && *command != ' ')
+ ++command;
+ while(*command != '\0' && *command == ' ')
+ ++command;
+ if(*command == '-') {
+ res = driver_output(port, command+1, strlen(command) - 1);
+ }
+ }
+ return void_ptr = port;
+}
+
+static void echo_drv_stop(EchoDrvData *data_p) {
+}
+
+static void echo_drv_output(EchoDrvData *data_p, char *buf, int len) {
+ void *void_ptr;
+ ErlDrvPort port = void_ptr = data_p;
+
+ driver_output(port, buf, len);
+}
+
+static void echo_drv_finish() {
+}
+
+static int echo_drv_control(EchoDrvData *data_p, unsigned int command,
+ char *buf, int len,
+ char **rbuf, int rlen) {
+ return 0;
+}
diff --git a/erts/emulator/test/port_SUITE_data/exit_drv.c b/erts/emulator/test/port_SUITE_data/exit_drv.c
new file mode 100644
index 0000000000..60f1b321bd
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/exit_drv.c
@@ -0,0 +1,68 @@
+#include <stdlib.h>
+#include "erl_driver.h"
+
+typedef struct _erl_drv_data ExitDrvData;
+
+static ExitDrvData *exit_drv_start(ErlDrvPort port, char *command);
+static void exit_drv_stop(ExitDrvData *data_p);
+static void exit_drv_output(ExitDrvData *data_p, char *buf, int len);
+static void exit_drv_finish(void);
+static int exit_drv_control(ExitDrvData *data_p, unsigned int command,
+ char *buf, int len,
+ char **rbuf, int rlen);
+
+static ErlDrvEntry exit_drv_entry = {
+ NULL, /* init */
+ exit_drv_start,
+ exit_drv_stop,
+ exit_drv_output,
+ NULL, /* ready_input */
+ NULL, /* ready_output */
+ "exit_drv",
+ exit_drv_finish,
+ NULL, /* handle */
+ exit_drv_control,
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL /* ready_async */
+};
+
+DRIVER_INIT(exit_drv)
+{
+ return &exit_drv_entry;
+}
+
+static ExitDrvData *
+exit_drv_start(ErlDrvPort port, char *command)
+{
+ return (ExitDrvData *) port;
+}
+
+static void
+exit_drv_stop(ExitDrvData *datap)
+{
+
+}
+
+static void
+exit_drv_output(ExitDrvData *datap, char *buf, int len)
+{
+ driver_exit((ErlDrvPort) datap, 0);
+}
+
+static void
+exit_drv_finish(void)
+{
+
+}
+
+static int
+exit_drv_control(ExitDrvData *datap,
+ unsigned int command,
+ char *buf,
+ int len,
+ char **rbuf,
+ int rlen)
+{
+ return 0;
+}
diff --git a/erts/emulator/test/port_SUITE_data/failure_drv.c b/erts/emulator/test/port_SUITE_data/failure_drv.c
new file mode 100644
index 0000000000..34d48e00f8
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/failure_drv.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include "erl_driver.h"
+
+typedef struct _erl_drv_data FailureDrvData;
+
+static FailureDrvData *failure_drv_start(ErlDrvPort, char *);
+static void failure_drv_stop(FailureDrvData *);
+static void failure_drv_output(FailureDrvData *, char *, int);
+static void failure_drv_finish(void);
+static int failure_drv_control(FailureDrvData *, unsigned int,
+ char *, int, char **, int);
+
+static ErlDrvEntry failure_drv_entry = {
+ NULL, /* init */
+ failure_drv_start,
+ failure_drv_stop,
+ failure_drv_output,
+ NULL, /* ready_input */
+ NULL, /* ready_output */
+ "failure_drv",
+ failure_drv_finish,
+ NULL, /* handle */
+ failure_drv_control,
+ NULL, /* timeout */
+ NULL, /* outputv */
+ NULL /* ready_async */
+};
+
+
+
+/* -------------------------------------------------------------------------
+** Entry functions
+**/
+
+DRIVER_INIT(failure_drv)
+{
+ return &failure_drv_entry;
+}
+
+static FailureDrvData *failure_drv_start(ErlDrvPort port, char *command) {
+ void *void_ptr;
+
+ return void_ptr = port;
+}
+
+static void failure_drv_stop(FailureDrvData *data_p) {
+}
+
+static void failure_drv_output(FailureDrvData *data_p, char *buf, int len) {
+ void *void_ptr;
+ ErlDrvPort port = void_ptr = data_p;
+
+ driver_failure_atom(port, "driver_failed");
+}
+
+static void failure_drv_finish() {
+}
+
+static int failure_drv_control(FailureDrvData *data_p, unsigned int command,
+ char *buf, int len,
+ char **rbuf, int rlen) {
+ return 0;
+}
diff --git a/erts/emulator/test/port_SUITE_data/port_test.c b/erts/emulator/test/port_SUITE_data/port_test.c
new file mode 100644
index 0000000000..7b4e386d87
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/port_test.c
@@ -0,0 +1,605 @@
+/*
+ * Author: Bjorn Gustavsson
+ * Purpose: A port program to be used for testing the open_port bif.
+ */
+
+#ifdef VXWORKS
+#include <vxWorks.h>
+#include <taskVarLib.h>
+#include <taskLib.h>
+#include <sysLib.h>
+#include <string.h>
+#include <ioLib.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifndef __WIN32__
+#include <unistd.h>
+
+#ifdef VXWORKS
+#include "reclaim.h"
+#include <sys/times.h>
+#else
+#include <sys/time.h>
+#endif
+
+#define O_BINARY 0
+#define _setmode(fd, mode)
+#endif
+
+#ifdef __WIN32__
+#include "windows.h"
+#include "winbase.h"
+#endif
+
+
+#ifdef VXWORKS
+#define REDIR_STDOUT(fd) ioTaskStdSet(0, 1, fd);
+#else
+#define REDIR_STDOUT(fd) if (dup2(fd, 1) == -1) { \
+ fprintf(stderr, "%s: failed to duplicate handle %d to 1: %d\n", \
+ port_data->progname, fd, errno); \
+ exit(1); \
+}
+#endif
+
+#ifdef VXWORKS
+#define MAIN(argc, argv) port_test(argc, argv)
+#else
+#define MAIN(argc, argv) main(argc, argv)
+#endif
+
+
+extern int errno;
+
+typedef struct {
+ char* progname; /* Name of this program (from argv[0]). */
+ int header_size; /* Number of bytes in each packet header:
+ * 1, 2, or 4, or 0 for a continous byte stream. */
+ int fd_from_erl; /* File descriptor from Erlang. */
+ int fd_to_erl; /* File descriptor to Erlang. */
+ unsigned char* io_buf; /* Buffer for file i/o. */
+ int io_buf_size; /* Current size of i/o buffer. */
+ int delay_mode; /* If set, this program will wait 5 seconds
+ * after reading the header for a packet
+ * before reading the rest.
+ */
+ int break_mode; /* If set, this program will close standard
+ * input, which should case broken pipe
+ * error in the writer.
+ */
+ int quit_mode; /* If set, this program will exit
+ * just after reading the packet header.
+ */
+ int slow_writes; /* Writes back the reply in chunks with
+ * sleeps in between. The value is the
+ * chunk size. If 0, normal writes are done.
+ */
+ char* output_file; /* File into which the result will be written. */
+ int no_packet_loop; /* No packet loop. */
+
+ int limited_bytecount; /* Only answer a limited number of bytes, then exit (stream mode) */
+
+} PORT_TEST_DATA;
+
+PORT_TEST_DATA* port_data;
+
+static int packet_loop();
+static void reply();
+static void write_reply();
+static void ensure_buf_big_enough();
+static int readn();
+static void delay(unsigned ms);
+static void dump(unsigned char* buf, int sz, int max);
+static void replace_stdout(char* filename);
+static void generate_reply(char* spec);
+
+#ifndef VXWORKS
+#ifndef HAVE_STRERROR
+extern int sys_nerr;
+#ifndef sys_errlist /* sys_errlist is sometimes defined to
+ call a function on win32 */
+extern char *sys_errlist[];
+#endif
+
+char*
+strerror(err)
+int err;
+{
+ static char msgstr[1024];
+
+ if (err == 0) {
+ msgstr[0] = '\0';
+ } else if (0 < err && err < sys_nerr) {
+ strcpy(msgstr, sys_errlist[err]);
+ } else {
+ sprintf(msgstr, "Unknown error %d", err);
+ }
+ return msgstr;
+}
+#endif
+#endif
+
+
+MAIN(argc, argv)
+int argc;
+char *argv[];
+{
+ int ret;
+#ifdef VXWORKS
+ if(taskVarAdd(0, (int *)&port_data) != OK) {
+ fprintf(stderr, "Can't do taskVarAdd in port_test\n");
+ exit(1);
+ }
+#endif
+ if((port_data = (PORT_TEST_DATA *) malloc(sizeof(PORT_TEST_DATA))) == NULL) {
+ fprintf(stderr, "Couldn't malloc for port_data");
+ exit(1);
+ }
+ port_data->header_size = 0;
+ port_data->io_buf_size = 0;
+ port_data->delay_mode = 0;
+ port_data->break_mode = 0;
+ port_data->quit_mode = 0;
+ port_data->slow_writes = 0;
+ port_data->output_file = NULL;
+ port_data->no_packet_loop = 0;
+
+ port_data->progname = argv[0];
+ port_data->fd_from_erl = 0;
+ port_data->fd_to_erl = 1;
+
+ port_data->limited_bytecount = 0;
+
+ _setmode(0, _O_BINARY);
+ _setmode(1, _O_BINARY);
+
+ while (argc > 1 && argv[1][0] == '-') {
+ switch (argv[1][1]) {
+ case 'b': /* Break mode. */
+ port_data->break_mode = 1;
+ break;
+ case 'c': /* Close standard output. */
+ close(port_data->fd_to_erl);
+ break;
+ case 'd': /* Delay mode. */
+ port_data->delay_mode = 1;
+ break;
+ case 'e':
+ port_data->fd_to_erl = 2;
+ break;
+ case 'h': /* Header size for packets. */
+ switch (argv[1][2]) {
+ case '0': port_data->header_size = 0; break;
+ case '1': port_data->header_size = 1; break;
+ case '2': port_data->header_size = 2; break;
+ case '4': port_data->header_size = 4; break;
+ case '\0':
+ fprintf(stderr, "%s: missing header size for -h\n", port_data->progname);
+ return 1;
+ default:
+ fprintf(stderr, "%s: illegal packet header size: %c\n",
+ port_data->progname, argv[1][2]);
+ return 1;
+ }
+ break;
+ case 'l':
+ port_data->limited_bytecount = atoi(argv[1]+2);
+ break;
+ case 'n': /* No packet loop. */
+ port_data->no_packet_loop = 1;
+ break;
+ case 'o': /* Output to file. */
+ port_data->output_file = argv[1]+2;
+ break;
+ case 'q': /* Quit mode. */
+ port_data->quit_mode = 1;
+ break;
+ case 'r': /* Generate reply. */
+ generate_reply(argv[1]+2);
+ break;
+ case 's': /* Slow writes. */
+ port_data->slow_writes = atoi(argv[1]+2);
+ break;
+ default:
+ fprintf(stderr, "Unrecognized switch: %s\n", argv[1]);
+ free(port_data);
+ exit(1);
+ }
+ argc--, argv++;
+ }
+
+ if (argc > 1) {
+ /* XXX Add error printout here */
+ }
+
+ if (port_data->no_packet_loop){
+ free(port_data);
+ exit(0);
+ }
+
+ /*
+ * If an output file was given, let it replace standard output.
+ */
+
+ if (port_data->output_file)
+ replace_stdout(port_data->output_file);
+
+ ret = packet_loop();
+ if(port_data->io_buf_size > 0)
+ free(port_data->io_buf);
+ free(port_data);
+ return ret;
+}
+
+static int
+packet_loop(void)
+{
+ int total_read = 0;
+ port_data->io_buf = (unsigned char*) malloc(1); /* Allocate once, so realloc works (SunOS) */
+
+
+ for (;;) {
+ int packet_length; /* Length of current packet. */
+ int i;
+ int bytes_read; /* Number of bytes read. */
+
+ /*
+ * Read the packet header, if any.
+ */
+
+ if (port_data->header_size == 0) {
+ if(port_data->limited_bytecount &&
+ port_data->limited_bytecount - total_read < 4096)
+ packet_length = port_data->limited_bytecount - total_read;
+ else
+ packet_length = 4096;
+ } else {
+ ensure_buf_big_enough(port_data->header_size);
+ if (readn(port_data->fd_from_erl, port_data->io_buf, port_data->header_size) != port_data->header_size) {
+ return(1);
+ }
+
+ /*
+ * Get the length of this packet.
+ */
+
+ packet_length = 0;
+ for (i = 0; i < port_data->header_size; i++)
+ packet_length = (packet_length << 8) | port_data->io_buf[i];
+ }
+
+
+ /*
+ * Delay if delay mode.
+ */
+
+ if (port_data->delay_mode) {
+ delay(5000L);
+ }
+
+ if (port_data->quit_mode) {
+ return(1);
+ } else if (port_data->break_mode) {
+ close(0);
+ delay(32000L);
+ return(1);
+ }
+
+ /*
+ * Read the packet itself.
+ */
+
+ ensure_buf_big_enough(packet_length+4+1); /* At least five bytes. */
+ port_data->io_buf[4] = '\0';
+ if (port_data->header_size == 0) {
+ bytes_read = read(port_data->fd_from_erl, port_data->io_buf+4, packet_length);
+ if (bytes_read == 0)
+ return(1);
+ if (bytes_read < 0) {
+ fprintf(stderr, "Error reading %d bytes: %s\n",
+ packet_length, strerror(errno));
+ return(1);
+ }
+ total_read += bytes_read;
+ } else {
+ bytes_read = readn(port_data->fd_from_erl, port_data->io_buf+4, packet_length);
+ if (bytes_read != packet_length) {
+ fprintf(stderr, "%s: couldn't read packet of length %d\r\n",
+ port_data->progname, packet_length);
+ return(1);
+ }
+ }
+
+ /*
+ * Act on the command.
+ */
+ if (port_data->header_size == 0) {
+ reply(port_data->io_buf+4, bytes_read);
+ if(port_data->limited_bytecount &&
+ port_data->limited_bytecount <= total_read){
+ delay(5000L);
+ return(0);
+ }
+ } else {
+ switch (port_data->io_buf[4]) {
+ case 'p': /* ping */
+ port_data->io_buf[4] = 'P';
+ reply(port_data->io_buf+4, bytes_read);
+ break;
+ case 'e': /* echo */
+ reply(port_data->io_buf+4, bytes_read);
+ break;
+ case 'x': /* exit */
+ return(5);
+ break;
+ default:
+ fprintf(stderr, "%s: bad packet of length %d received: ",
+ port_data->progname, bytes_read);
+ dump(port_data->io_buf+4, bytes_read, 10);
+ fprintf(stderr, "\r\n");
+ return(1);
+ }
+ }
+ }
+}
+
+/*
+ * Sends a packet back to Erlang.
+ */
+
+static void
+reply(buf, size)
+ char* buf; /* Buffer with reply. The four bytes before
+ * this pointer must be allocated so that
+ * this function can put the header there.
+ */
+ int size; /* Size of buffer to send. */
+{
+ int n; /* Temporary to hold size. */
+ int i; /* Loop counter. */
+
+ /*
+ * Fill the header starting with the least significant byte
+ * (this will work even if there is no header).
+ */
+
+ n = size;
+ for (i = 0; i < port_data->header_size; i++) {
+ *--buf = (char) n; /* Store least significant byte. */
+ n = n >> 8;
+ }
+
+ size += port_data->header_size;
+ write_reply(buf, size);
+}
+
+
+
+static void
+write_reply(buf, size)
+ char* buf; /* Buffer with reply. Must contain header. */
+ int size; /* Size of buffer to send. */
+{
+ int n; /* Temporary to hold size. */
+
+ if (port_data->slow_writes <= 0) { /* Normal, "fast", write. */
+ write(port_data->fd_to_erl, buf, size);
+ } else {
+ /*
+ * Write chunks with delays in between.
+ */
+
+ while (size > 0) {
+ n = size > port_data->slow_writes ? port_data->slow_writes : size;
+ write(port_data->fd_to_erl, buf, n);
+ size -= n;
+ buf += n;
+ if (size)
+ delay(500L);
+ }
+ }
+}
+
+
+/*
+ * Ensures that our I/O buffer is big enough for the packet to come.
+ */
+
+static void
+ensure_buf_big_enough(size)
+ int size; /* Needed size of buffer. */
+{
+ if (port_data->io_buf_size >= size)
+ return;
+
+ port_data->io_buf = (unsigned char*) realloc(port_data->io_buf, size);
+ if (port_data->io_buf == NULL) {
+ fprintf(stderr, "%s: insufficient memory for i/o buffer of size %d\n",
+ port_data->progname, size);
+ exit(1);
+ }
+ port_data->io_buf_size = size;
+}
+
+/*
+ * Reads len number of bytes.
+ */
+static int
+readn(fd, buf, len)
+ int fd; /* File descriptor to read from. */
+ unsigned char *buf; /* Store in this buffer. */
+ int len; /* Number of bytes to read. */
+{
+ int n; /* Byte count in last read call. */
+ int sofar; /* Bytes read so far. */
+
+ sofar = 0;
+ do {
+ if ((n = read(fd, buf+sofar, len-sofar)) <= 0)
+ /* error or EOF in read */
+ return(n);
+ sofar += n;
+ } while (sofar < len);
+ return sofar;
+}
+
+static void
+replace_stdout(filename)
+char* filename; /* Name of file to replace standard output. */
+{
+ int fd;
+
+ fd = open(filename, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
+ if (fd == -1) {
+ fprintf(stderr, "%s: failed to open %s for writing: %d\n",
+ port_data->progname, filename, errno);
+ exit(1);
+ }
+ REDIR_STDOUT(fd);
+}
+
+static void
+dump(buf, sz, max)
+ unsigned char* buf;
+ int sz;
+ int max;
+{
+ int i, imax;
+ char comma[5];
+
+ comma[0] = ',';
+ comma[1] = '\0';
+ if (!sz)
+ return;
+ if (sz > max)
+ imax = max;
+ else
+ imax = sz;
+
+ for (i=0; i<imax; i++) {
+ if (i == imax-1) {
+ if (sz > max)
+ strcpy(comma, ",...");
+ else
+ comma[0] = 0;
+ }
+ if (isdigit(buf[i])) {
+ fprintf(stderr, "%u%s", (int)(buf[i]), comma);
+ } else {
+ if (isalpha(buf[i])) {
+ fprintf(stderr, "%c%s", buf[i], comma);
+ }
+ else {
+ fprintf(stderr, "%u%s", (int)(buf[i]), comma);
+ }
+ }
+ }
+}
+
+/*
+ * Delays (sleeps) the given number of milli-seconds.
+ */
+
+static void
+delay(unsigned ms)
+{
+#ifdef VXWORKS
+ taskDelay((sysClkRateGet() * ms) / 1000);
+#else
+#ifdef __WIN32__
+ Sleep(ms);
+#else
+ struct timeval t;
+ t.tv_sec = ms/1000;
+ t.tv_usec = (ms % 1000) * 1000;
+
+ select(0, NULL, NULL, NULL, &t);
+#endif
+#endif
+}
+
+/*
+ * Generates a reply buffer given the specification.
+ *
+ * <packet-bytes>,<start-character>,<increment>,<size>
+ *
+ * Where:
+ * <packet-bytes> is
+ */
+static void
+generate_reply(spec)
+char* spec; /* Specification for reply. */
+{
+ typedef struct item {
+ int start; /* Start character. */
+ int incrementer; /* How much to increment. */
+ size_t size; /* Size of reply buffer. */
+ } Item;
+
+ Item items[256];
+ int last;
+ int cur;
+ size_t total_size;
+ char* buf; /* Reply buffer. */
+ char* s; /* Current pointer into buffer. */
+ int c;
+
+ total_size = 0;
+ last = 0;
+ while (*spec) {
+ char* colon;
+
+ items[last].incrementer = 1;
+ items[last].start = *spec++;
+ items[last].size = atoi(spec);
+
+ total_size += port_data->header_size+items[last].size;
+ last++;
+ if ((colon = strchr(spec, ':')) == NULL) {
+ spec += strlen(spec);
+ } else {
+ *colon = '\0';
+ spec = colon+1;
+ }
+ }
+
+ buf = (char *) malloc(total_size);
+ if (buf == NULL) {
+ fprintf(stderr, "%s: insufficent memory for reply buffer of size %d\n",
+ port_data->progname, total_size);
+ exit(1);
+ }
+
+ s = buf;
+ for (cur = 0; cur < last; cur++) {
+ int i;
+ size_t n;
+
+ n = items[cur].size;
+ s += port_data->header_size;
+ for (i = 0; i < port_data->header_size; i++) {
+ *--s = (char) n; /* Store least significant byte. */
+ n = n >> 8;
+ }
+ s += port_data->header_size;
+
+ c = items[cur].start;
+ for (i = 0; i < items[cur].size; i++) {
+ *s++ = c;
+ c++;
+ if (c > 126) {
+ c = 33;
+ }
+ }
+ }
+ write_reply(buf, s-buf);
+}
+
diff --git a/erts/emulator/test/port_SUITE_data/port_test.erl b/erts/emulator/test/port_SUITE_data/port_test.erl
new file mode 100644
index 0000000000..56abfd5ded
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/port_test.erl
@@ -0,0 +1,36 @@
+%%
+%% %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%
+%%
+
+-module(port_test).
+
+-export([env/1, pwd/0]).
+
+env([A]) ->
+ Var = atom_to_list(A),
+ Val = os:getenv(Var),
+ case Val of
+ false ->
+ io:format("0~n");
+ _ ->
+ io:format("1~s~n", [Val])
+ end.
+
+pwd() ->
+ {ok, Pwd} = file:get_cwd(),
+ io:format("~s~n", [Pwd]).
diff --git a/erts/emulator/test/port_SUITE_data/reclaim.h b/erts/emulator/test/port_SUITE_data/reclaim.h
new file mode 100644
index 0000000000..1d57dc5b8a
--- /dev/null
+++ b/erts/emulator/test/port_SUITE_data/reclaim.h
@@ -0,0 +1,60 @@
+#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. Finally, note that you can obviously not load your
+ application before the Erlang system when using this interface.
+*/
+
+/* Sorry, no ANSI prototypes yet... */
+extern int save_open(),save_creat(),save_socket(),save_accept(),save_close();
+#define open save_open
+#define creat save_creat
+#define socket save_socket
+#define accept save_accept
+#define close save_close
+extern FILE *save_fopen(), *save_fdopen(), *save_freopen();
+extern int save_fclose();
+#define fopen save_fopen
+#define fdopen save_fdopen
+#define freopen save_freopen
+#define fclose save_fclose
+/* XXX Should do opendir/closedir too... */
+extern char *save_malloc(), *save_calloc(), *save_realloc();
+extern void save_free(), save_cfree();
+#define malloc save_malloc
+#define calloc save_calloc
+#define realloc save_realloc
+#define free save_free
+#define cfree save_cfree
+
+#endif