Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions libos/include/libos_thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,10 @@ bool check_last_thread(bool mark_self_dead);

int walk_thread_list(int (*callback)(struct libos_thread*, void*), void* arg, bool one_shot);

/* Dump all current libos_thread entries from g_thread_list, getting one ref on each. */
int dump_all_threads(struct libos_thread*** out_threads, size_t* out_cnt);
void free_threads_array(struct libos_thread** threads, size_t count);

void get_handle_map(struct libos_handle_map* map);
void put_handle_map(struct libos_handle_map* map);

Expand All @@ -339,3 +343,4 @@ noreturn void process_exit(int error_code, int term_signal);

void release_robust_list(struct robust_list_head* head);
void release_clear_child_tid(int* clear_child_tid);
void wait_clear_child_tid(int* clear_child_tid, int child_tid);
49 changes: 49 additions & 0 deletions libos/src/bookkeep/libos_thread.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,55 @@ int walk_thread_list(int (*callback)(struct libos_thread*, void*), void* arg, bo
return ret;
}

void free_threads_array(struct libos_thread** threads, size_t count) {
for (size_t i = 0; i < count; i++) {
if (threads[i]) {
put_thread(threads[i]);
}
}

free(threads);
}

static size_t dump_all_threads_with_buf(struct libos_thread** threads, size_t max_count) {
size_t size = 0;

lock(&g_thread_list_lock);

struct libos_thread* thread;
LISTP_FOR_EACH_ENTRY(thread, &g_thread_list, list) {
if (size < max_count) {
threads[size] = thread;
get_thread(thread);
}
size++;
}

unlock(&g_thread_list_lock);
return size;
}

int dump_all_threads(struct libos_thread*** out_threads, size_t* out_cnt) {
size_t count = 1;

while (true) {
struct libos_thread** threads = calloc(count, sizeof(*threads));
if (!threads) {
return -ENOMEM;
}

size_t needed_count = dump_all_threads_with_buf(threads, count);
if (needed_count <= count) {
*out_threads = threads;
*out_cnt = needed_count;
return 0;
}

free_threads_array(threads, count);
count = needed_count;
}
}

BEGIN_CP_FUNC(signal_dispositions) {
__UNUSED(size);
assert(size == sizeof(struct libos_signal_dispositions));
Expand Down
24 changes: 24 additions & 0 deletions libos/src/sys/libos_exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,8 +180,32 @@ long libos_syscall_execve(const char* file, const char* const* argv, const char*
/* Just exit current thread. */
thread_exit(/*error_code=*/0, /*term_signal=*/0);
}

size_t count;
struct libos_thread** threads;
ret = dump_all_threads(&threads, &count);
if (ret < 0) {
return ret;
}

(void)kill_other_threads();

/* Wait until the async‑worker has cleared each remaining thread’s
* clear_child_tid before we unmap their VMAs. */
struct libos_thread* cur_thread = get_cur_thread();
for (size_t i = 0; i < count; i++) {
struct libos_thread* thread = threads[i];

/* Skip the main thread and current thread. */
if (thread->pal_handle == g_pal_public_state->first_thread || thread == cur_thread) {
continue;
}

wait_clear_child_tid(thread->clear_child_tid, thread->tid);
}

/* Put down the references (possibly deallocate them) and free the array */
free_threads_array(threads, count);
/* All other threads are dead. Restoring initial value in case we stay inside same process
* instance and call execve again. */
__atomic_store_n(&first, 0, __ATOMIC_RELAXED);
Expand Down
8 changes: 8 additions & 0 deletions libos/src/sys/libos_futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -985,3 +985,11 @@ void release_clear_child_tid(int* clear_child_tid) {
__atomic_store_n(clear_child_tid, 0, __ATOMIC_RELEASE);
futex_wake((uint32_t*)clear_child_tid, 1, FUTEX_BITSET_MATCH_ANY);
}

void wait_clear_child_tid(int* clear_child_tid, int child_tid) {
while (__atomic_load_n(clear_child_tid, __ATOMIC_ACQUIRE) != 0) {
/* Sleep until the async‑worker (release_clear_child_tid)
* writes 0 and issues FUTEX_WAKE on the same word. */
futex_wait((uint32_t*)clear_child_tid, child_tid, NULL, FUTEX_BITSET_MATCH_ANY);
}
}