Version: 1
-Previous: fd7035c31dfd7c0e3cbb3e8cc19fdae5d5922a31
-Head: 93192f998caf2e9f0fb2d42dcd5c505926421651
+Previous: dbf9c410d37fd42d4229189abbb305cda5cf076c
+Head: f34057dc48aa90a8a996efd71b2bd434991a48d9
Applied:
cma-rm-pd: 2ffda7f2991395570b9e776ff5ae256ca9684771
transpose: 7856c0c353736cee5399eb2f706a6ac2913cc368
- fork: 1768d762d8a2100e5250234ddf080b722a5e582f
- fork-xfer: 93192f998caf2e9f0fb2d42dcd5c505926421651
+ fork: f34057dc48aa90a8a996efd71b2bd434991a48d9
Unapplied:
rstream-fork: 2724e02d5b461f8c580249461271de0f7acefcab
dbg: 3ec7b3dd2db8422fd840e3cee062c629e7b8f5b6
Bottom: 47adffa1c470a8413209e0679e601e328605b9da
-Top: 06618864b863228d0a358680b7f0aeafe4237c7b
+Top: 4860efad80a95980f7d24b72f375f62f9d743186
Author: Sean Hefty <sean.hefty@intel.com>
-Date: 2012-07-13 15:25:53 -0700
+Date: 2012-07-24 11:40:10 -0700
librspreload: Support server apps that call fork()
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
-
---
diff --git a/src/preload.c b/src/preload.c
-index d2058e2..f824af3 100644
+index d2058e2..79340c6 100644
--- a/src/preload.c
+++ b/src/preload.c
@@ -46,6 +46,8 @@
};
static struct socket_calls real;
-@@ -92,10 +95,13 @@ static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
+@@ -92,10 +95,12 @@ static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
static int sq_size;
static int rq_size;
static int sq_inline;
+static int fork_support;
-+static int last_accept = -1;
enum fd_type {
fd_normal,
};
struct fd_info {
-@@ -207,6 +213,10 @@ void getenv_options(void)
+@@ -207,6 +212,10 @@ void getenv_options(void)
var = getenv("RS_INLINE");
if (var)
sq_inline = atoi(var);
}
static void init_preload(void)
-@@ -244,6 +254,7 @@ static void init_preload(void)
+@@ -244,6 +253,7 @@ static void init_preload(void)
real.setsockopt = dlsym(RTLD_NEXT, "setsockopt");
real.getsockopt = dlsym(RTLD_NEXT, "getsockopt");
real.fcntl = dlsym(RTLD_NEXT, "fcntl");
rs.socket = dlsym(RTLD_DEFAULT, "rsocket");
rs.bind = dlsym(RTLD_DEFAULT, "rbind");
-@@ -378,8 +389,16 @@ int socket(int domain, int type, int protocol)
+@@ -378,8 +388,16 @@ int socket(int domain, int type, int protocol)
ret = rsocket(domain, type, protocol);
recursive = 0;
if (ret >= 0) {
return index;
}
fd_close(index, &ret);
-@@ -418,31 +437,67 @@ int listen(int socket, int backlog)
+@@ -418,31 +436,161 @@ int listen(int socket, int backlog)
int accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
{
int fd, index, ret;
- fd_store(index, ret, fd_rsocket);
+ fd_store(index, ret, type);
-+ last_accept = (type == fd_fork) ? index : -1;
return index;
} else {
-+ last_accept = -1;
return real.accept(fd, addr, addrlen);
}
}
-+static int connect_fork(int socket, const struct sockaddr *addr, socklen_t addrlen)
++/*
++ * We can't fork RDMA connections and pass them from the parent to the child
++ * process. Instead, we need to establish the RDMA connection after calling
++ * fork. To do this, we delay establishing the RDMA connection until we try
++ * to send/receive on the server side. On the client side, we don't expect
++ * to fork, so we switch from a TCP connection to an rsocket when connecting.
++ */
++static int fork_active(int socket, const struct sockaddr *addr, socklen_t addrlen)
+{
+ int fd, ret;
+ uint32_t msg;
+ return rconnect(ret, addr, addrlen);
+}
+
- int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
- {
- struct sockaddr_in *sin;
- int fd, ret;
-
-- if (fd_get(socket, &fd) == fd_rsocket) {
-+ switch (fd_get(socket, &fd)) {
-+ case fd_fork:
-+ return connect_fork(socket, addr, addrlen);
-+ case fd_rsocket:
- sin = (struct sockaddr_in *) addr;
- if (ntohs(sin->sin_port) > 1024) {
- ret = rconnect(fd, addr, addrlen);
-@@ -456,6 +511,9 @@ int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
-
- rclose(fd);
- fd = ret;
-+ break;
-+ default:
-+ break;
- }
-
- return real.connect(fd, addr, addrlen);
-@@ -754,3 +812,85 @@ int fcntl(int socket, int cmd, ... /* arg */)
- va_end(args);
- return ret;
- }
-+
-+/*
-+ * We can't fork RDMA connections and pass them from the parent to the child
-+ * process. Intercept the fork call, and if we're the child establish the
-+ * RDMA connection after calling fork. The assumption is that the last
-+ * connection accepted by the server will be processed by the child after the
-+ * fork call.
-+ *
-+ * It would be better to establishing the RDMA connection once the child
-+ * process tries to use the connection after the fork call (i.e. in a read
-+ * or write call), rather than making the previous assumption.
-+ */
-+pid_t fork(void)
++static void fork_passive(int socket)
+{
+ struct sockaddr_in6 sin6;
-+ pid_t pid;
+ sem_t *sem;
+ int lfd, sfd, dfd, ret, param;
+ socklen_t len;
+ uint32_t msg;
+
-+ init_preload();
-+ pid = real.fork();
-+ if (pid || !fork_support || (last_accept < 0) ||
-+ (fd_get(last_accept, &sfd) != fd_fork))
-+ goto out;
++ fd_get(socket, &sfd);
+
+ len = sizeof sin6;
+ ret = real.getsockname(sfd, (struct sockaddr *) &sin6, &len);
+
+ sem = sem_open("/rsocket_fork", O_CREAT | O_RDWR,
+ S_IRWXU | S_IRWXG, 1);
-+ if (sem == SEM_FAILED)
++ if (sem == SEM_FAILED) {
++ ret = -1;
+ goto out;
++ }
+
+ lfd = rsocket(sin6.sin6_family, SOCK_STREAM, 0);
-+ if (lfd < 0)
++ if (lfd < 0) {
++ ret = lfd;
+ goto sclose;
++ }
+
+ param = 1;
+ rsetsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, ¶m, sizeof param);
+ goto lclose;
+
+ msg = 0;
-+ ret = real.write(sfd, &msg, sizeof msg);
-+ if (ret != sizeof msg)
++ len = real.write(sfd, &msg, sizeof msg);
++ if (len != sizeof msg)
+ goto lclose;
+
+ dfd = raccept(lfd, NULL, NULL);
-+ if (dfd < 0)
++ if (dfd < 0) {
++ ret = dfd;
+ goto lclose;
++ }
+
+ param = 1;
+ rsetsockopt(dfd, IPPROTO_TCP, TCP_NODELAY, ¶m, sizeof param);
+ copysockopts(dfd, sfd, &rs, &real);
+ real.shutdown(sfd, SHUT_RDWR);
+ real.close(sfd);
-+ fd_store(last_accept, dfd, fd_rsocket);
++ fd_store(socket, dfd, fd_rsocket);
+
+lclose:
+ rclose(lfd);
+sclose:
+ sem_close(sem);
+out:
-+ last_accept = -1;
-+ return pid;
++ if (ret)
++ fd_store(socket, sfd, fd_normal);
+}
++
++static inline enum fd_type fd_fork_get(int index, int *fd)
++{
++ struct fd_info *fdi;
++
++ fdi = idm_lookup(&idm, index);
++ if (fdi) {
++ if (fdi->type == fd_fork)
++ fork_passive(index);
++ *fd = fdi->fd;
++ return fdi->type;
++
++ } else {
++ *fd = index;
++ return fd_normal;
++ }
++}
++
+ int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
+ {
+ struct sockaddr_in *sin;
+ int fd, ret;
+
+- if (fd_get(socket, &fd) == fd_rsocket) {
++ switch (fd_get(socket, &fd)) {
++ case fd_fork:
++ return fork_active(socket, addr, addrlen);
++ case fd_rsocket:
+ sin = (struct sockaddr_in *) addr;
+ if (ntohs(sin->sin_port) > 1024) {
+ ret = rconnect(fd, addr, addrlen);
+@@ -456,6 +604,9 @@ int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
+
+ rclose(fd);
+ fd = ret;
++ break;
++ default:
++ break;
+ }
+
+ return real.connect(fd, addr, addrlen);
+@@ -464,7 +615,7 @@ int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
+ ssize_t recv(int socket, void *buf, size_t len, int flags)
+ {
+ int fd;
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rrecv(fd, buf, len, flags) : real.recv(fd, buf, len, flags);
+ }
+
+@@ -472,7 +623,7 @@ ssize_t recvfrom(int socket, void *buf, size_t len, int flags,
+ struct sockaddr *src_addr, socklen_t *addrlen)
+ {
+ int fd;
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rrecvfrom(fd, buf, len, flags, src_addr, addrlen) :
+ real.recvfrom(fd, buf, len, flags, src_addr, addrlen);
+ }
+@@ -480,7 +631,7 @@ ssize_t recvfrom(int socket, void *buf, size_t len, int flags,
+ ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
+ {
+ int fd;
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rrecvmsg(fd, msg, flags) : real.recvmsg(fd, msg, flags);
+ }
+
+@@ -488,7 +639,7 @@ ssize_t read(int socket, void *buf, size_t count)
+ {
+ int fd;
+ init_preload();
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rread(fd, buf, count) : real.read(fd, buf, count);
+ }
+
+@@ -496,14 +647,14 @@ ssize_t readv(int socket, const struct iovec *iov, int iovcnt)
+ {
+ int fd;
+ init_preload();
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rreadv(fd, iov, iovcnt) : real.readv(fd, iov, iovcnt);
+ }
+
+ ssize_t send(int socket, const void *buf, size_t len, int flags)
+ {
+ int fd;
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rsend(fd, buf, len, flags) : real.send(fd, buf, len, flags);
+ }
+
+@@ -511,7 +662,7 @@ ssize_t sendto(int socket, const void *buf, size_t len, int flags,
+ const struct sockaddr *dest_addr, socklen_t addrlen)
+ {
+ int fd;
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rsendto(fd, buf, len, flags, dest_addr, addrlen) :
+ real.sendto(fd, buf, len, flags, dest_addr, addrlen);
+ }
+@@ -519,7 +670,7 @@ ssize_t sendto(int socket, const void *buf, size_t len, int flags,
+ ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
+ {
+ int fd;
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rsendmsg(fd, msg, flags) : real.sendmsg(fd, msg, flags);
+ }
+
+@@ -527,7 +678,7 @@ ssize_t write(int socket, const void *buf, size_t count)
+ {
+ int fd;
+ init_preload();
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rwrite(fd, buf, count) : real.write(fd, buf, count);
+ }
+
+@@ -535,7 +686,7 @@ ssize_t writev(int socket, const struct iovec *iov, int iovcnt)
+ {
+ int fd;
+ init_preload();
+- return (fd_get(socket, &fd) == fd_rsocket) ?
++ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
+ rwritev(fd, iov, iovcnt) : real.writev(fd, iov, iovcnt);
+ }
+++ /dev/null
-Bottom: 06618864b863228d0a358680b7f0aeafe4237c7b
-Top: 4860efad80a95980f7d24b72f375f62f9d743186
-Author: Sean Hefty <sean.hefty@intel.com>
-Date: 2012-07-19 17:09:29 -0700
-
-rspreload: Move fork handling to first data transfer
-
-Instead of hooking fork and migrating the last accepted
-connection to rsockets, perform the migration when the socket
-first tries to send or receive data.
-
-This is necessary to handle more complex cases of fork, where
-the child process establishes connections.
-
-Signed-off-by: Sean Hefty <sean.hefty@intel.com>
-
-
----
-
-diff --git a/src/preload.c b/src/preload.c
-index f824af3..79340c6 100644
---- a/src/preload.c
-+++ b/src/preload.c
-@@ -96,7 +96,6 @@ static int sq_size;
- static int rq_size;
- static int sq_inline;
- static int fork_support;
--static int last_accept = -1;
-
- enum fd_type {
- fd_normal,
-@@ -453,15 +452,20 @@ int accept(int socket, struct sockaddr *addr, socklen_t *addrlen)
- }
-
- fd_store(index, ret, type);
-- last_accept = (type == fd_fork) ? index : -1;
- return index;
- } else {
-- last_accept = -1;
- return real.accept(fd, addr, addrlen);
- }
- }
-
--static int connect_fork(int socket, const struct sockaddr *addr, socklen_t addrlen)
-+/*
-+ * We can't fork RDMA connections and pass them from the parent to the child
-+ * process. Instead, we need to establish the RDMA connection after calling
-+ * fork. To do this, we delay establishing the RDMA connection until we try
-+ * to send/receive on the server side. On the client side, we don't expect
-+ * to fork, so we switch from a TCP connection to an rsocket when connecting.
-+ */
-+static int fork_active(int socket, const struct sockaddr *addr, socklen_t addrlen)
- {
- int fd, ret;
- uint32_t msg;
-@@ -489,6 +493,95 @@ static int connect_fork(int socket, const struct sockaddr *addr, socklen_t addrl
- return rconnect(ret, addr, addrlen);
- }
-
-+static void fork_passive(int socket)
-+{
-+ struct sockaddr_in6 sin6;
-+ sem_t *sem;
-+ int lfd, sfd, dfd, ret, param;
-+ socklen_t len;
-+ uint32_t msg;
-+
-+ fd_get(socket, &sfd);
-+
-+ len = sizeof sin6;
-+ ret = real.getsockname(sfd, (struct sockaddr *) &sin6, &len);
-+ if (ret)
-+ goto out;
-+ sin6.sin6_flowinfo = sin6.sin6_scope_id = 0;
-+ memset(&sin6.sin6_addr, 0, sizeof sin6.sin6_addr);
-+
-+ sem = sem_open("/rsocket_fork", O_CREAT | O_RDWR,
-+ S_IRWXU | S_IRWXG, 1);
-+ if (sem == SEM_FAILED) {
-+ ret = -1;
-+ goto out;
-+ }
-+
-+ lfd = rsocket(sin6.sin6_family, SOCK_STREAM, 0);
-+ if (lfd < 0) {
-+ ret = lfd;
-+ goto sclose;
-+ }
-+
-+ param = 1;
-+ rsetsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, ¶m, sizeof param);
-+
-+ sem_wait(sem);
-+ ret = rbind(lfd, (struct sockaddr *) &sin6, sizeof sin6);
-+ if (ret)
-+ goto lclose;
-+
-+ ret = rlisten(lfd, 1);
-+ if (ret)
-+ goto lclose;
-+
-+ msg = 0;
-+ len = real.write(sfd, &msg, sizeof msg);
-+ if (len != sizeof msg)
-+ goto lclose;
-+
-+ dfd = raccept(lfd, NULL, NULL);
-+ if (dfd < 0) {
-+ ret = dfd;
-+ goto lclose;
-+ }
-+
-+ param = 1;
-+ rsetsockopt(dfd, IPPROTO_TCP, TCP_NODELAY, ¶m, sizeof param);
-+ set_rsocket_options(dfd);
-+
-+ copysockopts(dfd, sfd, &rs, &real);
-+ real.shutdown(sfd, SHUT_RDWR);
-+ real.close(sfd);
-+ fd_store(socket, dfd, fd_rsocket);
-+
-+lclose:
-+ rclose(lfd);
-+ sem_post(sem);
-+sclose:
-+ sem_close(sem);
-+out:
-+ if (ret)
-+ fd_store(socket, sfd, fd_normal);
-+}
-+
-+static inline enum fd_type fd_fork_get(int index, int *fd)
-+{
-+ struct fd_info *fdi;
-+
-+ fdi = idm_lookup(&idm, index);
-+ if (fdi) {
-+ if (fdi->type == fd_fork)
-+ fork_passive(index);
-+ *fd = fdi->fd;
-+ return fdi->type;
-+
-+ } else {
-+ *fd = index;
-+ return fd_normal;
-+ }
-+}
-+
- int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
- {
- struct sockaddr_in *sin;
-@@ -496,7 +589,7 @@ int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
-
- switch (fd_get(socket, &fd)) {
- case fd_fork:
-- return connect_fork(socket, addr, addrlen);
-+ return fork_active(socket, addr, addrlen);
- case fd_rsocket:
- sin = (struct sockaddr_in *) addr;
- if (ntohs(sin->sin_port) > 1024) {
-@@ -522,7 +615,7 @@ int connect(int socket, const struct sockaddr *addr, socklen_t addrlen)
- ssize_t recv(int socket, void *buf, size_t len, int flags)
- {
- int fd;
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rrecv(fd, buf, len, flags) : real.recv(fd, buf, len, flags);
- }
-
-@@ -530,7 +623,7 @@ ssize_t recvfrom(int socket, void *buf, size_t len, int flags,
- struct sockaddr *src_addr, socklen_t *addrlen)
- {
- int fd;
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rrecvfrom(fd, buf, len, flags, src_addr, addrlen) :
- real.recvfrom(fd, buf, len, flags, src_addr, addrlen);
- }
-@@ -538,7 +631,7 @@ ssize_t recvfrom(int socket, void *buf, size_t len, int flags,
- ssize_t recvmsg(int socket, struct msghdr *msg, int flags)
- {
- int fd;
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rrecvmsg(fd, msg, flags) : real.recvmsg(fd, msg, flags);
- }
-
-@@ -546,7 +639,7 @@ ssize_t read(int socket, void *buf, size_t count)
- {
- int fd;
- init_preload();
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rread(fd, buf, count) : real.read(fd, buf, count);
- }
-
-@@ -554,14 +647,14 @@ ssize_t readv(int socket, const struct iovec *iov, int iovcnt)
- {
- int fd;
- init_preload();
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rreadv(fd, iov, iovcnt) : real.readv(fd, iov, iovcnt);
- }
-
- ssize_t send(int socket, const void *buf, size_t len, int flags)
- {
- int fd;
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rsend(fd, buf, len, flags) : real.send(fd, buf, len, flags);
- }
-
-@@ -569,7 +662,7 @@ ssize_t sendto(int socket, const void *buf, size_t len, int flags,
- const struct sockaddr *dest_addr, socklen_t addrlen)
- {
- int fd;
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rsendto(fd, buf, len, flags, dest_addr, addrlen) :
- real.sendto(fd, buf, len, flags, dest_addr, addrlen);
- }
-@@ -577,7 +670,7 @@ ssize_t sendto(int socket, const void *buf, size_t len, int flags,
- ssize_t sendmsg(int socket, const struct msghdr *msg, int flags)
- {
- int fd;
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rsendmsg(fd, msg, flags) : real.sendmsg(fd, msg, flags);
- }
-
-@@ -585,7 +678,7 @@ ssize_t write(int socket, const void *buf, size_t count)
- {
- int fd;
- init_preload();
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rwrite(fd, buf, count) : real.write(fd, buf, count);
- }
-
-@@ -593,7 +686,7 @@ ssize_t writev(int socket, const struct iovec *iov, int iovcnt)
- {
- int fd;
- init_preload();
-- return (fd_get(socket, &fd) == fd_rsocket) ?
-+ return (fd_fork_get(socket, &fd) == fd_rsocket) ?
- rwritev(fd, iov, iovcnt) : real.writev(fd, iov, iovcnt);
- }
-
-@@ -812,85 +905,3 @@ int fcntl(int socket, int cmd, ... /* arg */)
- va_end(args);
- return ret;
- }
--
--/*
-- * We can't fork RDMA connections and pass them from the parent to the child
-- * process. Intercept the fork call, and if we're the child establish the
-- * RDMA connection after calling fork. The assumption is that the last
-- * connection accepted by the server will be processed by the child after the
-- * fork call.
-- *
-- * It would be better to establishing the RDMA connection once the child
-- * process tries to use the connection after the fork call (i.e. in a read
-- * or write call), rather than making the previous assumption.
-- */
--pid_t fork(void)
--{
-- struct sockaddr_in6 sin6;
-- pid_t pid;
-- sem_t *sem;
-- int lfd, sfd, dfd, ret, param;
-- socklen_t len;
-- uint32_t msg;
--
-- init_preload();
-- pid = real.fork();
-- if (pid || !fork_support || (last_accept < 0) ||
-- (fd_get(last_accept, &sfd) != fd_fork))
-- goto out;
--
-- len = sizeof sin6;
-- ret = real.getsockname(sfd, (struct sockaddr *) &sin6, &len);
-- if (ret)
-- goto out;
-- sin6.sin6_flowinfo = sin6.sin6_scope_id = 0;
-- memset(&sin6.sin6_addr, 0, sizeof sin6.sin6_addr);
--
-- sem = sem_open("/rsocket_fork", O_CREAT | O_RDWR,
-- S_IRWXU | S_IRWXG, 1);
-- if (sem == SEM_FAILED)
-- goto out;
--
-- lfd = rsocket(sin6.sin6_family, SOCK_STREAM, 0);
-- if (lfd < 0)
-- goto sclose;
--
-- param = 1;
-- rsetsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, ¶m, sizeof param);
--
-- sem_wait(sem);
-- ret = rbind(lfd, (struct sockaddr *) &sin6, sizeof sin6);
-- if (ret)
-- goto lclose;
--
-- ret = rlisten(lfd, 1);
-- if (ret)
-- goto lclose;
--
-- msg = 0;
-- ret = real.write(sfd, &msg, sizeof msg);
-- if (ret != sizeof msg)
-- goto lclose;
--
-- dfd = raccept(lfd, NULL, NULL);
-- if (dfd < 0)
-- goto lclose;
--
-- param = 1;
-- rsetsockopt(dfd, IPPROTO_TCP, TCP_NODELAY, ¶m, sizeof param);
-- set_rsocket_options(dfd);
--
-- copysockopts(dfd, sfd, &rs, &real);
-- real.shutdown(sfd, SHUT_RDWR);
-- real.close(sfd);
-- fd_store(last_accept, dfd, fd_rsocket);
--
--lclose:
-- rclose(lfd);
-- sem_post(sem);
--sclose:
-- sem_close(sem);
--out:
-- last_accept = -1;
-- return pid;
--}