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{}