Description
Bugzilla Link | 47833 |
Version | trunk |
OS | Linux |
CC | @zygoloid |
Extended Description
Godbolt: https://godbolt.org/z/zYfvaM
Compile the following program with: -std=c++20 -fcoroutines-ts -stdlib=libc++ -O2 -pthread
#include <experimental/coroutine>
#include <thread>
#include <unistd.h>
#include <pthread.h>
auto switch_to_new_thread(std::thread& out) {
struct awaitable {
std::thread* p_out;
bool await_ready() { return false; }
void await_suspend(std::experimental::coroutine_handle<> h) {
std::thread& out = *p_out;
out = std::thread([h]() mutable {
h.resume();
});
}
void await_resume() {}
};
return awaitable{&out};
}
struct task{
struct promise_type {
task get_return_object() { return {}; }
std::experimental::suspend_never initial_suspend() { return {}; }
std::experimental::suspend_never final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
};
static task resuming_on_new_thread(std::thread& out) {
auto id1 = std::this_thread::get_id();
auto pthread1 = pthread_self();
auto pid1 = gettid();
co_await switch_to_new_thread(out);
auto id2 = std::this_thread::get_id();
auto pthread2 = pthread_self();
auto pid2 = gettid();
std::puts((id1 == id2) ? "this_thread::get_id() was same" : "this_thread::get_id() was different");
std::puts((pid1 == pid2) ? "gettid() was same" : "gettid() was different");
std::puts((pthread1 == pthread2) ? "pthread_self() was same" : "pthread_self() was different");
}
int main() {
std::thread out;
resuming_on_new_thread(out);
out.join();
}
Expected output:
this_thread::get_id() was different
gettid() was different
pthread_self() was different
Actual output:
this_thread::get_id() was same
gettid() was different
pthread_self() was same
The compiler generates code that calls the pthread_self() function once at the start of the coroutine and then caches the result in the coroutine frame and reloads the cached value after the coroutine resumes on another thread, leading to the second call to pthread_self() seemingly returning the wrong value.
This also affects std::this_thread::get_id(), which is a thin-wrapper over pthread_self(), and so if get_id() is inlined into the coroutine then it hits the same problem. If get_id() is not inlined into the coroutine (eg. when using -O1) then the second std::this_thread::get_id() gives the correct result.
Metadata
Metadata
Assignees
Type
Projects
Status