Skip to content

Commit

Permalink
Fix bogus "Decoder may not be used concurrently" after exceptions
Browse files Browse the repository at this point in the history
If stream decoding throws an exception (like on bad UTF-8) the deocder's
in_use flag would stay set preventing any further use of the decoder.
This can lead to great action-at-a-distance effects.

Fix by extending the MVM_tc_(set|release)_ex_release_mutex mechanism to
support such flags in addition to fully blown mutexes. This way we can
keep the light weight in_use flag for the cost of a single bit test and
branch when throwing exceptions.
  • Loading branch information
niner committed Aug 5, 2019
1 parent b3469f9 commit ebf1c6a
Show file tree
Hide file tree
Showing 2 changed files with 10 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/6model/reprs/Decoder.c
Expand Up @@ -112,11 +112,13 @@ void MVM_decoder_ensure_decoder(MVMThreadContext *tc, MVMObject *decoder, const
static void enter_single_user(MVMThreadContext *tc, MVMDecoder *decoder) {
if (!MVM_trycas(&(decoder->body.in_use), 0, 1))
MVM_exception_throw_adhoc(tc, "Decoder may not be used concurrently");
MVM_tc_set_ex_release_mutex(tc, (uv_mutex_t *)((uintptr_t)&(decoder->body.in_use) | 1));
}

/* Releases the decoder single-user sanity check flag. */
static void exit_single_user(MVMThreadContext *tc, MVMDecoder *decoder) {
decoder->body.in_use = 0;
MVM_tc_clear_ex_release_mutex(tc);
}

/* Configures the decoder with the specified encoding and other configuration. */
Expand Down
10 changes: 8 additions & 2 deletions src/core/threadcontext.c
Expand Up @@ -120,15 +120,21 @@ void MVM_tc_destroy(MVMThreadContext *tc) {
MVM_free(tc);
}

/* Setting and clearing mutex to release on exception throw. */
/* Setting and clearing mutex to release on exception throw.
* If the LSB of the mutex' address is set, it's not actually a mutex but a
* simple flag (an AO_t) that will be cleared on release. */
void MVM_tc_set_ex_release_mutex(MVMThreadContext *tc, uv_mutex_t *mutex) {
if (tc->ex_release_mutex)
MVM_exception_throw_adhoc(tc, "Internal error: multiple ex_release_mutex");
tc->ex_release_mutex = mutex;
}
void MVM_tc_release_ex_release_mutex(MVMThreadContext *tc) {
if (tc->ex_release_mutex)
uv_mutex_unlock(tc->ex_release_mutex);
if (MVM_UNLIKELY((uintptr_t)tc->ex_release_mutex & 1)) {
*((AO_t*)((uintptr_t)tc->ex_release_mutex & ~(uintptr_t)1)) = 0;
} else {
uv_mutex_unlock(tc->ex_release_mutex);
}
tc->ex_release_mutex = NULL;
}
void MVM_tc_clear_ex_release_mutex(MVMThreadContext *tc) {
Expand Down

0 comments on commit ebf1c6a

Please sign in to comment.