-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix deadlock on zombie_threads_mtx #234
Changes from 3 commits
1e9b098
979353a
5c45237
954305d
0a29387
ab910d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,6 +70,9 @@ thread_t *thread_create(const char *name, void (*fn)(void *), void *arg) { | |
td->td_kstack.stk_base = (void *)PG_VADDR_START(td->td_kstack_obj); | ||
td->td_kstack.stk_size = PAGESIZE; | ||
|
||
mtx_init(&td->td_lock, MTX_DEF); | ||
cv_init(&td->td_waitcv, "td_waitcv"); | ||
|
||
ctx_init(td, fn, arg); | ||
|
||
/* Do not lock the mutex if this call to thread_create was done before any | ||
|
@@ -119,6 +122,8 @@ noreturn void thread_exit(int exitcode) { | |
|
||
log("Thread '%s' {%p} has finished.", td->td_name, td); | ||
|
||
mtx_lock(&td->td_lock); | ||
|
||
/* Thread must not exit while in critical section! However, we can't use | ||
assert here, because assert also calls thread_exit. Thus, in case this | ||
condition is not met, we'll log the problem, and try to fix the problem. */ | ||
|
@@ -131,16 +136,18 @@ noreturn void thread_exit(int exitcode) { | |
fdtab_release(td->td_fdtable); | ||
|
||
mtx_lock(&zombie_threads_mtx); | ||
TAILQ_INSERT_TAIL(&zombie_threads, td, td_zombieq); | ||
mtx_unlock(&zombie_threads_mtx); | ||
|
||
critical_enter(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like we don't need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think I understand the solution you've linked to. The entire function is marked with a comment:
which suggests that there is an external mechanism which prevents the scheduler from running while a thread is exiting. The thread mutex gets locked only at the very last moment, which also hints at a different synchronization mechanism besides this mutex. Also, I do not understand what do you mean by:
Do we want to prevent the scheduler from switching context to threads whose mutex is locked? Should the scheduler lock (or, actually, try-lock) the thread mutex when picking next thread? For this to work well w/o obvious deadlock, we would also have to prevent preemption of threads who own their own thread mutex. I'm under the impression that this could lead to complex problems. I'd appreciate some detailed description of the idea you want me to implement. |
||
TAILQ_INSERT_TAIL(&zombie_threads, td, td_zombieq); | ||
td->td_exitcode = exitcode; | ||
sleepq_broadcast(&td->td_exitcode); | ||
td->td_state = TDS_INACTIVE; | ||
{ | ||
td->td_exitcode = exitcode; | ||
td->td_state = TDS_INACTIVE; | ||
cv_signal(&td->td_waitcv); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
mtx_unlock(&td->td_lock); | ||
} | ||
critical_leave(); | ||
|
||
mtx_unlock(&zombie_threads_mtx); | ||
|
||
sched_yield(); | ||
|
||
/* sched_yield will return immediately when scheduler is not active */ | ||
|
@@ -153,10 +160,10 @@ void thread_join(thread_t *p) { | |
thread_t *otd = p; | ||
log("Joining '%s' {%p} with '%s' {%p}", td->td_name, td, otd->td_name, otd); | ||
|
||
critical_enter(); | ||
mtx_lock(&otd->td_lock); | ||
while (otd->td_state != TDS_INACTIVE) | ||
sleepq_wait(&otd->td_exitcode, "Joining threads"); | ||
critical_leave(); | ||
cv_wait(&otd->td_waitcv, &otd->td_lock); | ||
mtx_unlock(&otd->td_lock); | ||
} | ||
|
||
/* It would be better to have a hash-map from tid_t to thread_t, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move these to the top of the structure and describe the purpose of
td_waitcv
.