Skip to content

Commit 3ce5c14

Browse files
committed
---
yaml --- r: 110504 b: refs/heads/snap-stage3 c: 7da2109 h: refs/heads/master v: v3
1 parent 10960c4 commit 3ce5c14

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
refs/heads/master: e415c25bcd81dc1f9a5a3d25d9b48ed2d545336b
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
4-
refs/heads/snap-stage3: 9a33330caaaedb9eef447ae862e9b87e3aa9880f
4+
refs/heads/snap-stage3: 7da210907e4bf04a208adf186691cf516f1ef930
55
refs/heads/try: 597a645456b55e1c886ce15d23a192abdf4d55cf
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b

branches/snap-stage3/src/libnative/io/process.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,37 @@ fn spawn_process_os(config: p::ProcessConfig,
524524
Ok(..) => fail!("short read on the cloexec pipe"),
525525
};
526526
}
527-
drop(input);
527+
// And at this point we've reached a special time in the life of the
528+
// child. The child must now be considered hamstrung and unable to
529+
// do anything other than syscalls really. Consider the following
530+
// scenario:
531+
//
532+
// 1. Thread A of process 1 grabs the malloc() mutex
533+
// 2. Thread B of process 1 forks(), creating thread C
534+
// 3. Thread C of process 2 then attempts to malloc()
535+
// 4. The memory of process 2 is the same as the memory of
536+
// process 1, so the mutex is locked.
537+
//
538+
// This situation looks a lot like deadlock, right? It turns out
539+
// that this is what pthread_atfork() takes care of, which is
540+
// presumably implemented across platforms. The first thing that
541+
// threads to *before* forking is to do things like grab the malloc
542+
// mutex, and then after the fork they unlock it.
543+
//
544+
// Despite this information, libnative's spawn has been witnessed to
545+
// deadlock on both OSX and FreeBSD. I'm not entirely sure why, but
546+
// all collected backtraces point at malloc/free traffic in the
547+
// child spawned process.
548+
//
549+
// For this reason, the block of code below should contain 0
550+
// invocations of either malloc of free (or their related friends).
551+
//
552+
// As an example of not having malloc/free traffic, we don't close
553+
// this file descriptor by dropping the FileDesc (which contains an
554+
// allocation). Instead we just close it manually. This will never
555+
// have the drop glue anyway because this code never returns (the
556+
// child will either exec() or invoke libc::exit)
557+
let _ = libc::close(input.fd());
528558

529559
fn fail(output: &mut file::FileDesc) -> ! {
530560
let errno = os::errno();

0 commit comments

Comments
 (0)