thread/Thread: add debug attribute "inside_handle"

This attribute shall be used only for IsInside() to make this safe
against a race condition described in #188:

> There is no requirement on the implementation that the ID of the
> created thread be available before the newly created thread starts
> executing.

http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_create.html):

This means that on some pthread implementations (e.g. Haiku), the
assert(thread.IsInside()) could fail.

Closes #188
This commit is contained in:
Max Kellermann 2018-01-08 09:58:18 +01:00
parent d989dbfec4
commit 2eef4e6716
3 changed files with 16 additions and 1 deletions

1
NEWS
View File

@ -1,4 +1,5 @@
ver 0.20.16 (not yet released)
* fix crash in debug build on Haiku and other operating systems
ver 0.20.15 (2018/01/05)
* queue: fix crash after seek failure

View File

@ -86,6 +86,10 @@ Thread::ThreadProc(void *ctx)
{
Thread &thread = *(Thread *)ctx;
#ifndef NDEBUG
thread.inside_handle = pthread_self();
#endif
thread.Run();
return nullptr;

View File

@ -41,6 +41,16 @@ class Thread {
DWORD id;
#else
pthread_t handle = pthread_t();
#ifndef NDEBUG
/**
* This handle is only used by IsInside(), and is set by the
* thread function. Since #handle is set by pthread_create()
* which is racy, we need this attribute for early checks
* inside the thread function.
*/
pthread_t inside_handle = pthread_t();
#endif
#endif
public:
@ -79,7 +89,7 @@ public:
default-constructed values" (comment from
libstdc++) - and if both libstdc++ and libc++ get
away with this, we can do it as well */
return pthread_self() == handle;
return pthread_self() == inside_handle;
#endif
}
#endif