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

Fix Build for MacOS, FreeBSD, GCC earlier than 4.7, and Clang earlier… #2104

Merged
merged 13 commits into from
Sep 1, 2021
Merged
Show file tree
Hide file tree
Changes from 8 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
59 changes: 59 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ include(FindPkgConfig)
# XXX See 'if (MINGW)' condition below, may need fixing.
include(FindThreads)
include(CheckFunctionExists)
include(CheckSymbolExists)

# Platform shortcuts
string(TOLOWER ${CMAKE_SYSTEM_NAME} SYSNAME_LC)
Expand Down Expand Up @@ -149,6 +150,13 @@ option(ENABLE_SOCK_CLOEXEC "Enable setting SOCK_CLOEXEC on a socket" ON)

option(ENABLE_CLANG_TSA "Enable Clang Thread Safety Analysis" OFF)

# NOTE: Use ATOMIC_USE_POSIX_MUTEX and will override the auto-detection of the
# Atomic implemetation in srtcore/atomic.h.
option(ATOMIC_USE_POSIX_MUTEX "Use POSIX Mutex to Implement Atomics" OFF)
if (ATOMIC_USE_POSIX_MUTEX)
add_definitions(-DATOMIC_USE_POSIX_MUTEX=1)
endif()

set(TARGET_srt "srt" CACHE STRING "The name for the SRT library")

# Use application-defined group reader
Expand Down Expand Up @@ -275,6 +283,57 @@ if (DEFINED HAVE_INET_PTON)
add_definitions(-DHAVE_INET_PTON=1)
endif()

# 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().
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':")
unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H)
unset(HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H CACHE)
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()
unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H)
unset(HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H CACHE)
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()
unset(HAVE_PTHREAD_GETNAME_NP)
unset(HAVE_PTHREAD_GETNAME_NP CACHE)
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)
endif()
unset(HAVE_PTHREAD_SETNAME_NP)
unset(HAVE_PTHREAD_SETNAME_NP CACHE)
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)
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()
maxsharabayko marked this conversation as resolved.
Show resolved Hide resolved
if ("0" MATCHES "1")
message(
STATUS
"HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H=${HAVE_PTHREAD_GETNAME_NP_IN_PTHREAD_NP_H}\n"
"HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H=${HAVE_PTHREAD_SETNAME_NP_IN_PTHREAD_NP_H}\n"
"HAVE_PTHREAD_GETNAME_NP=${HAVE_PTHREAD_GETNAME_NP}\n"
"HAVE_PTHREAD_SETNAME_NP=${HAVE_PTHREAD_SETNAME_NP}")
endif()
jlsantiago0 marked this conversation as resolved.
Show resolved Hide resolved

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
211 changes: 188 additions & 23 deletions srtcore/atomic.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,56 @@
line)[(2 * static_cast<int>(!!(condition))) - 1] _impl_UNUSED
#endif

#if defined(__GNUC__) || defined(__clang__) || defined(__xlc__)
#define ATOMIC_USE_GCC_INTRINSICS
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
// NOTE: Defined at the top level.
#elif defined(__APPLE__) && (__cplusplus >= 201103L)
// NOTE: Does support c++11 std::atomic, but the compiler may or
// may not support GCC atomic intrinsics. So go ahead and use the
// std::atomic implementation.
#define ATOMIC_USE_CPP11_ATOMIC
#elif (defined(__clang__) && defined(__clang_major__) && (__clang_major__ > 5)) \
|| defined(__xlc__)
// NOTE: Clang <6 does not support GCC __atomic_* intrinsics. I am unsure
// about Clang6. Since Clang sets __GNUC__ and __GNUC_MINOR__ of this era
// to <4.5, older Clang will catch the setting below to use the
// POSIX Mutex Implementation.
#define ATOMIC_USE_GCC_INTRINSICS
#elif defined(__GNUC__) \
&& ( (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) )
// NOTE: The __atomic_* family of intrisics were introduced in GCC-4.7.0.
// NOTE: This follows #if defined(__clang__), because most if, not all,
// versions of Clang define __GNUC__ and __GNUC_MINOR__ but often define
// them to 4.4 or an even earlier version. Most of the newish versions
// of Clang also support GCC Atomic Intrisics even if they set GCC version
// macros to <4.7.
#define ATOMIC_USE_GCC_INTRINSICS
#elif defined(__GNUC__) && !defined(ATOMIC_USE_POSIX_MUTEX)
// NOTE: GCC compiler built-ins for atomic operations are pure
// compiler extensions prior to GCC-4.7 and were grouped into the
// the __sync_* family of functions. GCC-4.7, both the c++11 and C11
// standards had been finalized, and GCC updated their built-ins to
// better reflect the new memory model and the new functions grouped
// into the __atomic_* family. Also the memory models were defined
// differently, than in pre 4.7.
// TODO: PORT to the pre GCC-4.7 __sync_* intrinsics. In the meantime use
// the POSIX Mutex Implementation.
#define ATOMIC_USE_POSIX_MUTEX 1
#elif defined(_MSC_VER)
#define ATOMIC_USE_MSVC_INTRINSICS
#include "atomic_msvc.h"
#define ATOMIC_USE_MSVC_INTRINSICS
#include "atomic_msvc.h"
#elif __cplusplus >= 201103L
#define ATOMIC_USE_CPP11_ATOMIC
#include <atomic>
#define ATOMIC_USE_CPP11_ATOMIC
#else
#error Unsupported compiler / system.
#error Unsupported compiler / system.
#endif
// Include any necessary headers for the selected Atomic Implementation.
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
#include <assert.h>
#include <stdio.h>
jlsantiago0 marked this conversation as resolved.
Show resolved Hide resolved
#include <pthread.h>
#endif
#if defined(ATOMIC_USE_CPP11_ATOMIC)
#include <atomic>
#endif

namespace srt {
Expand All @@ -82,31 +122,120 @@ class atomic {
sizeof(T) == 8,
"Only types of size 1, 2, 4 or 8 are supported");

atomic() : value_(static_cast<T>(0)) {}
atomic()
: value_(static_cast<T>(0))
{
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
const int lResult = pthread_mutex_init(&mutex_, NULL);
if (lResult != 0)
{
perror("Initializing Mutex");
assert(lResult == 0);
}
#endif
}

explicit atomic(const T value)
: value_(value)
{
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
const int lResult = pthread_mutex_init(&mutex_, NULL);
if (lResult != 0)
{
perror("Initializing Mutex");
assert(lResult == 0);
}
#endif
}

~atomic()
{
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
const int lResult = pthread_mutex_destroy(&mutex_);
if (lResult != 0)
{
perror("Destroying Mutex");
assert(lResult == 0);
}
#endif
}

explicit atomic(const T value) : value_(value) {}
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
class PosixMutexLockGuard
maxsharabayko marked this conversation as resolved.
Show resolved Hide resolved
{
private:
pthread_mutex_t * mutex_;
private:
// disallow default/copy/move constructors and assignment.
#if __cplusplus >= 201103L
PosixMutexLockGuard() = delete;
PosixMutexLockGuard(const PosixMutexLockGuard &) = delete;
PosixMutexLockGuard(const PosixMutexLockGuard &&) = delete;
PosixMutexLockGuard & operator=(const PosixMutexLockGuard &) = delete;
PosixMutexLockGuard & operator=(const PosixMutexLockGuard &&) = delete;
#else
PosixMutexLockGuard();
PosixMutexLockGuard(const PosixMutexLockGuard &);
PosixMutexLockGuard & operator=(const PosixMutexLockGuard &);
#endif
public:
explicit PosixMutexLockGuard(pthread_mutex_t * mutex__)
: mutex_(mutex__)
{
assert(mutex_ != NULL);
const int lResult = pthread_mutex_lock(mutex_);
if (lResult != 0)
{
perror("Locking Mutex");
assert(lResult == 0);
}
}
~PosixMutexLockGuard()
{
assert(mutex_ != NULL);
const int lResult = pthread_mutex_unlock(mutex_);
if (lResult != 0)
{
perror("UnLocking Mutex");
assert(lResult == 0);
}
}
};
#endif

/// @brief Performs an atomic increment operation (value + 1).
/// @returns The new value of the atomic object.
T operator++() {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
PosixMutexLockGuard lock_(&mutex_);
const T t = ++value_;
return t;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_add_fetch(&value_, 1, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
return msvc::interlocked<T>::increment(&value_);
#else
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
return ++value_;
#else
#error "Implement Me."
#endif
}

/// @brief Performs an atomic decrement operation (value - 1).
/// @returns The new value of the atomic object.
T operator--() {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
PosixMutexLockGuard lock_(&mutex_);
const T t = --value_;
return t;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_sub_fetch(&value_, 1, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
return msvc::interlocked<T>::decrement(&value_);
#else
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
return --value_;
#else
#error "Implement Me."
#endif
}

Expand All @@ -119,17 +248,28 @@ class atomic {
/// @param new_val The new value to write to the atomic object.
/// @returns True if new_value was written to the atomic object.
bool compare_exchange(const T expected_val, const T new_val) {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
PosixMutexLockGuard lock_(&mutex_);
bool result = false;
if (expected_val == value_)
{
value_ = new_val;
result = true;
}
return result;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
T e = expected_val;
return __atomic_compare_exchange_n(
&value_, &e, new_val, true, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
const T old_val =
msvc::interlocked<T>::compare_exchange(&value_, new_val, expected_val);
return (old_val == expected_val);
#else
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
T e = expected_val;
return value_.compare_exchange_weak(e, new_val);
#else
#error "Implement Me."
#endif
}

Expand All @@ -140,26 +280,37 @@ class atomic {
///
/// @param new_val The new value to write to the atomic object.
void store(const T new_val) {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
PosixMutexLockGuard lock_(&mutex_);
value_ = new_val;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
__atomic_store_n(&value_, new_val, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
(void)msvc::interlocked<T>::exchange(&value_, new_val);
#else
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
value_.store(new_val);
#else
#error "Implement Me."
#endif
}

/// @returns the current value of the atomic object.
/// @note Be careful about how this is used, since any operations on the
/// returned value are inherently non-atomic.
T load() const {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
PosixMutexLockGuard lock_(&mutex_);
const T t = value_;
return t;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_load_n(&value_, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
// TODO(m): Is there a better solution for MSVC?
return value_;
#else
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
return value_;
#else
#error "Implement Me."
#endif
}

Expand All @@ -171,12 +322,19 @@ class atomic {
/// @param new_val The new value to write to the atomic object.
/// @returns the old value.
T exchange(const T new_val) {
#if defined(ATOMIC_USE_GCC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
PosixMutexLockGuard lock_(&mutex_);
const T t = value_;
value_ = new_val;
return t;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
return __atomic_exchange_n(&value_, new_val, __ATOMIC_SEQ_CST);
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
return msvc::interlocked<T>::exchange(&value_, new_val);
#else
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
return value_.exchange(new_val);
#else
#error "Implement Me."
#endif
}

Expand All @@ -190,10 +348,17 @@ class atomic {
}

private:
#if defined(ATOMIC_USE_GCC_INTRINSICS) || defined(ATOMIC_USE_MSVC_INTRINSICS)
#if defined(ATOMIC_USE_POSIX_MUTEX) && (ATOMIC_USE_POSIX_MUTEX == 1)
T value_;
mutable pthread_mutex_t mutex_;
#elif defined(ATOMIC_USE_GCC_INTRINSICS)
volatile T value_;
#else
#elif defined(ATOMIC_USE_MSVC_INTRINSICS)
volatile T value_;
#elif defined(ATOMIC_USE_CPP11_ATOMIC)
std::atomic<T> value_;
#else
#error "Implement Me. (value_ type)"
#endif

ATOMIC_DISALLOW_COPY(atomic)
Expand Down
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
Loading