Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[core] Detect pthread_getname* availability #2111

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,9 @@ if (DEFINED HAVE_INET_PTON)
add_definitions(-DHAVE_INET_PTON=1)
endif()

include(FindPThreadGetSetName)
FindPThreadGetSetName() # Defines HAVE_PTHREAD_GETNAME_* and HAVE_PTHREAD_SETNAME_*

if (ENABLE_MONOTONIC_CLOCK)
if (NOT ENABLE_MONOTONIC_CLOCK_DEFAULT)
message(FATAL_ERROR "Your platform does not support CLOCK_MONOTONIC. Build with -DENABLE_MONOTONIC_CLOCK=OFF.")
Expand Down
18 changes: 9 additions & 9 deletions apps/srt-tunnel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,25 +223,25 @@ class Engine
Engine(Tunnel* p, Medium* m1, Medium* m2, const std::string& nid)
:
#ifdef HAVE_FULL_CXX11
media {m1, m2},
media {m1, m2},
#endif
parent_tunnel(p), nameid(nid)
parent_tunnel(p), nameid(nid)
{
#ifndef HAVE_FULL_CXX11
// MSVC is not exactly C++11 compliant and complains around
// initialization of an array.
// Leaving this method of initialization for clarity and
// possibly more preferred performance.
media[0] = m1;
media[1] = m2;
// MSVC is not exactly C++11 compliant and complains around
// initialization of an array.
// Leaving this method of initialization for clarity and
// possibly more preferred performance.
media[0] = m1;
media[1] = m2;
#endif
}

void Start()
{
Verb() << "START: " << media[DIR_IN]->uri() << " --> " << media[DIR_OUT]->uri();
std::string thrn = media[DIR_IN]->id() + ">" + media[DIR_OUT]->id();
ThreadName tn(thrn.c_str());
srt::ThreadName tn(thrn.c_str());

thr = thread([this]() { Worker(); });
}
Expand Down
82 changes: 82 additions & 0 deletions scripts/FindPThreadGetSetName.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#
# SRT - Secure, Reliable, Transport
# Copyright (c) 2021 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/.
#

# Check for pthread_getname_np(3) and pthread_setname_np(3)
# used in srtcore/threadname.h.
#
# Some BSD distros need to include <pthread_np.h> for pthread_getname_np().
#
# TODO: Some BSD distros have pthread_get_name_np() and pthread_set_name_np()
# instead of pthread_getname_np() and pthread_setname_np().
#
# Sets:
# HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H
# HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H
# HAVE_PTHREAD_GETNAME_NP
# HAVE_PTHREAD_SETNAME_NP
# Sets as appropriate:
# add_definitions(-DHAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=1)
# add_definitions(-DHAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=1)
# add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1)
# add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1)

include(CheckSymbolExists)

function(FindPThreadGetSetName)

unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H)
unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H PARENT_SCOPE)
unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H CACHE)
unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H PARENT_SCOPE)
unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H CACHE)

unset(HAVE_PTHREAD_GETNAME_NP)
unset(HAVE_PTHREAD_GETNAME_NP PARENT_SCOPE)
unset(HAVE_PTHREAD_GETNAME_NP CACHE)
unset(HAVE_PTHREAD_SETNAME_NP)
unset(HAVE_PTHREAD_SETNAME_NP PARENT_SCOPE)
unset(HAVE_PTHREAD_SETNAME_NP CACHE)

set(CMAKE_REQUIRED_DEFINITIONS
-D_GNU_SOURCE -D_DARWIN_C_SOURCE -D_POSIX_SOURCE=1)
set(CMAKE_REQUIRED_FLAGS "-pthread")

message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread_np.h':")
check_symbol_exists(
pthread_getname_np "pthread_np.h" HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H)
if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H)
add_definitions(-DHAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=1)
endif()
check_symbol_exists(
pthread_setname_np "pthread_np.h" HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
add_definitions(-DHAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=1)
endif()

message(STATUS "Checking for pthread_(g/s)etname_np in 'pthread.h':")
check_symbol_exists(pthread_getname_np "pthread.h" HAVE_PTHREAD_GETNAME_NP)
if (HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H)
set(HAVE_PTHREAD_GETNAME_NP TRUE PARENT_SCOPE)
endif()
check_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP)
if (HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
set(HAVE_PTHREAD_SETNAME_NP TRUE PARENT_SCOPE)
endif()
if (HAVE_PTHREAD_GETNAME_NP)
add_definitions(-DHAVE_PTHREAD_GETNAME_NP=1)
endif()
if (HAVE_PTHREAD_SETNAME_NP)
add_definitions(-DHAVE_PTHREAD_SETNAME_NP=1)
endif()

unset(CMAKE_REQUIRED_DEFINITIONS)
unset(CMAKE_REQUIRED_FLAGS)

endfunction(FindPThreadGetSetName)
2 changes: 1 addition & 1 deletion srtcore/srt_attr_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ used by SRT library internally.
#define SRT_ATTR_NO_THREAD_SAFETY_ANALYSIS
#else

#if defined(__clang__)
#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ > 5)
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
Expand Down
61 changes: 52 additions & 9 deletions srtcore/threadname.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,62 @@ written by
#ifndef INC_SRT_THREADNAME_H
#define INC_SRT_THREADNAME_H

#if defined(__APPLE__) || defined(__linux__)
#if defined(__linux__)
#include <sys/prctl.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

#include <pthread.h>
#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(__APPLE__) || defined(__linux__)
#if (defined(HAVE_PTHREAD_GETNAME_NP) && defined(HAVE_PTHREAD_GETNAME_NP)) \
|| defined(__linux__)

class ThreadNameImpl
{
Expand All @@ -47,8 +85,7 @@ class ThreadName
// 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(__APPLE__)
// since macos(10.6), ios(3.2)
#elif defined(HAVE_PTHREAD_GETNAME_NP)
return pthread_getname_np(pthread_self(), namebuf, BUFSIZE) == 0;
#else
#error "unsupported platform"
Expand All @@ -57,14 +94,18 @@ class ThreadName

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(__APPLE__)
// since macos(10.6), ios(3.2)
#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
Expand Down Expand Up @@ -178,4 +219,6 @@ class ThreadName
}
};

} // namespace srt

#endif
2 changes: 2 additions & 0 deletions test/test_threadname.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "gtest/gtest.h"
#include "threadname.h"

using namespace srt;

TEST(ThreadName, GetSet)
{
std::string name("getset");
Expand Down
10 changes: 5 additions & 5 deletions testing/srt-test-multiplex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,14 @@ struct MediumPair
applog.Note() << sout.str();
}
}
catch (Source::ReadEOF& x)
catch (const Source::ReadEOF&)
{
applog.Note() << "EOS - closing media for loop: " << name;
src->Close();
tar->Close();
applog.Note() << "CLOSED: " << name;
}
catch (std::runtime_error& x)
catch (const std::runtime_error& x)
{
applog.Note() << "INTERRUPTED: " << x.what();
src->Close();
Expand Down Expand Up @@ -196,7 +196,7 @@ class MediaBase
med.name = name;

// Ok, got this, so we can start transmission.
ThreadName tn(thread_name.c_str());
srt::ThreadName tn(thread_name.c_str());

med.runner = thread( [&med]() { med.TransmissionLoop(); });
return med;
Expand Down Expand Up @@ -577,7 +577,7 @@ int main( int argc, char** argv )

SrtModel m(up.host(), iport, up.parameters());

ThreadName::set("main");
srt::ThreadName::set("main");

// Note: for input, there must be an exactly defined
// number of sources. The loop rolls up to all these sources.
Expand Down Expand Up @@ -615,7 +615,7 @@ int main( int argc, char** argv )
break;
}

ThreadName::set("main");
srt::ThreadName::set("main");
}

applog.Note() << "All local stream definitions covered. Waiting for interrupt/broken all connections.";
Expand Down
4 changes: 2 additions & 2 deletions testing/srt-test-relay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ SrtMainLoop::SrtMainLoop(const string& srt_uri, bool input_echoback, const strin

void SrtMainLoop::InputRunner()
{
ThreadName::set("InputRN");
srt::ThreadName::set("InputRN");
// An extra thread with a loop that reads from the external input
// and writes into the SRT medium. When echoback mode is used,
// this thread isn't started at all and instead the SRT reading
Expand Down Expand Up @@ -438,7 +438,7 @@ void SrtMainLoop::run()

std::ostringstream tns;
tns << "Input:" << this;
ThreadName tn(tns.str().c_str());
srt::ThreadName tn(tns.str().c_str());
m_input_thr = thread([this] {
try {
InputRunner();
Expand Down
4 changes: 2 additions & 2 deletions testing/testactivemedia.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

void SourceMedium::Runner()
{
ThreadName::set("SourceRN");
srt::ThreadName::set("SourceRN");

Verb() << VerbLock << "Starting SourceMedium: " << this;
for (;;)
Expand Down Expand Up @@ -63,7 +63,7 @@ MediaPacket SourceMedium::Extract()

void TargetMedium::Runner()
{
ThreadName::set("TargetRN");
srt::ThreadName::set("TargetRN");
auto on_return_set = OnReturnSet(running, false);
Verb() << VerbLock << "Starting TargetMedium: " << this;
for (;;)
Expand Down
2 changes: 1 addition & 1 deletion testing/testactivemedia.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct Medium
running = true;
std::ostringstream tns;
tns << typeid(*this).name() << ":" << this;
ThreadName tn(tns.str().c_str());
srt::ThreadName tn(tns.str().c_str());
thr = thread( [this] { RunnerBase(); } );
}

Expand Down