Skip to content

Commit

Permalink
Add missing lock to fork() on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
jart committed Jan 4, 2025
1 parent e939659 commit fe01642
Show file tree
Hide file tree
Showing 19 changed files with 90 additions and 96 deletions.
27 changes: 7 additions & 20 deletions libc/intrin/msync-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@
#include "libc/calls/syscall-nt.internal.h"
#include "libc/intrin/maps.h"
#include "libc/nt/memory.h"
#include "libc/nt/runtime.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/sysparam.h"
#include "libc/sysv/consts/auxv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/errfuns.h"

Expand All @@ -36,28 +34,17 @@ textwindows int sys_msync_nt(char *addr, size_t size, int flags) {

int rc = 0;
__maps_lock();
struct Map *next, *map;
struct Map *map;
if (!(map = __maps_floor(addr)))
map = __maps_first();
for (; map && map->addr <= addr + size; map = next) {
next = __maps_next(map);
if (!__maps_isalloc(map))
continue;
for (; map && map->addr <= addr + size; map = __maps_next(map)) {
if (map->flags & MAP_ANONYMOUS)
continue;
if (MAX(addr, map->addr) >= MIN(addr + size, map->addr + map->size))
continue; // msync() is about coherency between file and memory
char *beg = MAX(addr, map->addr);
char *end = MIN(addr + size, map->addr + map->size);
if (beg >= end)
continue; // didn't overlap mapping

// 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))
if (!FlushViewOfFile(beg, end - beg))
rc = -1;
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
}
Expand Down
12 changes: 4 additions & 8 deletions libc/intrin/msync.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,19 @@ int msync(void *addr, size_t size, int flags) {
} else {
sysflags = MS_ASYNC;
}
if (flags & MS_INVALIDATE) {
if (flags & MS_INVALIDATE)
sysflags |= MS_INVALIDATE;
}

// FreeBSD's manual says "The flags argument was both MS_ASYNC and
// MS_INVALIDATE. Only one of these flags is allowed." which makes
// following the POSIX recommendation somewhat difficult.
if (IsFreebsd()) {
if (sysflags == (MS_ASYNC | MS_INVALIDATE)) {
if (IsFreebsd())
if (sysflags == (MS_ASYNC | MS_INVALIDATE))
sysflags = MS_INVALIDATE;
}
}

// FreeBSD specifies MS_SYNC as 0 so we shift the Cosmo constants
if (IsFreebsd()) {
if (IsFreebsd())
sysflags >>= 1;
}

BEGIN_CANCELATION_POINT;
if (!IsWindows()) {
Expand Down
2 changes: 1 addition & 1 deletion libc/log/gdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/rusage.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/w.h"
COSMOPOLITAN_C_START_
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/fork-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
#include "libc/nt/thread.h"
#include "libc/nt/thunk/msabi.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/symbols.internal.h"
#include "libc/sysv/consts/map.h"
Expand Down
8 changes: 7 additions & 1 deletion libc/proc/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#include "libc/nt/runtime.h"
#include "libc/nt/thread.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/runtime.h"
#include "libc/runtime/syslib.internal.h"
Expand Down Expand Up @@ -119,6 +119,9 @@ static void fork_prepare(void) {
_weaken(__localtime_lock)();
if (_weaken(__dlopen_lock))
_weaken(__dlopen_lock)();
if (IsWindows())
if (_weaken(__proc_lock))
_weaken(__proc_lock)();
if (_weaken(cosmo_stack_lock))
_weaken(cosmo_stack_lock)();
__cxa_lock();
Expand Down Expand Up @@ -151,6 +154,9 @@ static void fork_parent(void) {
__cxa_unlock();
if (_weaken(cosmo_stack_unlock))
_weaken(cosmo_stack_unlock)();
if (IsWindows())
if (_weaken(__proc_unlock))
_weaken(__proc_unlock)();
if (_weaken(__dlopen_unlock))
_weaken(__dlopen_unlock)();
if (_weaken(__localtime_unlock))
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/getpriority-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.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/errfuns.h"

Expand Down
2 changes: 1 addition & 1 deletion libc/proc/getrusage-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "libc/nt/struct/iocounters.h"
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/errfuns.h"
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/handle.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
#include "libc/calls/calls.h"
#include "libc/intrin/weaken.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"

// retrieves handle of process
// supports only current process and processes we created
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/kill-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
#include "libc/nt/memory.h"
#include "libc/nt/process.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/errfuns.h"
#ifdef __x86_64__
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/posix_spawn.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
#include "libc/proc/ntspawn.h"
#include "libc/proc/posix_spawn.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/sock/sock.h"
#include "libc/stdio/stdio.h"
Expand Down
15 changes: 6 additions & 9 deletions libc/proc/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/proc/proc.h"
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
Expand Down Expand Up @@ -47,7 +48,6 @@
#include "libc/nt/struct/processmemorycounters.h"
#include "libc/nt/synchronization.h"
#include "libc/nt/thread.h"
#include "libc/proc/proc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/map.h"
Expand All @@ -67,9 +67,8 @@

#define STACK_SIZE 65536

struct Procs __proc = {
.lock = PTHREAD_MUTEX_INITIALIZER,
};
struct Procs __proc;
static pthread_mutex_t __proc_lock_obj = PTHREAD_MUTEX_INITIALIZER;

textwindows static void __proc_stats(int64_t h, struct rusage *ru) {
bzero(ru, sizeof(*ru));
Expand Down Expand Up @@ -258,25 +257,23 @@ textwindows static void __proc_setup(void) {
*/
textwindows void __proc_lock(void) {
cosmo_once(&__proc.once, __proc_setup);
_pthread_mutex_lock(&__proc.lock);
_pthread_mutex_lock(&__proc_lock_obj);
}

/**
* Unlocks process tracker.
*/
textwindows void __proc_unlock(void) {
_pthread_mutex_unlock(&__proc.lock);
_pthread_mutex_unlock(&__proc_lock_obj);
}

/**
* Resets process tracker from forked child.
*/
textwindows void __proc_wipe_and_reset(void) {
// 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));
__proc.lock = lock;
_pthread_mutex_wipe_np(&__proc.lock);
}

/**
Expand Down
21 changes: 10 additions & 11 deletions libc/proc/proc.internal.h → libc/proc/proc.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ struct Proc {
struct Procs {
int waiters;
atomic_uint once;
pthread_mutex_t lock;
intptr_t thread;
intptr_t onbirth;
intptr_t haszombies;
Expand All @@ -41,16 +40,16 @@ struct Procs {

extern struct Procs __proc;

void __proc_lock(void) dontthrow;
void __proc_unlock(void) dontthrow;
int64_t __proc_handle(int) libcesque;
int64_t __proc_search(int) libcesque;
struct Proc *__proc_new(void) libcesque;
void __proc_add(struct Proc *) libcesque;
void __proc_free(struct Proc *) libcesque;
void __proc_wipe_and_reset(void) libcesque;
int __proc_harvest(struct Proc *, bool) libcesque;
int sys_wait4_nt(int, int *, int, struct rusage *) libcesque;
void __proc_lock(void);
void __proc_unlock(void);
int64_t __proc_handle(int);
int64_t __proc_search(int);
struct Proc *__proc_new(void);
void __proc_add(struct Proc *);
void __proc_free(struct Proc *);
void __proc_wipe_and_reset(void);
int __proc_harvest(struct Proc *, bool);
int sys_wait4_nt(int, int *, int, struct rusage *);

COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_LIBC_PROC_H_ */
2 changes: 1 addition & 1 deletion libc/proc/sched_getaffinity.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"

Expand Down
2 changes: 1 addition & 1 deletion libc/proc/sched_setaffinity.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.h"
#include "libc/nt/runtime.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h"

static dontinline textwindows int sys_sched_setaffinity_nt(
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/setpriority-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include "libc/nt/errors.h"
#include "libc/nt/process.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/errfuns.h"

Expand Down
35 changes: 14 additions & 21 deletions libc/proc/wait4-nt.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/sigset.h"
Expand All @@ -27,25 +28,22 @@
#include "libc/nt/events.h"
#include "libc/nt/runtime.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/sig.h"
#include "libc/sysv/consts/w.h"
#include "libc/sysv/errfuns.h"
#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) {
if (wstatus) {
if (wstatus)
*wstatus = pr->wstatus;
}
if (opt_out_rusage) {
if (opt_out_rusage)
*opt_out_rusage = pr->ru;
}
dll_remove(&__proc.zombies, &pr->elem);
if (dll_is_empty(__proc.zombies)) {
if (dll_is_empty(__proc.zombies))
ResetEvent(__proc.haszombies);
}
if (pr->waiters) {
pr->status = PROC_UNDEAD;
dll_make_first(&__proc.undead, &pr->elem);
Expand All @@ -56,19 +54,18 @@ static textwindows int __proc_reap(struct Proc *pr, int *wstatus,
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 Dll *e;
for (e = dll_first(__proc.zombies); e; e = dll_next(__proc.zombies, 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 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) {
for (;;) {

Expand Down Expand Up @@ -159,9 +156,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
// check if killed or win32 error
if (wi) {
if (pr) {
if (!--pr->waiters && pr->status == PROC_UNDEAD) {
if (!--pr->waiters && pr->status == PROC_UNDEAD)
__proc_free(pr);
}
} else {
--__proc.waiters;
}
Expand All @@ -178,17 +174,15 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,

// handle process exit notification
--pr->waiters;
if (pr->status == PROC_ALIVE) {
if (pr->status == PROC_ALIVE)
__proc_harvest(pr, true);
}
switch (pr->status) {
case PROC_ALIVE:
// exit caused by execve() reparenting
__proc_unlock();
if (!pr->waiters) {
if (!pr->waiters)
// avoid deadlock that could theoretically happen
SetEvent(__proc.onbirth);
}
__proc_unlock();
break;
case PROC_ZOMBIE:
// exit happened and we're the first to know
Expand All @@ -197,9 +191,8 @@ static textwindows int __proc_wait(int pid, int *wstatus, int options,
return rc;
case PROC_UNDEAD:
// exit happened but another thread waited first
if (!pr->waiters) {
if (!pr->waiters)
__proc_free(pr);
}
__proc_unlock();
return echild();
default:
Expand Down
2 changes: 1 addition & 1 deletion libc/proc/wait4.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include "libc/calls/struct/rusage.internal.h"
#include "libc/dce.h"
#include "libc/intrin/strace.h"
#include "libc/proc/proc.internal.h"
#include "libc/proc/proc.h"
#include "libc/sysv/errfuns.h"

/**
Expand Down
Loading

0 comments on commit fe01642

Please sign in to comment.