From dee83d7a89c021f63b746681d11ab72381bdc472 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 26 Dec 2022 18:59:17 +0300 Subject: fixes #3271 (Telegram: XP compatibility) --- .../tdlib/td/tdutils/td/utils/port/RwMutex.cpp | 133 +++++++++++++++++++++ .../tdlib/td/tdutils/td/utils/port/RwMutex.h | 32 +++-- protocols/Telegram/tdlib/tdutils.vcxproj | 1 + protocols/Telegram/tdlib/tdutils.vcxproj.filters | 1 + 4 files changed, 158 insertions(+), 9 deletions(-) create mode 100644 protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.cpp (limited to 'protocols/Telegram') diff --git a/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.cpp b/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.cpp new file mode 100644 index 0000000000..495856201e --- /dev/null +++ b/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.cpp @@ -0,0 +1,133 @@ +// +// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2022 +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +#pragma once + +#include + +#include "td/utils/port/RwMutex.h" + +typedef void(WINAPI *srwlock_function)(winlock_t*); +static srwlock_function srwlock_Init, srwlock_AcquireShared, srwlock_ReleaseShared, srwlock_AcquireExclusive, srwlock_ReleaseExclusive; + +static bool bInited = false; + +namespace td { + //---------------------------------------------------------------------------- + // Stub for slim read-write lock + // Copyright (C) 1995-2002 Brad Wilson + + static void WINAPI stub_srwlock_Init(winlock_t *srwl) { + srwl->readerCount = srwl->writerCount = 0; + } + + static void WINAPI stub_srwlock_AcquireShared(winlock_t *srwl) { + while (true) { + assert(srwl->writerCount >= 0 && srwl->readerCount >= 0); + + // If there's a writer already, spin without unnecessarily + // interlocking the CPUs + if (srwl->writerCount != 0) { + YieldProcessor(); + continue; + } + + // Add to the readers list + _InterlockedIncrement(&srwl->readerCount); + + // Check for writers again (we may have been preempted). If + // there are no writers writing or waiting, then we're done. + if (srwl->writerCount == 0) + break; + + // Remove from the readers list, spin, try again + _InterlockedDecrement(&srwl->readerCount); + YieldProcessor(); + } + } + + static void WINAPI stub_srwlock_ReleaseShared(winlock_t *srwl) { + assert(srwl->readerCount > 0); + _InterlockedDecrement(&srwl->readerCount); + } + + static void WINAPI stub_srwlock_AcquireExclusive(winlock_t *srwl) { + while (true) { + assert(srwl->writerCount >= 0 && srwl->readerCount >= 0); + + // If there's a writer already, spin without unnecessarily + // interlocking the CPUs + if (srwl->writerCount != 0) { + YieldProcessor(); + continue; + } + + // See if we can become the writer (expensive, because it inter- + // locks the CPUs, so writing should be an infrequent process) + if (_InterlockedExchange(&srwl->writerCount, 1) == 0) + break; + } + + // Now we're the writer, but there may be outstanding readers. + // Spin until there aren't any more; new readers will wait now + // that we're the writer. + while (srwl->readerCount != 0) { + assert(srwl->writerCount >= 0 && srwl->readerCount >= 0); + YieldProcessor(); + } + } + + static void WINAPI stub_srwlock_ReleaseExclusive(winlock_t *srwl) { + assert(srwl->writerCount == 1 && srwl->readerCount >= 0); + srwl->writerCount = 0; + } + + void InitializeLock(winlock_t &lock) + { + if (!bInited) { + HINSTANCE hKernel32dll = GetModuleHandleA("kernel32.dll"); + + const srwlock_function init = (srwlock_function)GetProcAddress(hKernel32dll, "InitializeSRWLock"); + if (init != NULL) { + srwlock_Init = init; + srwlock_AcquireShared = (srwlock_function)GetProcAddress(hKernel32dll, "AcquireSRWLockShared"); + srwlock_ReleaseShared = (srwlock_function)GetProcAddress(hKernel32dll, "ReleaseSRWLockShared"); + srwlock_AcquireExclusive = (srwlock_function)GetProcAddress(hKernel32dll, "AcquireSRWLockExclusive"); + srwlock_ReleaseExclusive = (srwlock_function)GetProcAddress(hKernel32dll, "ReleaseSRWLockExclusive"); + } else { + srwlock_Init = stub_srwlock_Init; + srwlock_AcquireShared = stub_srwlock_AcquireShared; + srwlock_ReleaseShared = stub_srwlock_ReleaseShared; + srwlock_AcquireExclusive = stub_srwlock_AcquireExclusive; + srwlock_ReleaseExclusive = stub_srwlock_ReleaseExclusive; + } + + bInited = true; + } + + srwlock_Init(&lock); + } + + void AcquireLockShared(winlock_t &lock) + { + srwlock_AcquireShared(&lock); + } + + void AcquireLockExclusive(winlock_t &lock) + { + srwlock_AcquireExclusive(&lock); + } + + void ReleaseLockShared(winlock_t &lock) + { + srwlock_ReleaseShared(&lock); + } + + void ReleaseLockExclusive(winlock_t &lock) + { + srwlock_ReleaseExclusive(&lock); + } +} // namespace td diff --git a/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.h b/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.h index 01de499bd0..1d88caceee 100644 --- a/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.h +++ b/protocols/Telegram/tdlib/td/tdutils/td/utils/port/RwMutex.h @@ -15,6 +15,17 @@ #include #endif +#if TD_PORT_WINDOWS +union winlock_t { + struct { + long volatile readerCount; + long volatile writerCount; + }; + + SRWLOCK rwlock; +}; +#endif + #include namespace td { @@ -83,18 +94,23 @@ class RwMutex { #if TD_PORT_POSIX pthread_rwlock_t mutex_; #elif TD_PORT_WINDOWS - unique_ptr mutex_; + winlock_t mutex_; #endif }; +void InitializeLock(winlock_t&); +void AcquireLockShared(winlock_t&); +void AcquireLockExclusive(winlock_t&); +void ReleaseLockShared(winlock_t&); +void ReleaseLockExclusive(winlock_t&); + inline void RwMutex::init() { CHECK(empty()); is_valid_ = true; #if TD_PORT_POSIX pthread_rwlock_init(&mutex_, nullptr); #elif TD_PORT_WINDOWS - mutex_ = make_unique(); - InitializeSRWLock(mutex_.get()); + InitializeLock(mutex_); #endif } @@ -102,8 +118,6 @@ inline void RwMutex::clear() { if (is_valid_) { #if TD_PORT_POSIX pthread_rwlock_destroy(&mutex_); -#elif TD_PORT_WINDOWS - mutex_.release(); #endif is_valid_ = false; } @@ -115,7 +129,7 @@ inline void RwMutex::lock_read_unsafe() { #if TD_PORT_POSIX pthread_rwlock_rdlock(&mutex_); #elif TD_PORT_WINDOWS - AcquireSRWLockShared(mutex_.get()); + AcquireLockShared(mutex_); #endif } @@ -124,7 +138,7 @@ inline void RwMutex::lock_write_unsafe() { #if TD_PORT_POSIX pthread_rwlock_wrlock(&mutex_); #elif TD_PORT_WINDOWS - AcquireSRWLockExclusive(mutex_.get()); + AcquireLockExclusive(mutex_); #endif } @@ -133,7 +147,7 @@ inline void RwMutex::unlock_read_unsafe() { #if TD_PORT_POSIX pthread_rwlock_unlock(&mutex_); #elif TD_PORT_WINDOWS - ReleaseSRWLockShared(mutex_.get()); + ReleaseLockShared(mutex_); #endif } @@ -142,7 +156,7 @@ inline void RwMutex::unlock_write_unsafe() { #if TD_PORT_POSIX pthread_rwlock_unlock(&mutex_); #elif TD_PORT_WINDOWS - ReleaseSRWLockExclusive(mutex_.get()); + ReleaseLockExclusive(mutex_); #endif } diff --git a/protocols/Telegram/tdlib/tdutils.vcxproj b/protocols/Telegram/tdlib/tdutils.vcxproj index 12c905256d..050adeda34 100644 --- a/protocols/Telegram/tdlib/tdutils.vcxproj +++ b/protocols/Telegram/tdlib/tdutils.vcxproj @@ -56,6 +56,7 @@ + diff --git a/protocols/Telegram/tdlib/tdutils.vcxproj.filters b/protocols/Telegram/tdlib/tdutils.vcxproj.filters index 4470712a66..f51361d15e 100644 --- a/protocols/Telegram/tdlib/tdutils.vcxproj.filters +++ b/protocols/Telegram/tdlib/tdutils.vcxproj.filters @@ -75,6 +75,7 @@ + -- cgit v1.2.3