From 6be030cd7c58a94138f413b00c5c2d4ac952e310 Mon Sep 17 00:00:00 2001
From: Justine Tunney <jtunney@gmail.com>
Date: Sat, 6 Jul 2024 01:39:15 -0700
Subject: [PATCH] Fix MODE=tinylinux build

---
 .../pthread_atfork_actual.c}                  |  0
 libc/proc/fork.c                              |  2 +
 libc/stdio/fflush_unlocked.c                  | 47 -------------------
 libc/stdio/flockfile.c                        | 38 +++++++++++++++
 libc/stdio/stderr.c                           | 22 ++++-----
 libc/stdio/stdin.c                            | 21 ++++-----
 libc/stdio/stdout.c                           | 41 +++++++---------
 test/libc/thread/pthread_atfork_test.c        |  4 --
 8 files changed, 77 insertions(+), 98 deletions(-)
 rename libc/{thread/pthread_atfork.c => intrin/pthread_atfork_actual.c} (100%)

diff --git a/libc/thread/pthread_atfork.c b/libc/intrin/pthread_atfork_actual.c
similarity index 100%
rename from libc/thread/pthread_atfork.c
rename to libc/intrin/pthread_atfork_actual.c
diff --git a/libc/proc/fork.c b/libc/proc/fork.c
index 3a48db798..f1f138231 100644
--- a/libc/proc/fork.c
+++ b/libc/proc/fork.c
@@ -46,6 +46,8 @@
 #include "libc/thread/posixthread.internal.h"
 #include "libc/thread/tls.h"
 
+__static_yoink("_pthread_atfork");
+
 extern pthread_mutex_t _pthread_lock_obj;
 
 static void _onfork_prepare(void) {
diff --git a/libc/stdio/fflush_unlocked.c b/libc/stdio/fflush_unlocked.c
index dac00a5e4..579bc3676 100644
--- a/libc/stdio/fflush_unlocked.c
+++ b/libc/stdio/fflush_unlocked.c
@@ -16,58 +16,11 @@
 │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
 │ PERFORMANCE OF THIS SOFTWARE.                                                │
 ╚─────────────────────────────────────────────────────────────────────────────*/
-#include "libc/calls/calls.h"
 #include "libc/cxxabi.h"
-#include "libc/errno.h"
 #include "libc/intrin/pushpop.internal.h"
-#include "libc/macros.internal.h"
 #include "libc/mem/arraylist.internal.h"
-#include "libc/mem/mem.h"
-#include "libc/runtime/runtime.h"
 #include "libc/stdio/fflush.internal.h"
 #include "libc/stdio/internal.h"
-#include "libc/stdio/stdio.h"
-#include "libc/sysv/consts/o.h"
-#include "libc/thread/thread.h"
-
-void(__fflush_lock)(void) {
-  pthread_mutex_lock(&__fflush_lock_obj);
-}
-
-void(__fflush_unlock)(void) {
-  pthread_mutex_unlock(&__fflush_lock_obj);
-}
-
-static void __stdio_fork_prepare(void) {
-  FILE *f;
-  __fflush_lock();
-  for (int i = 0; i < __fflush.handles.i; ++i)
-    if ((f = __fflush.handles.p[i]))
-      pthread_mutex_lock(&f->lock);
-}
-
-static void __stdio_fork_parent(void) {
-  FILE *f;
-  for (int i = __fflush.handles.i; i--;)
-    if ((f = __fflush.handles.p[i]))
-      pthread_mutex_unlock(&f->lock);
-  __fflush_unlock();
-}
-
-static void __stdio_fork_child(void) {
-  FILE *f;
-  for (int i = __fflush.handles.i; i--;) {
-    if ((f = __fflush.handles.p[i])) {
-      bzero(&f->lock, sizeof(f->lock));
-      f->lock._word = PTHREAD_MUTEX_RECURSIVE;
-    }
-  }
-  pthread_mutex_init(&__fflush_lock_obj, 0);
-}
-
-__attribute__((__constructor__(60))) static textstartup void stdioinit(void) {
-  pthread_atfork(__stdio_fork_prepare, __stdio_fork_parent, __stdio_fork_child);
-}
 
 /**
  * Blocks until data from stream buffer is written out.
diff --git a/libc/stdio/flockfile.c b/libc/stdio/flockfile.c
index 556f86b63..2c381295f 100644
--- a/libc/stdio/flockfile.c
+++ b/libc/stdio/flockfile.c
@@ -16,8 +16,10 @@
 │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
 │ PERFORMANCE OF THIS SOFTWARE.                                                │
 ╚─────────────────────────────────────────────────────────────────────────────*/
+#include "libc/stdio/fflush.internal.h"
 #include "libc/stdio/internal.h"
 #include "libc/stdio/stdio.h"
+#include "libc/str/str.h"
 #include "libc/thread/thread.h"
 
 /**
@@ -26,3 +28,39 @@
 void flockfile(FILE *f) {
   pthread_mutex_lock(&f->lock);
 }
+
+void(__fflush_lock)(void) {
+  pthread_mutex_lock(&__fflush_lock_obj);
+}
+
+void(__fflush_unlock)(void) {
+  pthread_mutex_unlock(&__fflush_lock_obj);
+}
+
+static void __stdio_fork_prepare(void) {
+  FILE *f;
+  __fflush_lock();
+  for (int i = 0; i < __fflush.handles.i; ++i)
+    if ((f = __fflush.handles.p[i]))
+      pthread_mutex_lock(&f->lock);
+}
+
+static void __stdio_fork_parent(void) {
+  FILE *f;
+  for (int i = __fflush.handles.i; i--;)
+    if ((f = __fflush.handles.p[i]))
+      pthread_mutex_unlock(&f->lock);
+  __fflush_unlock();
+}
+
+static void __stdio_fork_child(void) {
+  FILE *f;
+  for (int i = __fflush.handles.i; i--;)
+    if ((f = __fflush.handles.p[i]))
+      f->lock = (pthread_mutex_t)PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+  pthread_mutex_init(&__fflush_lock_obj, 0);
+}
+
+__attribute__((__constructor__(60))) static textstartup void stdioinit(void) {
+  pthread_atfork(__stdio_fork_prepare, __stdio_fork_parent, __stdio_fork_child);
+}
diff --git a/libc/stdio/stderr.c b/libc/stdio/stderr.c
index 4f80d4223..de694ed62 100644
--- a/libc/stdio/stderr.c
+++ b/libc/stdio/stderr.c
@@ -16,27 +16,25 @@
 │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
 │ PERFORMANCE OF THIS SOFTWARE.                                                │
 ╚─────────────────────────────────────────────────────────────────────────────*/
-#include "libc/calls/calls.h"
 #include "libc/stdio/internal.h"
-#include "libc/stdio/stdio.h"
 #include "libc/sysv/consts/fileno.h"
 #include "libc/sysv/consts/o.h"
 #include "libc/thread/thread.h"
 
+static FILE __stderr = {
+    .fd = STDERR_FILENO,
+    .bufmode = _IONBF,
+    .iomode = O_WRONLY,
+    .buf = __stderr.mem,
+    .size = sizeof(stderr->mem),
+    .lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+};
+
 /**
  * Pointer to standard error stream.
  */
-FILE *stderr;
-
-static FILE __stderr;
+FILE *stderr = &__stderr;
 
 __attribute__((__constructor__(60))) static textstartup void errinit(void) {
-  stderr = &__stderr;
-  stderr->fd = STDERR_FILENO;
-  stderr->bufmode = _IONBF;
-  stderr->iomode = O_WRONLY;
-  stderr->buf = stderr->mem;
-  stderr->size = sizeof(stderr->mem);
-  stderr->lock._word = PTHREAD_MUTEX_RECURSIVE;
   __fflush_register(stderr);
 }
diff --git a/libc/stdio/stdin.c b/libc/stdio/stdin.c
index 8f87e47ed..c5c3f6c2e 100644
--- a/libc/stdio/stdin.c
+++ b/libc/stdio/stdin.c
@@ -16,30 +16,29 @@
 │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
 │ PERFORMANCE OF THIS SOFTWARE.                                                │
 ╚─────────────────────────────────────────────────────────────────────────────*/
-#include "libc/calls/calls.h"
 #include "libc/calls/struct/stat.h"
 #include "libc/stdio/internal.h"
-#include "libc/stdio/stdio.h"
 #include "libc/sysv/consts/fileno.h"
 #include "libc/sysv/consts/o.h"
 #include "libc/sysv/consts/s.h"
 #include "libc/thread/thread.h"
 
+static FILE __stdin = {
+    .fd = STDIN_FILENO,
+    .iomode = O_RDONLY,
+    .bufmode = _IOFBF,
+    .buf = __stdin.mem,
+    .size = sizeof(stdin->mem),
+    .lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+};
+
 /**
  * Pointer to standard input stream.
  */
-FILE *stdin;
-
-static FILE __stdin;
+FILE *stdin = &__stdin;
 
 __attribute__((__constructor__(60))) static textstartup void initin(void) {
   struct stat st;
-  stdin = &__stdin;
-  stdin->fd = STDIN_FILENO;
-  stdin->iomode = O_RDONLY;
-  stdin->buf = stdin->mem;
-  stdin->size = sizeof(stdin->mem);
-  stdin->lock._word = PTHREAD_MUTEX_RECURSIVE;
   if (fstat(STDIN_FILENO, &st) || !S_ISREG(st.st_mode))
     stdin->bufmode = _IONBF;
   __fflush_register(stdin);
diff --git a/libc/stdio/stdout.c b/libc/stdio/stdout.c
index c00e5d3fa..4c6b9b2d6 100644
--- a/libc/stdio/stdout.c
+++ b/libc/stdio/stdout.c
@@ -16,39 +16,32 @@
 │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             │
 │ PERFORMANCE OF THIS SOFTWARE.                                                │
 ╚─────────────────────────────────────────────────────────────────────────────*/
-#include "libc/calls/calls.h"
-#include "libc/dce.h"
 #include "libc/stdio/internal.h"
-#include "libc/stdio/stdio.h"
 #include "libc/sysv/consts/fileno.h"
 #include "libc/sysv/consts/o.h"
 #include "libc/thread/thread.h"
 
+static FILE __stdout = {
+    .fd = STDOUT_FILENO,
+    .iomode = O_WRONLY,
+    .buf = __stdout.mem,
+    .size = sizeof(stdout->mem),
+    .lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP,
+
+    // Unlike other C libraries we don't bother calling fstat() to check
+    // if stdio is a character device and we instead choose to always
+    // line buffer it. We need it because there's no way to use the
+    // unbuffer command on a statically linked binary. This still goes
+    // fast. We value latency more than throughput, and stdio isn't the
+    // best api when the goal is throughput.
+    .bufmode = _IOLBF,
+};
+
 /**
  * Pointer to standard output stream.
  */
-FILE *stdout;
-
-static FILE __stdout;
+FILE *stdout = &__stdout;
 
 __attribute__((__constructor__(60))) static textstartup void outinit(void) {
-  stdout = &__stdout;
-
-  stdout->fd = STDOUT_FILENO;
-  stdout->iomode = O_WRONLY;
-  stdout->buf = stdout->mem;
-  stdout->size = sizeof(stdout->mem);
-  stdout->lock._word = PTHREAD_MUTEX_RECURSIVE;
-
-  /*
-   * Unlike other C libraries we don't bother calling fstat() to check
-   * if stdio is a character device and we instead choose to always line
-   * buffer it. We need it because there's no way to use the unbuffer
-   * command on a statically linked binary. This still goes fast. We
-   * value latency more than throughput, and stdio isn't the best api
-   * when the goal is throughput.
-   */
-  stdout->bufmode = _IOLBF;
-
   __fflush_register(stdout);
 }
diff --git a/test/libc/thread/pthread_atfork_test.c b/test/libc/thread/pthread_atfork_test.c
index f1e44139b..00a19cec5 100644
--- a/test/libc/thread/pthread_atfork_test.c
+++ b/test/libc/thread/pthread_atfork_test.c
@@ -83,12 +83,8 @@ void mu_wipe(void) {
   pthread_mutex_init(&mu, 0);
 }
 
-static atomic_bool once;
-
 void *Worker(void *arg) {
   for (int i = 0; i < 20; ++i) {
-    if (!atomic_exchange(&once, true))
-      __print_maps(0);
     mu_lock();
     usleep(20);
     mu_unlock();