Skip to content

Use compareExchange to set detach_state in pthread_join_js#15481

Merged
sbc100 merged 1 commit intomainfrom
join_swap_state
Nov 11, 2021
Merged

Use compareExchange to set detach_state in pthread_join_js#15481
sbc100 merged 1 commit intomainfrom
join_swap_state

Conversation

@sbc100
Copy link
Copy Markdown
Collaborator

@sbc100 sbc100 commented Nov 11, 2021

This is a little more robust in the face of racey/invalid code that does
stuff like joining from muliple threads or detaching a thread while it
is being joined.

This is a little more robust in the face of racey/invalid code that does
stuff like joining from muliple threads or detaching a thread while it
is being joined.
@sbc100 sbc100 requested review from kleisauke and kripken November 11, 2021 02:18
Copy link
Copy Markdown
Collaborator

@kleisauke kleisauke left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I left a small comment inline regarding that assert.

Comment on lines +896 to +900
#if ASSERTIONS
assert(old_state === {{{ cDefine('DT_JOINABLE') }}}, 'pthread_join attempted on thread 0x' + thread.toString(16) + ', which is in an invalid state:' + old_state);
#else
if (old_state !== {{{ cDefine('DT_JOINABLE') }}}) return {{{ cDefine('EINVAL') }}};
#endif
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps we should print an error, instead of abort()-ing when ASSERTIONS are enabled?

Suggested change
#if ASSERTIONS
assert(old_state === {{{ cDefine('DT_JOINABLE') }}}, 'pthread_join attempted on thread 0x' + thread.toString(16) + ', which is in an invalid state:' + old_state);
#else
if (old_state !== {{{ cDefine('DT_JOINABLE') }}}) return {{{ cDefine('EINVAL') }}};
#endif
if (old_state !== {{{ cDefine('DT_JOINABLE') }}}) {
#if ASSERTIONS
err('pthread_join attempted on thread 0x' + thread.toString(16) + ', which is in an invalid state:' + old_state);
#endif
return {{{ cDefine('EINVAL') }}};
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I considered that yes. But then I looked at the existing musl code it just aborts in this case. I think it means your program is invalid if this happens:

See:

if (state >= DT_DETACHED) a_crash();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, it is considered to be undefined behavior. I currently patched that with this:

// The thread is (already) detached and therefore not joinable.
// This also handle cases where the thread becomes detached
// *during* the join.
if (state >= DT_DETACHED) {
// Even though the man page says this is undefined
// behaviour we ave several tests in the posixtest suite
// that depend on this.
r = EINVAL;
break;
}

in PR #13007, since the POSIX test suite depend on this (__pthread_timedjoin_np is also used by pthread_detach, so detaching an already-detached thread would then also crash).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it enough to check for this on entry to pthread_join? Its seems like that is enough to make the testsuite happy anyway.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a followup patch that looked very much like

// The thread is (already) detached and therefore not joinable.
// This also handle cases where the thread becomes detached
// *during* the join.
if (state >= DT_DETACHED) {
// Even though the man page says this is undefined
// behaviour we ave several tests in the posixtest suite
// that depend on this.
r = EINVAL;
break;
}

Sorry my work seems to be overlapping so with things you have already done :-/

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it enough to check for this on entry to pthread_join?

This assertion cannot hurt I think.

Its seems like that is enough to make the testsuite happy anyway.

Ah interesting. Perhaps it was already caught by this check?:

if (state == DT_DETACHED || state == DT_EXITED) {
// The thread is detached or already joined, and therefore not joinable
return EINVAL;
}

Sorry my work seems to be overlapping so with things you have already done :-/

No worries. I'm still a student, so it's a great learning experience anyway.

@sbc100 sbc100 merged commit f065db6 into main Nov 11, 2021
@sbc100 sbc100 deleted the join_swap_state branch November 11, 2021 16:21
mmarczell-graphisoft pushed a commit to GRAPHISOFT/emscripten that referenced this pull request Jan 5, 2022
…n-core#15481)

This is a little more robust in the face of racey/invalid code that does
stuff like joining from muliple threads or detaching a thread while it
is being joined.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants