diff options
author | Warner Losh <imp@FreeBSD.org> | 2021-08-07 14:22:34 -0600 |
---|---|---|
committer | Warner Losh <imp@bsdimp.com> | 2021-09-10 14:13:06 -0600 |
commit | 63cca1067ac70df2d71c0064f7bf53e19334223c (patch) | |
tree | 4d02d6d0e6fbbec861ce27212c7d73f9bbfbd94f /bsd-user/main.c | |
parent | f0f7f9dca986bebf2a0b88dd83f84f5e39a61462 (diff) |
bsd-user: Implement interlock for atomic operations
Implement the internlock in fork_start() and fork_end() to properly cope
with atomic operations and to safely keep state for parent and child
processes.
Signed-off-by: Stacey Son <sson@FreeBSD.org>
Signed-off-by: Warner Losh <imp@bsdimp.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'bsd-user/main.c')
-rw-r--r-- | bsd-user/main.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/bsd-user/main.c b/bsd-user/main.c index 768f4ee41e..659dd2b512 100644 --- a/bsd-user/main.c +++ b/bsd-user/main.c @@ -69,15 +69,39 @@ unsigned long target_dflssiz = TARGET_DFLSSIZ; /* initial data size limit */ unsigned long target_maxssiz = TARGET_MAXSSIZ; /* max stack size */ unsigned long target_sgrowsiz = TARGET_SGROWSIZ; /* amount to grow stack */ +/* Helper routines for implementing atomic operations. */ void fork_start(void) { + start_exclusive(); + cpu_list_lock(); + mmap_fork_start(); } void fork_end(int child) { if (child) { + CPUState *cpu, *next_cpu; + /* + * Child processes created by fork() only have a single thread. Discard + * information about the parent threads. + */ + CPU_FOREACH_SAFE(cpu, next_cpu) { + if (cpu != thread_cpu) { + QTAILQ_REMOVE_RCU(&cpus, cpu, node); + } + } + mmap_fork_end(child); + /* + * qemu_init_cpu_list() takes care of reinitializing the exclusive + * state, so we don't need to end_exclusive() here. + */ + qemu_init_cpu_list(); gdbserver_fork(thread_cpu); + } else { + mmap_fork_end(child); + cpu_list_unlock(); + end_exclusive(); } } |