Add missing lock to fork() on Windows

This commit is contained in:
Justine Tunney 2025-01-03 19:01:58 -08:00
parent e939659b70
commit fe01642a20
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
19 changed files with 90 additions and 96 deletions

View file

@ -19,10 +19,8 @@
#include "libc/calls/syscall-nt.internal.h" #include "libc/calls/syscall-nt.internal.h"
#include "libc/intrin/maps.h" #include "libc/intrin/maps.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/sysparam.h" #include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -36,28 +34,17 @@ textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int rc = 0; int rc = 0;
__maps_lock(); __maps_lock();
struct Map *next, *map; struct Map *map;
if (!(map = __maps_floor(addr))) if (!(map = __maps_floor(addr)))
map = __maps_first(); map = __maps_first();
for (; map && map->addr <= addr + size; map = next) { for (; map && map->addr <= addr + size; map = __maps_next(map)) {
next = __maps_next(map);
if (!__maps_isalloc(map))
continue;
if (map->flags & MAP_ANONYMOUS) if (map->flags & MAP_ANONYMOUS)
continue; continue; // msync() is about coherency between file and memory
if (MAX(addr, map->addr) >= MIN(addr + size, map->addr + map->size)) char *beg = MAX(addr, map->addr);
char *end = MIN(addr + size, map->addr + map->size);
if (beg >= end)
continue; // didn't overlap mapping continue; // didn't overlap mapping
if (!FlushViewOfFile(beg, end - beg))
// get true size of win32 allocation
size_t allocsize = map->size;
while (next && !__maps_isalloc(next) &&
next->addr + allocsize == next->addr) {
allocsize += next->size;
next = __maps_next(next);
}
// perform the flush
if (!FlushViewOfFile(map->addr, allocsize))
rc = -1; rc = -1;
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC? // TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
} }

View file

@ -68,23 +68,19 @@ int msync(void *addr, size_t size, int flags) {
} else { } else {
sysflags = MS_ASYNC; sysflags = MS_ASYNC;
} }
if (flags & MS_INVALIDATE) { if (flags & MS_INVALIDATE)
sysflags |= MS_INVALIDATE; sysflags |= MS_INVALIDATE;
}
// FreeBSD's manual says "The flags argument was both MS_ASYNC and // FreeBSD's manual says "The flags argument was both MS_ASYNC and
// MS_INVALIDATE. Only one of these flags is allowed." which makes // MS_INVALIDATE. Only one of these flags is allowed." which makes
// following the POSIX recommendation somewhat difficult. // following the POSIX recommendation somewhat difficult.
if (IsFreebsd()) { if (IsFreebsd())
if (sysflags == (MS_ASYNC | MS_INVALIDATE)) { if (sysflags == (MS_ASYNC | MS_INVALIDATE))
sysflags = MS_INVALIDATE; sysflags = MS_INVALIDATE;
}
}
// FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants // FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants
if (IsFreebsd()) { if (IsFreebsd())
sysflags >>= 1; sysflags >>= 1;
}
BEGIN_CANCELATION_POINT; BEGIN_CANCELATION_POINT;
if (!IsWindows()) { if (!IsWindows()) {

View file

@ -3,7 +3,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/rusage.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/nr.h" #include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/w.h" #include "libc/sysv/consts/w.h"
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_

View file

@ -44,7 +44,7 @@
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/nt/winsock.h" #include "libc/nt/winsock.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/symbols.internal.h" #include "libc/runtime/symbols.internal.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"

View file

@ -37,7 +37,7 @@
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/runtime/syslib.internal.h" #include "libc/runtime/syslib.internal.h"
@ -119,6 +119,9 @@ static void fork_prepare(void) {
_weaken(__localtime_lock)(); _weaken(__localtime_lock)();
if (_weaken(__dlopen_lock)) if (_weaken(__dlopen_lock))
_weaken(__dlopen_lock)(); _weaken(__dlopen_lock)();
if (IsWindows())
if (_weaken(__proc_lock))
_weaken(__proc_lock)();
if (_weaken(cosmo_stack_lock)) if (_weaken(cosmo_stack_lock))
_weaken(cosmo_stack_lock)(); _weaken(cosmo_stack_lock)();
__cxa_lock(); __cxa_lock();
@ -151,6 +154,9 @@ static void fork_parent(void) {
__cxa_unlock(); __cxa_unlock();
if (_weaken(cosmo_stack_unlock)) if (_weaken(cosmo_stack_unlock))
_weaken(cosmo_stack_unlock)(); _weaken(cosmo_stack_unlock)();
if (IsWindows())
if (_weaken(__proc_unlock))
_weaken(__proc_unlock)();
if (_weaken(__dlopen_unlock)) if (_weaken(__dlopen_unlock))
_weaken(__dlopen_unlock)(); _weaken(__dlopen_unlock)();
if (_weaken(__localtime_unlock)) if (_weaken(__localtime_unlock))

View file

@ -22,7 +22,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/prio.h" #include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -29,7 +29,7 @@
#include "libc/nt/struct/iocounters.h" #include "libc/nt/struct/iocounters.h"
#include "libc/nt/struct/processmemorycounters.h" #include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/rusage.h" #include "libc/sysv/consts/rusage.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -19,7 +19,7 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/intrin/weaken.h" #include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
// retrieves handle of process // retrieves handle of process
// supports only current process and processes we created // supports only current process and processes we created

View file

@ -33,7 +33,7 @@
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__ #ifdef __x86_64__

View file

@ -58,7 +58,7 @@
#include "libc/proc/ntspawn.h" #include "libc/proc/ntspawn.h"
#include "libc/proc/posix_spawn.h" #include "libc/proc/posix_spawn.h"
#include "libc/proc/posix_spawn.internal.h" #include "libc/proc/posix_spawn.internal.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/sock/sock.h" #include "libc/sock/sock.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/proc/proc.h"
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
@ -47,7 +48,6 @@
#include "libc/nt/struct/processmemorycounters.h" #include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/nt/thread.h" #include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
@ -67,9 +67,8 @@
#define STACK_SIZE 65536 #define STACK_SIZE 65536
struct Procs __proc = { struct Procs __proc;
.lock = PTHREAD_MUTEX_INITIALIZER, static pthread_mutex_t __proc_lock_obj = PTHREAD_MUTEX_INITIALIZER;
};
textwindows static void __proc_stats(int64_t h, struct rusage *ru) { textwindows static void __proc_stats(int64_t h, struct rusage *ru) {
bzero(ru, sizeof(*ru)); bzero(ru, sizeof(*ru));
@ -258,14 +257,14 @@ textwindows static void __proc_setup(void) {
*/ */
textwindows void __proc_lock(void) { textwindows void __proc_lock(void) {
cosmo_once(&__proc.once, __proc_setup); cosmo_once(&__proc.once, __proc_setup);
_pthread_mutex_lock(&__proc.lock); _pthread_mutex_lock(&__proc_lock_obj);
} }
/** /**
* Unlocks process tracker. * Unlocks process tracker.
*/ */
textwindows void __proc_unlock(void) { textwindows void __proc_unlock(void) {
_pthread_mutex_unlock(&__proc.lock); _pthread_mutex_unlock(&__proc_lock_obj);
} }
/** /**
@ -273,10 +272,8 @@ textwindows void __proc_unlock(void) {
*/ */
textwindows void __proc_wipe_and_reset(void) { textwindows void __proc_wipe_and_reset(void) {
// TODO(jart): Should we preserve this state in forked children? // TODO(jart): Should we preserve this state in forked children?
pthread_mutex_t lock = __proc.lock; _pthread_mutex_wipe_np(&__proc_lock_obj);
bzero(&__proc, sizeof(__proc)); bzero(&__proc, sizeof(__proc));
__proc.lock = lock;
_pthread_mutex_wipe_np(&__proc.lock);
} }
/** /**

View file

@ -27,7 +27,6 @@ struct Proc {
struct Procs { struct Procs {
int waiters; int waiters;
atomic_uint once; atomic_uint once;
pthread_mutex_t lock;
intptr_t thread; intptr_t thread;
intptr_t onbirth; intptr_t onbirth;
intptr_t haszombies; intptr_t haszombies;
@ -41,16 +40,16 @@ struct Procs {
extern struct Procs __proc; extern struct Procs __proc;
void __proc_lock(void) dontthrow; void __proc_lock(void);
void __proc_unlock(void) dontthrow; void __proc_unlock(void);
int64_t __proc_handle(int) libcesque; int64_t __proc_handle(int);
int64_t __proc_search(int) libcesque; int64_t __proc_search(int);
struct Proc *__proc_new(void) libcesque; struct Proc *__proc_new(void);
void __proc_add(struct Proc *) libcesque; void __proc_add(struct Proc *);
void __proc_free(struct Proc *) libcesque; void __proc_free(struct Proc *);
void __proc_wipe_and_reset(void) libcesque; void __proc_wipe_and_reset(void);
int __proc_harvest(struct Proc *, bool) libcesque; int __proc_harvest(struct Proc *, bool);
int sys_wait4_nt(int, int *, int, struct rusage *) libcesque; int sys_wait4_nt(int, int *, int, struct rusage *);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_PROC_H_ */ #endif /* COSMOPOLITAN_LIBC_PROC_H_ */

View file

@ -24,7 +24,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -24,7 +24,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
static dontinline textwindows int sys_sched_setaffinity_nt( static dontinline textwindows int sys_sched_setaffinity_nt(

View file

@ -23,7 +23,7 @@
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/prio.h" #include "libc/sysv/consts/prio.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h" #include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h" #include "libc/calls/struct/sigset.h"
@ -27,25 +28,22 @@
#include "libc/nt/events.h" #include "libc/nt/events.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/synchronization.h" #include "libc/nt/synchronization.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/consts/sicode.h" #include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/w.h" #include "libc/sysv/consts/w.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
#ifdef __x86_64__ #ifdef __x86_64__
static textwindows int __proc_reap(struct Proc *pr, int *wstatus, textwindows static int __proc_reap(struct Proc *pr, int *wstatus,
struct rusage *opt_out_rusage) { struct rusage *opt_out_rusage) {
if (wstatus) { if (wstatus)
*wstatus = pr->wstatus; *wstatus = pr->wstatus;
} if (opt_out_rusage)
if (opt_out_rusage) {
*opt_out_rusage = pr->ru; *opt_out_rusage = pr->ru;
}
dll_remove(&__proc.zombies, &pr->elem); dll_remove(&__proc.zombies, &pr->elem);
if (dll_is_empty(__proc.zombies)) { if (dll_is_empty(__proc.zombies))
ResetEvent(__proc.haszombies); ResetEvent(__proc.haszombies);
}
if (pr->waiters) { if (pr->waiters) {
pr->status = PROC_UNDEAD; pr->status = PROC_UNDEAD;
dll_make_first(&__proc.undead, &pr->elem); dll_make_first(&__proc.undead, &pr->elem);
@ -56,19 +54,18 @@ static textwindows int __proc_reap(struct Proc *pr, int *wstatus,
return pr->pid; return pr->pid;
} }
static textwindows int __proc_check(int pid, int *wstatus, textwindows static int __proc_check(int pid, int *wstatus,
struct rusage *opt_out_rusage) { struct rusage *opt_out_rusage) {
struct Dll *e; struct Dll *e;
for (e = dll_first(__proc.zombies); e; e = dll_next(__proc.zombies, e)) { for (e = dll_first(__proc.zombies); e; e = dll_next(__proc.zombies, e)) {
struct Proc *pr = PROC_CONTAINER(e); struct Proc *pr = PROC_CONTAINER(e);
if (pid == -1 || pid == pr->pid) { if (pid == -1 || pid == pr->pid)
return __proc_reap(pr, wstatus, opt_out_rusage); return __proc_reap(pr, wstatus, opt_out_rusage);
} }
}
return 0; return 0;
} }
static textwindows int __proc_wait(int pid, int *wstatus, int options, textwindows static int __proc_wait(int pid, int *wstatus, int options,
struct rusage *rusage, sigset_t waitmask) { struct rusage *rusage, sigset_t waitmask) {
for (;;) { for (;;) {
@ -159,9 +156,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// check if killed or win32 error // check if killed or win32 error
if (wi) { if (wi) {
if (pr) { if (pr) {
if (!--pr->waiters && pr->status == PROC_UNDEAD) { if (!--pr->waiters && pr->status == PROC_UNDEAD)
__proc_free(pr); __proc_free(pr);
}
} else { } else {
--__proc.waiters; --__proc.waiters;
} }
@ -178,17 +174,15 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// handle process exit notification // handle process exit notification
--pr->waiters; --pr->waiters;
if (pr->status == PROC_ALIVE) { if (pr->status == PROC_ALIVE)
__proc_harvest(pr, true); __proc_harvest(pr, true);
}
switch (pr->status) { switch (pr->status) {
case PROC_ALIVE: case PROC_ALIVE:
// exit caused by execve() reparenting // exit caused by execve() reparenting
__proc_unlock(); if (!pr->waiters)
if (!pr->waiters) {
// avoid deadlock that could theoretically happen // avoid deadlock that could theoretically happen
SetEvent(__proc.onbirth); SetEvent(__proc.onbirth);
} __proc_unlock();
break; break;
case PROC_ZOMBIE: case PROC_ZOMBIE:
// exit happened and we're the first to know // exit happened and we're the first to know
@ -197,9 +191,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
return rc; return rc;
case PROC_UNDEAD: case PROC_UNDEAD:
// exit happened but another thread waited first // exit happened but another thread waited first
if (!pr->waiters) { if (!pr->waiters)
__proc_free(pr); __proc_free(pr);
}
__proc_unlock(); __proc_unlock();
return echild(); return echild();
default: default:

View file

@ -21,7 +21,7 @@
#include "libc/calls/struct/rusage.internal.h" #include "libc/calls/struct/rusage.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/strace.h" #include "libc/intrin/strace.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
/** /**

View file

@ -24,11 +24,13 @@
#include "libc/calls/syscall-sysv.internal.h" #include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/check.h" #include "libc/log/check.h"
#include "libc/macros.h" #include "libc/macros.h"
#include "libc/nexgen32e/rdtsc.h" #include "libc/nexgen32e/rdtsc.h"
#include "libc/proc/posix_spawn.h" #include "libc/proc/posix_spawn.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h" #include "libc/sysv/consts/msync.h"
@ -38,6 +40,7 @@
#include "libc/testlib/ezbench.h" #include "libc/testlib/ezbench.h"
#include "libc/testlib/subprocess.h" #include "libc/testlib/subprocess.h"
#include "libc/testlib/testlib.h" #include "libc/testlib/testlib.h"
#include "libc/thread/thread.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
void SetUpOnce(void) { void SetUpOnce(void) {
@ -70,32 +73,27 @@ TEST(fork, testSharedMemory) {
int *sharedvar; int *sharedvar;
int *privatevar; int *privatevar;
EXPECT_NE(MAP_FAILED, EXPECT_NE(MAP_FAILED,
(sharedvar = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, (sharedvar = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0))); MAP_SHARED | MAP_ANONYMOUS, -1, 0)));
EXPECT_NE(MAP_FAILED, EXPECT_NE(MAP_FAILED,
(privatevar = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, (privatevar = mmap(0, getpagesize(), PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0))); MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)));
stackvar = 1; stackvar = 1;
*sharedvar = 1; *sharedvar = 1;
*privatevar = 1; *privatevar = 1;
EXPECT_NE(-1, (pid = fork())); EXPECT_NE(-1, (pid = fork()));
if (!pid) { if (!pid) {
EXPECT_EQ(NULL, getenv("_FORK"));
++stackvar; ++stackvar;
++*sharedvar;
++*privatevar; ++*privatevar;
msync((void *)ROUNDDOWN((intptr_t)&stackvar, getpagesize()), getpagesize(), ++*sharedvar;
MS_SYNC);
EXPECT_NE(-1, msync(privatevar, getpagesize(), MS_SYNC));
EXPECT_NE(-1, msync(sharedvar, getpagesize(), MS_SYNC));
_exit(0); _exit(0);
} }
EXPECT_NE(-1, waitpid(pid, &ws, 0)); EXPECT_NE(-1, waitpid(pid, &ws, 0));
EXPECT_EQ(1, stackvar); EXPECT_EQ(1, stackvar);
EXPECT_EQ(2, *sharedvar); EXPECT_EQ(2, *sharedvar);
EXPECT_EQ(1, *privatevar); EXPECT_EQ(1, *privatevar);
EXPECT_NE(-1, munmap(sharedvar, getpagesize())); EXPECT_SYS(0, 0, munmap(sharedvar, getpagesize()));
EXPECT_NE(-1, munmap(privatevar, getpagesize())); EXPECT_SYS(0, 0, munmap(privatevar, getpagesize()));
} }
static volatile bool gotsigusr1; static volatile bool gotsigusr1;
@ -123,14 +121,20 @@ TEST(fork, childToChild) {
sigprocmask(SIG_BLOCK, &mask, &oldmask); sigprocmask(SIG_BLOCK, &mask, &oldmask);
ASSERT_NE(-1, (child1 = fork())); ASSERT_NE(-1, (child1 = fork()));
if (!child1) { if (!child1) {
kill(parent, SIGUSR2); if (kill(parent, SIGUSR2)) {
sigsuspend(0); kprintf("%s:%d: error: failed to kill parent: %m\n", __FILE__, __LINE__);
_Exit(1);
}
ASSERT_SYS(EINTR, -1, sigsuspend(0));
_Exit(!gotsigusr1); _Exit(!gotsigusr1);
} }
sigsuspend(0); EXPECT_SYS(EINTR, -1, sigsuspend(0));
ASSERT_NE(-1, (child2 = fork())); ASSERT_NE(-1, (child2 = fork()));
if (!child2) { if (!child2) {
kill(child1, SIGUSR1); if (kill(child1, SIGUSR1)) {
kprintf("%s:%d: error: failed to kill child1: %m\n", __FILE__, __LINE__);
_Exit(1);
}
_Exit(0); _Exit(0);
} }
ASSERT_NE(-1, wait(&ws)); ASSERT_NE(-1, wait(&ws));
@ -147,12 +151,20 @@ TEST(fork, preservesTlsMemory) {
EXITS(0); EXITS(0);
} }
#define CHECK_TERMSIG \
if (WIFSIGNALED(ws)) { \
kprintf("%s:%d: error: forked life subprocess terminated with %G\n", \
__FILE__, __LINE__, WTERMSIG(ws)); \
exit(1); \
}
void fork_wait_in_serial(void) { void fork_wait_in_serial(void) {
int pid, ws; int pid, ws;
ASSERT_NE(-1, (pid = fork())); ASSERT_NE(-1, (pid = fork()));
if (!pid) if (!pid)
_Exit(0); _Exit(0);
ASSERT_NE(-1, waitpid(pid, &ws, 0)); ASSERT_NE(-1, waitpid(pid, &ws, 0));
CHECK_TERMSIG;
ASSERT_TRUE(WIFEXITED(ws)); ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws)); ASSERT_EQ(0, WEXITSTATUS(ws));
} }
@ -165,6 +177,7 @@ void vfork_execl_wait_in_serial(void) {
_Exit(127); _Exit(127);
} }
ASSERT_NE(-1, waitpid(pid, &ws, 0)); ASSERT_NE(-1, waitpid(pid, &ws, 0));
CHECK_TERMSIG;
ASSERT_TRUE(WIFEXITED(ws)); ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(42, WEXITSTATUS(ws)); ASSERT_EQ(42, WEXITSTATUS(ws));
} }
@ -175,6 +188,7 @@ void vfork_wait_in_serial(void) {
if (!pid) if (!pid)
_Exit(0); _Exit(0);
ASSERT_NE(-1, waitpid(pid, &ws, 0)); ASSERT_NE(-1, waitpid(pid, &ws, 0));
CHECK_TERMSIG;
ASSERT_TRUE(WIFEXITED(ws)); ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws)); ASSERT_EQ(0, WEXITSTATUS(ws));
} }
@ -185,6 +199,7 @@ void sys_fork_wait_in_serial(void) {
if (!pid) if (!pid)
_Exit(0); _Exit(0);
ASSERT_NE(-1, waitpid(pid, &ws, 0)); ASSERT_NE(-1, waitpid(pid, &ws, 0));
CHECK_TERMSIG;
ASSERT_TRUE(WIFEXITED(ws)); ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws)); ASSERT_EQ(0, WEXITSTATUS(ws));
} }
@ -196,6 +211,7 @@ void posix_spawn_in_serial(void) {
char *envs[] = {NULL}; char *envs[] = {NULL};
ASSERT_EQ(0, posix_spawn(&pid, prog, NULL, NULL, args, envs)); ASSERT_EQ(0, posix_spawn(&pid, prog, NULL, NULL, args, envs));
ASSERT_NE(-1, waitpid(pid, &ws, 0)); ASSERT_NE(-1, waitpid(pid, &ws, 0));
CHECK_TERMSIG;
ASSERT_TRUE(WIFEXITED(ws)); ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(42, WEXITSTATUS(ws)); ASSERT_EQ(42, WEXITSTATUS(ws));
} }

View file

@ -37,7 +37,7 @@
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/mem/gc.h" #include "libc/mem/gc.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/proc/proc.internal.h" #include "libc/proc/proc.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"