Skip to content

Conversation

@mannk123
Copy link
Contributor

@mannk123 mannk123 commented Oct 28, 2022

Restored the musl circular thread list, and added a test case.

One notably adjustment needed for emscripten is, in pthread_create, to add the new thread to the list prior to handing off to a worker using __pthread_create_js, as there is a race condition otherwise since the new thread can potentially run and exit via _emscripten_thread_exit, before the call returns to pthread_create.

On top of that, there is one code path specific to emscripten (and not musl) - when workers are returned to the pool (returnWorkerToPool), _emscripten_thread_free_data is called to free the associated __pthread structure. It's possible for this to happen without the _emscripten_thread_exit cleanup code (removal from the list) having been called. So I also modified _emscripten_thread_free_data to perform the necessary adjustments to the thread list pointers.

Fixes: #8740

…nitialization behavior, and add relevant test case
@mannk123 mannk123 changed the title Fixes #8740 Restore the musl pthread circular buffer, in order to fix the pthread key recreation zero-initialization issue Oct 28, 2022
@mannk123 mannk123 changed the title Restore the musl pthread circular buffer, in order to fix the pthread key recreation zero-initialization issue Restore the musl pthread circular thread list, in order to fix the pthread key recreation zero-initialization issue Oct 28, 2022
…tialization behavior - add __tl_sync, and also handle cleanup of the circular list in the cleanupThread case
…tialization behavior - remove unused variable
…tialization behavior - update expectations
@mannk123
Copy link
Contributor Author

@kleisauke Thanks for the review, I have made the changes. After some investigation, also modified _emscripten_thread_free_data to adjust the thead list.

@mannk123 mannk123 requested a review from kleisauke October 28, 2022 20:31
__tl_lock();

t->next->prev = t->prev;
t->prev->next = t->next;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this needed in addition to the block in _emscripten_thread_exit? All threads should call _emscripten_thread_exit shouldn't they?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There was a race condition, and that block was supposed to be a fix for it.

What was happening was that, inside pthread_create, the new pthread gets added to the circular list after the call to __pthread_create_js. This leads to a race where the new thread starts running and exits (i.e. calls _emscripten_thread_exit), before it gets added to the list inside pthread_create, meaning the list now contains a DT_EXITED thread that should not be there.

The proper fix here is for the list to be updated before calling __pthread_create_js. If the call fails, the new pthread is then removed from the list. I have made that change.

However, I think it may still make sense to keep the block above, as there are cases where a pthread structure is freed using _emscripten_thread_free_data, without having called _emscripten_thread_exit:
i) In exitRuntime, terminateAllThreads is called which returns all workers to the thread pool and calls _emscripten_thread_free_data on them, regardless of whether they have exited.
ii) Any thread that calls exit() does not call _emscripten_thread_exit either (see e=='unwind' in worker.js), which may be potentially problematic when EXIT_RUNTIME is not enabled. Notably, in the PROXY_TO_PTHREAD case, the "main" thread is itself a pthread that ends up calling exit(), meaning it won't perform _emscripten_thread_exit cleanup either.

Given the above, it seems more correct to have that block above in _emscripten_thread_free_data.

Anyway, the above is just my beginner's understanding of the code, eager to know what you think!

Copy link
Collaborator

Choose a reason for hiding this comment

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

If a thread doesn't exit with _emscripten_thread_exit that would be a bug, and I don't think we should try to work around it unless we have to.

I suggest we leave _emscripten_thread_free_data alone, unless that change is needs to make a particular test pass?

@mannk123 mannk123 force-pushed the main branch 2 times, most recently from 4efc174 to e04d7a3 Compare October 29, 2022 17:19
…tialization behavior - in pthread_create, fix sequencing of when the new pthread is added to the list
@mannk123 mannk123 requested review from sbc100 and removed request for kleisauke October 29, 2022 19:57
Copy link
Collaborator

@sbc100 sbc100 left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! Looks good aside from a few of comments.

int __pthread_key_create(pthread_key_t *k, void (*dtor)(void *))
{
pthread_t self = __pthread_self();
pthread_t self = __pthread_self();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Revert his line


@requires_threads
def test_pthread_key_recreation(self):
self.btest_exit(test_file('pthread/test_pthread_key_recreation.cpp'), args=['-sUSE_PTHREADS', '-sPTHREAD_POOL_SIZE'])
Copy link
Collaborator

Choose a reason for hiding this comment

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

-sPTHREAD_POOL_SIZE=1 I think would be more clear here.

static pthread_key_t key;

static std::mutex mutex;
static std::condition_variable cond_var;
Copy link
Collaborator

Choose a reason for hiding this comment

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

It seems a little odd to make pthread-API stuff with C++ threed API stuff, but maybe its fine?

The alternative would be to use pthread_mutex_t and pthread_cond_t here (you could also then make this in a pure C test without any C++).

kme added 2 commits November 1, 2022 11:35
…tialization behavior - make changes based on PR review
@mannk123
Copy link
Contributor Author

mannk123 commented Nov 1, 2022

@sbc100 Thanks, I have made all the suggested changes.

@mannk123 mannk123 requested a review from sbc100 November 1, 2022 04:57
@sbc100 sbc100 merged commit a37b4b2 into emscripten-core:main Nov 1, 2022
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.

pthread_key_create does not initialize thread local variable with null

3 participants