Add CLock wrapper for std::mutex to replace lock_* functions

Replace usages of platform specific `lock_*` functions with `std::mutex` through the wrapper class `CLock`. Move lock classes to `base/lock.h`.

The `CLock` wrapper class is only necessary because the clang thread-safety attributes are not available for `std::mutex` except when explicitly using libc++.
This commit is contained in:
Robert Müller 2023-11-10 21:15:51 +01:00
parent de52ded86d
commit 3d858c28ee
15 changed files with 199 additions and 308 deletions

View file

@ -1844,7 +1844,7 @@ set_src(BASE GLOB_RECURSE src/base
hash_ctxt.h hash_ctxt.h
hash_libtomcrypt.cpp hash_libtomcrypt.cpp
hash_openssl.cpp hash_openssl.cpp
lock_scope.h lock.h
log.cpp log.cpp
log.h log.h
logger.h logger.h

135
src/base/lock.h Normal file
View file

@ -0,0 +1,135 @@
#ifndef BASE_LOCK_H
#define BASE_LOCK_H
#include <mutex>
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__) && (!defined(SWIG))
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define SCOPED_CAPABILITY \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define REQUIRES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define REQUIRES_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define RELEASE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define RELEASE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define RELEASE_GENERIC(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
#define TRY_ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define TRY_ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define EXCLUDES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define ASSERT_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define ASSERT_SHARED_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define RETURN_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
/**
* @defgroup Locks
* @see Threads
*/
/**
* Wrapper for `std::mutex`.
*
* @ingroup Locks
*
* @remark This wrapper is only necessary because the clang thread-safety attributes
* are not available for `std::mutex` except when explicitly using libc++.
*/
class CAPABILITY("mutex") CLock
{
public:
CLock() = default;
void lock() ACQUIRE()
{
m_Mutex.lock();
}
void unlock() RELEASE()
{
m_Mutex.unlock();
}
// To support negative capabilities, otherwise EXCLUDES(m_Lock) must be used instead of REQUIRES(!m_Lock)
const CLock &operator!() const { return *this; }
private:
std::mutex m_Mutex;
};
/**
* RAII-style wrapper for owning a `CLock`.
*
* @ingroup Locks
*
* @remark This wrapper is only necessary because the clang thread-safety attributes
* are not available for `std::lock_guard` except when explicitly using libc++.
*/
class SCOPED_CAPABILITY CLockScope
{
public:
explicit CLockScope(CLock &Lock) ACQUIRE(Lock, m_Lock) :
m_Lock(Lock)
{
m_Lock.lock();
}
~CLockScope() RELEASE() REQUIRES(m_Lock)
{
m_Lock.unlock();
}
private:
CLock &m_Lock;
};
#endif

View file

@ -1,24 +0,0 @@
#ifndef BASE_LOCK_SCOPE_H
#define BASE_LOCK_SCOPE_H
#include "system.h"
class SCOPED_CAPABILITY CLockScope
{
public:
CLockScope(LOCK Lock) ACQUIRE(Lock, m_Lock) :
m_Lock(Lock)
{
lock_wait(m_Lock);
}
~CLockScope() RELEASE() REQUIRES(m_Lock)
{
lock_unlock(m_Lock);
}
private:
LOCK m_Lock;
};
#endif

View file

@ -3,6 +3,8 @@
#include <atomic> #include <atomic>
#include <cctype> #include <cctype>
#include <charconv> #include <charconv>
#include <chrono>
#include <cinttypes>
#include <cmath> #include <cmath>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
@ -10,17 +12,12 @@
#include <iterator> // std::size #include <iterator> // std::size
#include <string_view> #include <string_view>
#include "lock.h"
#include "logger.h"
#include "system.h" #include "system.h"
#include "lock_scope.h"
#include "logger.h"
#include <sys/types.h> #include <sys/types.h>
#include <chrono>
#include <cinttypes>
#if defined(CONF_WEBSOCKETS) #if defined(CONF_WEBSOCKETS)
#include <engine/shared/websockets.h> #include <engine/shared/websockets.h>
#endif #endif
@ -474,10 +471,9 @@ int io_sync(IOHANDLE io)
#define ASYNC_BUFSIZE (8 * 1024) #define ASYNC_BUFSIZE (8 * 1024)
#define ASYNC_LOCAL_BUFSIZE (64 * 1024) #define ASYNC_LOCAL_BUFSIZE (64 * 1024)
// TODO: Use Thread Safety Analysis when this file is converted to C++
struct ASYNCIO struct ASYNCIO
{ {
LOCK lock; CLock lock;
IOHANDLE io; IOHANDLE io;
SEMAPHORE sphore; SEMAPHORE sphore;
void *thread; void *thread;
@ -530,13 +526,12 @@ static void aio_handle_free_and_unlock(ASYNCIO *aio) RELEASE(aio->lock)
aio->refcount--; aio->refcount--;
do_free = aio->refcount == 0; do_free = aio->refcount == 0;
lock_unlock(aio->lock); aio->lock.unlock();
if(do_free) if(do_free)
{ {
free(aio->buffer); free(aio->buffer);
sphore_destroy(&aio->sphore); sphore_destroy(&aio->sphore);
lock_destroy(aio->lock); delete aio;
free(aio);
} }
} }
@ -544,7 +539,7 @@ static void aio_thread(void *user)
{ {
ASYNCIO *aio = (ASYNCIO *)user; ASYNCIO *aio = (ASYNCIO *)user;
lock_wait(aio->lock); aio->lock.lock();
while(true) while(true)
{ {
struct BUFFERS buffers; struct BUFFERS buffers;
@ -563,9 +558,9 @@ static void aio_thread(void *user)
aio_handle_free_and_unlock(aio); aio_handle_free_and_unlock(aio);
break; break;
} }
lock_unlock(aio->lock); aio->lock.unlock();
sphore_wait(&aio->sphore); sphore_wait(&aio->sphore);
lock_wait(aio->lock); aio->lock.lock();
continue; continue;
} }
@ -589,26 +584,25 @@ static void aio_thread(void *user)
} }
} }
aio->read_pos = (aio->read_pos + buffers.len1 + buffers.len2) % aio->buffer_size; aio->read_pos = (aio->read_pos + buffers.len1 + buffers.len2) % aio->buffer_size;
lock_unlock(aio->lock); aio->lock.unlock();
io_write(aio->io, local_buffer, local_buffer_len); io_write(aio->io, local_buffer, local_buffer_len);
io_flush(aio->io); io_flush(aio->io);
result_io_error = io_error(aio->io); result_io_error = io_error(aio->io);
lock_wait(aio->lock); aio->lock.lock();
aio->error = result_io_error; aio->error = result_io_error;
} }
} }
ASYNCIO *aio_new(IOHANDLE io) ASYNCIO *aio_new(IOHANDLE io)
{ {
ASYNCIO *aio = (ASYNCIO *)malloc(sizeof(*aio)); ASYNCIO *aio = new ASYNCIO;
if(!aio) if(!aio)
{ {
return 0; return 0;
} }
aio->io = io; aio->io = io;
aio->lock = lock_create();
sphore_init(&aio->sphore); sphore_init(&aio->sphore);
aio->thread = 0; aio->thread = 0;
@ -616,8 +610,7 @@ ASYNCIO *aio_new(IOHANDLE io)
if(!aio->buffer) if(!aio->buffer)
{ {
sphore_destroy(&aio->sphore); sphore_destroy(&aio->sphore);
lock_destroy(aio->lock); delete aio;
free(aio);
return 0; return 0;
} }
aio->buffer_size = ASYNC_BUFSIZE; aio->buffer_size = ASYNC_BUFSIZE;
@ -632,8 +625,7 @@ ASYNCIO *aio_new(IOHANDLE io)
{ {
free(aio->buffer); free(aio->buffer);
sphore_destroy(&aio->sphore); sphore_destroy(&aio->sphore);
lock_destroy(aio->lock); delete aio;
free(aio);
return 0; return 0;
} }
return aio; return aio;
@ -662,12 +654,12 @@ static unsigned int next_buffer_size(unsigned int cur_size, unsigned int need_si
void aio_lock(ASYNCIO *aio) ACQUIRE(aio->lock) void aio_lock(ASYNCIO *aio) ACQUIRE(aio->lock)
{ {
lock_wait(aio->lock); aio->lock.lock();
} }
void aio_unlock(ASYNCIO *aio) RELEASE(aio->lock) void aio_unlock(ASYNCIO *aio) RELEASE(aio->lock)
{ {
lock_unlock(aio->lock); aio->lock.unlock();
sphore_signal(&aio->sphore); sphore_signal(&aio->sphore);
} }
@ -752,7 +744,7 @@ int aio_error(ASYNCIO *aio)
void aio_free(ASYNCIO *aio) void aio_free(ASYNCIO *aio)
{ {
lock_wait(aio->lock); aio->lock.lock();
if(aio->thread) if(aio->thread)
{ {
thread_detach(aio->thread); thread_detach(aio->thread);
@ -885,98 +877,6 @@ bool thread_init_and_detach(void (*threadfunc)(void *), void *u, const char *nam
return thread != nullptr; return thread != nullptr;
} }
#if defined(CONF_FAMILY_UNIX)
typedef pthread_mutex_t LOCKINTERNAL;
#elif defined(CONF_FAMILY_WINDOWS)
typedef CRITICAL_SECTION LOCKINTERNAL;
#else
#error not implemented on this platform
#endif
LOCK lock_create()
{
LOCKINTERNAL *lock = (LOCKINTERNAL *)malloc(sizeof(*lock));
#if defined(CONF_FAMILY_UNIX)
int result;
#endif
if(!lock)
return 0;
#if defined(CONF_FAMILY_UNIX)
result = pthread_mutex_init(lock, 0x0);
if(result != 0)
{
dbg_msg("lock", "init failed: %d", result);
free(lock);
return 0;
}
#elif defined(CONF_FAMILY_WINDOWS)
InitializeCriticalSection((LPCRITICAL_SECTION)lock);
#else
#error not implemented on this platform
#endif
return (LOCK)lock;
}
void lock_destroy(LOCK lock)
{
#if defined(CONF_FAMILY_UNIX)
int result = pthread_mutex_destroy((LOCKINTERNAL *)lock);
if(result != 0)
dbg_msg("lock", "destroy failed: %d", result);
#elif defined(CONF_FAMILY_WINDOWS)
DeleteCriticalSection((LPCRITICAL_SECTION)lock);
#else
#error not implemented on this platform
#endif
free(lock);
}
int lock_trylock(LOCK lock)
{
#if defined(CONF_FAMILY_UNIX)
return pthread_mutex_trylock((LOCKINTERNAL *)lock);
#elif defined(CONF_FAMILY_WINDOWS)
return !TryEnterCriticalSection((LPCRITICAL_SECTION)lock);
#else
#error not implemented on this platform
#endif
}
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wthread-safety-analysis"
#endif
void lock_wait(LOCK lock)
{
#if defined(CONF_FAMILY_UNIX)
int result = pthread_mutex_lock((LOCKINTERNAL *)lock);
if(result != 0)
dbg_msg("lock", "lock failed: %d", result);
#elif defined(CONF_FAMILY_WINDOWS)
EnterCriticalSection((LPCRITICAL_SECTION)lock);
#else
#error not implemented on this platform
#endif
}
void lock_unlock(LOCK lock)
{
#if defined(CONF_FAMILY_UNIX)
int result = pthread_mutex_unlock((LOCKINTERNAL *)lock);
if(result != 0)
dbg_msg("lock", "unlock failed: %d", result);
#elif defined(CONF_FAMILY_WINDOWS)
LeaveCriticalSection((LPCRITICAL_SECTION)lock);
#else
#error not implemented on this platform
#endif
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
void sphore_init(SEMAPHORE *sem) void sphore_init(SEMAPHORE *sem)
{ {

View file

@ -14,10 +14,13 @@
#define __USE_GNU #define __USE_GNU
#endif #endif
#include <chrono>
#include <cinttypes> #include <cinttypes>
#include <cstdarg> #include <cstdarg>
#include <cstdint> #include <cstdint>
#include <ctime> #include <ctime>
#include <functional>
#include <mutex>
#include <string> #include <string>
#ifdef __MINGW32__ #ifdef __MINGW32__
@ -41,9 +44,6 @@
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <chrono>
#include <functional>
#if __cplusplus >= 201703L #if __cplusplus >= 201703L
#define MAYBE_UNUSED [[maybe_unused]] #define MAYBE_UNUSED [[maybe_unused]]
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -607,107 +607,11 @@ void thread_detach(void *thread);
*/ */
bool thread_init_and_detach(void (*threadfunc)(void *), void *user, const char *name); bool thread_init_and_detach(void (*threadfunc)(void *), void *user, const char *name);
// Enable thread safety attributes only with clang.
// The attributes can be safely erased when compiling with other compilers.
#if defined(__clang__) && (!defined(SWIG))
#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
#else
#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
#endif
#define CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
#define SCOPED_CAPABILITY \
THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
#define GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
#define PT_GUARDED_BY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
#define ACQUIRED_BEFORE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
#define ACQUIRED_AFTER(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
#define REQUIRES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
#define REQUIRES_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
#define ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
#define ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
#define RELEASE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
#define RELEASE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
#define RELEASE_GENERIC(...) \
THREAD_ANNOTATION_ATTRIBUTE__(release_generic_capability(__VA_ARGS__))
#define TRY_ACQUIRE(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
#define TRY_ACQUIRE_SHARED(...) \
THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
#define EXCLUDES(...) \
THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
#define ASSERT_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
#define ASSERT_SHARED_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
#define RETURN_CAPABILITY(x) \
THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
#define NO_THREAD_SAFETY_ANALYSIS \
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
/** /**
* @defgroup Locks * @defgroup Semaphore
*
* Synchronization primitives.
*
* @see Threads * @see Threads
*/ */
typedef CAPABILITY("mutex") void *LOCK;
/**
* @ingroup Locks
*/
LOCK lock_create();
/**
* @ingroup Locks
*/
void lock_destroy(LOCK lock);
/**
* @ingroup Locks
*/
int lock_trylock(LOCK lock) TRY_ACQUIRE(1, lock);
/**
* @ingroup Locks
*/
void lock_wait(LOCK lock) ACQUIRE(lock);
/**
* @ingroup Locks
*/
void lock_unlock(LOCK lock) RELEASE(lock);
/* Group: Semaphores */
#if defined(CONF_FAMILY_WINDOWS) #if defined(CONF_FAMILY_WINDOWS)
typedef void *SEMAPHORE; typedef void *SEMAPHORE;
#elif defined(CONF_PLATFORM_MACOS) #elif defined(CONF_PLATFORM_MACOS)
@ -721,19 +625,19 @@ typedef sem_t SEMAPHORE;
#endif #endif
/** /**
* @ingroup Locks * @ingroup Semaphore
*/ */
void sphore_init(SEMAPHORE *sem); void sphore_init(SEMAPHORE *sem);
/** /**
* @ingroup Locks * @ingroup Semaphore
*/ */
void sphore_wait(SEMAPHORE *sem); void sphore_wait(SEMAPHORE *sem);
/** /**
* @ingroup Locks * @ingroup Semaphore
*/ */
void sphore_signal(SEMAPHORE *sem); void sphore_signal(SEMAPHORE *sem);
/** /**
* @ingroup Locks * @ingroup Semaphore
*/ */
void sphore_destroy(SEMAPHORE *sem); void sphore_destroy(SEMAPHORE *sem);

View file

@ -10,7 +10,7 @@
#include <engine/shared/serverinfo.h> #include <engine/shared/serverinfo.h>
#include <engine/storage.h> #include <engine/storage.h>
#include <base/lock_scope.h> #include <base/lock.h>
#include <base/system.h> #include <base/system.h>
#include <memory> #include <memory>
@ -51,7 +51,7 @@ private:
}; };
class CJob : public IJob class CJob : public IJob
{ {
LOCK m_Lock; CLock m_Lock;
std::shared_ptr<CData> m_pData; std::shared_ptr<CData> m_pData;
std::unique_ptr<CHttpRequest> m_pHead PT_GUARDED_BY(m_Lock); std::unique_ptr<CHttpRequest> m_pHead PT_GUARDED_BY(m_Lock);
std::unique_ptr<CHttpRequest> m_pGet PT_GUARDED_BY(m_Lock); std::unique_ptr<CHttpRequest> m_pGet PT_GUARDED_BY(m_Lock);
@ -59,8 +59,7 @@ private:
public: public:
CJob(std::shared_ptr<CData> pData) : CJob(std::shared_ptr<CData> pData) :
m_pData(std::move(pData)) { m_Lock = lock_create(); } m_pData(std::move(pData)) {}
~CJob() override { lock_destroy(m_Lock); }
void Abort() REQUIRES(!m_Lock); void Abort() REQUIRES(!m_Lock);
}; };

View file

@ -1,6 +1,7 @@
#include "updater.h" #include "updater.h"
#include <base/lock_scope.h>
#include <base/system.h> #include <base/system.h>
#include <engine/client.h> #include <engine/client.h>
#include <engine/engine.h> #include <engine/engine.h>
#include <engine/external/json-parser/json.h> #include <engine/external/json-parser/json.h>
@ -94,7 +95,6 @@ CUpdater::CUpdater()
m_pEngine = NULL; m_pEngine = NULL;
m_State = CLEAN; m_State = CLEAN;
m_Percent = 0; m_Percent = 0;
m_Lock = lock_create();
IStorage::FormatTmpPath(m_aClientExecTmp, sizeof(m_aClientExecTmp), CLIENT_EXEC); IStorage::FormatTmpPath(m_aClientExecTmp, sizeof(m_aClientExecTmp), CLIENT_EXEC);
IStorage::FormatTmpPath(m_aServerExecTmp, sizeof(m_aServerExecTmp), SERVER_EXEC); IStorage::FormatTmpPath(m_aServerExecTmp, sizeof(m_aServerExecTmp), SERVER_EXEC);
@ -107,11 +107,6 @@ void CUpdater::Init()
m_pEngine = Kernel()->RequestInterface<IEngine>(); m_pEngine = Kernel()->RequestInterface<IEngine>();
} }
CUpdater::~CUpdater()
{
lock_destroy(m_Lock);
}
void CUpdater::SetCurrentState(int NewState) void CUpdater::SetCurrentState(int NewState)
{ {
CLockScope ls(m_Lock); CLockScope ls(m_Lock);

View file

@ -1,7 +1,10 @@
#ifndef ENGINE_CLIENT_UPDATER_H #ifndef ENGINE_CLIENT_UPDATER_H
#define ENGINE_CLIENT_UPDATER_H #define ENGINE_CLIENT_UPDATER_H
#include <base/lock.h>
#include <engine/updater.h> #include <engine/updater.h>
#include <map> #include <map>
#include <string> #include <string>
@ -39,7 +42,7 @@ class CUpdater : public IUpdater
class IStorage *m_pStorage; class IStorage *m_pStorage;
class IEngine *m_pEngine; class IEngine *m_pEngine;
LOCK m_Lock; CLock m_Lock;
int m_State; int m_State;
char m_aStatus[256] GUARDED_BY(m_Lock); char m_aStatus[256] GUARDED_BY(m_Lock);
@ -68,7 +71,6 @@ class CUpdater : public IUpdater
public: public:
CUpdater(); CUpdater();
~CUpdater();
int GetCurrentState() override REQUIRES(!m_Lock); int GetCurrentState() override REQUIRES(!m_Lock);
void GetCurrentFile(char *pBuf, int BufSize) override REQUIRES(!m_Lock); void GetCurrentFile(char *pBuf, int BufSize) override REQUIRES(!m_Lock);

View file

@ -1,11 +1,11 @@
#if defined(CONF_VIDEORECORDER) #if defined(CONF_VIDEORECORDER)
#include <engine/shared/config.h> #include "video.h"
#include <engine/storage.h>
#include <base/lock_scope.h>
#include <engine/client/graphics_threaded.h> #include <engine/client/graphics_threaded.h>
#include <engine/shared/config.h>
#include <engine/sound.h> #include <engine/sound.h>
#include <engine/storage.h>
extern "C" { extern "C" {
#include <libavutil/avutil.h> #include <libavutil/avutil.h>
@ -14,12 +14,9 @@ extern "C" {
#include <libswscale/swscale.h> #include <libswscale/swscale.h>
}; };
#include <chrono>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include "video.h"
#include <chrono>
#include <thread> #include <thread>
using namespace std::chrono_literals; using namespace std::chrono_literals;
@ -35,7 +32,7 @@ using namespace std::chrono_literals;
#endif #endif
const size_t FORMAT_GL_NCHANNELS = 4; const size_t FORMAT_GL_NCHANNELS = 4;
LOCK g_WriteLock = 0; CLock g_WriteLock;
CVideo::CVideo(CGraphics_Threaded *pGraphics, ISound *pSound, IStorage *pStorage, int Width, int Height, const char *pName) : CVideo::CVideo(CGraphics_Threaded *pGraphics, ISound *pSound, IStorage *pStorage, int Width, int Height, const char *pName) :
m_pGraphics(pGraphics), m_pGraphics(pGraphics),
@ -66,13 +63,11 @@ CVideo::CVideo(CGraphics_Threaded *pGraphics, ISound *pSound, IStorage *pStorage
ms_TickTime = time_freq() / m_FPS; ms_TickTime = time_freq() / m_FPS;
ms_pCurrentVideo = this; ms_pCurrentVideo = this;
g_WriteLock = lock_create();
} }
CVideo::~CVideo() CVideo::~CVideo()
{ {
ms_pCurrentVideo = 0; ms_pCurrentVideo = 0;
lock_destroy(g_WriteLock);
} }
void CVideo::Start() void CVideo::Start()

View file

@ -1,6 +1,7 @@
#ifndef ENGINE_CLIENT_VIDEO_H #ifndef ENGINE_CLIENT_VIDEO_H
#define ENGINE_CLIENT_VIDEO_H #define ENGINE_CLIENT_VIDEO_H
#include <base/lock.h>
#include <base/system.h> #include <base/system.h>
extern "C" { extern "C" {
@ -21,7 +22,7 @@ class CGraphics_Threaded;
class ISound; class ISound;
class IStorage; class IStorage;
extern LOCK g_WriteLock; extern CLock g_WriteLock;
// a wrapper around a single output AVStream // a wrapper around a single output AVStream
struct OutputStream struct OutputStream

View file

@ -1,7 +1,8 @@
#include "register.h" #include "register.h"
#include <base/lock_scope.h> #include <base/lock.h>
#include <base/log.h> #include <base/log.h>
#include <engine/console.h> #include <engine/console.h>
#include <engine/engine.h> #include <engine/engine.h>
#include <engine/shared/config.h> #include <engine/shared/config.h>
@ -40,12 +41,7 @@ class CRegister : public IRegister
class CGlobal class CGlobal
{ {
public: public:
~CGlobal() CLock m_Lock;
{
lock_destroy(m_Lock);
}
LOCK m_Lock = lock_create();
int m_InfoSerial GUARDED_BY(m_Lock) = -1; int m_InfoSerial GUARDED_BY(m_Lock) = -1;
int m_LatestSuccessfulInfoSerial GUARDED_BY(m_Lock) = -1; int m_LatestSuccessfulInfoSerial GUARDED_BY(m_Lock) = -1;
}; };
@ -59,13 +55,9 @@ class CRegister : public IRegister
m_pGlobal(std::move(pGlobal)) m_pGlobal(std::move(pGlobal))
{ {
} }
~CShared()
{
lock_destroy(m_Lock);
}
std::shared_ptr<CGlobal> m_pGlobal; std::shared_ptr<CGlobal> m_pGlobal;
LOCK m_Lock = lock_create(); CLock m_Lock;
int m_NumTotalRequests GUARDED_BY(m_Lock) = 0; int m_NumTotalRequests GUARDED_BY(m_Lock) = 0;
int m_LatestResponseStatus GUARDED_BY(m_Lock) = STATUS_NONE; int m_LatestResponseStatus GUARDED_BY(m_Lock) = STATUS_NONE;
int m_LatestResponseIndex GUARDED_BY(m_Lock) = -1; int m_LatestResponseIndex GUARDED_BY(m_Lock) = -1;
@ -326,13 +318,12 @@ void CRegister::CProtocol::SendRegister()
void CRegister::CProtocol::SendDeleteIfRegistered(bool Shutdown) void CRegister::CProtocol::SendDeleteIfRegistered(bool Shutdown)
{ {
lock_wait(m_pShared->m_Lock);
bool ShouldSendDelete = m_pShared->m_LatestResponseStatus == STATUS_OK;
m_pShared->m_LatestResponseStatus = STATUS_NONE;
lock_unlock(m_pShared->m_Lock);
if(!ShouldSendDelete)
{ {
return; const CLockScope LockScope(m_pShared->m_Lock);
const bool ShouldSendDelete = m_pShared->m_LatestResponseStatus == STATUS_OK;
m_pShared->m_LatestResponseStatus = STATUS_NONE;
if(!ShouldSendDelete)
return;
} }
char aAddress[64]; char aAddress[64];

View file

@ -17,7 +17,7 @@
// TODO: Non-global pls? // TODO: Non-global pls?
static CURLSH *gs_pShare; static CURLSH *gs_pShare;
static LOCK gs_aLocks[CURL_LOCK_DATA_LAST + 1]; static CLock gs_aLocks[CURL_LOCK_DATA_LAST + 1];
static bool gs_Initialized = false; static bool gs_Initialized = false;
static int GetLockIndex(int Data) static int GetLockIndex(int Data)
@ -34,14 +34,14 @@ static void CurlLock(CURL *pHandle, curl_lock_data Data, curl_lock_access Access
(void)pHandle; (void)pHandle;
(void)Access; (void)Access;
(void)pUser; (void)pUser;
lock_wait(gs_aLocks[GetLockIndex(Data)]); gs_aLocks[GetLockIndex(Data)].lock();
} }
static void CurlUnlock(CURL *pHandle, curl_lock_data Data, void *pUser) RELEASE(gs_aLocks[GetLockIndex(Data)]) static void CurlUnlock(CURL *pHandle, curl_lock_data Data, void *pUser) RELEASE(gs_aLocks[GetLockIndex(Data)])
{ {
(void)pHandle; (void)pHandle;
(void)pUser; (void)pUser;
lock_unlock(gs_aLocks[GetLockIndex(Data)]); gs_aLocks[GetLockIndex(Data)].unlock();
} }
int CurlDebug(CURL *pHandle, curl_infotype Type, char *pData, size_t DataSize, void *pUser) int CurlDebug(CURL *pHandle, curl_infotype Type, char *pData, size_t DataSize, void *pUser)
@ -88,10 +88,6 @@ bool HttpInit(IStorage *pStorage)
dbg_msg("http", "libcurl version %s (compiled = " LIBCURL_VERSION ")", pVersion->version); dbg_msg("http", "libcurl version %s (compiled = " LIBCURL_VERSION ")", pVersion->version);
} }
for(auto &Lock : gs_aLocks)
{
Lock = lock_create();
}
curl_share_setopt(gs_pShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS); curl_share_setopt(gs_pShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
curl_share_setopt(gs_pShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); curl_share_setopt(gs_pShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
curl_share_setopt(gs_pShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT); curl_share_setopt(gs_pShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);

View file

@ -2,8 +2,6 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */
#include "jobs.h" #include "jobs.h"
#include <base/lock_scope.h>
IJob::IJob() : IJob::IJob() :
m_Status(STATE_PENDING) m_Status(STATE_PENDING)
{ {
@ -20,7 +18,6 @@ CJobPool::CJobPool()
{ {
// empty the pool // empty the pool
m_Shutdown = false; m_Shutdown = false;
m_Lock = lock_create();
sphore_init(&m_Semaphore); sphore_init(&m_Semaphore);
m_pFirstJob = 0; m_pFirstJob = 0;
m_pLastJob = 0; m_pLastJob = 0;
@ -85,7 +82,6 @@ void CJobPool::Destroy()
for(void *pThread : m_vpThreads) for(void *pThread : m_vpThreads)
thread_wait(pThread); thread_wait(pThread);
m_vpThreads.clear(); m_vpThreads.clear();
lock_destroy(m_Lock);
sphore_destroy(&m_Semaphore); sphore_destroy(&m_Semaphore);
} }

View file

@ -3,6 +3,7 @@
#ifndef ENGINE_SHARED_JOBS_H #ifndef ENGINE_SHARED_JOBS_H
#define ENGINE_SHARED_JOBS_H #define ENGINE_SHARED_JOBS_H
#include <base/lock.h>
#include <base/system.h> #include <base/system.h>
#include <atomic> #include <atomic>
@ -41,7 +42,7 @@ class CJobPool
std::vector<void *> m_vpThreads; std::vector<void *> m_vpThreads;
std::atomic<bool> m_Shutdown; std::atomic<bool> m_Shutdown;
LOCK m_Lock; CLock m_Lock;
SEMAPHORE m_Semaphore; SEMAPHORE m_Semaphore;
std::shared_ptr<IJob> m_pFirstJob GUARDED_BY(m_Lock); std::shared_ptr<IJob> m_pFirstJob GUARDED_BY(m_Lock);
std::shared_ptr<IJob> m_pLastJob GUARDED_BY(m_Lock); std::shared_ptr<IJob> m_pLastJob GUARDED_BY(m_Lock);

View file

@ -1,5 +1,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <base/lock.h>
#include <base/system.h> #include <base/system.h>
#include <base/tl/threading.h> #include <base/tl/threading.h>
@ -82,17 +83,16 @@ TEST(Thread, SemaphoreMultiThreaded)
static void LockThread(void *pUser) static void LockThread(void *pUser)
{ {
LOCK *pLock = (LOCK *)pUser; CLock *pLock = (CLock *)pUser;
lock_wait(*pLock); pLock->lock();
lock_unlock(*pLock); pLock->unlock();
} }
TEST(Thread, Lock) TEST(Thread, Lock)
{ {
LOCK Lock = lock_create(); CLock Lock;
lock_wait(Lock); Lock.lock();
void *pThread = thread_init(LockThread, &Lock, "lock"); void *pThread = thread_init(LockThread, &Lock, "lock");
lock_unlock(Lock); Lock.unlock();
thread_wait(pThread); thread_wait(pThread);
lock_destroy(Lock);
} }