mirror of
https://github.com/ossrs/srs.git
synced 2025-02-15 04:42:04 +00:00
224 lines
6.5 KiB
C++
224 lines
6.5 KiB
C++
/*
|
|
* SRT - Secure, Reliable, Transport
|
|
* Copyright (c) 2018 Haivision Systems Inc.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
*/
|
|
|
|
/*****************************************************************************
|
|
written by
|
|
Haivision Systems Inc.
|
|
*****************************************************************************/
|
|
|
|
#ifndef INC_SRT_THREADNAME_H
|
|
#define INC_SRT_THREADNAME_H
|
|
|
|
// NOTE:
|
|
// HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H
|
|
// HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H
|
|
// HAVE_PTHREAD_GETNAME_NP
|
|
// HAVE_PTHREAD_GETNAME_NP
|
|
// Are detected and set in ../CMakeLists.txt.
|
|
// OS Availability of pthread_getname_np(..) and pthread_setname_np(..)::
|
|
// MacOS(10.6)
|
|
// iOS(3.2)
|
|
// AIX(7.1)
|
|
// FreeBSD(version?), OpenBSD(Version?)
|
|
// Linux-GLIBC(GLIBC-2.12).
|
|
// Linux-MUSL(MUSL-1.1.20 Partial Implementation. See below).
|
|
// MINGW-W64(4.0.6)
|
|
|
|
#if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \
|
|
|| defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
|
|
#include <pthread_np.h>
|
|
#if defined(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H) \
|
|
&& !defined(HAVE_PTHREAD_GETNAME_NP)
|
|
#define HAVE_PTHREAD_GETNAME_NP 1
|
|
#endif
|
|
#if defined(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H) \
|
|
&& !defined(HAVE_PTHREAD_SETNAME_NP)
|
|
#define HAVE_PTHREAD_SETNAME_NP 1
|
|
#endif
|
|
#endif
|
|
|
|
#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \
|
|
|| defined(__linux__)
|
|
// NOTE:
|
|
// Linux pthread_getname_np() and pthread_setname_np() became available
|
|
// in GLIBC-2.12 and later.
|
|
// Some Linux runtimes do not have pthread_getname_np(), but have
|
|
// pthread_setname_np(), for instance MUSL at least as of v1.1.20.
|
|
// So using the prctl() for Linux is more portable.
|
|
#if defined(__linux__)
|
|
#include <sys/prctl.h>
|
|
#endif
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
#include "common.h"
|
|
#include "sync.h"
|
|
|
|
namespace srt {
|
|
|
|
class ThreadName
|
|
{
|
|
|
|
#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \
|
|
|| defined(__linux__)
|
|
|
|
class ThreadNameImpl
|
|
{
|
|
public:
|
|
static const size_t BUFSIZE = 64;
|
|
static const bool DUMMY_IMPL = false;
|
|
|
|
static bool get(char* namebuf)
|
|
{
|
|
#if defined(__linux__)
|
|
// since Linux 2.6.11. The buffer should allow space for up to 16
|
|
// bytes; the returned string will be null-terminated.
|
|
return prctl(PR_GET_NAME, (unsigned long)namebuf, 0, 0) != -1;
|
|
#elif defined(HAVE_PTHREAD_GETNAME_NP)
|
|
return pthread_getname_np(pthread_self(), namebuf, BUFSIZE) == 0;
|
|
#else
|
|
#error "unsupported platform"
|
|
#endif
|
|
}
|
|
|
|
static bool set(const char* name)
|
|
{
|
|
SRT_ASSERT(name != NULL);
|
|
#if defined(__linux__)
|
|
// The name can be up to 16 bytes long, including the terminating
|
|
// null byte. (If the length of the string, including the terminating
|
|
// null byte, exceeds 16 bytes, the string is silently truncated.)
|
|
return prctl(PR_SET_NAME, (unsigned long)name, 0, 0) != -1;
|
|
#elif defined(HAVE_PTHREAD_SETNAME_NP)
|
|
#if defined(__APPLE__)
|
|
return pthread_setname_np(name) == 0;
|
|
#else
|
|
return pthread_setname_np(pthread_self(), name) == 0;
|
|
#endif
|
|
#else
|
|
#error "unsupported platform"
|
|
#endif
|
|
}
|
|
|
|
explicit ThreadNameImpl(const std::string& name)
|
|
: reset(false)
|
|
{
|
|
tid = pthread_self();
|
|
|
|
if (!get(old_name))
|
|
return;
|
|
|
|
reset = set(name.c_str());
|
|
if (reset)
|
|
return;
|
|
|
|
// Try with a shorter name. 15 is the upper limit supported by Linux,
|
|
// other platforms should support a larger value. So 15 should works
|
|
// on all platforms.
|
|
const size_t max_len = 15;
|
|
if (name.size() > max_len)
|
|
reset = set(name.substr(0, max_len).c_str());
|
|
}
|
|
|
|
~ThreadNameImpl()
|
|
{
|
|
if (!reset)
|
|
return;
|
|
|
|
// ensure it's called on the right thread
|
|
if (tid == pthread_self())
|
|
set(old_name);
|
|
}
|
|
|
|
private:
|
|
ThreadNameImpl(ThreadNameImpl& other);
|
|
ThreadNameImpl& operator=(const ThreadNameImpl& other);
|
|
|
|
private:
|
|
bool reset;
|
|
pthread_t tid;
|
|
char old_name[BUFSIZE];
|
|
};
|
|
|
|
#else
|
|
|
|
class ThreadNameImpl
|
|
{
|
|
public:
|
|
static const bool DUMMY_IMPL = true;
|
|
static const size_t BUFSIZE = 64;
|
|
|
|
static bool get(char* output)
|
|
{
|
|
// The default implementation will simply try to get the thread ID
|
|
std::ostringstream bs;
|
|
bs << "T" << sync::this_thread::get_id();
|
|
size_t s = bs.str().copy(output, BUFSIZE - 1);
|
|
output[s] = '\0';
|
|
return true;
|
|
}
|
|
|
|
static bool set(const char*) { return false; }
|
|
|
|
ThreadNameImpl(const std::string&) {}
|
|
|
|
~ThreadNameImpl() // just to make it "non-trivially-destructible" for compatibility with normal version
|
|
{
|
|
}
|
|
};
|
|
|
|
#endif // platform dependent impl
|
|
|
|
// Why delegate to impl:
|
|
// 1. to make sure implementation on different platforms have the same interface.
|
|
// 2. it's simple to add some wrappers like get(const std::string &).
|
|
ThreadNameImpl impl;
|
|
|
|
public:
|
|
static const bool DUMMY_IMPL = ThreadNameImpl::DUMMY_IMPL;
|
|
static const size_t BUFSIZE = ThreadNameImpl::BUFSIZE;
|
|
|
|
/// @brief Print thread ID to the provided buffer.
|
|
/// The size of the destination buffer is assumed to be at least ThreadName::BUFSIZE.
|
|
/// @param [out] output destination buffer to get thread name
|
|
/// @return true on success, false on failure
|
|
static bool get(char* output) {
|
|
return ThreadNameImpl::get(output);
|
|
}
|
|
|
|
static bool get(std::string& name)
|
|
{
|
|
char buf[BUFSIZE];
|
|
bool ret = get(buf);
|
|
if (ret)
|
|
name = buf;
|
|
return ret;
|
|
}
|
|
|
|
static bool set(const std::string& name) { return ThreadNameImpl::set(name.c_str()); }
|
|
|
|
explicit ThreadName(const std::string& name)
|
|
: impl(name)
|
|
{
|
|
}
|
|
|
|
private:
|
|
ThreadName(const ThreadName&);
|
|
ThreadName(const char*);
|
|
ThreadName& operator=(const ThreadName& other);
|
|
};
|
|
|
|
} // namespace srt
|
|
|
|
#endif
|