wrapper: fork() before exec()ing

This CL is a wild guess that tries to work around what appears to be an
incredibly rare Go runtime bug
(https://github.com/golang/go/issues/24484). As mentioned on the
chromium bug, apparently execve is taking a while... somehow, and
`pthread_create` fails with `EAGAIN` concurrently.

So the intent here is to `fork()` + `exec()`. `fork()` will
  a) dispose of the thread that's trying to `pthread_create`
  b) isolate the `exec` in its own process, so the parent's runtime can
     spin up as many threads as it likes in peace.

This slows down an 'ideal' kernel build (aka a build where ccache is a
100% hit rate, so the compiler wrapper's overheads are very pronounced)
by ~4% in my measurements.

BUG=chromium:1095528
TEST=sdk tryjob; CQ

Change-Id: I73e1b238738b74c85def4709c09610f586fb04e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/2252552
Reviewed-by: Manoj Gupta <manojgupta@chromium.org>
Tested-by: George Burgess <gbiv@chromium.org>
diff --git a/compiler_wrapper/libc_exec.go b/compiler_wrapper/libc_exec.go
index f8db9d8..d986773 100644
--- a/compiler_wrapper/libc_exec.go
+++ b/compiler_wrapper/libc_exec.go
@@ -7,15 +7,31 @@
 package main
 
 // #include <errno.h>
+// #include <stdio.h>
 // #include <stdlib.h>
 // #include <string.h>
 // #include <unistd.h>
+// #include <sys/types.h>
+// #include <sys/wait.h>
 //
 // int libc_exec(const char *pathname, char *const argv[], char *const envp[]) {
-//	if (execve(pathname, argv, envp) != 0) {
+//	// Since fork() brings us to one thread, we can only use async-signal-safe funcs below.
+//	pid_t pid = fork();
+//	if (pid == 0) {
+//		execve(pathname, argv, envp);
+//		fprintf(stderr, "exec failed (errno: %d)\n", errno);
+//		_exit(1);
+//	}
+//	if (pid < 0) {
 //		return errno;
 //	}
-//	return 0;
+//
+//	int wstatus;
+//	pid_t waited = waitpid(pid, &wstatus, 0);
+//	if (waited == -1) {
+//		return errno;
+//	}
+//	exit(WEXITSTATUS(wstatus));
 //}
 import "C"
 import (
@@ -29,7 +45,7 @@
 // Note that this changes the go binary to be a dynamically linked one.
 // See crbug.com/1000863 for details.
 // To use this version of exec, please add '-tags libc_exec' when building Go binary.
-// Without the tags, libc_exec.go will be used.
+// Without the tags, libc_exec.go will not be used.
 
 func execCmd(env env, cmd *command) error {
 	freeList := []unsafe.Pointer{}