ref: 9a388068afc910ad273cb32a983f7cd4ed6c6f51
parent: 32048b6b17efd288f303045e3d1417ca21c39901
author: Ori Bernstein <[email protected]>
date: Thu Jan 9 16:19:32 EST 2014
Fix fork on osx fork() has a funky ABI, and you need to check %edx to know if you're the parent or child, and clear the PID in userspace.
--- a/libstd/sys-osx.myr
+++ b/libstd/sys-osx.myr
@@ -531,14 +531,16 @@
const sysctl : (mib : int[:], old : byte[:]#, new : byte[:] -> int)
;;
+extern const __osx_fork : (->int64)
+
/* process control */
const exit = {status; syscall(Sysexit, status castto(int64))}
const getpid = {; -> syscall(Sysgetpid, 1)}
const kill = {pid, sig; -> syscall(Syskill, pid, sig)}
-const fork = {; -> syscall(Sysfork)}
+const fork = {; -> __osx_fork()}
const wait4 = {pid, loc, opt, usage; -> syscall(Syswait4, pid, loc, opt, usage)}
const waitpid = {pid, loc, opt;
- -> wait4(pid, loc, opt, 0 castto(byte#))
+ -> wait4(pid, loc, opt, 0 castto(rusage#))
}
const execv = {cmd, args
--- a/libstd/syscall-osx.s
+++ b/libstd/syscall-osx.s
@@ -23,3 +23,30 @@
success:
popq %rbp
ret
+
+/*
+ * OSX is dumb about fork, and needs an assembly wrapper.
+ * The fork() syscall, when called directly, returns the pid in both
+ * processes, which means that both parent and child think they're
+ * the parent.
+ *
+ * checking this involves peeking in %edx, so we need to do this in asm.
+ */
+.globl _std$__osx_fork
+_std$__osx_fork:
+ pushq %rbp
+
+ movq $0x2000002,%rax
+ syscall
+
+ jae forksuccess
+ negq %rax
+
+forksuccess:
+ testl %edx,%edx
+ jz isparent
+ xorq %rax,%rax
+isparent:
+ popq %rbp
+ ret
+