diff options
author | Lukas Larsson <[email protected]> | 2014-03-27 09:59:57 +0100 |
---|---|---|
committer | Lukas Larsson <[email protected]> | 2014-03-27 09:59:57 +0100 |
commit | ed483c484f1752151e73ed0c060b61312e59a397 (patch) | |
tree | e67bf81a49a7fcb6ec4380f5fa73fbc920bb3199 | |
parent | 978f3cbfa9eb46dcb6987e2b0ce5b4b7727dd17b (diff) | |
parent | d2a5dc042c02dce5bc518eb576ea496af50e6373 (diff) | |
download | otp-ed483c484f1752151e73ed0c060b61312e59a397.tar.gz otp-ed483c484f1752151e73ed0c060b61312e59a397.tar.bz2 otp-ed483c484f1752151e73ed0c060b61312e59a397.zip |
Merge branch 'lukas/ose/master-17.0/OTP-11334'
* lukas/ose/master-17.0/OTP-11334:
ose: Fix erts assert failed printouts
ose: fix for packet_bytes in fd/spawn driver.
ose: Prepare slave for running on OSE
ose: Fix bug when hunting for signal proxy
ose: Implement tcp inet driver for OSE
ose: Add ifdefs for HAVE_UDP
ose: Yielding has to be done differently for background processes.
ose: Print faults in aio sys driver calls
ose: Prinout errno when to_erl read fails
ose: erlang display goes to ramlog printf
ose: Initiate stdin/stdout/stderr
ose: Break lmconf into one per load module
ose: Reset busy port when pdq empty
ose: Restore the owner of the signal
29 files changed, 904 insertions, 216 deletions
diff --git a/HOWTO/INSTALL-CROSS.md b/HOWTO/INSTALL-CROSS.md index cb9d12e753..10f463c06d 100644 --- a/HOWTO/INSTALL-CROSS.md +++ b/HOWTO/INSTALL-CROSS.md @@ -537,7 +537,11 @@ When a variable has been set, no warning will be issued. * `erl_xcomp_ose_LM_LCF` - OSE load module linker configuration file -* `erl_xcomp_ose_LM_CONF` - OSE load module default configuration file +* `erl_xcomp_ose_BEAM_LM_CONF` - Beam OSE load module configuration file + +* `erl_xcomp_ose_EPMD_LM_CONF` - EPMD OSE load module configuration file + +* `erl_xcomp_ose_RUN_ERL_LM_CONF` - run_erl_lm OSE load module configuration file Copyright and License --------------------- diff --git a/aclocal.m4 b/aclocal.m4 index c51c26794a..2b47f7c4bc 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file]) +AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) ]) diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index c51c26794a..2b47f7c4bc 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file]) +AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) ]) diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index b06d5aeb12..7aaded200c 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -887,7 +887,7 @@ <fsummary>Print a term on standard output</fsummary> <desc> <p>Prints a text representation of <c><anno>Term</anno></c> on the standard - output.</p> + output. On OSE the term is printed to the ramlog.</p> <warning> <p>This BIF is intended for debugging only.</p> </warning> diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 58e77ed1fa..58639c7190 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -1035,7 +1035,7 @@ else ifeq ($(findstring ose,$(TARGET)),ose) $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) $(LCF) $(call build-ose-load-module, $@, $(INIT_OBJS) $(OBJS), $(STATIC_NIF_LIBS) \ - $(STATIC_DRIVER_LIBS) $(LIBS), $(LMCONF)) + $(STATIC_DRIVER_LIBS) $(LIBS), $(BEAM_LMCONF)) else $(BINDIR)/$(EMULATOR_EXECUTABLE): $(INIT_OBJS) $(OBJS) $(DEPLIBS) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 357a4b7bcb..e33594b026 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -93,6 +93,10 @@ typedef unsigned long long llu_t; #define INT16_MAX (32767) #endif +#ifdef __OSE__ +#include "inet.h" +#endif + #ifdef __WIN32__ #define STRNCASECMP strncasecmp @@ -121,10 +125,6 @@ typedef unsigned long long llu_t; #undef WANT_NONBLOCKING #include "sys.h" -#ifdef __OSE__ -#include "inet.h" -#endif - #undef EWOULDBLOCK #undef ETIMEDOUT @@ -200,6 +200,7 @@ typedef unsigned long long llu_t; #define HAVE_MULTICAST_SUPPORT +#define HAVE_UDP #define ERRNO_BLOCK WSAEWOULDBLOCK @@ -294,29 +295,55 @@ static unsigned long zero_value = 0; static unsigned long one_value = 1; #elif defined (__OSE__) + +/* + * Some notes about how inet (currently only tcp) works on OSE. + * The driver uses OSE signals to communicate with the one_inet + * process. Because of the difference in how signals and file descriptors + * work the whole select/deselect mechanic is very different. + * In ose when a sock_select is done a function is called. That function + * notes the changes that the driver want to do, but does not act on it. + * later when the function returns the new desired state is compared + * to the previous state and the apprioriate actions are taken. The action + * is usually to either request more data from the stack or stop requesting + * data. + * + * One thing to note is that the driver never does select/deselect. It always + * listens for the signals. Flow of data is regulated by sending or not sending + * signals to the ose inet process. + * + * The interesting functions to look at are: + * * inet_driver_select : called when sock_select is called + * * tcp_inet_ose_dispatch_signal : checks state changes and sends new signals + * * tcp_inet_drv_output_ose : ready output callback, reads signals and calls + * dispatch_signal + * * tcp_inet_drv_input_ose : ready input callback. + */ + +#include "efs.h" #include "sys/socket.h" #include "sys/uio.h" #include "sfk/sys/sfk_uio.h" #include "netinet/in.h" #include "netinet/tcp.h" #include "netdb.h" +#include "ose_spi/socket.sig" -ssize_t writev(int fd, const struct iovec *iov, int iovcnt) -{ - return 0; -} + +static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz); #define INVALID_SOCKET -1 #define INVALID_EVENT -1 #define SOCKET_ERROR -1 #define SOCKET int -#define HANDLE long int -#define FD_READ ERL_DRV_READ -#define FD_WRITE ERL_DRV_WRITE -#define FD_CLOSE 0 -#define FD_CONNECT ERL_DRV_WRITE -#define FD_ACCEPT ERL_DRV_READ +#define HANDLE int +#define FD_READ ERL_DRV_READ +#define FD_WRITE ERL_DRV_WRITE +#define FD_CLOSE 0 +#define FD_CONNECT (1<<4) +#define FD_ACCEPT (1<<5) +#define SOCK_FD_ERROR (1<<6) #define sock_connect(s, addr, len) connect((s), (addr), (len)) #define sock_listen(s, b) listen((s), (b)) @@ -335,11 +362,12 @@ ssize_t writev(int fd, const struct iovec *iov, int iovcnt) #define sock_sendto(s,buf,blen,flag,addr,alen) \ sendto((s),(buf),(blen),(flag),(addr),(alen)) #define sock_sendv(s, vec, size, np, flag) \ - (*(np) = writev((s), (struct iovec*)(vec), (size))) + (*(np) = writev_fallback((s), (struct iovec*)(vec), (size), (*(np)))) #define sock_sendmsg(s,msghdr,flag) sendmsg((s),(msghdr),(flag)) #define sock_open(af, type, proto) socket((af), (type), (proto)) #define sock_close(s) close((s)) +#define sock_dup(s) dup((s)) #define sock_shutdown(s, how) shutdown((s), (how)) #define sock_hostname(buf, len) gethostname((buf), (len)) @@ -355,19 +383,6 @@ ssize_t writev(int fd, const struct iovec *iov, int iovcnt) #define sock_create_event(d) ((d)->s) /* return file descriptor */ #define sock_close_event(e) /* do nothing */ -#define inet_driver_select(port, e, mode, on) \ - driver_select(port, e, mode | (on?ERL_DRV_USE:0), on) - -#define sock_select(d, flags, onoff) do { \ - ASSERT(!(d)->is_ignored); \ - (d)->event_mask = (onoff) ? \ - ((d)->event_mask | (flags)) : \ - ((d)->event_mask & ~(flags)); \ - DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ - (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ - inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ - } while(0) - #ifndef WANT_NONBLOCKING #define WANT_NONBLOCKING #endif @@ -397,6 +412,16 @@ typedef unsigned long u_long; #define IN_EXPERIMENTAL(a) ((((in_addr_t)(a)) & 0xe0000000) == 0xe0000000) #define IN_BADCLASS(a) ((((in_addr_t)(a)) & 0xf0000000) == 0xf0000000) +#define sock_select(d, flags, onoff) do { \ + ASSERT(!(d)->is_ignored); \ + (d)->event_mask = (onoff) ? \ + ((d)->event_mask | (flags)) : \ + ((d)->event_mask & ~(flags)); \ + DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX, s=%d\r\n", \ + __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask, (d)->s)); \ + inet_driver_select((d), (flags), (onoff)); \ + } while(0) + #else /* !__OSE__ && !__WIN32__ */ #include <sys/time.h> @@ -438,6 +463,8 @@ typedef unsigned long u_long; #include <setns.h> #endif +#define HAVE_UDP + /* SCTP support -- currently for UNIX platforms only: */ #undef HAVE_SCTP #if defined(HAVE_SCTP_H) @@ -660,13 +687,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n) (d)->event_mask = (onoff) ? \ ((d)->event_mask | (flags)) : \ ((d)->event_mask & ~(flags)); \ - DEBUGF(("sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ - (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ + DEBUGF(("(%s / %d) sock_select(%ld): flags=%02X, onoff=%d, event_mask=%02lX\r\n", \ + __FILE__, __LINE__, (long) (d)->port, (flags), (onoff), (unsigned long) (d)->event_mask)); \ inet_driver_select((d)->port, (ErlDrvEvent)(long)(d)->event, (flags), (onoff)); \ } while(0) -#endif /* #ifdef __WIN32__ #else */ +#endif /* !__WIN32__ && !__OSE__ */ #ifdef HAVE_SOCKLEN_T # define SOCKLEN_T socklen_t @@ -1119,6 +1146,13 @@ typedef struct { char *netns; /* Socket network namespace name as full file path */ #endif +#ifdef __OSE__ + int select_state; /* state to keep track of whether we + should trigger another read/write + request at end of ready_input/output */ + ErlDrvEvent events[6]; +#endif + } inet_descriptor; @@ -1134,8 +1168,10 @@ static void tcp_inet_stop(ErlDrvData); static void tcp_inet_command(ErlDrvData, char*, ErlDrvSizeT); static void tcp_inet_commandv(ErlDrvData, ErlIOVec*); static void tcp_inet_flush(ErlDrvData drv_data); +#ifndef __OSE__ static void tcp_inet_drv_input(ErlDrvData, ErlDrvEvent); static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event); +#endif static ErlDrvData tcp_inet_start(ErlDrvPort, char* command); static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData, unsigned int, char*, ErlDrvSizeT, char**, ErlDrvSizeT); @@ -1147,7 +1183,72 @@ static void tcp_inet_event(ErlDrvData, ErlDrvEvent); static void find_dynamic_functions(void); #endif -static struct erl_drv_entry tcp_inet_driver_entry = +#ifdef __OSE__ +/* The structure of the signal used for requesting asynchronous + * notification from the stack. Under normal circumstances the network stack + * shouldn't overwrite the value set in the fd field by the sender + * of the request */ +struct OseAsyncSig { + struct FmEvent event; + int fd; +}; + +union SIGNAL { + SIGSELECT signo; + struct OseAsyncSig async; +}; + +static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize); +static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev); +static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event); +static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event); +static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig); + +#ifdef INET_DRV_DEBUG + +static char *read_req = "SO_EVENT_READ_REQUEST"; +static char *read_rep = "SO_EVENT_READ_REPLY"; +static char *write_req = "SO_EVENT_WRITE_REQUEST"; +static char *write_rep = "SO_EVENT_WRITE_REPLY"; +static char *eof_req = "SO_EVENT_EOF_REQUEST"; +static char *eof_rep = "SO_EVENT_EOF_REPLY"; +static char *accept_req = "SO_EVENT_ACCEPT_REQUEST"; +static char *accept_rep = "SO_EVENT_ACCEPT_REPLY"; +static char *connect_req = "SO_EVENT_CONNECT_REQUEST"; +static char *connect_rep = "SO_EVENT_CONNECT_REPLY"; +static char *error_req = "SO_EVENT_ERROR_REQUEST"; +static char *error_rep = "SO_EVENT_ERROR_REPLY"; +static char signo_tmp[32]; + +static char *signo_to_string(SIGSELECT signo) { + switch (signo) { + case SO_EVENT_READ_REQUEST: { return read_req; } + case SO_EVENT_READ_REPLY: { return read_rep; } + case SO_EVENT_WRITE_REQUEST: { return write_req; } + case SO_EVENT_WRITE_REPLY: { return write_rep; } + case SO_EVENT_EOF_REQUEST: { return eof_req; } + case SO_EVENT_EOF_REPLY: { return eof_rep; } + case SO_EVENT_ACCEPT_REQUEST: { return accept_req; } + case SO_EVENT_ACCEPT_REPLY: { return accept_rep; } + case SO_EVENT_CONNECT_REQUEST: { return connect_req; } + case SO_EVENT_CONNECT_REPLY: { return connect_rep; } + case SO_EVENT_ERROR_REQUEST: { return error_req; } + case SO_EVENT_ERROR_REPLY: { return error_rep; } + } + + snprintf(signo_tmp,32,"0x%x",signo); + + return signo_tmp; +} + +#endif + +#endif /* __OSE__ */ + + +static struct erl_drv_entry tcp_inet_driver_entry = { tcp_inet_init, /* inet_init will add this driver !! */ tcp_inet_start, @@ -1156,6 +1257,9 @@ static struct erl_drv_entry tcp_inet_driver_entry = #ifdef __WIN32__ tcp_inet_event, NULL, +#elif defined(__OSE__) + tcp_inet_drv_input_ose, /*ready_input*/ + tcp_inet_drv_output_ose, /*ready_output*/ #else tcp_inet_drv_input, tcp_inet_drv_output, @@ -1163,9 +1267,17 @@ static struct erl_drv_entry tcp_inet_driver_entry = "tcp_inet", NULL, NULL, +#ifdef __OSE__ + tcp_inet_ctl_ose, +#else tcp_inet_ctl, +#endif tcp_inet_timeout, +#ifdef __OSE__ + tcp_inet_commandv_ose, +#else tcp_inet_commandv, +#endif NULL, tcp_inet_flush, NULL, @@ -1181,6 +1293,7 @@ static struct erl_drv_entry tcp_inet_driver_entry = +#ifdef HAVE_UDP static int packet_inet_init(void); static void packet_inet_stop(ErlDrvData); static void packet_inet_command(ErlDrvData, char*, ErlDrvSizeT); @@ -1230,6 +1343,7 @@ static struct erl_drv_entry udp_inet_driver_entry = NULL, inet_stop_select }; +#endif #ifdef HAVE_SCTP static struct erl_drv_entry sctp_inet_driver_entry = @@ -1293,6 +1407,7 @@ static int tcp_deliver(tcp_descriptor* desc, int len); static int tcp_inet_output(tcp_descriptor* desc, HANDLE event); static int tcp_inet_input(tcp_descriptor* desc, HANDLE event); +#ifdef HAVE_UDP typedef struct { inet_descriptor inet; /* common data structure (DON'T MOVE) */ int read_packets; /* Number of packets to read per invocation */ @@ -1304,10 +1419,19 @@ typedef struct { static int packet_inet_input(udp_descriptor* udesc, HANDLE event); static int packet_inet_output(udp_descriptor* udesc, HANDLE event); +#endif /* convert descriptor poiner to inet_descriptor pointer */ #define INETP(d) (&(d)->inet) +#ifdef __OSE__ +static void inet_driver_select(inet_descriptor* desc, + int flags, int onoff); +static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, + int prev_select_state, + union SIGNAL *sig); +#endif + static int async_ref = 0; /* async reference id generator */ #define NEW_ASYNC_ID() ((async_ref++) & 0xffff) @@ -1324,7 +1448,6 @@ static int async_ref = 0; /* async reference id generator */ static ErlDrvTermData am_ok; static ErlDrvTermData am_tcp; -static ErlDrvTermData am_udp; static ErlDrvTermData am_error; static ErlDrvTermData am_einval; static ErlDrvTermData am_inet_async; @@ -1334,10 +1457,13 @@ static ErlDrvTermData am_closed; static ErlDrvTermData am_tcp_passive; static ErlDrvTermData am_tcp_closed; static ErlDrvTermData am_tcp_error; -static ErlDrvTermData am_udp_passive; -static ErlDrvTermData am_udp_error; static ErlDrvTermData am_empty_out_q; static ErlDrvTermData am_ssl_tls; +#ifdef HAVE_UDP +static ErlDrvTermData am_udp; +static ErlDrvTermData am_udp_passive; +static ErlDrvTermData am_udp_error; +#endif #ifdef HAVE_SCTP static ErlDrvTermData am_sctp; static ErlDrvTermData am_sctp_passive; @@ -1545,6 +1671,7 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ # define SCTP_ANC_BUFF_SIZE INET_DEF_BUFFER/2 /* XXX: not very good... */ #endif +#ifdef HAVE_UDP static int load_ip_port(ErlDrvTermData* spec, int i, char* buf) { spec[i++] = ERL_DRV_INT; @@ -1579,6 +1706,7 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf) } return i; } +#endif #ifdef HAVE_SCTP @@ -1745,10 +1873,12 @@ static void release_buffer(ErlDrvBinary* buf) } } +#ifdef HAVE_UDP static ErlDrvBinary* realloc_buffer(ErlDrvBinary* buf, ErlDrvSizeT newsz) { return driver_realloc_binary(buf, newsz); } +#endif /* use a TRICK, access the refc field to see if any one else has * a ref to this buffer then call driver_free_binary else @@ -3409,6 +3539,7 @@ static int tcp_error_message(tcp_descriptor* desc, int err) return erl_drv_output_term(desc->inet.dport, spec, i); } +#ifdef HAVE_UDP /* ** active mode message: ** {udp, S, IP, Port, [H1,...Hsz | Data]} or @@ -3499,6 +3630,7 @@ static int packet_binary_message ASSERT(i <= PACKET_ERL_DRV_TERM_DATA_LEN); return erl_drv_output_term(desc->dport, spec, i); } +#endif /* ** active mode message: send active-to-passive transition message @@ -3513,6 +3645,9 @@ static int packet_binary_message DEBUGF(("packet_passive_message(%ld):\r\n", (long)desc->port)); +#if !defined(HAVE_UDP) && !defined(HAVE_SCTP) + i = LOAD_ATOM(spec, i, am_tcp_passive); +#else if (desc->sprotocol == IPPROTO_TCP) i = LOAD_ATOM(spec, i, am_tcp_passive); else { @@ -3522,12 +3657,14 @@ static int packet_binary_message i = LOAD_ATOM(spec, i, am_udp_passive); #endif } +#endif i = LOAD_PORT(spec, i, desc->dport); i = LOAD_TUPLE(spec, i, 2); ASSERT(i <= 6); return erl_drv_output_term(desc->dport, spec, i); } +#ifdef HAVE_UDP /* ** send active message {udp_error|sctp_error, S, Error} */ @@ -3554,7 +3691,7 @@ static int packet_error_message(udp_descriptor* udesc, int err) ASSERT(i == sizeof(spec)/sizeof(*spec)); return erl_drv_output_term(desc->dport, spec, i); } - +#endif /* ** active=TRUE: @@ -3619,7 +3756,7 @@ tcp_reply_binary_data(tcp_descriptor* desc, ErlDrvBinary* bin, int offs, int len return code; } - +#ifdef HAVE_UDP static int packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz, ErlDrvBinary * bin, int offs, int len, @@ -3642,6 +3779,7 @@ packet_reply_binary_data(inet_descriptor* desc, unsigned int hsz, return code; } } +#endif /* ---------------------------------------------------------------------------- @@ -3817,7 +3955,9 @@ static int inet_init() INIT_ATOM(ok); INIT_ATOM(tcp); +#ifdef HAVE_UDP INIT_ATOM(udp); +#endif INIT_ATOM(error); INIT_ATOM(einval); INIT_ATOM(inet_async); @@ -3827,8 +3967,10 @@ static int inet_init() INIT_ATOM(tcp_passive); INIT_ATOM(tcp_closed); INIT_ATOM(tcp_error); +#ifdef HAVE_UDP INIT_ATOM(udp_passive); INIT_ATOM(udp_error); +#endif INIT_ATOM(empty_out_q); INIT_ATOM(ssl_tls); @@ -3847,7 +3989,10 @@ static int inet_init() /* add TCP, UDP and SCTP drivers */ add_driver_entry(&tcp_inet_driver_entry); +#ifdef HAVE_UDP add_driver_entry(&udp_inet_driver_entry); +#endif + #ifdef HAVE_SCTP /* Check the size of SCTP AssocID -- currently both this driver and the Erlang part require 32 bit: */ @@ -4176,6 +4321,16 @@ static void desc_close(inet_descriptor* desc) desc->forced_events = 0; desc->send_would_block = 0; #endif +#ifdef __OSE__ + if (desc->events[0]) { + driver_select(desc->port,desc->events[0],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[1],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[2],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[3],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[4],FD_READ|FD_WRITE|ERL_DRV_USE,0); + driver_select(desc->port,desc->events[5],FD_READ|FD_WRITE|ERL_DRV_USE,0); + } +#else /* * We should close the fd here, but the other driver might still * be selecting on it. @@ -4185,6 +4340,7 @@ static void desc_close(inet_descriptor* desc) ERL_DRV_USE, 0); else inet_stop_select((ErlDrvEvent)(long)desc->event,NULL); +#endif desc->event = INVALID_EVENT; /* closed by stop_select callback */ desc->s = INVALID_SOCKET; desc->event_mask = 0; @@ -4226,6 +4382,64 @@ static int erl_inet_close(inet_descriptor* desc) return 0; } +#ifdef __OSE__ +static void inet_select_init(inet_descriptor* desc) +{ + desc->events[0] = + erl_drv_ose_event_alloc(SO_EVENT_READ_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[0], + ERL_DRV_READ|ERL_DRV_USE, 1); + + desc->events[1] = + erl_drv_ose_event_alloc(SO_EVENT_EOF_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[1], + ERL_DRV_READ|ERL_DRV_USE, 1); + + desc->events[2] = + erl_drv_ose_event_alloc(SO_EVENT_ACCEPT_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[2], + ERL_DRV_READ|ERL_DRV_USE, 1); + + /* trigger tcp_inet_input */ + desc->events[3] = + erl_drv_ose_event_alloc(SO_EVENT_WRITE_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[3], + ERL_DRV_WRITE|ERL_DRV_USE, 1); + + desc->events[4] = + erl_drv_ose_event_alloc(SO_EVENT_CONNECT_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[4], + ERL_DRV_WRITE|ERL_DRV_USE, 1); + + desc->events[5] = + erl_drv_ose_event_alloc(SO_EVENT_ERROR_REPLY, + desc->s, + inet_resolve_signal, + NULL); + driver_select(desc->port, desc->events[5], + ERL_DRV_WRITE|ERL_DRV_USE, 1); + + /* Issue a select on error event before any other select to be sure we are + prepared to receive error notifications from the stack, even in the + situations when select isn't issued */ + sock_select(desc, SOCK_FD_ERROR, 1); +} +#endif static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, char** rbuf, ErlDrvSizeT rsize) @@ -4309,6 +4523,10 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type, #ifdef __WIN32__ driver_select(desc->port, desc->event, ERL_DRV_READ, 1); #endif +#ifdef __OSE__ + inet_select_init(desc); +#endif + desc->state = INET_STATE_OPEN; desc->stype = type; desc->sfamily = domain; @@ -4328,7 +4546,14 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, return ctl_error(sock_errno(), rbuf, rsize); if (name.sa.sa_family != domain) return ctl_error(EINVAL, rbuf, rsize); +#ifdef __OSE__ + /* for fdopen duplicating the sd will allow to uniquely identify + the signal from OSE with erlang port */ + desc->s = sock_dup(s); +#else desc->s = s; +#endif + if ((desc->event = sock_create_event(desc)) == INVALID_EVENT) return ctl_error(sock_errno(), rbuf, rsize); SET_NONBLOCKING(desc->s); @@ -4338,8 +4563,15 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type, desc->state = INET_STATE_BOUND; /* assume bound */ if (type == SOCK_STREAM) { /* check if connected */ sz = sizeof(name); - if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) + if (!IS_SOCKET_ERROR(sock_peer(s, (struct sockaddr*) &name, &sz))) { desc->state = INET_STATE_CONNECTED; +#ifdef __OSE__ + /* since we are dealing with different descriptors (i.e. inet and + socket) the select part should be initialized with the right + values */ + inet_select_init(desc); +#endif + } } desc->prebound = 1; /* used to prevent a real close since @@ -4365,8 +4597,7 @@ struct addr_if { #ifndef SIOCGIFNETMASK -static struct in_addr net_mask(in) -struct in_addr in; +static struct in_addr net_mask(struct in_addr in) { register u_long i = sock_ntohl(in.s_addr); @@ -5929,6 +6160,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) } continue; +#ifdef HAVE_UDP case INET_LOPT_UDP_READ_PACKETS: if (desc->stype == SOCK_DGRAM) { udp_descriptor* udesc = (udp_descriptor*) desc; @@ -5936,6 +6168,7 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) udesc->read_packets = ival; } continue; +#endif #ifdef HAVE_SETNS case INET_LOPT_NETNS: @@ -6902,6 +7135,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, } continue; +#ifdef HAVE_UDP case INET_LOPT_UDP_READ_PACKETS: if (desc->stype == SOCK_DGRAM) { *ptr++ = opt; @@ -6911,6 +7145,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, TRUNCATE_TO(0,ptr); } continue; +#endif #ifdef HAVE_SETNS case INET_LOPT_NETNS: @@ -8041,6 +8276,15 @@ static ErlDrvData inet_start(ErlDrvPort port, int size, int protocol) #ifdef HAVE_SETNS desc->netns = NULL; #endif +#ifdef __OSE__ + desc->select_state = 0; + desc->events[0] = NULL; + desc->events[1] = NULL; + desc->events[2] = NULL; + desc->events[3] = NULL; + desc->events[4] = NULL; + desc->events[5] = NULL; +#endif return (ErlDrvData)desc; } @@ -8761,6 +9005,11 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s, copy_desc->inet.port = port; copy_desc->inet.dport = driver_mk_port(port); + +#ifdef __OSE__ + inet_select_init(©_desc->inet); +#endif + *err = 0; return copy_desc; } @@ -8822,8 +9071,22 @@ static void tcp_inet_stop(ErlDrvData e) inet_stop(INETP(desc)); } +#ifdef __OSE__ + +static ErlDrvSSizeT tcp_inet_ctl_ose(ErlDrvData e, unsigned int cmd, + char* buf, ErlDrvSizeT len, + char** rbuf, ErlDrvSizeT rsize) { - + tcp_descriptor* desc = (tcp_descriptor*)e; + int prev_select_state = INETP(desc)->select_state; + + ErlDrvSSizeT res = tcp_inet_ctl(e,cmd,buf,len,rbuf,rsize); + + tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); + + return res; +} +#endif /* TCP requests from Erlang */ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, @@ -9039,7 +9302,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, ErlDrvTermData caller = driver_caller(desc->inet.port); tcp_descriptor* accept_desc; int err; - + if ((accept_desc = tcp_inet_copy(desc,s,caller,&err)) == NULL) { sock_close(s); return ctl_error(err, rbuf, rsize); @@ -9073,7 +9336,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char tbuf[2]; int n; - DEBUGF(("tcp_inet_ctl(%ld): RECV\r\n", (long)desc->inet.port)); + DEBUGF(("tcp_inet_ctl(%ld): RECV (s=%d)\r\n", + (long)desc->inet.port, desc->inet.s)); /* INPUT: Timeout(4), Length(4) */ if (!IS_CONNECTED(INETP(desc))) { if (desc->tcp_add_flags & TCP_ADDF_DELAYED_CLOSE_RECV) { @@ -9245,6 +9509,16 @@ static void tcp_inet_command(ErlDrvData e, char *buf, ErlDrvSizeT len) DEBUGF(("tcp_inet_command(%ld) }\r\n", (long)desc->inet.port)); } +#ifdef __OSE__ + +static void tcp_inet_commandv_ose(ErlDrvData e, ErlIOVec* ev) { + int prev_select_state = INETP((tcp_descriptor*)e)->select_state; + tcp_inet_commandv(e, ev); + tcp_inet_ose_dispatch_signals((tcp_descriptor*)e,prev_select_state,NULL); +} + +#endif + static void tcp_inet_commandv(ErlDrvData e, ErlIOVec* ev) { @@ -9308,6 +9582,22 @@ static void inet_stop_select(ErlDrvEvent event, void* _) { #ifdef __WIN32__ WSACloseEvent((HANDLE)event); +#elif defined(__OSE__) + ErlDrvOseEventId id; + union SIGNAL *sig; + erl_drv_ose_event_fetch(event, NULL, &id,NULL); + DEBUGF(("inet_stop_select(?#?) {s=%d\n",id)); + sock_close((int)id); + /* On socket close all the signals waiting to be processed as part of the + select should be deallocated */ + while((sig = erl_drv_ose_get_signal(event))) { + DEBUGF(("inet_stop_select(?#?): Freeing signal %s\n", + signo_to_string(sig->signo))); + free_buf(&sig); + } + erl_drv_ose_event_free(event); + DEBUGF(("inet_stop_select(?#?) }\n")); + #else sock_close((SOCKET)(long)event); #endif @@ -9427,12 +9717,13 @@ static int tcp_remain(tcp_descriptor* desc, int* len) int n = desc->i_ptr - ptr; /* number of bytes read */ int tlen; - DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d\r\n", - (long)desc->inet.port, desc->inet.s, n, nfill, nsz)); + DEBUGF(("tcp_remain(%ld): s=%d, n=%d, nfill=%d nsz=%d, tlen %d\r\n", + (long)desc->inet.port, desc->inet.s, n, nfill, nsz, tlen)); tlen = packet_get_length(desc->inet.htype, ptr, n, desc->inet.psize, desc->i_bufsz, &desc->http_state); + if (tlen > 0) { if (tlen <= n) { /* got a packet */ *len = tlen; @@ -9840,7 +10131,146 @@ static void tcp_inet_event(ErlDrvData e, ErlDrvEvent event) return; } -#endif /* WIN32 */ +#elif defined(__OSE__) /* !__WIN32__ */ +/* The specific resolve signal function. It will return the socket descriptor + for which the select was issued */ +static ErlDrvOseEventId inet_resolve_signal(union SIGNAL *sig) { + DEBUGF(("%s(?#?): s=%d got signal %s, status = %d, extra = %d, sender = 0x%x\n", + __FUNCTION__,sig->async.fd,signo_to_string(sig->signo), + sig->async.event.status, + sig->async.event.extra,sender(&sig))); + if (sig->signo == SO_EVENT_READ_REPLY || + sig->signo == SO_EVENT_ACCEPT_REPLY || + sig->signo == SO_EVENT_EOF_REPLY || + sig->signo == SO_EVENT_WRITE_REPLY || + sig->signo == SO_EVENT_ERROR_REPLY || + sig->signo == SO_EVENT_CONNECT_REPLY ) { + return sig->async.fd; + } + + return -1; +} + +static void inet_driver_select(inet_descriptor* desc, + int flags, int onoff) { + ASSERT(!desc->is_ignored); + + if(onoff) { + desc->select_state |= flags; + } else { + desc->select_state &= ~flags; + } +} + +static ssize_t writev_fallback(int fd, const struct iovec *iov, int iovcnt, int max_sz) +{ + size_t data_len = 0; + size_t sent = 0; + ssize_t n; + int i; + + for(i = 0; i < iovcnt; i++) + { + data_len = iov[i].iov_len; +tryagain: + n = sock_send(fd, iov[i].iov_base, data_len, 0); + if (IS_SOCKET_ERROR(n)) { + /* If buffer length is greater than the amount stack is able to + * send out then try to send at least max_sz (this comes with + * SO_EVENT_WRITE_REPLY signal*/ + if ((errno == EMSGSIZE) && (max_sz > 0) && (data_len > max_sz)) { + data_len = max_sz; + goto tryagain; + } + break; + } + sent += n; + } + return sent; +} + +#define OSE_EVENT_REQ(TCP_DESC,EVENT) do { \ + union SIGNAL *sig = alloc(sizeof(struct OseAsyncSig), EVENT); \ + sig->async.fd = INETP(TCP_DESC)->s; \ + ose_request_event(INETP(TCP_DESC)->s, &sig, 1); \ + DEBUGF(("%s(%ld): s=%d sent %s\r\n",__FUNCTION__, \ + INETP(TCP_DESC)->port,INETP(TCP_DESC)->s,signo_to_string(EVENT))); \ + } while(0) + +static void tcp_inet_ose_dispatch_signals(tcp_descriptor *desc, + int prev_select_state, + union SIGNAL *sig) { + if (sig) { + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d resend\r\n", + (long)INETP(desc)->port,INETP(desc)->s)); + /* We are reacting to a signal, which means that if + the select_state for that signal is still activated + we should send a new signal */ + switch (sig->signo) { + case SO_EVENT_READ_REPLY: { + if (INETP(desc)->select_state & FD_READ) + OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); + break; + } + case SO_EVENT_WRITE_REPLY: { + if (INETP(desc)->select_state & FD_WRITE) + OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); + break; + } + case SO_EVENT_CONNECT_REPLY: { + if (INETP(desc)->select_state & FD_CONNECT) + OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); + break; + } + case SO_EVENT_ACCEPT_REPLY: { + if (INETP(desc)->select_state & FD_ACCEPT) + OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); + break; + } + case SO_EVENT_ERROR_REPLY: { + if (INETP(desc)->select_state & SOCK_FD_ERROR) + OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); + break; + } + + } + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", + (long)INETP(desc)->port)); + } + + if (INETP(desc)->select_state != prev_select_state) { + /* If the select state has changed we have to issue signals for + the state parts that have changed. */ + int xor_select_state = INETP(desc)->select_state ^ prev_select_state; + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) {s=%d select change\r\n", + (long)INETP(desc)->port,INETP(desc)->s)); + if ((xor_select_state & FD_READ) && + (INETP(desc)->select_state & FD_READ)) { + OSE_EVENT_REQ(desc,SO_EVENT_READ_REQUEST); + } + if ((xor_select_state & FD_WRITE) && + (INETP(desc)->select_state & FD_WRITE)) { + OSE_EVENT_REQ(desc,SO_EVENT_WRITE_REQUEST); + } + if ((xor_select_state & FD_CONNECT) && + (INETP(desc)->select_state & FD_CONNECT)) { + OSE_EVENT_REQ(desc,SO_EVENT_CONNECT_REQUEST); + } + if ((xor_select_state & FD_ACCEPT) && + (INETP(desc)->select_state & FD_ACCEPT)) { + OSE_EVENT_REQ(desc,SO_EVENT_ACCEPT_REQUEST); + } + if ((xor_select_state & SOCK_FD_ERROR) && + (INETP(desc)->select_state & SOCK_FD_ERROR)) { + OSE_EVENT_REQ(desc,SO_EVENT_ERROR_REQUEST); + } + + DEBUGF(("tcp_inet_ose_dispatch_signals(%ld) }\r\n", + (long)INETP(desc)->port)); + } +} + +#endif /* __OSE__ */ /* socket has input: @@ -9861,7 +10291,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) unsigned int len; inet_address remote; inet_async_op *this_op = desc->inet.opt; - + len = sizeof(desc->inet.remote); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len); if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) { @@ -9930,7 +10360,6 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event) while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) { len = sizeof(desc->inet.remote); s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len); - if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) { /* Just try again, no real error, keep the last return code */ goto done; @@ -10256,6 +10685,49 @@ static int tcp_send(tcp_descriptor* desc, char* ptr, ErlDrvSizeT len) return 0; } +#ifdef __OSE__ + +static void tcp_inet_drv_output_ose(ErlDrvData data, ErlDrvEvent event) +{ + union SIGNAL *event_sig = erl_drv_ose_get_signal(event); + + while (event_sig) { + int prev_select_state = INETP((tcp_descriptor*)data)->select_state; + int res = tcp_inet_output((tcp_descriptor*)data, (HANDLE)event_sig); + if (res != -1) { + tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, + prev_select_state,event_sig); + free_buf(&event_sig); + event_sig = erl_drv_ose_get_signal(event); + } else { + /* NOTE: here the event object could have been deallocated!!!! + inet_stop_select is called when doing driver_select(ERL_DRV_USE,0) + */ + free_buf(&event_sig); + return; + } + } +} + +static void tcp_inet_drv_input_ose(ErlDrvData data, ErlDrvEvent event) +{ + union SIGNAL *event_sig = erl_drv_ose_get_signal(event); + + while (event_sig) { + int prev_select_state = INETP((tcp_descriptor*)data)->select_state; + int res = tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); + if (res != -1) { + tcp_inet_ose_dispatch_signals((tcp_descriptor*)data, prev_select_state, + event_sig); + free_buf(&event_sig); + event_sig = erl_drv_ose_get_signal(event); + } else { + free_buf(&event_sig); + return; + } + } +} +#else static void tcp_inet_drv_output(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_output((tcp_descriptor*)data, (HANDLE)event); @@ -10265,6 +10737,7 @@ static void tcp_inet_drv_input(ErlDrvData data, ErlDrvEvent event) { (void)tcp_inet_input((tcp_descriptor*)data, (HANDLE)event); } +#endif /* socket ready for ouput: ** 1. INET_STATE_CONNECTING => non block connect ? @@ -10330,6 +10803,13 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) ssize_t n; SysIOVec* iov; +#ifdef __OSE__ + /* For large size buffers case the amount of data that the stack is + able to send out (received in the .extra field) should be passed + down to writev_fallback */ + n = event ? ((union SIGNAL*)event)->async.event.extra : 0; +#endif + if ((iov = driver_peekq(ix, &vsize)) == NULL) { sock_select(INETP(desc), FD_WRITE, 0); send_empty_out_q_msgs(INETP(desc)); @@ -10341,8 +10821,8 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) if (IS_SOCKET_ERROR(sock_sendv(desc->inet.s, iov, vsize, &n, 0))) { write_error: if ((sock_errno() != ERRNO_BLOCK) && (sock_errno() != EINTR)) { - DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d\r\n", - (long)desc->inet.port, vsize, sock_errno())); + DEBUGF(("tcp_inet_output(%ld): sock_sendv(%d) errno = %d (errno %d)\r\n", + (long)desc->inet.port, vsize, sock_errno(), errno)); ret = tcp_send_error(desc, sock_errno()); goto done; } @@ -10355,6 +10835,12 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event) sizes > (max 32 bit signed int) */ size_t howmuch = 0x7FFFFFFF; /* max signed 32 bit */ int x; +#ifdef __OSE__ + /* For EWOULDBLOCK sock_sendv returns 0 so we have to be sure it + wasn't the case */ + if(sock_errno() == ERRNO_BLOCK) + goto done; +#endif for(x = 0; x < vsize && iov[x].iov_len == 0; ++x) ; if (x < vsize) { @@ -10499,6 +10985,7 @@ static udp_descriptor* sctp_inet_copy(udp_descriptor* desc, SOCKET s, int* err) +#ifdef HAVE_UDP static int packet_inet_init() { return 0; @@ -10529,6 +11016,7 @@ static ErlDrvData udp_inet_start(ErlDrvPort port, char *args) set_default_msgq_limits(port); return data; } +#endif #ifdef HAVE_SCTP static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args) @@ -10539,6 +11027,7 @@ static ErlDrvData sctp_inet_start(ErlDrvPort port, char *args) } #endif +#ifdef HAVE_UDP static void packet_inet_stop(ErlDrvData e) { /* There should *never* be any "empty out q" subscribers on @@ -11049,7 +11538,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len) else inet_reply_ok(desc); } - +#endif #ifdef __WIN32__ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event) @@ -11071,6 +11560,7 @@ static void packet_inet_event(ErlDrvData e, ErlDrvEvent event) #endif +#ifdef HAVE_UDP static void packet_inet_drv_input(ErlDrvData e, ErlDrvEvent event) { (void) packet_inet_input((udp_descriptor*)e, (HANDLE)event); @@ -11327,6 +11817,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event) DEBUGF(("packet_inet_output(%ld) }\r\n", (long)desc->port)); return ret; } +#endif /*---------------------------------------------------------------------------*/ diff --git a/erts/emulator/sys/ose/default.lmconf b/erts/emulator/sys/ose/beam.lmconf index a66b0ece56..4ad46b01d9 100644 --- a/erts/emulator/sys/ose/default.lmconf +++ b/erts/emulator/sys/ose/beam.lmconf @@ -4,12 +4,13 @@ OSE_LM_POOL_SIZE=0x200000 OSE_LM_MAIN_NAME=main OSE_LM_MAIN_STACK_SIZE=0xF000 OSE_LM_MAIN_PRIORITY=20 +## Has to be of a type that allows MAM OSE_LM_PROGRAM_TYPE=APP_RAM OSE_LM_DATA_INIT=YES OSE_LM_BSS_INIT=YES OSE_LM_EXEC_MODEL=SHARED HEAP_MAX_SIZE=1000000000 -HEAP_SMALL_BUF_INIT_SIZE=64000000 +HEAP_SMALL_BUF_INIT_SIZE=20971520 HEAP_LARGE_BUF_THRESHOLD=16000000 HEAP_LOCK_TYPE=2 diff --git a/erts/emulator/sys/ose/erl_main.c b/erts/emulator/sys/ose/erl_main.c index 03119c3fec..23a9bc93a4 100644 --- a/erts/emulator/sys/ose/erl_main.c +++ b/erts/emulator/sys/ose/erl_main.c @@ -30,6 +30,8 @@ int main(int argc, char **argv) { + (void)stdin;(void)stdout;(void)stderr; + /* When starting using pm_create -c ARGV="-- -root ..", argv[0] is the first part of ARGV and not the name of the executable. So we shuffle some pointers here to make erl_start happy. */ diff --git a/erts/emulator/sys/ose/erl_poll.c b/erts/emulator/sys/ose/erl_poll.c index ca1ed6e53a..7d2a3d1e0b 100644 --- a/erts/emulator/sys/ose/erl_poll.c +++ b/erts/emulator/sys/ose/erl_poll.c @@ -551,7 +551,12 @@ int erts_poll_wait(ErtsPollSet ps, fd.id, fd.signo, current_process()); erts_send_error_to_logger_nogl(dsbufp); timeout = 0; - ASSERT(0); + /* Under normal circumstances the signal is deallocated by the + * driver that issued the select operation. But in this case + * there's no driver waiting for such signal so we have to + * deallocate it here */ + if (sig) + free_buf(&sig); } else { int i; struct erts_sys_fd_type *fd = NULL; @@ -737,6 +742,7 @@ union SIGNAL *erl_drv_ose_get_signal(ErlDrvEvent drv_ev) { ev->msgs = msg->next; ethr_mutex_unlock(&ev->mtx); erts_free(ERTS_ALC_T_FD_SIG_LIST,msg); + restore(sig); return sig; } } diff --git a/erts/emulator/sys/ose/sys.c b/erts/emulator/sys/ose/sys.c index c892cc69c7..5b950a7dae 100644 --- a/erts/emulator/sys/ose/sys.c +++ b/erts/emulator/sys/ose/sys.c @@ -195,7 +195,9 @@ static volatile int children_died; write_buff += sizeof(struct aiocb *); \ memcpy(write_buff,BUFF,SIZE+1); \ SET_AIO(*write_req,FD,SIZE,write_buff); \ - aio_write(write_req); \ + if (aio_write(write_req)) \ + ramlog_printf("%s:%d: write failed with %d\n", \ + __FILE__,__LINE__,errno); \ } \ } while(0) @@ -210,13 +212,13 @@ static volatile int children_died; driver_free(buffer_ptr); \ } while(0) -/* When we have several schedulers, we need to make sure - * that scheduler issuing aio_dispatch() is the owner on the signal */ #define DISPATCH_AIO(sig) do { \ - restore(sig); \ - aio_dispatch(sig); \ + if (aio_dispatch(sig)) \ + ramlog_printf("%s:%d: dispatch failed with %d\n", \ + __FILE__,__LINE__,errno); \ } while(0) +#define AIO_PIPE_SIZE 1024 /* debug print macros */ #define DEBUG_RES 0 @@ -371,6 +373,63 @@ thr_create_prepare_child(void *vtcdp) #endif /* #ifdef USE_THREADS */ +/* The two functions below are stolen from win_con.c + They have to use malloc/free/realloc directly becasue + we want to do able to do erts_printf very early on. + */ +#define VPRINTF_BUF_INC_SIZE 128 +static erts_dsprintf_buf_t * +grow_vprintf_buf(erts_dsprintf_buf_t *dsbufp, size_t need) +{ + char *buf; + size_t size; + + ASSERT(dsbufp); + + if (!dsbufp->str) { + size = (((need + VPRINTF_BUF_INC_SIZE - 1) + / VPRINTF_BUF_INC_SIZE) + * VPRINTF_BUF_INC_SIZE); + buf = (char *) malloc(size * sizeof(char)); + } + else { + size_t free_size = dsbufp->size - dsbufp->str_len; + + if (need <= free_size) + return dsbufp; + + size = need - free_size + VPRINTF_BUF_INC_SIZE; + size = (((size + VPRINTF_BUF_INC_SIZE - 1) + / VPRINTF_BUF_INC_SIZE) + * VPRINTF_BUF_INC_SIZE); + size += dsbufp->size; + buf = (char *) realloc((void *) dsbufp->str, + size * sizeof(char)); + } + if (!buf) + return NULL; + if (buf != dsbufp->str) + dsbufp->str = buf; + dsbufp->size = size; + return dsbufp; +} + +static int erts_sys_ramlog_printf(char *format, va_list arg_list) +{ + int res,i; + erts_dsprintf_buf_t dsbuf = ERTS_DSPRINTF_BUF_INITER(grow_vprintf_buf); + res = erts_vdsprintf(&dsbuf, format, arg_list); + if (res >= 0) { + for (i = 0; i < dsbuf.str_len; i+= 50) + /* We print 50 characters at a time because otherwise + the ramlog looks broken */ + ramlog_printf("%.*s",dsbuf.str_len-50 < 0?dsbuf.str_len:50,dsbuf.str+i); + } + if (dsbuf.str) + free((void *) dsbuf.str); + return res; +} + void erts_sys_pre_init(void) { @@ -409,6 +468,9 @@ erts_sys_pre_init(void) children_died = 0; #endif #endif /* USE_THREADS */ + + erts_printf_stdout_func = erts_sys_ramlog_printf; + erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0); } @@ -650,7 +712,7 @@ static void stop_select(ErlDrvEvent, void*); static PROCESS get_signal_proxy_pid(void) { union SIGNAL *sig; - SIGSELECT any_sig[] = {0}; + SIGSELECT any_sig[] = {1,ERTS_SIGNAL_OSE_DRV_ATTACH}; if (!sig_proxy_pid) { sig = alloc(sizeof(union SIGNAL), ERTS_SIGNAL_OSE_DRV_ATTACH); @@ -685,7 +747,7 @@ resolve_signal(union SIGNAL* sig) { struct erl_drv_entry spawn_driver_entry = { spawn_init, spawn_start, - erl_stop, + NULL, /* erl_stop, */ output, ready_input, ready_output, @@ -784,7 +846,11 @@ set_driver_data(ErlDrvPort port_num, /* READ */ if (read_write & DO_READ) { - efs_examine_fd(ifd, FLIB_FD_HANDLE, &driver_data[ifd].handle, 0); + EfsStatus res = efs_examine_fd(ifd, FLIB_FD_HANDLE, + &driver_data[ifd].handle, 0); + if (res != EFS_SUCCESS) + ramlog_printf("%s:%d: efs_examine_fd(%d) failed with %d\n", + __FILE__,__LINE__,ifd,errno); driver_data[ifd].ifd = ifd; driver_data[ifd].packet_bytes = packet_bytes; driver_data[ifd].port_num = port_num; @@ -792,10 +858,9 @@ set_driver_data(ErlDrvPort port_num, /* async read struct */ memset(&driver_data[ifd].aiocb, 0, sizeof(struct aiocb)); - driver_data[ifd].aiocb.aio_buf = driver_alloc(255); + driver_data[ifd].aiocb.aio_buf = driver_alloc(AIO_PIPE_SIZE); driver_data[ifd].aiocb.aio_fildes = ifd; - driver_data[ifd].aiocb.aio_nbytes = 255; - + driver_data[ifd].aiocb.aio_nbytes = (packet_bytes?packet_bytes:AIO_PIPE_SIZE); driver_data[ifd].alive = 1; driver_data[ifd].status = 0; driver_data[ifd].input_event = @@ -826,7 +891,9 @@ set_driver_data(ErlDrvPort port_num, (void) driver_select(port_num, driver_data[ifd].input_event, (ERL_DRV_READ | ERL_DRV_USE), 1); - aio_read(&driver_data[ifd].aiocb); + if (aio_read(&driver_data[ifd].aiocb)) + ramlog_printf("%s:%d: aio_read(%d) failed with %d\n", + __FILE__,__LINE__,ifd,errno); } else { /* WRITE ONLY */ efs_examine_fd(ofd, FLIB_FD_HANDLE, &driver_data[ofd].handle, 0); @@ -926,7 +993,7 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) { int ifd[2]; int ofd[2]; - static uint32_t ticker = 0; + static uint32_t ticker = 1; PmStatus pm_status; OSDOMAIN domain = PM_NEW_DOMAIN; PROCESS progpid, mainbid, mainpid; @@ -938,39 +1005,53 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) int handle_size; char *ptr; - /* handle arguments */ - ptr = strchr(name, ' '); - if (ptr != NULL) { - *ptr ='\0'; - ptr++; - args = ptr; + + args = driver_alloc(strlen(name)+1); + strcpy(args, name); + /* We need to handle name in three parts + * - install handle (must be unique) + * - install binary (needed for ose_pm_install_load_module()) + * - full path (as argument to the spawned applications env.var + */ + + /* full path including arguments */ + args = driver_alloc(strlen(name)+1); + strcpy(args, name); + + /* handle path */ + tmp_handle = strrchr(name, '/'); + if (tmp_handle == NULL) { + tmp_handle = name; } else { - args = NULL; + tmp_handle++; } - /* create an install handle */ - ptr = strrchr(name, '/'); + /* handle args */ + ptr = strchr(tmp_handle, ' '); if (ptr != NULL) { - ptr++; - tmp_handle = ptr; + *ptr = '\0'; + handle_size = ptr - tmp_handle; } else { - tmp_handle = name; + handle_size = strlen(name)+1; } - handle_size = strlen(tmp_handle)+1; - handle_size += (ticker<10)?3:((ticker<100)?4:5); + /* make room for ticker */ + handle_size += (ticker<10)?3:((ticker<100)?4:5); handle = driver_alloc(handle_size); - snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker); - + do { - snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker++); + snprintf(handle, handle_size, "%s_%d", tmp_handle, ticker); pm_status = ose_pm_install_load_module(0, "ELF", name, handle, 0, 0, NULL); - + ticker++; } while (pm_status == PM_EINSTALL_HANDLE_ALREADY_INSTALLED); - DEBUG_CHECK_RES(pm_status, PM_SUCCESS); + + if (pm_status != PM_SUCCESS) { + errno = ENOSYS; /* FIXME add comment */ + return ERL_DRV_ERROR_ERRNO; + } /* Create Program */ pm_status = ose_pm_create_program(&domain, handle, 0, 0, @@ -1143,17 +1224,13 @@ static void erl_stop(ErlDrvData drv_data) if (data->ifd != data->ofd) { /* read and write */ nbio_stop_fd(data->port_num, data->input_event); nbio_stop_fd(data->port_num, data->output_event); - driver_select(data->port_num, data->input_event, ERL_DRV_USE, 0); - driver_select(data->port_num, data->output_event, ERL_DRV_USE, 0); } else { /* write only */ nbio_stop_fd(data->port_num, data->output_event); - driver_select(data->port_num, data->output_event, ERL_DRV_USE, 0); } } else { /* read only */ nbio_stop_fd(data->port_num, data->input_event); - driver_select(data->port_num, data->input_event, ERL_DRV_USE, 0); } close(data->ifd); close(data->ofd); @@ -1177,18 +1254,31 @@ static void output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len) lbp = lb + (4-(data->packet_bytes)); if ((sz = driver_sizeq(data->port_num)) > 0) { - driver_enq(data->port_num, lbp, data->packet_bytes); - driver_enq(data->port_num, buf, len); - if (sz + len + data->packet_bytes >= (1 << 13)) + if (data->packet_bytes != 0) { + driver_enq(data->port_num, lbp, data->packet_bytes); + } + driver_enq(data->port_num, buf, len); + + if (sz + len + data->packet_bytes >= (1 << 13)) set_busy_port(data->port_num, 1); } else { - driver_enq(data->port_num, buf, len); /* n is the skip value */ - + char *pbbuf; + if (data->packet_bytes != 0) { + pbbuf = malloc(len + data->packet_bytes); + int i; + for (i = 0; i < data->packet_bytes; i++) { + *pbbuf++ = *lbp++; + } + strncpy(pbbuf, buf, len); + pbbuf -= data->packet_bytes; + } driver_select(data->port_num, data->output_event, ERL_DRV_WRITE|ERL_DRV_USE, 1); - - WRITE_AIO(data->ofd, len, buf); + WRITE_AIO(data->ofd, + (data->packet_bytes ? len+data->packet_bytes : len), + (data->packet_bytes ? pbbuf : buf)); + if (data->packet_bytes != 0) free(pbbuf); } return; /* 0; */ } @@ -1204,12 +1294,12 @@ static int port_inp_failure(ErlDrvPort port_num, ErlDrvEvent ready_fd, int res) ASSERT(res <= 0); erl_drv_ose_event_fetch(ready_fd,&sig_no, NULL, (void **)&fd); - /* As we need to handle two signals, we do this in two steps */ if (driver_data[*fd].alive) { report_exit_status(driver_data[*fd].report_exit, 0); /* status? */ } else { + driver_select(port_num,ready_fd,DO_READ|DO_WRITE,0); clear_fd_data(*fd); driver_report_exit(driver_data[*fd].port_num, driver_data[*fd].status); /* As we do not really know if the spawn has crashed or exited nicely @@ -1248,6 +1338,10 @@ static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd) } else { res = sig->fm_read_reply.actual; + if (res == 0) { + port_inp_failure(data->port_num, ready_fd, res); + break; + } if (data->packet_bytes == 0) { if (res < 0) { @@ -1258,6 +1352,7 @@ static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd) else if (res == 0) { /* read of 0 bytes, eof, otherside of pipe is assumed dead */ port_inp_failure(data->port_num, ready_fd, res); + break; } else { buf = driver_alloc(res); @@ -1267,100 +1362,91 @@ static void ready_input(ErlDrvData drv_data, ErlDrvEvent ready_fd) driver_output(data->port_num, (char*) buf, res); driver_free(buf); } + /* clear the previous read */ + memset(data->aiocb.aio_buf, 0, res); + + /* issue a new read */ + DISPATCH_AIO(sig); + aio_read(&data->aiocb); } - /* We try to read the remainder */ - else if (fd_data[data->ifd].remain > 0) { - if (res < 0) { - if ((errno != EINTR) && (errno != ERRNO_BLOCK)) { - port_inp_failure(data->port_num, ready_fd, res); + else if (data->packet_bytes && fd_data[data->ifd].remain > 0) { + /* we've read a partial package, or a header */ + + if (res == fd_data[data->ifd].remain) { /* we are done! */ + char *buf = data->aiocb.aio_buf; + int i; + + /* do we have anything buffered? */ + if (fd_data[data->ifd].buf != NULL) { + memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz, + buf, res); + buf = fd_data[data->ifd].buf; } - } - else if (res == 0) { - port_inp_failure(data->port_num, ready_fd, res); - } - else if (res == fd_data[data->ifd].remain) { /* we're done */ - driver_output(data->port_num, - fd_data[data->ifd].buf, - fd_data[data->ifd].sz); + + fd_data[data->ifd].sz += res; + driver_output(data->port_num, buf, (fd_data[data->ifd].sz>0?fd_data[data->ifd].sz:res)); clear_fd_data(data->ifd); - } - else { /* if (res < fd_data[fd].remain) */ - fd_data[data->ifd].cpos += res; - fd_data[data->ifd].remain -= res; - } - } - else if (fd_data[data->ifd].remain == 0) { /* clean fd */ - if (res < 0) { - if ((errno != EINTR) && (errno != ERRNO_BLOCK)) { - port_inp_failure(data->port_num, ready_fd, res); + + /* clear the previous read */ + memset(data->aiocb.aio_buf, 0, res); + + /* issue a new read */ + DISPATCH_AIO(sig); + data->aiocb.aio_nbytes = data->packet_bytes; + + if (data->aiocb.aio_buf == NULL) { + port_inp_failure(data->port_num, ready_fd, -1); } + aio_read(&data->aiocb); } - else if (res == 0) { /* eof */ - port_inp_failure(data->port_num, ready_fd, res); - } - else if (res < data->packet_bytes - fd_data[data->ifd].psz) { - memcpy(fd_data[data->ifd].pbuf+fd_data[data->ifd].psz, - (void *)data->aiocb.aio_buf, res); - fd_data[data->ifd].psz += res; - } - else { /* if (res >= packet_bytes) */ - unsigned char* cpos = (unsigned char*)data->aiocb.aio_buf; - int bytes_left = res; - - while (1) { - int psz = fd_data[data->ifd].psz; - char* pbp = fd_data[data->ifd].pbuf + psz; - - while (bytes_left && (psz < data->packet_bytes)) { - *pbp++ = *cpos++; - bytes_left--; - psz++; - } - - if (psz < data->packet_bytes) { - fd_data[data->ifd].psz = psz; - break; - } - fd_data[data->ifd].psz = 0; - - switch (data->packet_bytes) { - case 1: h = get_int8(fd_data[data->ifd].pbuf); break; - case 2: h = get_int16(fd_data[data->ifd].pbuf); break; - case 4: h = get_int32(fd_data[data->ifd].pbuf); break; - default: ASSERT(0); return; /* -1; */ - } - - if (h <= (bytes_left)) { - driver_output(data->port_num, (char*) cpos, h); - cpos += h; - bytes_left -= h; - continue; - } - else { /* The last message we got was split */ - char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h); - if (!buf) { - errno = ENOMEM; - port_inp_failure(data->port_num, ready_fd, -1); - } - else { - erts_smp_atomic_add_nob(&sys_misc_mem_sz, h); - sys_memcpy(buf, cpos, bytes_left); - fd_data[data->ifd].buf = buf; - fd_data[data->ifd].sz = h; - fd_data[data->ifd].remain = h - bytes_left; - fd_data[data->ifd].cpos = buf + bytes_left; - } - break; - } + else if(res < fd_data[data->ifd].remain) { /* received part of a package */ + if (fd_data[data->ifd].sz == 0) { + + fd_data[data->ifd].sz += res; + memcpy(fd_data[data->ifd].buf, data->aiocb.aio_buf, res); + fd_data[data->ifd].remain -= res; + } + else { + memcpy(fd_data[data->ifd].buf + fd_data[data->ifd].sz, + data->aiocb.aio_buf, res); + fd_data[data->ifd].sz += res; + fd_data[data->ifd].remain -= res; + } + /* clear the previous read */ + memset(data->aiocb.aio_buf, 0, res); + + /* issue a new read */ + DISPATCH_AIO(sig); + data->aiocb.aio_nbytes = fd_data[data->ifd].remain; + + if (data->aiocb.aio_buf == NULL) { + port_inp_failure(data->port_num, ready_fd, -1); } + aio_read(&data->aiocb); } } + else if (data->packet_bytes && fd_data[data->ifd].remain == 0) { /* we've recieved a header */ + + /* analyze the header FIXME */ + switch (data->packet_bytes) { + case 1: h = get_int8(data->aiocb.aio_buf); break; + case 2: h = get_int16(data->aiocb.aio_buf); break; + case 4: h = get_int32(data->aiocb.aio_buf); break; + } - /* reset the read buffer and init next asynch read */ - DISPATCH_AIO(sig); - memset((void *)data->aiocb.aio_buf, 0, 255); + fd_data[data->ifd].buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h + data->packet_bytes); + fd_data[data->ifd].remain = ((h + data->packet_bytes) - res); - if (res > 0) { + /* clear the previous read */ + memset(data->aiocb.aio_buf, 0, data->packet_bytes); + + /* issue a new read */ + DISPATCH_AIO(sig); + data->aiocb.aio_nbytes = h; + + if (data->aiocb.aio_buf == NULL) { + port_inp_failure(data->port_num, ready_fd, -1); + } aio_read(&data->aiocb); } } @@ -1400,11 +1486,16 @@ static void ready_output(ErlDrvData drv_data, ErlDrvEvent ready_fd) DISPATCH_AIO(sig); FREE_AIO(sig->fm_write_reply.buffer); res = driver_deq(data->port_num, iov[0].iov_len); - if (res > 0) { + if (res > 0) { iov = driver_peekq(data->port_num, &vlen); WRITE_AIO(data->ofd, iov[0].iov_len, iov[0].iov_base); } } + else if (vlen == 0) { + DISPATCH_AIO(sig); + FREE_AIO(sig->fm_write_reply.buffer); + } + } sig = erl_drv_ose_get_signal(ready_fd); } @@ -1650,10 +1741,10 @@ erl_assert_error(const char* expr, const char* func, { fflush(stdout); fprintf(stderr, "%s:%d:%s() Assertion failed: %s\n", - file, func, line, expr); + file, line, func, expr); fflush(stderr); ramlog_printf("%s:%d:%s() Assertion failed: %s\n", - file, func, line, expr); + file, line, func, expr); abort(); } diff --git a/erts/epmd/src/Makefile.in b/erts/epmd/src/Makefile.in index 2ea8630491..8dc8dae5f6 100644 --- a/erts/epmd/src/Makefile.in +++ b/erts/epmd/src/Makefile.in @@ -148,7 +148,7 @@ endif ifeq ($(findstring ose,$(TARGET)),ose) $(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(OSE_LM_OBJS) - $(call build-ose-load-module, $@, $(EPMD_OBJS) $(OSE_LM_OBJS), $(LIBS), $(LMCONF)) + $(call build-ose-load-module, $@, $(EPMD_OBJS) $(OSE_LM_OBJS), $(LIBS), $(EPMD_LMCONF)) else $(BINDIR)/$(EPMD): $(EPMD_OBJS) $(ERTS_LIB) $(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(EPMD_OBJS) $(LIBS) diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in index cfd36af962..0cf965f915 100644 --- a/erts/etc/common/Makefile.in +++ b/erts/etc/common/Makefile.in @@ -509,7 +509,7 @@ $(OBJDIR)/crt0_lm.o: $(CRT0_LM) OSE_LM_OBJS += $(OBJDIR)/ose_confd.o $(OBJDIR)/crt0_lm.o $(BINDIR)/run_erl_lm: $(OBJDIR)/run_erl_main.o $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(OBJDIR)/run_erl_common.o $(OBJDIR)/to_erl_common.o $(OSE_LM_OBJS) - $(call build-ose-load-module, $@, $^, $(LIBS), $(LMCONF)) + $(call build-ose-load-module, $@, $^, $(LIBS), $(RUN_ERL_LMCONF)) $(OBJDIR)/run_erl_main.o: $(OSEETC)/run_erl_main.c $(OSEETC)/run_erl.h ../common/to_erl_common.h $(RC_GENERATED) diff --git a/erts/etc/common/to_erl_common.c b/erts/etc/common/to_erl_common.c index a49be44b6c..ab706fffe0 100644 --- a/erts/etc/common/to_erl_common.c +++ b/erts/etc/common/to_erl_common.c @@ -126,7 +126,8 @@ static int version_handshake(char* buf, int len, int wfd); #define READ_AIO(REQ,FD,SIZE,BUFF) \ SET_AIO(REQ,FD,SIZE,BUFF); \ if (aio_read(&(REQ)) != 0) \ - fprintf(stderr,"aio_read of child_read_req(%d) failed\n",FD) + fprintf(stderr,"aio_read of child_read_req(%d) failed" \ + "with error %d\n",FD,errno) union SIGNAL { SIGSELECT signo; diff --git a/erts/etc/ose/etc.lmconf b/erts/etc/ose/etc.lmconf new file mode 100644 index 0000000000..b402b325b1 --- /dev/null +++ b/erts/etc/ose/etc.lmconf @@ -0,0 +1,20 @@ +OSE_LM_STACK_SIZES=256,512,1024,2048,4096,8192,16384,65536 +OSE_LM_SIGNAL_SIZES=31,63,127,255,1023,4095,16383,65535 +OSE_LM_POOL_SIZE=0x200000 +OSE_LM_MAIN_NAME=main +OSE_LM_MAIN_STACK_SIZE=0xF000 +OSE_LM_MAIN_PRIORITY=20 +## Has to be of a type that allows MAM +OSE_LM_PROGRAM_TYPE=APP_RAM +OSE_LM_DATA_INIT=YES +OSE_LM_BSS_INIT=YES +OSE_LM_EXEC_MODEL=SHARED +HEAP_MAX_SIZE=1000000000 +HEAP_SMALL_BUF_INIT_SIZE=64000000 +HEAP_LARGE_BUF_THRESHOLD=16000000 +HEAP_LOCK_TYPE=2 + +# Setting the environment variable EFS_RESOLVE_TMO on the block to 0. +# This will eliminiate delays when trying to open files on not mounted +# volumes. +EFS_RESOLVE_TMO=0 diff --git a/erts/etc/ose/run_erl_main.c b/erts/etc/ose/run_erl_main.c index d396ebe93b..2d92924ff2 100644 --- a/erts/etc/ose/run_erl_main.c +++ b/erts/etc/ose/run_erl_main.c @@ -45,6 +45,8 @@ int main(int argc, char **argv) char run_erl_usage[320], to_erl_usage[120]; + (void)stdin;(void)stdout;(void)stderr; + sprintf(run_erl_usage,RUN_ERL_USAGE,"run_erl [-daemon] [-block blockname]"); sprintf(to_erl_usage,TO_ERL_USAGE,"pipename"); diff --git a/erts/include/internal/ethr_mutex.h b/erts/include/internal/ethr_mutex.h index ee861065c5..6c931e0cd4 100644 --- a/erts/include/internal/ethr_mutex.h +++ b/erts/include/internal/ethr_mutex.h @@ -354,7 +354,7 @@ void ethr_rwmutex_rwunlock(ethr_rwmutex *); #ifdef ETHR_MTX_HARD_DEBUG #define ETHR_MTX_HARD_ASSERT(A) \ - ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, #A))) + ((void) ((A) ? 1 : ethr_assert_failed(__FILE__, __LINE__, __func__,#A))) #else #define ETHR_MTX_HARD_ASSERT(A) ((void) 1) #endif diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index 64f1fae6d8..54acd1295a 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -396,6 +396,18 @@ extern ethr_runtime_t ethr_runtime__; #include "ethr_atomics.h" /* The atomics API */ +#if defined (ETHR_OSE_THREADS) +static ETHR_INLINE void +ose_yield(void) +{ + if (get_ptype(current_process()) == OS_PRI_PROC) { + set_pri(get_pri(current_process())); + } else { + delay(1); + } +} +#endif + #if defined(__GNUC__) && !defined(ETHR_OSE_THREADS) # ifndef ETHR_SPIN_BODY # if defined(__i386__) || defined(__x86_64__) @@ -414,9 +426,9 @@ extern ethr_runtime_t ethr_runtime__; # endif #elif defined(ETHR_OSE_THREADS) # ifndef ETHR_SPIN_BODY -# define ETHR_SPIN_BODY set_pri(get_pri(current_process())) +# define ETHR_SPIN_BODY ose_yield() # else -# error "OSE should use set_pri(get_pri(current_process()))" +# error "OSE should use ose_yield()" # endif #endif @@ -449,7 +461,7 @@ extern ethr_runtime_t ethr_runtime__; # define ETHR_YIELD() (pthread_yield(), 0) # endif # elif defined(ETHR_OSE_THREADS) -# define ETHR_YIELD() (set_pri(get_pri(current_process())), 0) +# define ETHR_YIELD() (ose_yield(), 0) # else # define ETHR_YIELD() (ethr_compiler_barrier(), 0) # endif diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4 index c51c26794a..2b47f7c4bc 100644 --- a/lib/erl_interface/aclocal.m4 +++ b/lib/erl_interface/aclocal.m4 @@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file]) +AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) ]) diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index 2461f3ff25..fdc244f959 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -197,6 +197,9 @@ do_load_resolv({win32,Type}, longnames) -> win32_load_from_registry(Type), inet_db:set_lookup([native]); +do_load_resolv({ose,_}, _) -> + inet_db:set_lookup([file]); + do_load_resolv(_, _) -> inet_db:set_lookup([native]). diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index 3bda391b8e..187fd0001b 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -67,7 +67,7 @@ unsetenv(_) -> %%% End of BIFs -spec type() -> {Osfamily, Osname} when - Osfamily :: unix | win32, + Osfamily :: unix | win32 | ose, Osname :: atom(). type() -> diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index ee8bfcceb1..a261766eaa 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -50,6 +50,14 @@ oct_acceptor/1, otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]). +init_per_testcase(wrapping_oct, Config) when is_list(Config) -> + Dog = case os:type() of + {ose,_} -> + test_server:timetrap(test_server:minutes(20)); + _Else -> + test_server:timetrap(test_server:seconds(600)) + end, + [{watchdog, Dog}|Config]; init_per_testcase(iter_max_socks, Config) when is_list(Config) -> Dog = case os:type() of {win32,_} -> @@ -58,6 +66,14 @@ init_per_testcase(iter_max_socks, Config) when is_list(Config) -> test_server:timetrap(test_server:seconds(240)) end, [{watchdog, Dog}|Config]; +init_per_testcase(accept_system_limit, Config) when is_list(Config) -> + case os:type() of + {ose,_} -> + {skip,"Skip in OSE"}; + _ -> + Dog = test_server:timetrap(test_server:seconds(240)), + [{watchdog,Dog}|Config] + end; init_per_testcase(_Func, Config) when is_list(Config) -> Dog = test_server:timetrap(test_server:seconds(240)), [{watchdog, Dog}|Config]. @@ -2705,13 +2721,11 @@ wrapping_oct(doc) -> wrapping_oct(suite) -> []; wrapping_oct(Config) when is_list(Config) -> - Dog = test_server:timetrap(test_server:seconds(600)), {ok,Sock} = gen_tcp:listen(0,[{active,false},{mode,binary}]), {ok,Port} = inet:port(Sock), spawn_link(?MODULE,oct_acceptor,[Sock]), Res = oct_datapump(Port,16#1FFFFFFFF), gen_tcp:close(Sock), - test_server:timetrap_cancel(Dog), ok = Res, ok. diff --git a/lib/megaco/aclocal.m4 b/lib/megaco/aclocal.m4 index c51c26794a..2b47f7c4bc 100644 --- a/lib/megaco/aclocal.m4 +++ b/lib/megaco/aclocal.m4 @@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file]) +AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) ]) diff --git a/lib/odbc/aclocal.m4 b/lib/odbc/aclocal.m4 index c51c26794a..2b47f7c4bc 100644 --- a/lib/odbc/aclocal.m4 +++ b/lib/odbc/aclocal.m4 @@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file]) +AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) ]) diff --git a/lib/ose/doc/src/ose_intro.xml b/lib/ose/doc/src/ose_intro.xml index 0dd3ec409e..b5e3ef8b33 100644 --- a/lib/ose/doc/src/ose_intro.xml +++ b/lib/ose/doc/src/ose_intro.xml @@ -78,7 +78,7 @@ rtose@acp3400> pm_start 0x110059</code> seperate machine the paths have to be updated. In the example above <c>/usr/local/lib/erlang</c> was replaced by <c>/mst/erlang/</c>. The goal is to in future releases not have to do the special argument handling - but for now (17.0-rc2) you have to do it. + but for now (OTP 17.0) you have to do it. </p> <note> Because of a limitation in the way the OSE handles stdio when starting @@ -146,7 +146,7 @@ os:type(). It is possible to set the priorities you want for the OSE processes that thr emulator creates in the lmconf. An example of how to do it can be found in the default lmconf file in - $ERL_TOP/erts/emulator/sys/ose/default.lmconf. + $ERL_TOP/erts/emulator/sys/ose/beam.lmconf. </p> </section> diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl index 3e647635bc..1898dc8aba 100644 --- a/lib/stdlib/src/slave.erl +++ b/lib/stdlib/src/slave.erl @@ -290,7 +290,10 @@ register_unique_name(Number) -> %% no need to use rsh. mk_cmd(Host, Name, Args, Waiter, Prog0) -> - Prog = quote_progname(Prog0), + Prog = case os:type() of + {ose,_} -> mk_ose_prog(Prog0); + _ -> quote_progname(Prog0) + end, BasicCmd = lists:concat([Prog, " -detached -noinput -master ", node(), " ", long_or_short(), Name, "@", Host, @@ -310,6 +313,24 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) -> end end. +%% On OSE we have to pass the beam arguments directory to the slave +%% process. To find out what arguments that should be passed on we +%% make an assumption. All arguments after the last "--" should be +%% skipped. So given these arguments: +%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- -name test@localhost +%% we send +%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- +%% to the slave with whatever other args that are added in mk_cmd. +mk_ose_prog(Prog) -> + SkipTail = fun("--",[]) -> + ["--"]; + (_,[]) -> + []; + (Arg,Args) -> + [Arg," "|Args] + end, + [Prog,tl(lists:foldr(SkipTail,[],erlang:system_info(emu_args)))]. + %% This is an attempt to distinguish between spaces in the program %% path and spaces that separate arguments. The program is quoted to %% allow spaces in the path. diff --git a/lib/wx/aclocal.m4 b/lib/wx/aclocal.m4 index c51c26794a..2b47f7c4bc 100644 --- a/lib/wx/aclocal.m4 +++ b/lib/wx/aclocal.m4 @@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)]) AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)]) -AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file]) +AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)]) +AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file]) AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file]) ]) diff --git a/make/ose_lm.mk.in b/make/ose_lm.mk.in index 2e659ada1a..5455ad94c6 100644 --- a/make/ose_lm.mk.in +++ b/make/ose_lm.mk.in @@ -37,7 +37,9 @@ LDR1FLAGS = @erl_xcomp_ose_ldflags_pass1@ LDR2FLAGS = @erl_xcomp_ose_ldflags_pass2@ OSEROOT = @erl_xcomp_ose_OSEROOT@ LCF = @erl_xcomp_ose_LM_LCF@ -LMCONF = @erl_xcomp_ose_LM_CONF@ +BEAM_LMCONF = @erl_xcomp_ose_BEAM_LM_CONF@ +EPMD_LMCONF = @erl_xcomp_ose_EPMD_LM_CONF@ +RUN_ERL_LMCONF = @erl_xcomp_ose_RUN_ERL_LM_CONF@ STRIP = @erl_xcomp_ose_STRIP@ LM_POST_LINK = @erl_xcomp_ose_LM_POST_LINK@ LM_SET_CONF = @erl_xcomp_ose_LM_SET_CONF@ diff --git a/xcomp/erl-xcomp-powerpc-ose5.conf b/xcomp/erl-xcomp-powerpc-ose5.conf index 60b75b36c1..bf49b32827 100644 --- a/xcomp/erl-xcomp-powerpc-ose5.conf +++ b/xcomp/erl-xcomp-powerpc-ose5.conf @@ -338,8 +338,14 @@ erl_xcomp_ose_LM_ELF_SIZE="${OSEROOT}/bin/${HOST}/lm_elf_size" # * `erl_xcomp_ose_LM_LCF` - OSE load module linker configuration file erl_xcomp_ose_LM_LCF="${ERL_TOP}/erts/emulator/sys/ose/gcc_${GCCVERSION}_lm_ppc.lcf" -# * `erl_xcomp_ose_LM_CONF` - OSE load module default configuration file -erl_xcomp_ose_LM_CONF="${ERL_TOP}/erts/emulator/sys/ose/default.lmconf" +# * `erl_xcomp_ose_BEAM_LM_CONF` - beam OSE load module configuration file +erl_xcomp_ose_BEAM_LM_CONF="${ERL_TOP}/erts/emulator/sys/ose/beam.lmconf" + +# * `erl_xcomp_ose_RUN_ERL_LM_CONF` - run_erl_lm OSE load module configuration file +erl_xcomp_ose_RUN_ERL_LM_CONF="${ERL_TOP}/erts/etc/ose/etc.lmconf" + +# * `erl_xcomp_ose_EPMD_LM_CONF` - epmd OSE load module configuration file +erl_xcomp_ose_EPMD_LM_CONF="${ERL_TOP}/erts/etc/ose/etc.lmconf" # * `erl_xcomp_ose_CONFD` - OSE confd source file erl_xcomp_ose_CONFD="${OSEROOT}/src/ose_confd.c" diff --git a/xcomp/erl-xcomp-vars.sh b/xcomp/erl-xcomp-vars.sh index c5e245b4b6..5e55c3af1b 100644 --- a/xcomp/erl-xcomp-vars.sh +++ b/xcomp/erl-xcomp-vars.sh @@ -26,4 +26,4 @@ # and precious variables in $ERL_TOP/erts/aclocal.m4. # -erl_xcomp_vars="erl_xcomp_sysroot erl_xcomp_isysroot erl_xcomp_bigendian erl_xcomp_double_middle_endian erl_xcomp_linux_clock_gettime_correction erl_xcomp_linux_nptl erl_xcomp_linux_usable_sigusrx erl_xcomp_linux_usable_sigaltstack erl_xcomp_poll erl_xcomp_kqueue erl_xcomp_putenv_copy erl_xcomp_reliable_fpe erl_xcomp_getaddrinfo erl_xcomp_gethrvtime_procfs_ioctl erl_xcomp_clock_gettime_cpu_time erl_xcomp_after_morecore_hook erl_xcomp_dlsym_brk_wrappers erl_xcomp_posix_memalign erl_xcomp_ose_ldflags_pass1 erl_xcomp_ose_ldflags_pass2 erl_xcomp_ose_OSEROOT erl_xcomp_ose_STRIP erl_xcomp_ose_LM_POST_LINK erl_xcomp_ose_LM_SET_CONF erl_xcomp_ose_LM_GET_CONF erl_xcomp_ose_LM_ELF_SIZE erl_xcomp_ose_LM_LCF erl_xcomp_ose_LM_CONF erl_xcomp_ose_CONFD erl_xcomp_ose_CRT0_LM" +erl_xcomp_vars="erl_xcomp_sysroot erl_xcomp_isysroot erl_xcomp_bigendian erl_xcomp_double_middle_endian erl_xcomp_linux_clock_gettime_correction erl_xcomp_linux_nptl erl_xcomp_linux_usable_sigusrx erl_xcomp_linux_usable_sigaltstack erl_xcomp_poll erl_xcomp_kqueue erl_xcomp_putenv_copy erl_xcomp_reliable_fpe erl_xcomp_getaddrinfo erl_xcomp_gethrvtime_procfs_ioctl erl_xcomp_clock_gettime_cpu_time erl_xcomp_after_morecore_hook erl_xcomp_dlsym_brk_wrappers erl_xcomp_posix_memalign erl_xcomp_ose_ldflags_pass1 erl_xcomp_ose_ldflags_pass2 erl_xcomp_ose_OSEROOT erl_xcomp_ose_STRIP erl_xcomp_ose_LM_POST_LINK erl_xcomp_ose_LM_SET_CONF erl_xcomp_ose_LM_GET_CONF erl_xcomp_ose_LM_ELF_SIZE erl_xcomp_ose_LM_LCF erl_xcomp_ose_BEAM_LM_CONF erl_xcomp_ose_EPMD_LM_CONF erl_xcomp_ose_RUN_ERL_LM_CONF erl_xcomp_ose_CONFD erl_xcomp_ose_CRT0_LM" |