From d325cb71a20a6baf83d86437faa3164b67231057 Mon Sep 17 00:00:00 2001 From: janbar Date: Thu, 8 Feb 2024 21:36:33 +0100 Subject: [PATCH] sync upstream lib cppmyth 2.17.0 --- lib/cppmyth/CMakeLists.txt | 7 +- lib/cppmyth/src/local_config.h.in | 8 + lib/cppmyth/src/mythfileplayback.cpp | 10 +- lib/cppmyth/src/mythintrinsic.cpp | 113 ------- lib/cppmyth/src/mythintrinsic.h | 51 --- lib/cppmyth/src/mythlivetvplayback.cpp | 46 +-- lib/cppmyth/src/mythrecordingplayback.cpp | 10 +- lib/cppmyth/src/mythsharedptr.cpp | 100 ++++++ lib/cppmyth/src/mythsharedptr.h | 103 +++--- .../src/private/{ => os/threads}/atomic.h | 297 ++++++++++++++---- lib/cppmyth/src/private/os/threads/latch.cpp | 283 +++++++++++++++++ lib/cppmyth/src/private/os/threads/latch.h | 228 ++++++++++++++ .../src/private/os/threads/os-threads.h | 6 + lib/cppmyth/src/private/os/unix/os-types.h | 2 +- lib/cppmyth/src/private/os/windows/os-types.h | 7 + lib/cppmyth/src/private/wsresponse.cpp | 3 +- lib/cppmyth/src/private/wsresponse.h | 7 +- lib/cppmyth/src/proto/mythprotobase.cpp | 10 +- lib/cppmyth/src/proto/mythprotobase.h | 4 +- lib/cppmyth/src/proto/mythprotoevent.cpp | 6 +- lib/cppmyth/src/proto/mythprotomonitor.cpp | 50 +-- lib/cppmyth/src/proto/mythprotoplayback.cpp | 18 +- lib/cppmyth/src/proto/mythprotorecorder.cpp | 34 +- lib/cppmyth/src/proto/mythprototransfer.cpp | 31 +- 24 files changed, 1046 insertions(+), 388 deletions(-) delete mode 100644 lib/cppmyth/src/mythintrinsic.cpp delete mode 100644 lib/cppmyth/src/mythintrinsic.h create mode 100644 lib/cppmyth/src/mythsharedptr.cpp rename lib/cppmyth/src/private/{ => os/threads}/atomic.h (70%) create mode 100644 lib/cppmyth/src/private/os/threads/latch.cpp create mode 100644 lib/cppmyth/src/private/os/threads/latch.h diff --git a/lib/cppmyth/CMakeLists.txt b/lib/cppmyth/CMakeLists.txt index 562d3b26..ff08294b 100644 --- a/lib/cppmyth/CMakeLists.txt +++ b/lib/cppmyth/CMakeLists.txt @@ -18,8 +18,8 @@ endif () ############################################################################### # set lib version here set (PACKAGE_VERSION_MAJOR 2) -set (PACKAGE_VERSION_MINOR 16) -set (PACKAGE_VERSION_PATCH 4) +set (PACKAGE_VERSION_MINOR 17) +set (PACKAGE_VERSION_PATCH 0) set (PACKAGE_VERSION ${PACKAGE_VERSION_MAJOR}.${PACKAGE_VERSION_MINOR}.${PACKAGE_VERSION_PATCH}) set (PACKAGE_LIB_SOVERSION ${PACKAGE_VERSION_MAJOR}) @@ -142,7 +142,8 @@ file (GLOB SRC_FILES src/*.cpp) file (GLOB OS_SRC_FILES - src/private/os/threads/threadpool.cpp) + src/private/os/threads/threadpool.cpp + src/private/os/threads/latch.cpp) if (MSVC) list (APPEND OS_SRC_FILES diff --git a/lib/cppmyth/src/local_config.h.in b/lib/cppmyth/src/local_config.h.in index 8c265eb7..7bf39de5 100644 --- a/lib/cppmyth/src/local_config.h.in +++ b/lib/cppmyth/src/local_config.h.in @@ -29,4 +29,12 @@ #undef LIBVERSION #define LIBVERSION "@PACKAGE_VERSION@" +#if __cplusplus < 201103L +#undef explicit +#define explicit +#undef nullptr +#define nullptr NULL +#endif + + #endif /* CPPMYTH_CONFIG_H */ diff --git a/lib/cppmyth/src/mythfileplayback.cpp b/lib/cppmyth/src/mythfileplayback.cpp index 0e28614c..c8520235 100644 --- a/lib/cppmyth/src/mythfileplayback.cpp +++ b/lib/cppmyth/src/mythfileplayback.cpp @@ -22,7 +22,7 @@ #include "mythfileplayback.h" #include "mythlivetvplayback.h" #include "private/debug.h" -#include "private/os/threads/mutex.h" +#include "private/os/threads/latch.h" #include "private/builtin.h" #include @@ -50,7 +50,7 @@ FilePlayback::~FilePlayback() bool FilePlayback::Open() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (ProtoPlayback::IsOpen()) return true; return ProtoPlayback::Open(); @@ -59,7 +59,7 @@ bool FilePlayback::Open() void FilePlayback::Close() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); CloseTransfer(); ProtoPlayback::Close(); } @@ -67,7 +67,7 @@ void FilePlayback::Close() bool FilePlayback::OpenTransfer(const std::string& pathname, const std::string& sgname) { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!ProtoPlayback::IsOpen()) return false; CloseTransfer(); @@ -80,7 +80,7 @@ bool FilePlayback::OpenTransfer(const std::string& pathname, const std::string& void FilePlayback::CloseTransfer() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (m_transfer) { TransferDone(*m_transfer); diff --git a/lib/cppmyth/src/mythintrinsic.cpp b/lib/cppmyth/src/mythintrinsic.cpp deleted file mode 100644 index 6f819bca..00000000 --- a/lib/cppmyth/src/mythintrinsic.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2015 Jean-Luc Barriere - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#include "mythintrinsic.h" - -#include "local_config.h" -#if __cplusplus >= 201103L -#include -typedef std::atomic counter_t; -#define GETVALUE(p) (p)->load() -#define INCREMENT(p) ((p)->fetch_add(1, std::memory_order_relaxed) + 1) -#define DECREMENT(p) ((p)->fetch_sub(1, std::memory_order_relaxed) - 1) - -#elif defined _MSC_VER -#define WIN32_LEAN_AND_MEAN -#include -typedef volatile LONG counter_t; -#define GETVALUE(p) (*(p)) -#define INCREMENT(p) InterlockedIncrement(p) -#define DECREMENT(p) InterlockedDecrement(p) - -#elif defined __APPLE__ -#include -typedef volatile int32_t counter_t; -#define GETVALUE(p) (*(p)) -#define INCREMENT(p) OSAtomicIncrement32(p) -#define DECREMENT(p) OSAtomicDecrement32(p) - -#elif defined HAS_BUILTIN_SYNC_ADD_AND_FETCH -typedef volatile int counter_t; -#define GETVALUE(p) (*(p)) -#define INCREMENT(p) __sync_add_and_fetch(p, 1) -#if defined HAS_BUILTIN_SYNC_SUB_AND_FETCH -#define DECREMENT(p) __sync_sub_and_fetch(p, 1) -#else -#define DECREMENT(p) __sync_add_and_fetch(p, -1) -#endif - -#else -#include "private/atomic.h" -#ifndef ATOMIC_NOATOMIC -typedef Myth::atomic counter_t; -#define GETVALUE(p) (p)->load() -#define INCREMENT(p) (p)->add_fetch(1) -#define DECREMENT(p) (p)->sub_fetch(1) -// -// Don't know how to do atomic operation for the architecture -// -#elif defined USE_LOCKED -#include "mythlocked.h" -typedef Myth::LockedNumber counter_t; -#define GETVALUE(p) (p)->Load() -#define INCREMENT(p) (p)->Add(1) -#define DECREMENT(p) (p)->Sub(1) - -#else -#error Atomic add/sub are not. Overcome using definition USE_LOCKED. -#endif -#endif - -using namespace Myth; - -namespace Myth -{ - struct IntrinsicCounter::Counter - { - counter_t counter; - Counter(int val) : counter(val) {} - }; -} - -IntrinsicCounter::IntrinsicCounter(int val) -: m_ptr(new Counter(val)) -{ -} - -IntrinsicCounter::~IntrinsicCounter() -{ - delete m_ptr; -} - -int IntrinsicCounter::GetValue() -{ - return GETVALUE(&m_ptr->counter); -} - -int IntrinsicCounter::Increment() -{ - return INCREMENT(&m_ptr->counter); -} - -int IntrinsicCounter::Decrement() -{ - return DECREMENT(&m_ptr->counter); -} diff --git a/lib/cppmyth/src/mythintrinsic.h b/lib/cppmyth/src/mythintrinsic.h deleted file mode 100644 index 1447c989..00000000 --- a/lib/cppmyth/src/mythintrinsic.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2015 Jean-Luc Barriere - * - * This Program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This Program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - * http://www.gnu.org/copyleft/gpl.html - * - */ - -#ifndef MYTHINTRINSIC_H -#define MYTHINTRINSIC_H - -namespace Myth -{ - class IntrinsicCounter - { - public: - IntrinsicCounter(int val); - - ~IntrinsicCounter(); - - int GetValue(); - - int Increment(); - - int Decrement(); - - private: - struct Counter; - Counter* m_ptr; - - // Prevent copy - IntrinsicCounter(const IntrinsicCounter& other); - IntrinsicCounter& operator=(const IntrinsicCounter& other); - }; - -} - -#endif /* MYTHINTRINSIC_H */ diff --git a/lib/cppmyth/src/mythlivetvplayback.cpp b/lib/cppmyth/src/mythlivetvplayback.cpp index f13f71b1..7567c11f 100644 --- a/lib/cppmyth/src/mythlivetvplayback.cpp +++ b/lib/cppmyth/src/mythlivetvplayback.cpp @@ -23,7 +23,7 @@ #include "private/debug.h" #include "private/socket.h" #include "private/ringbuffer.h" -#include "private/os/threads/mutex.h" +#include "private/os/threads/latch.h" #include "private/os/threads/timeout.h" #include "private/builtin.h" @@ -107,7 +107,7 @@ LiveTVPlayback::~LiveTVPlayback() bool LiveTVPlayback::Open() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (ProtoMonitor::IsOpen()) return true; if (ProtoMonitor::Open()) @@ -134,7 +134,7 @@ bool LiveTVPlayback::Open() void LiveTVPlayback::Close() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); m_recorder.reset(); ProtoMonitor::Close(); } @@ -159,7 +159,7 @@ void LiveTVPlayback::SetLimitTuneAttempts(bool limit) bool LiveTVPlayback::SpawnLiveTV(const std::string& chanNum, const ChannelList& channels) { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!ProtoMonitor::IsOpen() || !m_eventHandler.IsConnected()) { DBG(DBG_ERROR, "%s: not connected\n", __FUNCTION__); @@ -186,9 +186,9 @@ bool LiveTVPlayback::SpawnLiveTV(const std::string& chanNum, const ChannelList& OS::CTimeout timeout(delayMs); do { - lock.Unlock(); // Release the latch to allow chain update + lock.unlock(); // Release the latch to allow chain update usleep(TICK_USEC); - lock.Lock(); + lock.lock(); if (!m_chain.switchOnCreate) { DBG(DBG_DEBUG, "%s: tune delay (%" PRIu32 "ms)\n", __FUNCTION__, (delayMs - timeout.TimeLeft())); @@ -222,7 +222,7 @@ bool LiveTVPlayback::SpawnLiveTV(const ChannelPtr& thisChannel) void LiveTVPlayback::StopLiveTV() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (m_recorder && m_recorder->IsPlaying()) { m_recorder->StopLiveTV(); @@ -237,7 +237,7 @@ void LiveTVPlayback::InitChain() { BUILTIN_BUFFER buf; // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); time_to_iso8601(time(NULL), &buf); m_chain.UID = m_socket->GetMyHostName(); m_chain.UID.append("-").append(buf.data); @@ -252,7 +252,7 @@ void LiveTVPlayback::InitChain() void LiveTVPlayback::ClearChain() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); m_chain.currentSequence = 0; m_chain.lastSequence = 0; m_chain.watch = false; @@ -273,7 +273,7 @@ bool LiveTVPlayback::IsChained(const Program& program) void LiveTVPlayback::HandleChainUpdate() { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CWriteLock lock(*m_latch); // Lock chain ProtoRecorderPtr recorder(m_recorder); if (!recorder) return; @@ -309,7 +309,7 @@ void LiveTVPlayback::HandleChainUpdate() bool LiveTVPlayback::SwitchChain(unsigned sequence) { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); // Check for out of range if (sequence < 1 || sequence > m_chain.lastSequence) return false; @@ -380,7 +380,7 @@ void LiveTVPlayback::HandleBackendMessage(EventMessagePtr msg) { if (recorder->GetNum() == (int)rnum) { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CWriteLock lock(*m_latch); // Lock chain m_chain.watch = true; } } @@ -426,7 +426,7 @@ void LiveTVPlayback::HandleBackendMessage(EventMessagePtr msg) case EVENT_UPDATE_FILE_SIZE: if (msg->subject.size() >= 3) { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CWriteLock lock(*m_latch); // Lock chain if (m_chain.lastSequence > 0) { int64_t newsize; @@ -492,7 +492,7 @@ void LiveTVPlayback::SetChunk(unsigned size) int64_t LiveTVPlayback::GetSize() const { int64_t size = 0; - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CReadLock lock(*m_latch); // Lock chain for (chained_t::const_iterator it = m_chain.chained.begin(); it != m_chain.chained.end(); ++it) size += it->first->GetSize(); return size; @@ -563,9 +563,9 @@ int LiveTVPlayback::_read(void* buffer, unsigned n) for (;;) { // Reading ahead - m_mutex->Lock(); + m_latch->lock_shared(); unsigned lastseq = m_chain.lastSequence; - m_mutex->Unlock(); + m_latch->unlock_shared(); if (m_chain.currentSequence == lastseq) { int64_t rp = recorder->GetFilePosition(); @@ -639,7 +639,7 @@ int64_t LiveTVPlayback::Seek(int64_t offset, WHENCE_t whence) int64_t LiveTVPlayback::_seek(int64_t offset, WHENCE_t whence) { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CWriteLock lock(*m_latch); // Lock chain if (!m_recorder || !m_chain.currentSequence) return -1; @@ -715,7 +715,7 @@ int64_t LiveTVPlayback::_seek(int64_t offset, WHENCE_t whence) int64_t LiveTVPlayback::GetPosition() const { int64_t pos = 0; - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CReadLock lock(*m_latch); // Lock chain if (m_chain.currentSequence) { unsigned s = m_chain.currentSequence - 1; @@ -744,7 +744,7 @@ bool LiveTVPlayback::KeepLiveRecording(bool keep) { ProtoRecorderPtr recorder(m_recorder); // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (recorder && recorder->IsPlaying()) { ProgramPtr prog = recorder->GetCurrentRecording(); @@ -770,7 +770,7 @@ bool LiveTVPlayback::KeepLiveRecording(bool keep) ProgramPtr LiveTVPlayback::GetPlayedProgram() const { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CReadLock lock(*m_latch); // Lock chain if (m_chain.currentSequence > 0) return m_chain.chained[m_chain.currentSequence - 1].second; return ProgramPtr(); @@ -778,7 +778,7 @@ ProgramPtr LiveTVPlayback::GetPlayedProgram() const time_t LiveTVPlayback::GetLiveTimeStart() const { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CReadLock lock(*m_latch); // Lock chain if (m_chain.lastSequence) return m_chain.chained[0].second->recording.startTs; return (time_t)(-1); @@ -786,13 +786,13 @@ time_t LiveTVPlayback::GetLiveTimeStart() const unsigned LiveTVPlayback::GetChainedCount() const { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CReadLock lock(*m_latch); // Lock chain return m_chain.lastSequence; } ProgramPtr LiveTVPlayback::GetChainedProgram(unsigned sequence) const { - OS::CLockGuard lock(*m_mutex); // Lock chain + OS::CReadLock lock(*m_latch); // Lock chain if (sequence > 0 && sequence <= m_chain.lastSequence) return m_chain.chained[sequence - 1].second; return ProgramPtr(); diff --git a/lib/cppmyth/src/mythrecordingplayback.cpp b/lib/cppmyth/src/mythrecordingplayback.cpp index 6a55c8b0..6fb6b03e 100644 --- a/lib/cppmyth/src/mythrecordingplayback.cpp +++ b/lib/cppmyth/src/mythrecordingplayback.cpp @@ -22,7 +22,7 @@ #include "mythrecordingplayback.h" #include "private/debug.h" #include "private/ringbuffer.h" -#include "private/os/threads/mutex.h" +#include "private/os/threads/latch.h" #include "private/builtin.h" #include @@ -87,7 +87,7 @@ RecordingPlayback::~RecordingPlayback() bool RecordingPlayback::Open() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (ProtoPlayback::IsOpen()) return true; if (ProtoPlayback::Open()) @@ -102,7 +102,7 @@ bool RecordingPlayback::Open() void RecordingPlayback::Close() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); CloseTransfer(); ProtoPlayback::Close(); } @@ -110,7 +110,7 @@ void RecordingPlayback::Close() bool RecordingPlayback::OpenTransfer(ProgramPtr recording) { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!ProtoPlayback::IsOpen()) return false; CloseTransfer(); @@ -131,7 +131,7 @@ bool RecordingPlayback::OpenTransfer(ProgramPtr recording) void RecordingPlayback::CloseTransfer() { // Begin critical section - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); m_recording.reset(); if (m_transfer) { diff --git a/lib/cppmyth/src/mythsharedptr.cpp b/lib/cppmyth/src/mythsharedptr.cpp new file mode 100644 index 00000000..b6951172 --- /dev/null +++ b/lib/cppmyth/src/mythsharedptr.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 Jean-Luc Barriere + * + * This Program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This Program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "mythsharedptr.h" + +#include "local_config.h" +#include "private/os/threads/atomic.h" + +using namespace Myth; + +shared_ptr_base::shared_ptr_base() +: c(NULL) +, deleted(NULL) { } + +shared_ptr_base::~shared_ptr_base() +{ + clear_counter(); + if (deleted != NULL) + delete deleted; +} + +shared_ptr_base::shared_ptr_base(const shared_ptr_base& s) +: c(s.c) +, deleted(NULL) +{ + /* handles race condition with clearing of s */ + if (c != NULL && c->add_fetch(1) == 1) + c = NULL; +} + +shared_ptr_base& shared_ptr_base::operator=(const shared_ptr_base& s) +{ + if (this != &s) + { + clear_counter(); + c = s.c; + /* handles race condition with clearing of s */ + if (c != NULL && c->add_fetch(1) == 1) + c = NULL; + } + return *this; +} + +bool shared_ptr_base::clear_counter() +{ + if (c != NULL && c->sub_fetch(1) == 0) + { + /* delete later */ + if (deleted != NULL) + delete deleted; + deleted = c; + c = NULL; + return true; + } + c = NULL; + return false; +} + +void shared_ptr_base::reset_counter(int val) +{ + clear_counter(); + if (deleted != NULL) + { + c = deleted; + deleted = NULL; + c->store(val); + } + else + c = new OS::Atomic(val); +} + +void shared_ptr_base::swap_counter(shared_ptr_base& s) +{ + OS::Atomic* _c = c; + c = s.c; + s.c = _c; +} + +int shared_ptr_base::get_counter() const +{ + return (c != NULL ? c->load() : 0); +} diff --git a/lib/cppmyth/src/mythsharedptr.h b/lib/cppmyth/src/mythsharedptr.h index 8b10e050..51e2d8f3 100644 --- a/lib/cppmyth/src/mythsharedptr.h +++ b/lib/cppmyth/src/mythsharedptr.h @@ -22,36 +22,58 @@ #ifndef MYTHSHAREDPTR_H #define MYTHSHAREDPTR_H -#include "mythintrinsic.h" - #include // for NULL namespace Myth { + namespace OS { + class Atomic; + } + + class shared_ptr_base + { + private: + OS::Atomic* c; + OS::Atomic* deleted; + protected: + virtual ~shared_ptr_base(); + shared_ptr_base(); + shared_ptr_base(const shared_ptr_base& s); + shared_ptr_base& operator=(const shared_ptr_base& s); + bool clear_counter(); /* if deleted, then true */ + void reset_counter(int val); + void swap_counter(shared_ptr_base& s); + int get_counter() const; + bool is_null() const { return c == NULL; } + }; + template - class shared_ptr + class shared_ptr : private shared_ptr_base { + private: + T *p; public: - shared_ptr() : p(NULL), c(NULL) { } + shared_ptr() + : shared_ptr_base() + , p(NULL) { } - explicit shared_ptr(T* s) : p(s), c(NULL) + explicit shared_ptr(T* s) + : shared_ptr_base() + , p(s) { - if (p != NULL) - { - c = new IntrinsicCounter(1); - } + if (s != NULL) + shared_ptr_base::reset_counter(1); } - shared_ptr(const shared_ptr& s) : p(s.p), c(s.c) + shared_ptr(const shared_ptr& s) + : shared_ptr_base(s) + , p(s.p) { - if (c != NULL) - if (c->Increment() < 2) - { - c = NULL; - p = NULL; - } + /* handles race condition with clearing of s */ + if (shared_ptr_base::is_null()) + p = NULL; } shared_ptr& operator=(const shared_ptr& s) @@ -60,19 +82,16 @@ namespace Myth { reset(); p = s.p; - c = s.c; - if (c != NULL) - if (c->Increment() < 2) - { - c = NULL; - p = NULL; - } + shared_ptr_base::operator = (s); + /* handles race condition with clearing of s */ + if (shared_ptr_base::is_null()) + p = NULL; } return *this; } #if __cplusplus >= 201103L - shared_ptr& operator=(shared_ptr&& s) + shared_ptr& operator=(shared_ptr&& s) noexcept { if (this != &s) swap(s); @@ -87,13 +106,8 @@ namespace Myth void reset() { - if (c != NULL) - if (c->Decrement() == 0) - { - delete p; - delete c; - } - c = NULL; + if (shared_ptr_base::clear_counter()) + delete p; p = NULL; } @@ -102,32 +116,31 @@ namespace Myth if (p != s) { reset(); + p = s; if (s != NULL) - { - p = s; - c = new IntrinsicCounter(1); - } + shared_ptr_base::reset_counter(1); } } T *get() const { - return (c != NULL) ? p : NULL; + return p; } void swap(shared_ptr& s) { - T *tmp_p = p; - IntrinsicCounter *tmp_c = c; + T* _p = p; p = s.p; - c = s.c; - s.p = tmp_p; - s.c = tmp_c; + s.p = _p; + shared_ptr_base::swap_counter(s); + /* handles race condition with clearing of s */ + if (shared_ptr_base::is_null()) + p = NULL; } - unsigned use_count() const + int use_count() const { - return (unsigned) (c != NULL ? c->GetValue() : 0); + return shared_ptr_base::get_counter(); } T *operator->() const @@ -149,10 +162,6 @@ namespace Myth { return p == NULL; } - - protected: - T *p; - IntrinsicCounter *c; }; } diff --git a/lib/cppmyth/src/private/atomic.h b/lib/cppmyth/src/private/os/threads/atomic.h similarity index 70% rename from lib/cppmyth/src/private/atomic.h rename to lib/cppmyth/src/private/os/threads/atomic.h index ef19b2ff..8057d7d3 100644 --- a/lib/cppmyth/src/private/atomic.h +++ b/lib/cppmyth/src/private/os/threads/atomic.h @@ -1,5 +1,6 @@ +#pragma once /* - * Copyright (C) 2014-2015 Jean-Luc Barriere + * Copyright (C) 2014-2024 Jean-Luc Barriere * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published @@ -19,12 +20,220 @@ * */ -#ifndef ATOMIC_H -#define ATOMIC_H +#if __cplusplus >= 201103L -#include "local_config.h" +#include +#ifdef NSROOT +namespace NSROOT { +#endif +namespace OS +{ + class Atomic + { + private: + std::atomic m_val; + public: + Atomic(int val) : m_val(val) {} + int load() + { + return m_val.load(std::memory_order_relaxed); + } + int operator()() + { + return load(); + } + void store(int val) + { + m_val.store(val, std::memory_order_relaxed); + } + int operator=(int val) + { + store(val); + return val; + } + int add_fetch(int amount) + { + return m_val.fetch_add(amount, std::memory_order_relaxed) + amount; + } + int increment() + { + return add_fetch(1); + } + int sub_fetch(int amount) + { + return m_val.fetch_sub(amount, std::memory_order_relaxed) - amount; + } + int decrement() + { + return sub_fetch(1); + } + }; +} +#ifdef NSROOT +} +#endif -#ifdef __GNUC__ +#elif defined _MSC_VER +#define WIN32_LEAN_AND_MEAN +#include +#ifdef NSROOT +namespace NSROOT { +#endif +namespace OS +{ + class Atomic + { + private: + volatile LONG m_val; + public: + Atomic(int val) : m_val(val) {} + int load() + { + return (int)m_val; + } + int operator()() + { + return load(); + } + void store(int val) + { + m_val = val; + } + int operator=(int val) + { + store(val); + return val; + } + int add_fetch(int amount) + { + return (int)InterlockedAdd(&m_val, amount); + } + int increment() + { + return (int)InterlockedIncrement(&m_val); + } + int sub_fetch(int amount) + { + return (int)InterlockedAdd(&m_val, (-amount)); + } + int decrement() + { + return (int)InterlockedDecrement(&m_val); + } + }; +} +#ifdef NSROOT +} +#endif + +#elif defined __APPLE__ +#include +#ifdef NSROOT +namespace NSROOT { +#endif +namespace OS +{ + class Atomic + { + private: + volatile int m_val; + public: + Atomic(int val) : m_val(val) {} + int load() + { + return m_val; + } + int operator()() + { + return load(); + } + void store(int val) + { + m_val = val; + } + int operator=(int val) + { + store(val); + return val; + } + int add_fetch(int amount) + { + return OSAtomicAdd32(amount, &m_val); + } + int increment() + { + return OSAtomicIncrement32(&m_val); + } + int sub_fetch(int amount) + { + return OSAtomicAdd32((-amount), &m_val); + } + int decrement() + { + return OSAtomicDecrement32(&m_val); + } + }; +} +#ifdef NSROOT +} +#endif + +#elif defined HAS_BUILTIN_SYNC_ADD_AND_FETCH +#ifdef NSROOT +namespace NSROOT { +#endif +namespace OS +{ + class Atomic + { + private: + volatile int m_val; + public: + Atomic(int val) : m_val(val) {} + int load() + { + return m_val; + } + int operator()() + { + return load(); + } + void store(int val) + { + m_val = val; + } + int operator=(int val) + { + store(val); + return val; + } + int add_fetch(int amount) + { + return __sync_add_and_fetch(&m_val, amount); + } + int increment() + { + return add_fetch(1); + } + int sub_fetch(int amount) + { +#if defined HAS_BUILTIN_SYNC_SUB_AND_FETCH + return __sync_sub_and_fetch(&m_val, amount); +#else + return __sync_add_and_fetch(&m_val, (-amount)); +#endif + } + int decrement() + { + return sub_fetch(1); + } + }; +} +#ifdef NSROOT +} +#endif + +#elif defined __GNUC__ #if defined __arm__ && (!defined __thumb__ || defined __thumb2__) /* The __ARM_ARCH define is provided by gcc 4.8. Construct it otherwise. */ @@ -51,46 +260,37 @@ #endif #endif -namespace NSROOT +#ifdef NSROOT +namespace NSROOT { +#endif +namespace OS { - template - class atomic + class Atomic { - public: - typedef volatile T atomic_t; - - atomic(T val) : m_val(val) {} - - atomic_t load() - { - return m_val; - } - private: - atomic_t m_val; - }; - - template<> - class atomic - { + volatile int m_val; public: - typedef volatile int atomic_t; - - atomic(int val) : m_val(val) {} - + Atomic(int val) : m_val(val) {} int __attribute__((always_inline)) load() { return m_val; } - int __attribute__((always_inline)) operator()() { return load(); } - + void __attribute__((always_inline)) store(int val) + { + m_val = val; + } + int __attribute__((always_inline)) operator=(int val) + { + store(val); + return val; + } int __attribute__((always_inline)) add_fetch(int amount) { - atomic_t __val; + int __val; #if defined __mips__ int temp; @@ -201,24 +401,17 @@ namespace NSROOT : "memory"); #else -/* warning unknown architecture, atomic increment is not... */ -#ifndef ATOMIC_NOATOMIC -#define ATOMIC_NOATOMIC -#endif - __val = m_val += amount; - +#error Atomic add are not. #endif return __val; } - - int __attribute__((always_inline)) operator++() + int __attribute__((always_inline)) increment() { return add_fetch(1); } - int __attribute__((always_inline)) sub_fetch(int amount) { - atomic_t __val; + int __val; #if defined __mips__ int temp; @@ -329,30 +522,20 @@ namespace NSROOT : "memory"); #else -/* warning unknown architecture, atomic deccrement is not... */ -#ifndef ATOMIC_NOATOMIC -#define ATOMIC_NOATOMIC -#endif - __val = m_val -= amount; - +#error Atomic sub are not. #endif return __val; } - - int __attribute__((always_inline)) operator--() + int __attribute__((always_inline)) decrement() { return sub_fetch(1); } - - private: - atomic_t m_val; }; } +#ifdef NSROOT +} +#endif #else -#ifndef ATOMIC_NOATOMIC -#define ATOMIC_NOATOMIC +#error Atomic operations for the architecture are not. #endif -#endif - -#endif /* ATOMIC_H */ diff --git a/lib/cppmyth/src/private/os/threads/latch.cpp b/lib/cppmyth/src/private/os/threads/latch.cpp new file mode 100644 index 00000000..29b7f828 --- /dev/null +++ b/lib/cppmyth/src/private/os/threads/latch.cpp @@ -0,0 +1,283 @@ +/* + * Copyright (C) 2024 Jean-Luc Barriere + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "latch.h" + +#include // for memset, memcmp + +#ifdef NSROOT +using namespace NSROOT::OS; +#else +using namespace OS; +#endif + +unsigned CLatch::hash_bucket(thread_t * t) +{ + const unsigned char * ptr = reinterpret_cast(t); + /* DJB Hash Function */ + unsigned h = 5381; + for (unsigned i = 0; i < sizeof(thread_t); ++i) + { + h = ((h << 5) + h) + *ptr++; + } + return h % latch_bucket_count; +} + +CLatch::CLatch(bool _px) +: s_spin(0) +, x_wait(0) +, s_count(0) +, x_flag(0) +, px(_px) +{ + mutex_init(&x_gate_lock); + cond_init(&x_gate); + mutex_init(&s_gate_lock); + cond_init(&s_gate); + memset(s_buckets, 0, sizeof(int) * latch_bucket_count); +} + +CLatch::~CLatch() +{ + cond_destroy(&s_gate); + mutex_destroy(&s_gate_lock); + cond_destroy(&x_gate); + mutex_destroy(&x_gate_lock); +} + +/** + * The X flag is set as follows based on the locking steps + * Step 0 : X is released + * Step 1 : X is held, but waits for release of S + * Step 2 : X was released and left available for one of request in wait + * Step 3 : X is held + * Step N : X recursive N-3 + */ +#define X_STEP_0 0 +#define X_STEP_1 1 +#define X_STEP_2 2 +#define X_STEP_3 3 + +/* Depending on the internal implementation of conditional variable, + * a race condition could arise, permanently blocking the thread; + * Setting a timeout works around the issue. + */ +#define EXIT_TIMEOUT 1000 + +void CLatch::lock() +{ + thread_t tid = thread_self(); + + spin_lock(); + + if (!thread_equal(x_owner, tid)) + { + /* increments the count of request in wait */ + ++x_wait; + for (;;) + { + /* if flag is 0 or 2 then it hold X with no wait, + * in other case it have to wait for X gate + */ + if (x_flag == X_STEP_0 || x_flag == X_STEP_2) + { + x_flag = X_STEP_1; + --x_wait; + break; + } + else + { + /* !!! pop gate then unlock spin */ + mutex_lock(&x_gate_lock); + spin_unlock(); + cond_timedwait(&x_gate, &x_gate_lock, EXIT_TIMEOUT); + mutex_unlock(&x_gate_lock); + } + spin_lock(); + } + + /* X = 1, check the releasing of S */ + for (;;) + { + /* if the count of S is zeroed then it finalize with no wait, + * in other case it have to wait for S gate */ + if (s_count == 0) + { + x_flag = X_STEP_3; + break; + } + else + { + /* !!! pop gate then unlock spin (reverse order for S notifier) */ + mutex_lock(&s_gate_lock); + spin_unlock(); + cond_timedwait(&s_gate, &s_gate_lock, EXIT_TIMEOUT); + mutex_unlock(&s_gate_lock); + spin_lock(); + /* check if the notifier has hand over, else retry */ + if (x_flag == X_STEP_3) + { + break; + } + } + } + + /* X = 3, set owner */ + x_owner = tid; + } + else + { + /* recursive X lock */ + ++x_flag; + } + + spin_unlock(); +} + +void CLatch::unlock() +{ + thread_t tid = thread_self(); + + spin_lock(); + if (thread_equal(x_owner, tid)) + { + /* decrement recursive lock */ + if (--x_flag == X_STEP_2) + { + x_owner = {}; + /* hand-over to a request in wait for X, else release */ + if (x_wait == 0) + { + x_flag = X_STEP_0; + } + /* !!! unlock spin then pop gate (reverse order for receiver) */ + spin_unlock(); + mutex_lock(&x_gate_lock); + cond_broadcast(&x_gate); + mutex_unlock(&x_gate_lock); + } + else + { + spin_unlock(); + } + } + else + { + spin_unlock(); + } +} + +void CLatch::lock_shared() +{ + thread_t tid = thread_self(); + + spin_lock(); + if (!thread_equal(x_owner, tid)) + { + /* if flag is 0 or 1 then it hold S with no wait, + * in other case it have to wait for X gate + */ + for (;;) + { + if (!px) + { + /* X precedence is false */ + if (x_flag < X_STEP_2) + { + break; + } + } + else + { + /* X precedence is true, + * estimate if this thread holds a recursive S lock + */ + if (x_flag == X_STEP_0 || (x_flag == X_STEP_1 && + s_buckets[hash_bucket(&tid)] > 0)) + { + break; + } + } + /* !!! pop gate then unlock spin */ + mutex_lock(&x_gate_lock); + spin_unlock(); + cond_timedwait(&x_gate, &x_gate_lock, EXIT_TIMEOUT); + mutex_unlock(&x_gate_lock); + spin_lock(); + } + } + ++s_count; + if (px) + { + /* X precedence is true */ + ++s_buckets[hash_bucket(&tid)]; + } + spin_unlock(); +} + +void CLatch::unlock_shared() +{ + thread_t tid = thread_self(); + + spin_lock(); + if (px) + { + /* X precedence is true */ + --s_buckets[hash_bucket(&tid)]; + } + /* on last S, finalize X request in wait, and notify */ + if (--s_count == 0 && x_flag == X_STEP_1 && !thread_equal(x_owner, tid)) + { + x_flag = X_STEP_3; + /* !!! unlock spin then pop gate (reverse order for X receiver) */ + spin_unlock(); + mutex_lock(&s_gate_lock); + cond_signal(&s_gate); + mutex_unlock(&s_gate_lock); + } + else + { + spin_unlock(); + } +} + +bool CLatch::try_lock_shared() +{ + thread_t tid = thread_self(); + + spin_lock(); + /* if X = 0 then it hold S with success, + * in other case fails + */ + if (x_flag == X_STEP_0 || thread_equal(x_owner, tid)) + { + ++s_count; + if (px) + { + /* X precedence is true */ + ++s_buckets[hash_bucket(&tid)]; + } + spin_unlock(); + return true; + } + spin_unlock(); + return false; +} diff --git a/lib/cppmyth/src/private/os/threads/latch.h b/lib/cppmyth/src/private/os/threads/latch.h new file mode 100644 index 00000000..ec3ca61f --- /dev/null +++ b/lib/cppmyth/src/private/os/threads/latch.h @@ -0,0 +1,228 @@ +#pragma once +/* + * Copyright (C) 2024 Jean-Luc Barriere + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + * http://www.gnu.org/copyleft/gpl.html + * + */ + +#include "os-threads.h" +#include "atomic.h" + +#define latch_bucket_count 64 + +#ifdef NSROOT +namespace NSROOT { +#endif +namespace OS +{ + + class CLatch + { + public: + CLatch(bool _px); + CLatch() : CLatch(true) { } + ~CLatch(); + + /* Locks the latch for exclusive ownership, + * blocks if the latch is not available + */ + void lock(); + + /* Unlocks the latch (exclusive ownership) */ + void unlock(); + + /* Locks the latch for shared ownership, + * blocks if the latch is not available + */ + void lock_shared(); + + /* Unlocks the latch (shared ownership) */ + void unlock_shared(); + + /* Tries to lock the latch for shared ownership, + * returns true if the latch has no exclusive ownership or any request for + * exclusive ownership, else false + */ + bool try_lock_shared(); + + private: + mutable Atomic s_spin; + thread_t x_owner; + + volatile int x_wait; /* counts requests in wait for X */ + volatile int s_count; /* counts held S locks */ + volatile int x_flag; /* X status: 0, 1, 2, or 3 */ + + mutex_t x_gate_lock; + condition_t x_gate; /* wait for release of X */ + mutex_t s_gate_lock; + condition_t s_gate; /* wait for release of S */ + + bool px; /* enable X precedence */ + int s_buckets[latch_bucket_count]; + + // Prevent copy + CLatch(const CLatch& other); + CLatch& operator=(const CLatch& other); + + void spin_lock() + { + for (;;) + { + if (s_spin.load() == 0 && s_spin.increment() == 1) + break; + sched_yield(); + } + } + void spin_unlock() { s_spin.store(0); } + + static unsigned hash_bucket(thread_t * t); + }; + + class CReadLock + { + private: + CLatch *p = nullptr; + bool owns = false; + + CReadLock(const CReadLock& other); + CReadLock& operator=(const CReadLock& other); + + public: + + static struct adopt_lock_t { } adopt_lock; + + CReadLock() { } + + CReadLock(CLatch& latch) : p(&latch), owns(true) { latch.lock_shared(); } + + /* Assume the calling thread already has ownership of the shared lock */ + CReadLock(CLatch& latch, adopt_lock_t) : p(&latch), owns(true) { } + + ~CReadLock() + { + if (owns) + { + p->unlock_shared(); + } + } + + void swap(CReadLock& rl) + { + CLatch * _p = p; + bool _owns = owns; + p = rl.p; + owns = rl.owns; + rl.p = _p; + rl.owns = _owns; + } + + bool owns_lock() const + { + return owns; + } + + void lock() + { + if (!owns && p != nullptr) + { + p->lock_shared(); + owns = true; + } + } + + void unlock() + { + if (owns) + { + owns = false; + p->unlock_shared(); + } + } + + bool try_lock() + { + if (!owns && p != nullptr) + { + owns = p->try_lock_shared(); + } + return owns; + } + }; + + class CWriteLock + { + private: + CLatch *p = nullptr; + bool owns = false; + + CWriteLock(const CWriteLock& other); + CWriteLock& operator=(const CWriteLock& other); + + public: + + CWriteLock() = default; + + explicit CWriteLock(CLatch& latch) : p(&latch), owns(true) { latch.lock(); } + + ~CWriteLock() + { + if (owns) + { + p->unlock(); + } + } + + void swap(CWriteLock& wl) + { + CLatch * _p = p; + bool _owns = owns; + p = wl.p; + owns = wl.owns; + wl.p = _p; + wl.owns = _owns; + } + + bool owns_lock() const + { + return owns; + } + + void lock() + { + if (!owns && p != nullptr) + { + p->lock(); + owns = true; + } + } + + void unlock() + { + if (owns) + { + owns = false; + p->unlock(); + } + } + }; + +} +#ifdef NSROOT +} +#endif diff --git a/lib/cppmyth/src/private/os/threads/os-threads.h b/lib/cppmyth/src/private/os/threads/os-threads.h index 7f7fa6ef..7dde903f 100644 --- a/lib/cppmyth/src/private/os/threads/os-threads.h +++ b/lib/cppmyth/src/private/os/threads/os-threads.h @@ -72,6 +72,12 @@ namespace OS return pthread_create(thread, &_attr, func, arg) == 0; } +#define thread_self() __thread_self() + inline thread_t __thread_self() { return pthread_self(); } + +#define thread_equal(a, b) __thread_equal(a, b) + inline int __thread_equal(thread_t t1, thread_t t2) { return pthread_equal(t1, t2); } + typedef pthread_mutex_t mutex_t; #define mutex_init(a) __mutex_init(a) diff --git a/lib/cppmyth/src/private/os/unix/os-types.h b/lib/cppmyth/src/private/os/unix/os-types.h index 8e3c5ed5..1a80a193 100644 --- a/lib/cppmyth/src/private/os/unix/os-types.h +++ b/lib/cppmyth/src/private/os/unix/os-types.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -50,7 +51,6 @@ typedef LONG HRESULT; #if defined(__APPLE__) #include /* for fpos_t */ -#include #include typedef int64_t off64_t; typedef off_t __off_t; diff --git a/lib/cppmyth/src/private/os/windows/os-types.h b/lib/cppmyth/src/private/os/windows/os-types.h index 25a1b4ed..1bfbe50a 100644 --- a/lib/cppmyth/src/private/os/windows/os-types.h +++ b/lib/cppmyth/src/private/os/windows/os-types.h @@ -62,6 +62,13 @@ __inline unsigned int sleep(unsigned int sec) return 0; } +__inline int sched_yield() +{ + if (SwitchToThread()) + return 0; + return (-1); +} + /* Using MS Visual C++ compilers */ #if defined(_MSC_VER) diff --git a/lib/cppmyth/src/private/wsresponse.cpp b/lib/cppmyth/src/private/wsresponse.cpp index 45789675..2b8be283 100644 --- a/lib/cppmyth/src/private/wsresponse.cpp +++ b/lib/cppmyth/src/private/wsresponse.cpp @@ -35,8 +35,7 @@ using namespace NSROOT; -WSResponse::WSResponse(const WSRequest &request, int maxRedirs, bool trustedLocation, bool followAny) -: p(0) +void WSResponse::init(const WSRequest &request, int maxRedirs, bool trustedLocation, bool followAny) { p = new _response(request); while (0 < maxRedirs--) diff --git a/lib/cppmyth/src/private/wsresponse.h b/lib/cppmyth/src/private/wsresponse.h index 46703034..420635da 100644 --- a/lib/cppmyth/src/private/wsresponse.h +++ b/lib/cppmyth/src/private/wsresponse.h @@ -40,8 +40,10 @@ namespace NSROOT class WSResponse { public: - WSResponse(const WSRequest& request) : WSResponse(request, 1, true, false) { } - WSResponse(const WSRequest &request, int maxRedirs, bool trustedLocation, bool followAny); + WSResponse(const WSRequest& request) + { init(request, 1, true, false); } + WSResponse(const WSRequest &request, int maxRedirs, bool trustedLocation, bool followAny) + { init(request, maxRedirs, trustedLocation, followAny); } ~WSResponse(); bool IsSuccessful() const { return p->IsSuccessful(); } @@ -61,6 +63,7 @@ namespace NSROOT static bool ReadHeaderLine(NetSocket *socket, const char *eol, std::string& line, size_t *len); private: + void init(const WSRequest &request, int maxRedirs, bool trustedLocation, bool followAny); // prevent copy WSResponse(const WSResponse&); diff --git a/lib/cppmyth/src/proto/mythprotobase.cpp b/lib/cppmyth/src/proto/mythprotobase.cpp index c5bbb7db..18922ed3 100644 --- a/lib/cppmyth/src/proto/mythprotobase.cpp +++ b/lib/cppmyth/src/proto/mythprotobase.cpp @@ -22,7 +22,7 @@ #include "mythprotobase.h" #include "../private/debug.h" #include "../private/socket.h" -#include "../private/os/threads/mutex.h" +#include "../private/os/threads/latch.h" #include "../private/cppdef.h" #include "../private/builtin.h" @@ -58,7 +58,7 @@ static myth_protomap_t protomap[] = { }; ProtoBase::ProtoBase(const std::string& server, unsigned port) -: m_mutex(new OS::CMutex) +: m_latch(new OS::CLatch) , m_socket(new TcpSocket()) , m_protoVersion(0) , m_server(server) @@ -77,7 +77,7 @@ ProtoBase::~ProtoBase() { this->Close(); SAFE_DELETE(m_socket); - SAFE_DELETE(m_mutex); + SAFE_DELETE(m_latch); } void ProtoBase::HangException() @@ -286,7 +286,7 @@ bool ProtoBase::OpenConnection(int rcvbuf) myth_protomap_t *map; unsigned tmp_ver; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!my_version) // try first version of the map @@ -355,7 +355,7 @@ bool ProtoBase::OpenConnection(int rcvbuf) void ProtoBase::Close() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (m_socket->IsValid()) { diff --git a/lib/cppmyth/src/proto/mythprotobase.h b/lib/cppmyth/src/proto/mythprotobase.h index 3f18551d..01a3029f 100644 --- a/lib/cppmyth/src/proto/mythprotobase.h +++ b/lib/cppmyth/src/proto/mythprotobase.h @@ -36,7 +36,7 @@ namespace Myth namespace OS { - class CMutex; + class CLatch; } class TcpSocket; @@ -68,7 +68,7 @@ namespace Myth virtual ERROR_t GetProtoError() const; protected: - OS::CMutex *m_mutex; + OS::CLatch *m_latch; TcpSocket *m_socket; unsigned m_protoVersion; std::string m_server; diff --git a/lib/cppmyth/src/proto/mythprotoevent.cpp b/lib/cppmyth/src/proto/mythprotoevent.cpp index cdad4861..a696d72c 100644 --- a/lib/cppmyth/src/proto/mythprotoevent.cpp +++ b/lib/cppmyth/src/proto/mythprotoevent.cpp @@ -22,7 +22,7 @@ #include "mythprotoevent.h" #include "../private/debug.h" #include "../private/socket.h" -#include "../private/os/threads/mutex.h" +#include "../private/os/threads/latch.h" #include "../private/builtin.h" #include @@ -83,7 +83,7 @@ void ProtoEvent::Close() bool ProtoEvent::Announce75() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); std::string cmd("ANN Monitor "); cmd.append(m_socket->GetMyHostName()).append(" 1"); @@ -130,7 +130,7 @@ SignalStatusPtr ProtoEvent::RcvSignalStatus() int ProtoEvent::RcvBackendMessage(unsigned timeout, EventMessage **msg) { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); struct timeval tv; tv.tv_sec = timeout; tv.tv_usec = 0; diff --git a/lib/cppmyth/src/proto/mythprotomonitor.cpp b/lib/cppmyth/src/proto/mythprotomonitor.cpp index c224e8af..d0aa69bf 100644 --- a/lib/cppmyth/src/proto/mythprotomonitor.cpp +++ b/lib/cppmyth/src/proto/mythprotomonitor.cpp @@ -23,7 +23,7 @@ #include "mythprotorecorder.h" #include "../private/debug.h" #include "../private/socket.h" -#include "../private/os/threads/mutex.h" +#include "../private/os/threads/latch.h" #include "../private/builtin.h" #include @@ -85,7 +85,7 @@ bool ProtoMonitor::IsOpen() bool ProtoMonitor::Announce75() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); std::string cmd("ANN Monitor "); cmd.append(m_socket->GetMyHostName()).append(" 0"); @@ -104,7 +104,7 @@ bool ProtoMonitor::Announce75() bool ProtoMonitor::Announce88() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); std::string cmd((m_frontend ? "ANN Frontend " : "ANN Monitor ")); cmd.append(m_socket->GetMyHostName()).append(" 0"); @@ -129,7 +129,7 @@ ProtoRecorderPtr ProtoMonitor::GetRecorderFromNum75(int rnum) std::string hostname; uint16_t port; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return recorder; std::string cmd("GET_RECORDER_FROM_NUM"); @@ -158,7 +158,7 @@ bool ProtoMonitor::QueryFreeSpaceSummary75(int64_t *total, int64_t *used) { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_FREE_SPACE_SUMMARY"); @@ -182,7 +182,7 @@ std::string ProtoMonitor::GetSetting75(const std::string& hostname, const std::s { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return field; std::string cmd("QUERY_SETTING "); @@ -206,7 +206,7 @@ bool ProtoMonitor::SetSetting75(const std::string& hostname, const std::string& { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("SET_SETTING "); @@ -229,7 +229,7 @@ bool ProtoMonitor::QueryGenpixmap75(const Program& program) { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_GENPIXMAP2"); @@ -255,7 +255,7 @@ bool ProtoMonitor::DeleteRecording75(const Program& program, bool force, bool fo BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("DELETE_RECORDING "); @@ -289,7 +289,7 @@ bool ProtoMonitor::UndeleteRecording75(const Program& program) { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("UNDELETE_RECORDING"); @@ -315,7 +315,7 @@ bool ProtoMonitor::StopRecording75(const Program& program) std::string field; int32_t num; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("STOP_RECORDING"); @@ -341,7 +341,7 @@ bool ProtoMonitor::CancelNextRecording75(int rnum, bool cancel) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_RECORDER "); @@ -369,7 +369,7 @@ StorageGroupFilePtr ProtoMonitor::QuerySGFile75(const std::string& hostname, con int64_t tmpi; StorageGroupFilePtr sgfile; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return sgfile; std::string cmd("QUERY_SG_FILEQUERY"); @@ -408,7 +408,7 @@ MarkListPtr ProtoMonitor::GetCutList75(const Program& program) int32_t nb; MarkListPtr list(new MarkList); - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("QUERY_CUTLIST "); @@ -451,7 +451,7 @@ MarkListPtr ProtoMonitor::GetCommBreakList75(const Program& program) int32_t nb; MarkListPtr list(new MarkList); - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("QUERY_COMMBREAK "); @@ -491,7 +491,7 @@ bool ProtoMonitor::BlockShutdown75() { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("BLOCK_SHUTDOWN"); @@ -513,7 +513,7 @@ bool ProtoMonitor::AllowShutdown75() { std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("ALLOW_SHUTDOWN"); @@ -537,7 +537,7 @@ std::vector ProtoMonitor::GetFreeCardIdList75() std::vector ids; int32_t rnum; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return ids; std::string cmd("GET_FREE_RECORDER_LIST"); @@ -571,7 +571,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs75() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) break; std::string cmd("QUERY_RECORDER "); @@ -618,7 +618,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs79() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) break; std::string cmd("QUERY_RECORDER "); @@ -673,7 +673,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs81() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) break; std::string cmd("QUERY_RECORDER "); @@ -726,7 +726,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs87(int rnum) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO "); @@ -773,7 +773,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs89(int rnum) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO "); @@ -822,7 +822,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs90(int rnum) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO "); @@ -872,7 +872,7 @@ CardInputListPtr ProtoMonitor::GetFreeInputs91(int rnum) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO "); diff --git a/lib/cppmyth/src/proto/mythprotoplayback.cpp b/lib/cppmyth/src/proto/mythprotoplayback.cpp index a086a471..e3a52dda 100644 --- a/lib/cppmyth/src/proto/mythprotoplayback.cpp +++ b/lib/cppmyth/src/proto/mythprotoplayback.cpp @@ -22,7 +22,7 @@ #include "mythprotoplayback.h" #include "../private/debug.h" #include "../private/socket.h" -#include "../private/os/threads/mutex.h" +#include "../private/os/threads/latch.h" #include "../private/builtin.h" #include @@ -80,7 +80,7 @@ bool ProtoPlayback::IsOpen() bool ProtoPlayback::Announce75() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); std::string cmd("ANN Playback "); cmd.append(m_socket->GetMyHostName()).append(" 0"); @@ -101,7 +101,7 @@ void ProtoPlayback::TransferDone75(ProtoTransfer& transfer) { BUILTIN_BUFFER buf; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!transfer.IsOpen()) return; std::string cmd("QUERY_FILETRANSFER "); @@ -121,7 +121,7 @@ bool ProtoPlayback::TransferIsOpen75(ProtoTransfer& transfer) std::string field; int8_t status = 0; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_FILETRANSFER "); @@ -169,11 +169,11 @@ int ProtoPlayback::TransferRequestBlock(ProtoTransfer& transfer, void *buffer, u if ((filePosition + n) > fileRequest) { // Begin critical section - m_mutex->Lock(); + m_latch->lock(); bool ok = TransferRequestBlock75(transfer, n); if (!ok) { - m_mutex->Unlock(); + m_latch->unlock(); goto err; } request = true; @@ -240,7 +240,7 @@ int ProtoPlayback::TransferRequestBlock(ProtoTransfer& transfer, void *buffer, u { int32_t rlen = TransferRequestBlockFeedback75(); request = false; // request is completed - m_mutex->Unlock(); + m_latch->unlock(); if (rlen < 0) goto err; DBG(DBG_DEBUG, "%s: receive block size (%u)\n", __FUNCTION__, (unsigned)rlen); @@ -257,7 +257,7 @@ int ProtoPlayback::TransferRequestBlock(ProtoTransfer& transfer, void *buffer, u { if (RcvMessageLength()) FlushMessage(); - m_mutex->Unlock(); + m_latch->unlock(); } // Recover the file position or die if (TransferSeek(transfer, filePosition, WHENCE_SET) < 0) @@ -334,7 +334,7 @@ int64_t ProtoPlayback::TransferSeek75(ProtoTransfer& transfer, int64_t offset, W return -1; } - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!transfer.IsOpen()) return -1; std::string cmd("QUERY_FILETRANSFER "); diff --git a/lib/cppmyth/src/proto/mythprotorecorder.cpp b/lib/cppmyth/src/proto/mythprotorecorder.cpp index afb43eb0..5f8d8b8d 100644 --- a/lib/cppmyth/src/proto/mythprotorecorder.cpp +++ b/lib/cppmyth/src/proto/mythprotorecorder.cpp @@ -21,7 +21,7 @@ #include "mythprotorecorder.h" #include "../private/debug.h" -#include "../private/os/threads/mutex.h" +#include "../private/os/threads/latch.h" #include "../private/builtin.h" @@ -89,7 +89,7 @@ bool ProtoRecorder::IsTunable(const Channel& channel) void ProtoRecorder::DoneRecordingCallback() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); m_liveRecording = false; DBG(DBG_DEBUG, "%s: completed\n", __FUNCTION__); } @@ -99,7 +99,7 @@ bool ProtoRecorder::SpawnLiveTV75(const std::string& chainid, const std::string& BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_RECORDER "); @@ -132,7 +132,7 @@ bool ProtoRecorder::StopLiveTV75() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_RECORDER "); @@ -157,7 +157,7 @@ bool ProtoRecorder::CheckChannel75(const std::string& channum) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_RECORDER "); @@ -184,7 +184,7 @@ ProgramPtr ProtoRecorder::GetCurrentRecording75() BUILTIN_BUFFER buf; ProgramPtr program; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return program; std::string cmd("QUERY_RECORDER "); @@ -212,7 +212,7 @@ int64_t ProtoRecorder::GetFilePosition75() int64_t pos; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen() || !IsPlaying()) return -1; std::string cmd("QUERY_RECORDER "); @@ -241,7 +241,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs75() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("QUERY_RECORDER "); @@ -280,7 +280,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs79() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("QUERY_RECORDER "); @@ -327,7 +327,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs81() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("QUERY_RECORDER "); @@ -375,7 +375,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs87() CardInputListPtr list = CardInputListPtr(new CardInputList()); std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO 0"); @@ -420,7 +420,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs89() CardInputListPtr list = CardInputListPtr(new CardInputList()); std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO 0"); @@ -467,7 +467,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs90() CardInputListPtr list = CardInputListPtr(new CardInputList()); std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO 0"); @@ -515,7 +515,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs91() CardInputListPtr list = CardInputListPtr(new CardInputList()); std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return list; std::string cmd("GET_FREE_INPUT_INFO 0"); @@ -556,7 +556,7 @@ CardInputListPtr ProtoRecorder::GetFreeInputs91() bool ProtoRecorder::IsLiveRecording() { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); return m_liveRecording; } @@ -565,7 +565,7 @@ bool ProtoRecorder::SetLiveRecording75(bool keep) BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_RECORDER "); @@ -596,7 +596,7 @@ bool ProtoRecorder::FinishRecording75() BUILTIN_BUFFER buf; std::string field; - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); if (!IsOpen()) return false; std::string cmd("QUERY_RECORDER "); diff --git a/lib/cppmyth/src/proto/mythprototransfer.cpp b/lib/cppmyth/src/proto/mythprototransfer.cpp index cc04525e..abf644a3 100644 --- a/lib/cppmyth/src/proto/mythprototransfer.cpp +++ b/lib/cppmyth/src/proto/mythprototransfer.cpp @@ -22,7 +22,7 @@ #include "mythprototransfer.h" #include "../private/debug.h" #include "../private/socket.h" -#include "../private/os/threads/mutex.h" +#include "../private/os/threads/latch.h" #include "../private/builtin.h" #include @@ -69,7 +69,7 @@ bool ProtoTransfer::Open() void ProtoTransfer::Close() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); ProtoBase::Close(); // Clean hanging and disable retry m_tainted = m_hang = false; @@ -80,22 +80,17 @@ void ProtoTransfer::Close() void ProtoTransfer::Lock() { - m_mutex->Lock(); + m_latch->lock(); } void ProtoTransfer::Unlock() { - m_mutex->Unlock(); -} - -bool ProtoTransfer::TryLock() -{ - return m_mutex->TryLock(); + m_latch->unlock(); } void ProtoTransfer::Flush() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); int64_t unread = m_fileRequest - m_filePosition; if (unread > 0) { @@ -116,7 +111,7 @@ void ProtoTransfer::Flush() bool ProtoTransfer::Announce75() { - OS::CLockGuard lock(*m_mutex); + OS::CWriteLock lock(*m_latch); m_filePosition = m_fileSize = m_fileRequest = 0; std::string cmd("ANN FileTransfer "); cmd.append(m_socket->GetMyHostName()); @@ -157,42 +152,42 @@ std::string ProtoTransfer::GetStorageGroupName() const int64_t ProtoTransfer::GetSize() const { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); return m_fileSize; } int64_t ProtoTransfer::GetPosition() const { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); return m_filePosition; } int64_t ProtoTransfer::GetRequested() const { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); return m_fileRequest; } int64_t ProtoTransfer::GetRemaining() const { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); return (m_fileSize - m_filePosition); } void ProtoTransfer::SetSize(int64_t size) { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); m_fileSize = size; } void ProtoTransfer::SetPosition(int64_t position) { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); m_filePosition = position; } void ProtoTransfer::SetRequested(int64_t requested) { - OS::CLockGuard lock(*m_mutex); + OS::CReadLock lock(*m_latch); m_fileRequest = requested; }