libkazv
Loading...
Searching...
No Matches
thread-safety-helper.hpp
Go to the documentation of this file.
1/*
2 * This file is part of libkazv.
3 * SPDX-FileCopyrightText: 2020-2021 Tusooa Zhu <tusooa@kazv.moe>
4 * SPDX-License-Identifier: AGPL-3.0-or-later
5 */
6
7#pragma once
8
9#include <libkazv-config.hpp>
10
11#if LIBKAZV_BUILT_WITH_DEBUG
12#ifndef KAZV_USE_THREAD_SAFETY_HELPER
13#define KAZV_USE_THREAD_SAFETY_HELPER
14#endif
15#endif
16
17#ifdef KAZV_USE_THREAD_SAFETY_HELPER
18#include <mutex>
19struct ThreadNotMatchException // Don't derive from std::exception to avoid catch-all catch clauses
20{
21 std::string m_what;
22
23 std::string what() const;
24};
25
26struct EventLoopThreadIdKeeper
27{
28 mutable std::mutex m_mutex;
29 std::optional<std::thread::id> m_id;
30
32 void set(std::thread::id id) {
33 std::lock_guard<std::mutex> g(m_mutex);
34 m_id = id;
35 }
36
37 std::optional<std::thread::id> get() const {
38 std::lock_guard<std::mutex> g(m_mutex);
39 return m_id;
40 }
41};
42#define KAZV_THREAD_ID_VAR _threadSafetyHelper_threadId
43#define KAZV_ON_EVENT_LOOP_VAR _threadSafetyHelper_onEventLoop
44#define KAZV_EVENT_LOOP_THREAD_ID_KEEPER_VAR _threadSafetyHelper_eventLoopThreadIdKeeper
45#define KAZV_DECLARE_THREAD_ID() bool KAZV_ON_EVENT_LOOP_VAR{false}; \
46 std::thread::id KAZV_THREAD_ID_VAR = std::this_thread::get_id();
47#define KAZV_DECLARE_EVENT_LOOP_THREAD_ID_KEEPER(_initializer) \
48 EventLoopThreadIdKeeper *KAZV_EVENT_LOOP_THREAD_ID_KEEPER_VAR = _initializer
49//#define KAZV_INIT_THREAD_ID_FROM_KEEPER() KAZV_THREAD_ID_VAR(KAZV_EVENT_LOOP_THREAD_ID_KEEPER_VAR.get())
50#define KAZV_VERIFY_THREAD_ID() \
51 do { \
52 auto _threadSafetyHelper_local_idActual = std::this_thread::get_id(); \
53 \
54 if (KAZV_ON_EVENT_LOOP_VAR) { \
55 auto _threadSafetyHelper_local_idExpected = \
56 KAZV_EVENT_LOOP_THREAD_ID_KEEPER_VAR ? KAZV_EVENT_LOOP_THREAD_ID_KEEPER_VAR->get() : std::nullopt; \
57 auto cond = \
58 _threadSafetyHelper_local_idExpected.has_value() \
59 ? _threadSafetyHelper_local_idExpected.value() == _threadSafetyHelper_local_idActual \
60 /* if the id is not set yet it means the event loop is not yet run, so it does not matter anyway */ \
61 : true; \
62 if (!cond) { \
63 throw ThreadNotMatchException{"Current object belongs to the event loop, but method is called outside the event loop"}; \
64 } \
65 } else { \
66 if (! (KAZV_THREAD_ID_VAR == _threadSafetyHelper_local_idActual)) { \
67 throw ThreadNotMatchException{"Current thread id does not match the id of the thread where it belongs"}; \
68 } \
69 } \
70 } while (false)
71
72#else
73#define KAZV_DECLARE_THREAD_ID()
74#define KAZV_VERIFY_THREAD_ID()
75#define KAZV_DECLARE_EVENT_LOOP_THREAD_ID_KEEPER(_initializer)
76#endif