0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-27 15:41:05 +08:00

Implement thread name on windows, cleanup thread naming internals

This commit is contained in:
Romain Moret 2019-05-20 19:27:12 +02:00
parent 046ccfc408
commit 27005cc1ae
8 changed files with 75 additions and 34 deletions

View File

@ -426,14 +426,10 @@ void zmq::thread_ctx_t::start_thread (thread_t &thread_,
_thread_affinity_cpus);
char namebuf[16] = "";
#ifdef ZMQ_HAVE_WINDOWS
LIBZMQ_UNUSED (name_);
#else
snprintf (namebuf, sizeof (namebuf), "%s%sZMQbg%s%s",
_thread_name_prefix.empty () ? "" : _thread_name_prefix.c_str (),
_thread_name_prefix.empty () ? "" : "/", name_ ? "/" : "",
name_ ? name_ : "");
#endif
thread_.start (tfn_, arg_, namebuf);
}

View File

@ -57,10 +57,8 @@ zmq::io_thread_t::~io_thread_t ()
void zmq::io_thread_t::start ()
{
char name[16] = "";
#ifndef ZMQ_HAVE_WINDOWS
snprintf (name, sizeof (name), "IO/%u",
get_tid () - zmq::ctx_t::reaper_tid - 1);
#endif
// Start the underlying I/O thread.
_poller->start (name);
}

View File

@ -47,6 +47,7 @@ static unsigned int __stdcall thread_routine (void *arg_)
#endif
{
zmq::thread_t *self = (zmq::thread_t *) arg_;
self->applyThreadName ();
self->_tfn (self->_arg);
return 0;
}
@ -54,9 +55,10 @@ static unsigned int __stdcall thread_routine (void *arg_)
void zmq::thread_t::start (thread_fn *tfn_, void *arg_, const char *name_)
{
LIBZMQ_UNUSED (name_);
_tfn = tfn_;
_arg = arg_;
if (name_)
strncpy (_name, name_, sizeof (_name));
#if defined _WIN32_WCE
_descriptor =
(HANDLE) CreateThread (NULL, 0, &::thread_routine, this, 0, NULL);
@ -92,10 +94,48 @@ void zmq::thread_t::setSchedulingParameters (
LIBZMQ_UNUSED (affinity_cpus_);
}
void zmq::thread_t::setThreadName (const char *name_)
void zmq::thread_t::
applySchedulingParameters () // to be called in secondary thread context
{
// not implemented
LIBZMQ_UNUSED (name_);
}
namespace
{
#pragma pack(push, 8)
struct thread_info_t
{
DWORD _type;
LPCSTR _name;
DWORD _thread_id;
DWORD _flags;
};
#pragma pack(pop)
}
void zmq::thread_t::
applyThreadName () // to be called in secondary thread context
{
if (!_name[0])
return;
thread_info_t thread_info;
thread_info._type = 0x1000;
thread_info._name = _name;
thread_info._thread_id = -1;
thread_info._flags = 0;
#pragma warning(push)
#pragma warning(disable : 6320 6322)
__try {
DWORD MS_VC_EXCEPTION = 0x406D1388;
RaiseException (MS_VC_EXCEPTION, 0,
sizeof (thread_info) / sizeof (ULONG_PTR),
(ULONG_PTR *) &thread_info);
}
__except (EXCEPTION_CONTINUE_EXECUTION) {
}
#pragma warning(pop)
}
#elif defined ZMQ_HAVE_VXWORKS
@ -154,10 +194,10 @@ void zmq::thread_t::
}
}
void zmq::thread_t::setThreadName (const char *name_)
void zmq::thread_t::
applyThreadName () // to be called in secondary thread context
{
// not implemented
LIBZMQ_UNUSED (name_);
}
#else
@ -181,7 +221,7 @@ static void *thread_routine (void *arg_)
#endif
zmq::thread_t *self = (zmq::thread_t *) arg_;
self->applySchedulingParameters ();
self->setThreadName (self->_name.c_str ());
self->applyThreadName ();
self->_tfn (self->_arg);
return NULL;
}
@ -191,7 +231,8 @@ void zmq::thread_t::start (thread_fn *tfn_, void *arg_, const char *name_)
{
_tfn = tfn_;
_arg = arg_;
_name = name_;
if (name_)
strncpy (_name, name_, sizeof (_name));
int rc = pthread_create (&_descriptor, NULL, thread_routine, this);
posix_assert (rc);
_started = true;
@ -301,7 +342,8 @@ void zmq::thread_t::
#endif
}
void zmq::thread_t::setThreadName (const char *name_)
void zmq::thread_t::
applyThreadName () // to be called in secondary thread context
{
/* The thread name is a cosmetic string, added to ease debugging of
* multi-threaded applications. It is not a big issue if this value
@ -310,7 +352,7 @@ void zmq::thread_t::setThreadName (const char *name_)
* "int rc" is retained where available, to help debuggers stepping
* through code to see its value - but otherwise it is ignored.
*/
if (!name_)
if (!_name[0])
return;
/* Fails with permission denied on Android 5/6 */
@ -319,19 +361,19 @@ void zmq::thread_t::setThreadName (const char *name_)
#endif
#if defined(ZMQ_HAVE_PTHREAD_SETNAME_1)
int rc = pthread_setname_np (name_);
int rc = pthread_setname_np (_name);
if (rc)
return;
#elif defined(ZMQ_HAVE_PTHREAD_SETNAME_2)
int rc = pthread_setname_np (pthread_self (), name_);
int rc = pthread_setname_np (pthread_self (), _name);
if (rc)
return;
#elif defined(ZMQ_HAVE_PTHREAD_SETNAME_3)
int rc = pthread_setname_np (pthread_self (), name_, NULL);
int rc = pthread_setname_np (pthread_self (), _name, NULL);
if (rc)
return;
#elif defined(ZMQ_HAVE_PTHREAD_SET_NAME)
pthread_set_name_np (pthread_self (), name_);
pthread_set_name_np (pthread_self (), _name);
#endif
}

View File

@ -37,7 +37,7 @@
#include <pthread.h>
#endif
#include <set>
#include <string>
#include <cstring>
namespace zmq
{
@ -56,11 +56,11 @@ class thread_t
inline thread_t () :
_tfn (NULL),
_arg (NULL),
_name (""),
_started (false),
_thread_priority (ZMQ_THREAD_PRIORITY_DFLT),
_thread_sched_policy (ZMQ_THREAD_SCHED_POLICY_DFLT)
{
memset (_name, 0, sizeof (_name));
}
#ifdef ZMQ_HAVE_VXWORKS
@ -74,6 +74,8 @@ class thread_t
// Creates OS thread. 'tfn' is main thread function. It'll be passed
// 'arg' as an argument.
// Name is 16 characters max including terminating NUL. Thread naming is
// implemented only for pthread, and windows when a debugger is attached.
void start (thread_fn *tfn_, void *arg_, const char *name_);
// Returns whether the thread was started, i.e. start was called.
@ -92,16 +94,13 @@ class thread_t
int scheduling_policy_,
const std::set<int> &affinity_cpus_);
// Sets the thread name, 16 characters max including terminating NUL.
// Only implemented for pthread. Has no effect on other platforms.
void setThreadName (const char *name_);
// These are internal members. They should be private, however then
// they would not be accessible from the main C routine of the thread.
void applySchedulingParameters ();
void applyThreadName ();
thread_fn *_tfn;
void *_arg;
std::string _name;
char _name[16];
private:
bool _started;

View File

@ -95,3 +95,10 @@ static inline int poll (struct pollfd *pfd, unsigned long nfds, int timeout)
#define AI_NUMERICSERV 0x0400
#endif
#endif
// In MSVC prior to v14, snprintf is not available
// The closest implementation is the _snprintf_s function
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf(buffer_, count_, format_, ...) \
_snprintf_s (buffer_, count_, _TRUNCATE, format_, __VA_ARGS__)
#endif

View File

@ -48,10 +48,6 @@
char error_message_buffer[256];
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif
void *handler;
void *zap_thread;
void *server;

View File

@ -96,6 +96,13 @@ enum
};
#endif
// In MSVC prior to v14, snprintf is not available
// The closest implementation is the _snprintf_s function
#if defined _MSC_VER && _MSC_VER < 1900
#define snprintf(buffer_, count_, format_, ...) \
_snprintf_s (buffer_, count_, _TRUNCATE, format_, __VA_ARGS__)
#endif
#define LIBZMQ_UNUSED(object) (void) object
// Bounce a message from client to server and back

View File

@ -35,10 +35,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <unity.h>
#if defined(_MSC_VER) && _MSC_VER <= 1800
#define snprintf _snprintf
#endif
// Internal helper functions that are not intended to be directly called from
// tests. They must be declared in the header since they are used by macros.