-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Fix for async cancellation during __timedwait. NFC #19963
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| Canceling thread.. | ||
| Thread started! | ||
| Called clean-up handler with arg 42 | ||
| After canceling, shared variable = 1. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| // Copyright 2015 The Emscripten Authors. All rights reserved. | ||
| // Emscripten is available under two separate licenses, the MIT license and the | ||
| // University of Illinois/NCSA Open Source License. Both these licenses can be | ||
| // found in the LICENSE file. | ||
|
|
||
| #include <pthread.h> | ||
| #include <sys/types.h> | ||
| #include <stdio.h> | ||
| #include <stdlib.h> | ||
| #include <stdbool.h> | ||
| #include <assert.h> | ||
| #include <unistd.h> | ||
| #include <errno.h> | ||
| #include <emscripten/console.h> | ||
|
|
||
| pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; | ||
| _Atomic long res = 43; | ||
| _Atomic int started = false; | ||
|
|
||
| static void cleanup_handler(void *arg) | ||
| { | ||
| long a = (long)arg; | ||
| emscripten_outf("Called clean-up handler with arg %ld", a); | ||
| res -= a; | ||
| } | ||
|
|
||
| static void *thread_start(void *arg) { | ||
| // Setup thread for async cancelation only | ||
| pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); | ||
| pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); | ||
|
|
||
| pthread_cleanup_push(cleanup_handler, (void*)42); | ||
|
|
||
| emscripten_out("Thread started!"); | ||
|
|
||
| // Signal the main thread that are started | ||
| started = true; | ||
|
|
||
| // This mutex is locked by the main thread so this call should never return. | ||
| // pthread_mutex_lock is not a cancellation point so deferred cancellation | ||
| // won't work here, async cancelation should. | ||
| pthread_mutex_lock(&mutex); | ||
|
|
||
| assert(false && "pthread_mutex_lock returned!"); | ||
| pthread_cleanup_pop(0); | ||
| } | ||
|
|
||
| int main() { | ||
| pthread_mutex_lock(&mutex); | ||
|
|
||
| emscripten_out("Starting thread.."); | ||
| pthread_t thr; | ||
| int s = pthread_create(&thr, NULL, thread_start, (void*)0); | ||
| assert(s == 0); | ||
| // Busy wait until thread is started | ||
| while (!started) { | ||
| sched_yield(); | ||
| } | ||
|
|
||
| emscripten_out("Canceling thread.."); | ||
| s = pthread_cancel(thr); | ||
| assert(s == 0); | ||
| // Busy wait until thread cancel handler has been run | ||
| while (res != 1) { | ||
| sched_yield(); | ||
| } | ||
|
|
||
| emscripten_out("Joining thread.."); | ||
| s = pthread_join(thr, NULL); | ||
| assert(s == 0); | ||
| emscripten_out("done"); | ||
| return 0; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| Starting thread.. | ||
| Thread started! | ||
| Canceling thread.. | ||
| Called clean-up handler with arg 42 | ||
| Joining thread.. | ||
| done |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
so the
returnbelow is never reached, right? It might be helpful to clarify that.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.
Actually, maybe it is reached if
self->cancelasyncis false andself->canceldisableis true? Does it make sense to return ECANCELED in that case?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.
Apparently there are at least some tests that depend on that behaviour yes.
I tried completely removing the
return ECANCELED;and these test fail: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.
I found that reason for this.
canceldisablecan be in a third state calledPTHREAD_CANCEL_MASKEDwhich is used in pthread_cond_timedwait.c. The expectation here seems to be that__timedwait_cpwill detect cancellation and return ECANCELLED, as we are doing here. Which is why this is needed.