aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/unix
diff options
context:
space:
mode:
authorLukas Larsson <[email protected]>2015-09-11 16:35:48 +0200
committerLukas Larsson <[email protected]>2015-12-15 10:05:46 +0100
commit0ad8c5f46bc0173c09fa5e7e91f917de82389068 (patch)
tree9848f9145e0ba303cec6d39de3b8c65206cef6e5 /erts/emulator/sys/unix
parent123797a395b96b083d895c6ed7f41c56f4eafc78 (diff)
downloadotp-0ad8c5f46bc0173c09fa5e7e91f917de82389068.tar.gz
otp-0ad8c5f46bc0173c09fa5e7e91f917de82389068.tar.bz2
otp-0ad8c5f46bc0173c09fa5e7e91f917de82389068.zip
erts: Move os_pid to port hash to child setup
Had to move the hashing because of a race that can otherwise happen where a new os_pid value was inserted into the hash before the previous value had been removed. Also replaced the protocol inbetween erts and child setup to be a binary protocol. This was done in order to deal with the varying size of Eterm.
Diffstat (limited to 'erts/emulator/sys/unix')
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c127
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.h68
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h9
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c211
4 files changed, 250 insertions, 165 deletions
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 1f7ead0ec3..f74cb0f356 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -60,6 +60,8 @@
#include "erl_driver.h"
#include "sys_uds.h"
+#include "hash.h"
+#include "erl_child_setup.h"
#define SET_CLOEXEC(fd) fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC)
@@ -105,6 +107,10 @@ void sys_sigrelease(int sig)
sigprocmask(SIG_UNBLOCK, &mask, (sigset_t *)NULL);
}
+static void add_os_pid_to_port_id_mapping(Eterm, pid_t);
+static Eterm get_port_id(pid_t);
+static int forker_hash_init(void);
+
static int max_files = -1;
static int sigchld_pipe[2];
@@ -114,7 +120,7 @@ start_new_child(int pipes[])
int size, res, i, pos = 0;
char *buff, *o_buff;
- char *cmd, *wd, **new_environ, **args = NULL, cbuff[1];
+ char *cmd, *wd, **new_environ, **args = NULL;
Sint cnt, flags;
@@ -194,7 +200,12 @@ start_new_child(int pipes[])
DEBUG_PRINT("read ack");
do {
- res = read(pipes[0], cbuff, 1);
+ ErtsSysForkerProto proto;
+ res = read(pipes[0], &proto, sizeof(proto));
+ if (res > 0) {
+ ASSERT(proto.action == ErtsSysForkerProtoAction_Ack);
+ ASSERT(res == sizeof(proto));
+ }
} while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK));
if (res < 1) {
errno = EPIPE;
@@ -355,6 +366,8 @@ main(int argc, char *argv[])
exit(1);
}
+ forker_hash_init();
+
SET_CLOEXEC(uds_fd);
DEBUG_PRINT("Starting forker %d", max_files);
@@ -376,9 +389,10 @@ main(int argc, char *argv[])
if (FD_ISSET(uds_fd, &read_fds)) {
int pipes[3], res, os_pid;
- char buff[256];
+ ErtsSysForkerProto proto;
errno = 0;
- if ((res = sys_uds_read(uds_fd, buff, 1, pipes, 3, MSG_DONTWAIT)) < 0) {
+ if ((res = sys_uds_read(uds_fd, (char*)&proto, sizeof(proto),
+ pipes, 3, MSG_DONTWAIT)) < 0) {
if (errno == EINTR)
continue;
DEBUG_PRINT("erl_child_setup failed to read from uds: %d, %d", res, errno);
@@ -391,8 +405,8 @@ main(int argc, char *argv[])
}
/* Since we use unix domain sockets and send the entire data in
one go we *should* get the entire payload at once. */
- ASSERT(res == 1);
- ASSERT(buff[0] == 'S');
+ ASSERT(res == sizeof(proto));
+ ASSERT(proto.action == ErtsSysForkerProtoAction_Start);
sys_sigblock(SIGCHLD);
@@ -402,10 +416,14 @@ main(int argc, char *argv[])
if (os_pid == 0)
start_new_child(pipes);
+ add_os_pid_to_port_id_mapping(proto.u.start.port_id, os_pid);
+
/* We write an ack here, but expect the reply on
the pipes[0] inside the fork */
- res = sprintf(buff,"GO:%010d:%010d", os_pid, errno);
- while (write(pipes[1], buff, res + 1) < 0 && errno == EINTR)
+ proto.action = ErtsSysForkerProtoAction_Go;
+ proto.u.go.os_pid = os_pid;
+ proto.u.go.error_number = errno;
+ while (write(pipes[1], &proto, sizeof(proto)) < 0 && errno == EINTR)
; /* remove gcc warning */
sys_sigrelease(SIGCHLD);
@@ -416,16 +434,23 @@ main(int argc, char *argv[])
if (FD_ISSET(sigchld_pipe[0], &read_fds)) {
int ibuff[2];
- char buff[256];
+ ErtsSysForkerProto proto;
res = read(sigchld_pipe[0], ibuff, sizeof(ibuff));
if (res <= 0) {
if (errno == EINTR)
continue;
ABORT("Failed to read from sigchld pipe: %d (%d)", res, errno);
}
- res = snprintf(buff, 256, "SIGCHLD:%010d:%010d", ibuff[0], ibuff[1]);
+
+ proto.u.sigchld.port_id = get_port_id((pid_t)(ibuff[0]));
+
+ if (proto.u.sigchld.port_id == THE_NON_VALUE)
+ continue; /* exit status report not requested */
+
+ proto.action = ErtsSysForkerProtoAction_SigChld;
+ proto.u.sigchld.error_number = ibuff[1];
DEBUG_PRINT("send %s to %d", buff, uds_fd);
- if (write(uds_fd, buff, res + 1) < 0) {
+ if (write(uds_fd, &proto, sizeof(proto)) < 0) {
if (errno == EINTR)
continue;
/* The uds was close, which most likely means that the VM
@@ -437,3 +462,83 @@ main(int argc, char *argv[])
}
return 1;
}
+
+typedef struct exit_status {
+ HashBucket hb;
+ pid_t os_pid;
+ Eterm port_id;
+} ErtsSysExitStatus;
+
+static Hash *forker_hash;
+
+static void add_os_pid_to_port_id_mapping(Eterm port_id, pid_t os_pid)
+{
+ if (port_id != THE_NON_VALUE) {
+ /* exit status report requested */
+ ErtsSysExitStatus es;
+ es.os_pid = os_pid;
+ es.port_id = port_id;
+ hash_put(forker_hash, &es);
+ }
+}
+
+static Eterm get_port_id(pid_t os_pid)
+{
+ ErtsSysExitStatus est, *es;
+ Eterm port_id;
+ est.os_pid = os_pid;
+ es = hash_remove(forker_hash, &est);
+ if (!es) return THE_NON_VALUE;
+ port_id = es->port_id;
+ free(es);
+ return port_id;
+}
+
+static int fcmp(void *a, void *b)
+{
+ ErtsSysExitStatus *sa = a;
+ ErtsSysExitStatus *sb = b;
+ return !(sa->os_pid == sb->os_pid);
+}
+
+static HashValue fhash(void *e)
+{
+ ErtsSysExitStatus *se = e;
+ Uint32 val = se->os_pid;
+ val = (val+0x7ed55d16) + (val<<12);
+ val = (val^0xc761c23c) ^ (val>>19);
+ val = (val+0x165667b1) + (val<<5);
+ val = (val+0xd3a2646c) ^ (val<<9);
+ val = (val+0xfd7046c5) + (val<<3);
+ val = (val^0xb55a4f09) ^ (val>>16);
+ return val;
+}
+
+static void *falloc(void *e)
+{
+ ErtsSysExitStatus *se = e;
+ ErtsSysExitStatus *ne = malloc(sizeof(ErtsSysExitStatus));
+ ne->os_pid = se->os_pid;
+ ne->port_id = se->port_id;
+ return ne;
+}
+
+static void *meta_alloc(int type, size_t size) { return malloc(size); }
+static void meta_free(int type, void *p) { free(p); }
+
+static int forker_hash_init(void)
+{
+ HashFunctions forker_hash_functions;
+ forker_hash_functions.hash = fhash;
+ forker_hash_functions.cmp = fcmp;
+ forker_hash_functions.alloc = falloc;
+ forker_hash_functions.free = free;
+ forker_hash_functions.meta_alloc = meta_alloc;
+ forker_hash_functions.meta_free = meta_free;
+ forker_hash_functions.meta_print = NULL;
+
+ forker_hash = hash_new(0, "forker_hash",
+ 16, forker_hash_functions);
+
+ return 1;
+}
diff --git a/erts/emulator/sys/unix/erl_child_setup.h b/erts/emulator/sys/unix/erl_child_setup.h
new file mode 100644
index 0000000000..c3258f7cbe
--- /dev/null
+++ b/erts/emulator/sys/unix/erl_child_setup.h
@@ -0,0 +1,68 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2015-2015. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ *
+ * This file defines the interface inbetween erts and child_setup.
+ */
+
+#ifndef _ERL_UNIX_FORKER_H
+#define _ERL_UNIX_FORKER_H
+
+#include "sys.h"
+
+#define FORKER_ARGV_NO_OF_ARGS 3
+#define FORKER_ARGV_PROGNAME_IX 0 /* Program name */
+#define FORKER_ARGV_MAX_FILES 1 /* max_files */
+
+#define FORKER_FLAG_USE_STDIO (1 << 0) /* dup the pipe to stdin/stderr */
+#define FORKER_FLAG_EXIT_STATUS (1 << 1) /* send the exit status to parent */
+#define FORKER_FLAG_DO_READ (1 << 2) /* dup write fd */
+#define FORKER_FLAG_DO_WRITE (1 << 3) /* dup read fd */
+
+#if SIZEOF_VOID_P == SIZEOF_LONG
+typedef unsigned long ErtsSysPortId;
+#elif SIZEOF_VOID_P == SIZEOF_INT
+typedef unsigned int ErtsSysPortId;
+#elif SIZEOF_VOID_P == SIZEOF_LONG_LONG
+typedef unsigned long long ErtsSysPortId;
+#endif
+
+typedef struct ErtsSysForkerProto_ {
+ enum {
+ ErtsSysForkerProtoAction_Start,
+ ErtsSysForkerProtoAction_Go,
+ ErtsSysForkerProtoAction_SigChld,
+ ErtsSysForkerProtoAction_Ack
+ } action;
+ union {
+ struct {
+ ErtsSysPortId port_id;
+ int fds[3];
+ } start;
+ struct {
+ pid_t os_pid;
+ int error_number;
+ } go;
+ struct {
+ ErtsSysPortId port_id;
+ int error_number;
+ } sigchld;
+ } u;
+} ErtsSysForkerProto;
+
+#endif /* #ifndef _ERL_UNIX_FORKER_H */
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index c46f2c1fa2..0352ee1b3c 100644
--- a/erts/emulator/sys/unix/erl_unix_sys.h
+++ b/erts/emulator/sys/unix/erl_unix_sys.h
@@ -410,15 +410,6 @@ void erts_sys_unblock_fpe(int);
#define ERTS_FP_ERROR_THOROUGH(p, f, A) __ERTS_FP_ERROR_THOROUGH(&(p)->fp_exception, f, A)
-#define FORKER_ARGV_NO_OF_ARGS 3
-#define FORKER_ARGV_PROGNAME_IX 0 /* Program name */
-#define FORKER_ARGV_MAX_FILES 1 /* max_files */
-
-#define FORKER_FLAG_USE_STDIO (1 << 0) /* dup the pipe to stdin/stderr */
-#define FORKER_FLAG_EXIT_STATUS (1 << 1) /* send the exit status to parent */
-#define FORKER_FLAG_DO_READ (1 << 2) /* dup write fd */
-#define FORKER_FLAG_DO_WRITE (1 << 3) /* dup read fd */
-
/* Threads */
#ifdef USE_THREADS
extern int init_async(int);
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 6a1f2f6b2c..82096e5779 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -76,6 +76,8 @@ static Eterm forker_port;
#include "erl_sys_driver.h"
#include "sys_uds.h"
+#include "erl_child_setup.h"
+
#if defined IOV_MAX
#define MAXIOV IOV_MAX
#elif defined UIO_MAXIOV
@@ -120,12 +122,6 @@ typedef struct driver_data {
ErtsSysBlocking *blocking;
} ErtsSysDriverData;
-typedef struct exit_status {
- HashBucket hb;
- pid_t os_pid;
- Eterm port_id;
-} ErtsSysExitStatus;
-
#define DIR_SEPARATOR_CHAR '/'
#if defined(__ANDROID__)
@@ -241,21 +237,18 @@ static void outputv(ErlDrvData, ErlIOVec*);
static void stop_select(ErlDrvEvent, void*);
/* II.V Forker prototypes */
-static int forker_init(void);
static ErlDrvData forker_start(ErlDrvPort, char*, SysDriverOpts*);
static void forker_stop(ErlDrvData);
static void forker_ready_input(ErlDrvData, ErlDrvEvent);
static void forker_ready_output(ErlDrvData, ErlDrvEvent);
static ErlDrvSSizeT forker_control(ErlDrvData, unsigned int, char *,
ErlDrvSizeT, char **, ErlDrvSizeT);
-static void forker_add_os_pid_mapping(ErtsSysDriverData *);
-static void forker_remove_os_pid_mapping(ErtsSysDriverData *);
/* III Driver entries */
/* III.I The spawn driver */
struct erl_drv_entry spawn_driver_entry = {
- forker_init,
+ NULL,
spawn_start,
stop,
output,
@@ -794,12 +787,16 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
{
/* send ofd[0] + ifd[1] + stderrfd to forker port */
- int *fds = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(int)*3);
- memset(fds, 0, sizeof(int)*3);
- fds[0] = ofd[0];
- fds[1] = ifd[1];
- fds[2] = stderrfd;
- if (erl_drv_port_control(forker_port, 'S', (char*)fds, sizeof(int)*3)) {
+ ErtsSysForkerProto *proto =
+ erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA,
+ sizeof(ErtsSysForkerProto));
+ memset(proto, 0, sizeof(ErtsSysForkerProto));
+ proto->action = ErtsSysForkerProtoAction_Start;
+ proto->u.start.fds[0] = ofd[0];
+ proto->u.start.fds[1] = ifd[1];
+ proto->u.start.fds[2] = stderrfd;
+ proto->u.start.port_id = opts->exit_status ? erts_drvport2id(port_num) : THE_NON_VALUE;
+ if (erl_drv_port_control(forker_port, 'S', (char*)proto, sizeof(*proto))) {
/* The forker port has been killed, we close both fd's which will
make open_port throw an epipe error */
close(ofd[0]);
@@ -824,8 +821,12 @@ static ErlDrvSSizeT spawn_control(ErlDrvData e, unsigned int cmd, char *buf,
ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
{
ErtsSysDriverData *dd = (ErtsSysDriverData*)e;
+ ErtsSysForkerProto *proto = (ErtsSysForkerProto *)buf;
- memcpy(&dd->status, buf, sizeof(dd->status));
+ ASSERT(len == sizeof(*proto));
+ ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
+
+ dd->status = proto->u.sigchld.error_number;
dd->alive = -1;
if (dd->ifd)
@@ -1134,10 +1135,6 @@ static void stop(ErlDrvData ev)
ErtsSysDriverData* dd = (ErtsSysDriverData*)ev;
ErlDrvPort prt = dd->port_num;
- if (dd->alive == 1)
- /* Stop has been called before the exit status has been reported */
- forker_remove_os_pid_mapping(dd);
-
if (dd->ifd) {
nbio_stop_fd(prt, dd->ifd);
driver_select(prt, abs(dd->ifd->fd), ERL_DRV_USE, 0); /* close(ifd); */
@@ -1354,10 +1351,10 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
if (dd->pid == 0) {
/* the pid is sent from erl_child_setup. spawn driver only. */
- char message_buffer[3 + 10 + 1 + 10 + 1];
- int reason, res;
+ ErtsSysForkerProto proto;
+ int res;
- if((res = read(ready_fd, message_buffer, sizeof(message_buffer))) <= 0) {
+ if((res = read(ready_fd, &proto, sizeof(proto))) <= 0) {
/* hmm, child setup seems to have closed the pipe too early...
we close the port as there is not much else we can do */
if (res < 0 && errno == ERRNO_BLOCK)
@@ -1369,21 +1366,25 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
return;
}
- if(sscanf(message_buffer,"GO:%010d:%010d", &dd->pid, &reason) == 2) {
- if (dd->pid == -1) {
- /* Setup failed! The only reason why this should happen is if
- the fork fails. */
- errno = reason;
- port_inp_failure(dd, -1);
- return;
- }
+ ASSERT(proto.action == ErtsSysForkerProtoAction_Go);
+ dd->pid = proto.u.go.os_pid;
+
+ if (dd->pid == -1) {
+ /* Setup failed! The only reason why this should happen is if
+ the fork fails. */
+ errno = proto.u.go.error_number;
+ port_inp_failure(dd, -1);
+ return;
+ }
+
+ proto.action = ErtsSysForkerProtoAction_Ack;
- if (driver_sizeq(port_num) > 0) {
- driver_enq(port_num, "A", 1);
+ if (driver_sizeq(port_num) > 0) {
+ driver_enq(port_num, (char*)&proto, sizeof(proto));
} else {
- if (write(abs(dd->ofd->fd), "A", 1) < 0)
+ if (write(abs(dd->ofd->fd), &proto, sizeof(proto)) < 0)
if (errno == ERRNO_BLOCK || errno == EINTR)
- driver_enq(port_num, "A", 1);
+ driver_enq(port_num, (char*)&proto, sizeof(proto));
/* do nothing on failure here. If the ofd is broken, then
the ifd will probably also be broken and trigger
a port_inp_failure */
@@ -1400,15 +1401,9 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
child setup will close this fd if fd < 0 */
driver_select(port_num, abs(dd->ofd->fd), ERL_DRV_WRITE|ERL_DRV_USE, 1);
- if (dd->alive == 1)
- forker_add_os_pid_mapping(dd);
-
erl_drv_set_os_pid(port_num, dd->pid);
erl_drv_init_ack(port_num, e);
return;
- }
- ASSERT(0);
- return;
}
if (packet_bytes == 0) {
@@ -1652,10 +1647,6 @@ void fd_ready_async(ErlDrvData drv_data,
/* Forker driver */
static int forker_fd;
-static Hash *forker_hash;
-static erts_smp_mtx_t forker_hash_mtx;
-
-static void ffree(void *e);
static ErlDrvData forker_start(ErlDrvPort port_num, char* name,
SysDriverOpts* opts)
@@ -1749,16 +1740,18 @@ static ErlDrvData forker_start(ErlDrvPort port_num, char* name,
static void forker_stop(ErlDrvData e)
{
- /* we probably should do something here */
+ /* we probably should do something here,
+ the port has been closed by the user. */
}
static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
{
- int res, *exit_status;
- char buff[8+10+1+10+1] = {0};
- ErtsSysExitStatus est, *es;
+ int res;
+ ErtsSysForkerProto *proto;
+
+ proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
- if ((res = read(fd, buff, sizeof(buff))) < 0) {
+ if ((res = read(fd, proto, sizeof(*proto))) < 0) {
if (errno == ERRNO_BLOCK)
return;
erl_exit(ERTS_DUMP_EXIT, "Failed to read from erl_child_setup: %d\n", errno);
@@ -1767,26 +1760,15 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
if (res == 0)
erl_exit(ERTS_DUMP_EXIT, "erl_child_setup closed\n");
- if (sscanf(buff, "SIGCHLD:%010d:%010d", &est.os_pid, &res) != 2)
- erl_exit(ERTS_DUMP_EXIT, "Got corrupt data from erl_child_setup: %.s\n",
- buff, sizeof(buff));
-
- erts_smp_mtx_lock(&forker_hash_mtx);
- es = hash_remove(forker_hash, &est);
- erts_smp_mtx_unlock(&forker_hash_mtx);
+ ASSERT(res == sizeof(*proto));
+ ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
- if (!es)
- return;
-
- exit_status = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(int));
- exit_status[0] = res;
/* ideally this would be a port_command call, but as command is
already used by the spawn_driver, we use control instead.
Note that when using erl_drv_port_control it is an asynchronous
control. */
- erl_drv_port_control(es->port_id, 'S', (char*)exit_status, sizeof(int));
-
- ffree(es);
+ erl_drv_port_control(proto->u.sigchld.port_id, 'S',
+ (char*)proto, sizeof(*proto));
}
@@ -1797,18 +1779,19 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
while(driver_sizeq(port_num) > 0) {
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
- int *fds = (int*)iov[0].iov_base;
- ASSERT(iov[0].iov_len >= sizeof(int)*3);
- if (sys_uds_write(forker_fd, "S", 1, fds, 3, 0) < 0) {
+ 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);
}
- close(fds[0]);
- close(fds[1]);
- if (fds[1] != fds[2])
- close(fds[2]);
- driver_deq(port_num, sizeof(int)*3);
+ 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));
}
driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
@@ -1817,7 +1800,7 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
{
- int *fds = (int*)buf;
+ ErtsSysForkerProto *proto = (ErtsSysForkerProto *)buf;
ErlDrvPort port_num = (ErlDrvPort)e;
int res;
@@ -1826,7 +1809,8 @@ static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
return 0;
}
- if ((res = sys_uds_write(forker_fd, "S", 1, fds, 3, 0)) < 0) {
+ if ((res = sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
+ proto->u.start.fds, 3, 0)) < 0) {
if (errno == ERRNO_BLOCK) {
driver_enq(port_num, buf, len);
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
@@ -1834,74 +1818,11 @@ 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);
}
- close(fds[0]);
- close(fds[1]);
- if (fds[1] != fds[2])
- close(fds[2]);
- return 0;
-}
-static void forker_add_os_pid_mapping(ErtsSysDriverData *dd)
-{
- Eterm port_id = erts_drvport2id(dd->port_num);
- ErtsSysExitStatus es;
- es.os_pid = dd->pid;
- es.port_id = port_id;
- erts_smp_mtx_lock(&forker_hash_mtx);
- hash_put(forker_hash, &es);
- erts_smp_mtx_unlock(&forker_hash_mtx);
-}
-
-static void forker_remove_os_pid_mapping(ErtsSysDriverData *dd)
-{
- ErtsSysExitStatus est, *es;
- est.os_pid = dd->pid;
- erts_smp_mtx_lock(&forker_hash_mtx);
- es = hash_remove(forker_hash, &est);
- erts_smp_mtx_unlock(&forker_hash_mtx);
- if (es)
- ffree(es);
-}
-
-static int fcmp(void *a, void *b)
-{
- ErtsSysExitStatus *sa = a;
- ErtsSysExitStatus *sb = b;
- return !(sa->os_pid == sb->os_pid);
-}
-
-static HashValue fhash(void *e)
-{
- ErtsSysExitStatus *se = e;
- return make_hash2(make_small(se->os_pid));
-}
-
-static void *falloc(void *e)
-{
- ErtsSysExitStatus *se = e;
- ErtsSysExitStatus *ne = erts_alloc(ERTS_ALC_T_DRV, sizeof(ErtsSysExitStatus));
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, sizeof(ErtsSysBlocking));
- ne->os_pid = se->os_pid;
- ne->port_id = se->port_id;
- return ne;
-}
-
-static void ffree(void *e)
-{
- erts_free(ERTS_ALC_T_DRV, e);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, -sizeof(ErtsSysBlocking));
-}
-
-static int forker_init(void)
-{
- HashFunctions forker_hash_functions;
- forker_hash_functions.hash = fhash;
- forker_hash_functions.cmp = fcmp;
- forker_hash_functions.alloc = falloc;
- forker_hash_functions.free = ffree;
- forker_hash = hash_new(ERTS_ALC_T_DRV, "forker_hash",
- 16, forker_hash_functions);
- erts_smp_mtx_init(&forker_hash_mtx, "forker_hash_mtx");
-
- return 1;
+ 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]);
+ return 0;
}