94 lines
2.7 KiB
C++
Raw Normal View History

2021-02-07 14:58:59 +01:00
#include "./thread_helper.h"
#include <cstring>
#include <system_error>
#ifdef WIN32
#include <Windows.h>
#else
#include <pthread.h>
#endif
std::string threads::name(std::thread &thread) {
#ifdef WIN32
static std::string _empty{};
return _empty;
#else
char buffer[255]; /* min 16 characters */
pthread_getname_np(thread.native_handle(), buffer, 255);
return std::string{buffer};
#endif
}
bool threads::name(std::thread &thread, const std::string_view &name) {
#ifdef WIN32
return false;
#else
char buffer[255]; /* min 16 characters */
memcpy(buffer, name.data(), name.length());
buffer[name.length()] = '\0';
buffer[16] = '\0'; /* cut of the name after 16 characters */
auto error = pthread_setname_np(thread.native_handle(), buffer);
return error == 0;
#endif
}
bool threads::save_join(std::thread &thread, bool rd) {
try {
if(thread.joinable())
thread.join();
} catch(const std::system_error& ex) {
if(ex.code() == std::errc::resource_deadlock_would_occur) {
if(rd)
return false;
throw;
} else if(ex.code() == std::errc::no_such_process) {
return false;
} else if(ex.code() == std::errc::invalid_argument) {
return false;
} else {
throw;
}
}
return true;
}
bool threads::timed_join(std::thread &thread, const std::chrono::nanoseconds &timeout) {
#ifdef WIN32
auto result = WaitForSingleObject(thread.native_handle(), (DWORD) std::chrono::floor<std::chrono::milliseconds>(timeout).count());
if(result != 0)
return false;
if(thread.joinable())
thread.join();
return result;
#else
struct timespec ts{};
if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
return false; /* failed to get clock time */
auto seconds = std::chrono::floor<std::chrono::seconds>(timeout);
auto nanoseconds = std::chrono::ceil<std::chrono::nanoseconds>(timeout) - seconds;
ts.tv_sec += seconds.count();
ts.tv_nsec += nanoseconds.count();
if(ts.tv_nsec >= 1e9) {
ts.tv_sec += 1;
ts.tv_nsec -= 1e9;
}
auto result = pthread_timedjoin_np(thread.native_handle(), nullptr, &ts);
if(result > 0 && result != ESRCH) return false;
/* let the std lib set their flags */
std::thread _empty{}; /* could be destroyed even with an "active" thread handle because we overwrote the std::terminate() function with a macro */
_empty = std::move(thread);
/*
* Undefined behaviour:
* We destroy everything in a non trivial class,
* But when we take a closer look its just a wrapper around the native_handle type which could be an DWORD or a pthread_t which are both trivial destructible!
*/
memset(&_empty, 0, sizeof(_empty)); // NOLINT(bugprone-undefined-memory-manipulation)
return true;
#endif
}