Add callbacks for fork() (XCC)
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 22 Mar 2016 15:16:09 +0000 (11:16 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 22 Mar 2016 15:16:09 +0000 (11:16 -0400)
If a process forks but does not exec, some user-level subsystems (e.g.
select) will need to run a callback in the child.

Rebuild glibc.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Makefile
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/Versions
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fork.c
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fork_cb.c [new file with mode: 0644]
tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/fork_cb.h [new file with mode: 0644]

index fa44dc5..36915a1 100644 (file)
@@ -56,9 +56,11 @@ endif
 ifeq ($(subdir),stdlib)
 sysdep_routines += user_fd
 sysdep_routines += close_cb
+sysdep_routines += fork_cb
 endif
 sysdep_headers += sys/user_fd.h
 sysdep_headers += sys/close_cb.h
+sysdep_headers += sys/fork_cb.h
 # Epoll: uses User FDs, implemented in iplib
 sysdep_headers += sys/epoll.h bits/epoll.h
 
index adcdb22..696c992 100644 (file)
 #include <sys/types.h>
 #include <stdlib.h>
 #include <ros/syscall.h>
+#include <sys/fork_cb.h>
 
 /* Clone the calling process, creating an exact copy.
    Return -1 for errors, 0 to the new process,
    and the process ID of the new process to the old process.  */
 pid_t __fork(void)
 {
-       return ros_syscall(SYS_fork, 0, 0, 0, 0, 0, 0);
+       pid_t ret;
+       struct fork_cb *cb;
+
+       ret = ros_syscall(SYS_fork, 0, 0, 0, 0, 0, 0);
+       if (ret == 0) {
+               cb = fork_callbacks;
+               while (cb) {
+                       cb->func();
+                       cb = cb->next;
+               }
+       }
+       return ret;
 }
 libc_hidden_def (__fork)
 weak_alias (__fork, fork)
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fork_cb.c b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/fork_cb.c
new file mode 100644 (file)
index 0000000..7a2ef56
--- /dev/null
@@ -0,0 +1,20 @@
+/* Copyright (c) 2016 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * fork() callbacks.  See sys/fork_cb.h. */
+
+#include <sys/fork_cb.h>
+#include <ros/common.h>
+
+struct fork_cb *fork_callbacks;
+
+void register_fork_cb(struct fork_cb *cb)
+{
+       struct fork_cb *old;
+
+       do {
+               old = ACCESS_ONCE(fork_callbacks);
+               cb->next = old;
+       } while (!__sync_bool_compare_and_swap(&fork_callbacks, old, cb));
+}
diff --git a/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/fork_cb.h b/tools/compilers/gcc-glibc/glibc-2.19-akaros/sysdeps/akaros/sys/fork_cb.h
new file mode 100644 (file)
index 0000000..fcb4db5
--- /dev/null
@@ -0,0 +1,33 @@
+/* Copyright (c) 2016 Google Inc.
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * fork() callbacks.
+ *
+ * These are called after a process forks by the child.
+ *
+ * To register a cb, do your own allocation of a fork_cb, fill in func, then
+ * call register_fork_cb.  You cannot remove your CB.  Concurrent calls to
+ * fork() may or may not run your callback.
+ *
+ * Due to the plethora of user-level implementations of things normally in the
+ * kernel, such as select(), those systems may need to deal with fork() in a
+ * special way.  Imagine a process that forks, but does not exec.  The state of
+ * those systems may no longer be valid, since they may rely on kernel state
+ * that is no longer present.
+ *
+ * Specifically, select is built in taps, and select is supposed to be
+ * stateless, but ours relies on kernel state (taps).  Taps are not inherited
+ * (via fork or dup).  If you forked, select() would think it had taps set up,
+ * when in fact it didn't. */
+
+#pragma once
+
+struct fork_cb {
+       struct fork_cb                          *next;
+       void (*func)(void);
+};
+
+extern struct fork_cb *fork_callbacks; /* for use within glibc */
+
+void register_fork_cb(struct fork_cb *cb);