From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- erts/emulator/test/port_SUITE_data/Makefile.src | 26 + erts/emulator/test/port_SUITE_data/dir/dummy | 1 + erts/emulator/test/port_SUITE_data/echo_args.c | 12 + erts/emulator/test/port_SUITE_data/echo_drv.c | 85 ++++ erts/emulator/test/port_SUITE_data/exit_drv.c | 68 +++ erts/emulator/test/port_SUITE_data/failure_drv.c | 63 +++ erts/emulator/test/port_SUITE_data/port_test.c | 605 +++++++++++++++++++++++ erts/emulator/test/port_SUITE_data/port_test.erl | 36 ++ erts/emulator/test/port_SUITE_data/reclaim.h | 60 +++ 9 files changed, 956 insertions(+) create mode 100644 erts/emulator/test/port_SUITE_data/Makefile.src create mode 100644 erts/emulator/test/port_SUITE_data/dir/dummy create mode 100644 erts/emulator/test/port_SUITE_data/echo_args.c create mode 100644 erts/emulator/test/port_SUITE_data/echo_drv.c create mode 100644 erts/emulator/test/port_SUITE_data/exit_drv.c create mode 100644 erts/emulator/test/port_SUITE_data/failure_drv.c create mode 100644 erts/emulator/test/port_SUITE_data/port_test.c create mode 100644 erts/emulator/test/port_SUITE_data/port_test.erl create mode 100644 erts/emulator/test/port_SUITE_data/reclaim.h (limited to 'erts/emulator/test/port_SUITE_data') 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 + +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 +#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 +#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 +#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 +#include +#include +#include +#include +#include +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +#include + +#ifdef VXWORKS +#include "reclaim.h" +#include +#else +#include +#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 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. + * + * ,,, + * + * Where: + * 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 -- cgit v1.2.3