Last active
April 19, 2019 17:31
-
-
Save ppetraki/c09e3147efc07e192404a4452ca1905c to your computer and use it in GitHub Desktop.
dump std::thread attributes. Uses neat local printf adapter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <thread> | |
#include <mutex> | |
#include <cstdio> | |
#include <pthread.h> | |
#include <errno.h> | |
class fmt { | |
std::string buf_; | |
public: | |
#if 1 | |
template <typename... Args> | |
fmt( std::string const& format, Args... args ) | |
: buf_{ | |
std::string( std::snprintf( nullptr, 0, format.c_str(), args... ) + 1 /* asciiz */, 0 )} | |
{ | |
std::snprintf( const_cast<char*>(buf_.data()), buf_.size(), format.c_str(), args... ); | |
} | |
#else | |
// just a more thorough explanation of the same constructor | |
template <typename... Args> | |
fmt( std::string const& format, Args... args ) | |
{ | |
// by not providing a buffer and sizeof(buffer), snprintf returns the | |
// total number of chars that would have been printed if size had been | |
// sufficiently large which is equal to the string and the size of | |
// it's formating, minus the ascii zero. | |
size_t size = std::snprintf( nullptr, 0, format.c_str(), args... ); | |
size += 1; // asciiz | |
// now we know the entire size. it's assured in c++ versions >= c++11 | |
// that std string's internal buffer is stored contiguously. | |
buf_ = std::string( size, 0 ); // fill constructor | |
// write the formatted string to our internal buffer | |
std::snprintf( const_cast<char*>(buf_.data()), buf_.size(), format.c_str(), args... ); | |
} | |
#endif | |
friend std::ostream& operator<<( std::ostream& os, fmt const& op1 ) | |
{ | |
os << op1.buf_; | |
return os; | |
} | |
std::string str() const { return buf_; } | |
}; // class fmt | |
// adaption of, | |
// https://stackoverflow.com/questions/8408258/how-to-create-and-display-threads-attributes | |
// for std::thread | |
class thread_attr { | |
pthread_attr_t attr_; | |
std::thread::id tid_; | |
public: | |
thread_attr( std::thread& th ) | |
{ | |
tid_ = th.get_id(); | |
pthread_attr_init( &attr_ ); | |
if ( pthread_getattr_np( th.native_handle(), &attr_ ) ) { | |
// class destructor is not called if we throw an exception | |
// from within a constructor | |
pthread_attr_destroy( &attr_ ); | |
throw std::runtime_error( "failed to get thread attributes" ); | |
} | |
} | |
~thread_attr() noexcept { pthread_attr_destroy( &attr_ ); } | |
pthread_attr_t const& operator()() const { return attr_; } | |
std::size_t id() const { return std::hash<std::thread::id>{}( tid_ ); } | |
friend std::ostream& operator<<( std::ostream& os, thread_attr const& op1 ) | |
{ | |
const char* prefix = " "; | |
// set errno if we mess up | |
auto handle_error_en = []( int en, const char* msg ) { | |
errno = en; | |
throw std::runtime_error( msg ); | |
}; | |
os << "tid: " << op1.id() << std::endl; | |
const pthread_attr_t* attr = &op1(); | |
int s, i; | |
s = pthread_attr_getdetachstate( attr, &i ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getdetachstate" ); | |
os << fmt( "%sDetach state = %s\n", prefix, | |
( i == PTHREAD_CREATE_DETACHED ) | |
? "PTHREAD_CREATE_DETACHED" | |
: ( i == PTHREAD_CREATE_JOINABLE ) ? "PTHREAD_CREATE_JOINABLE" : "???" ); | |
s = pthread_attr_getscope( attr, &i ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getscope" ); | |
os << fmt( "%sScope = %s\n", prefix, | |
( i == PTHREAD_SCOPE_SYSTEM ) | |
? "PTHREAD_SCOPE_SYSTEM" | |
: ( i == PTHREAD_SCOPE_PROCESS ) ? "PTHREAD_SCOPE_PROCESS" : "???" ); | |
s = pthread_attr_getinheritsched( attr, &i ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getinheritsched" ); | |
os << fmt( "%sInherit scheduler = %s\n", prefix, | |
( i == PTHREAD_INHERIT_SCHED ) | |
? "PTHREAD_INHERIT_SCHED" | |
: ( i == PTHREAD_EXPLICIT_SCHED ) ? "PTHREAD_EXPLICIT_SCHED" : "???" ); | |
s = pthread_attr_getschedpolicy( attr, &i ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getschedpolicy" ); | |
os << fmt( "%sScheduling policy = %s\n", prefix, | |
( i == SCHED_OTHER ) | |
? "SCHED_OTHER" | |
: ( i == SCHED_FIFO ) ? "SCHED_FIFO" | |
: ( i == SCHED_RR ) ? "SCHED_RR" : "???" ); | |
struct sched_param sp; | |
s = pthread_attr_getschedparam( attr, &sp ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getschedparam" ); | |
os << fmt( "%sScheduling priority = %d\n", prefix, sp.sched_priority ); | |
size_t v; | |
s = pthread_attr_getguardsize( attr, &v ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getguardsize" ); | |
os << fmt( "%sGuard size = %d bytes\n", prefix, v ); | |
void* stkaddr; | |
s = pthread_attr_getstack( attr, &stkaddr, &v ); | |
if ( s != 0 ) handle_error_en( s, "pthread_attr_getstack" ); | |
os << fmt( "%sStack address = %p\n", prefix, stkaddr ); | |
os << fmt( "%sStack size = 0x%x bytes\n", prefix, v ); | |
return os; | |
} | |
}; // class thread_attr | |
int main( int argc, char* argv[] ) | |
{ | |
(void)argc; | |
(void)argv; | |
std::mutex checkpoint; | |
std::thread th{[&]() { checkpoint.lock(); }}; | |
auto attr = thread_attr( th ); | |
checkpoint.unlock(); | |
th.join(); | |
std::cout << attr << std::endl; | |
return 0; | |
} | |
/* example output | |
tid: 23992903604122022 | |
Detach state = PTHREAD_CREATE_JOINABLE | |
Scope = PTHREAD_SCOPE_SYSTEM | |
Inherit scheduler = PTHREAD_INHERIT_SCHED | |
Scheduling policy = SCHED_OTHER | |
Scheduling priority = 0 | |
Guard size = 4096 bytes | |
Stack address = 0x7f8b9594c000 | |
Stack size = 0x800000 bytes | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment