mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +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
 |