aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c2
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.h8
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c48
3 files changed, 43 insertions, 15 deletions
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index fdffc7f119..998a0d297f 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -426,9 +426,11 @@ main(int argc, char *argv[])
while (write(pipes[1], &proto, sizeof(proto)) < 0 && errno == EINTR)
; /* remove gcc warning */
+#ifdef FORKER_PROTO_START_ACK
proto.action = ErtsSysForkerProtoAction_StartAck;
while (write(uds_fd, &proto, sizeof(proto)) < 0 && errno == EINTR)
; /* remove gcc warning */
+#endif
sys_sigrelease(SIGCHLD);
close(pipes[0]);
diff --git a/erts/emulator/sys/unix/erl_child_setup.h b/erts/emulator/sys/unix/erl_child_setup.h
index 93b39d46b2..a28b136bfc 100644
--- a/erts/emulator/sys/unix/erl_child_setup.h
+++ b/erts/emulator/sys/unix/erl_child_setup.h
@@ -25,6 +25,14 @@
#include "sys.h"
+#ifdef __FreeBSD__
+/* The freebsd sendmsg man page explicitly states that
+ you should not close fds before they are known
+ to have reached the other side, so this Ack protects
+ against that. */
+#define FORKER_PROTO_START_ACK 1
+#endif
+
#define FORKER_ARGV_NO_OF_ARGS 3
#define FORKER_ARGV_PROGNAME_IX 0 /* Program name */
#define FORKER_ARGV_MAX_FILES 1 /* max_files */
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index dc1c00ff96..2a7cd91265 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -1762,17 +1762,13 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
ASSERT(res == sizeof(*proto));
+#ifdef FORKER_PROTO_START_ACK
if (proto->action == ErtsSysForkerProtoAction_StartAck) {
/* Ideally we would like to not have to ack each Start
command being sent over the uds, but it would seem
that some operating systems (only observed on FreeBSD)
throw away data on the uds when the socket becomes full,
so we have to.
-
- Also the freebsd manual explicitly states that
- you should not close fds before they are known
- to have reached the other side, so this Ack protects
- against that as well.
*/
ErlDrvPort port_num = (ErlDrvPort)e;
int vlen;
@@ -1788,7 +1784,9 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
if (driver_sizeq(port_num) > 0)
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
- } else {
+ } else
+#endif
+ {
ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
/* ideally this would be a port_command call, but as command is
@@ -1805,16 +1803,27 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
{
ErlDrvPort port_num = (ErlDrvPort)e;
- int vlen;
- SysIOVec *iov = driver_peekq(port_num, &vlen);
- ErtsSysForkerProto *proto = (ErtsSysForkerProto *)iov[0].iov_base;
- ASSERT(iov[0].iov_len >= (sizeof(*proto)));
- if (sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
- proto->u.start.fds, 3, 0) < 0) {
- if (errno == ERRNO_BLOCK)
- return;
- erl_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup uds: %d", errno);
+#ifndef FORKER_PROTO_START_ACK
+ while (driver_sizeq(port_num) > 0) {
+#endif
+ int vlen;
+ SysIOVec *iov = driver_peekq(port_num, &vlen);
+ ErtsSysForkerProto *proto = (ErtsSysForkerProto *)iov[0].iov_base;
+ ASSERT(iov[0].iov_len >= (sizeof(*proto)));
+ if (sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
+ proto->u.start.fds, 3, 0) < 0) {
+ if (errno == ERRNO_BLOCK)
+ return;
+ erl_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ }
+#ifndef FORKER_PROTO_START_ACK
+ close(proto->u.start.fds[0]);
+ close(proto->u.start.fds[1]);
+ if (proto->u.start.fds[1] != proto->u.start.fds[2])
+ close(proto->u.start.fds[2]);
+ driver_deq(port_num, sizeof(*proto));
}
+#endif
driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
}
@@ -1840,5 +1849,14 @@ static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
erl_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
+#ifndef FORKER_PROTO_START_ACK
+ ASSERT(res == sizeof(*proto));
+ close(proto->u.start.fds[0]);
+ close(proto->u.start.fds[1]);
+ if (proto->u.start.fds[1] != proto->u.start.fds[2])
+ close(proto->u.start.fds[2]);
+ driver_deq(port_num, sizeof(*proto));
+#endif
+
return 0;
}