aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/unix
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2015-10-14 09:56:03 +0200
committerLukas Larsson <[email protected]>2015-12-15 10:05:47 +0100
commit6fc7ccb41da5e9ec4357b40811ad740dd6a3b5b2 (patch)
tree156706b673d6ee9fd9d87b5fc11619e043f3ab34 /erts/emulator/sys/unix
parentb96e62d346eea60b2300dce22d8d892387de4681 (diff)
downloadotp-6fc7ccb41da5e9ec4357b40811ad740dd6a3b5b2.tar.gz
otp-6fc7ccb41da5e9ec4357b40811ad740dd6a3b5b2.tar.bz2
otp-6fc7ccb41da5e9ec4357b40811ad740dd6a3b5b2.zip
erts: Only use forker StackAck on freebsd
Diffstat (limited to 'erts/emulator/sys/unix')
-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;
}