Skip to content
Merged
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
43 changes: 37 additions & 6 deletions include/tscpp/util/TsSharedMutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#pragma once

#include <pthread.h>
#include <string.h>

#if __has_include(<ts/ts.h>)
#include <ts/ts.h>
Expand Down Expand Up @@ -53,6 +54,30 @@

namespace ts
{
class Strerror
{
public:
Strerror(int err_num)
{
_c_str = strerror_r(err_num, _buf, 256);
if (!_c_str) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some docs show that with the GNU-specific strerror_r(), if err_num is unknown, it can return an "unknown error nnn" message which won't make _c_str null, making the conditional think that strerror_r() did not fail when it did. Maybe use the XSI-compliant version (returning int) and returning _buf which also has the error string

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TS is compiled with -D_GNU_SOURCE, which means that only the GNU-specific strerror_r() is available. Even if it never returns null (currently), I'd rather leave the handling in for future-safety.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This breaks build on macOS #8642

_c_str = "strerror_r() call failed";
} else {
_buf[255] = '\0';
}
}

char const *
c_str() const
{
return (_c_str);
}

private:
char _buf[256];
char const *_c_str;
};

// A class with the same interface as std::shared_mutex, but which is not prone to writer starvation.
//
class shared_mutex
Expand All @@ -70,7 +95,7 @@ class shared_mutex
{
int error = pthread_rwlock_wrlock(&_lock);
if (error != 0) {
TSFatal("pthread_rwlock_wrlock(%p) failed: %s (%d)", &_lock, strerror(error), error);
_call_fatal("pthread_rwlock_wrlock", &_lock, error);
}
X(_exclusive = true;)
}
Expand All @@ -83,7 +108,7 @@ class shared_mutex
return false;
}
if (error != 0) {
TSFatal("pthread_rwlock_trywrlock(%p) failed: %s (%d)", &_lock, strerror(error), error);
_call_fatal("pthread_rwlock_trywrlock", &_lock, error);
}
X(_exclusive = true;)

Expand All @@ -104,7 +129,7 @@ class shared_mutex
{
int error = pthread_rwlock_rdlock(&_lock);
if (error != 0) {
TSFatal("pthread_rwlock_rdlock(%p) failed: %s (%d)", &_lock, strerror(error), error);
_call_fatal("pthread_rwlock_rdlock", &_lock, error);
}
X(++_shared;)
}
Expand All @@ -117,7 +142,7 @@ class shared_mutex
return false;
}
if (error != 0) {
TSFatal("pthread_rwlock_tryrdlock(%p) failed: %s (%d)", &_lock, strerror(error), error);
_call_fatal("pthread_rwlock_tryrdlock", &_lock, error);
}

X(++_shared;)
Expand All @@ -139,7 +164,7 @@ class shared_mutex
{
int error = pthread_rwlock_destroy(&_lock);
if (error != 0) {
TSFatal("pthread_rwlock_destory(%p) failed: %s (%d)", &_lock, strerror(error), error);
_call_fatal("pthread_rwlock_destroy", &_lock, error);
}
}

Expand All @@ -157,7 +182,7 @@ class shared_mutex
{
int error = pthread_rwlock_unlock(&_lock);
if (error != 0) {
TSFatal("pthread_rwlock_unlock(%p) failed: %s (%d)", &_lock, strerror(error), error);
_call_fatal("pthread_rwlock_unlock", &_lock, error);
}
}

Expand All @@ -175,6 +200,12 @@ class shared_mutex
#endif
#endif

void
_call_fatal(char const *func_name, void *ptr, int errnum)
{
TSFatal("%s(%p) failed: %s (%d)", func_name, ptr, Strerror(errnum).c_str(), errnum);
}

// In debug builds, make sure shared vs. exlusive locks and unlocks are properly paired.
//
X(std::atomic<bool> _exclusive;)
Expand Down