morph
0.1.0
Asynchronous bridge between GUI thread and business models
Toggle main menu visibility
Loading...
Searching...
No Matches
owner_probe.hpp
Go to the documentation of this file.
1
// SPDX-License-Identifier: Apache-2.0
2
3
#pragma once
4
#include <atomic>
5
#include <cassert>
6
#include <core/async/IExecutor.hpp>
7
#include <cstdio>
8
9
/// @file
10
/// @brief The check every loop-owned body makes on entry: "am I on my owner?"
11
///
12
/// A component whose state belongs to one executor (an `IoLoop`'s loop, for the
13
/// transports, the timeout scheduler and the network monitor) calls
14
/// `noteOwner(site, owner)` at the top of each body that touches that state. In
15
/// a debug build it asserts the calling thread is inside a task of `owner`.
16
///
17
/// A test replaces the assertion with an observation: it installs a probe, and
18
/// every `noteOwner` hands the probe the site and the owner instead of
19
/// asserting. The probe reads the executor scope itself, so a test proves the
20
/// body ran posted without trusting the component's own answer, and a test that
21
/// puts the wrong behaviour back sees a failed check rather than an abort.
22
23
namespace
morph::exec::detail {
24
25
/// @brief What a test installs to observe owner checks: called with the site
26
/// name and the owner the body expects, on the thread running the body.
27
using
OwnerProbe = void (*)(
char
const
* site, ::core::async::IExecutor
const
& owner)
noexcept
;
28
29
/// @brief The installed probe, or null.
30
/// @return The process-wide probe slot.
31
[[nodiscard]]
inline
std::atomic<OwnerProbe>& ownerProbe() noexcept {
32
static
std::atomic<OwnerProbe> probe{
nullptr
};
33
return
probe;
34
}
35
36
/// @brief Records that @p site is running a body that must run on @p owner.
37
///
38
/// With a probe installed, hands it the site and the owner. Otherwise asserts,
39
/// in a debug build, that a task of @p owner is running on the calling thread.
40
/// @param site A static string naming the body, e.g. `"TimeoutScheduler::schedule"`.
41
/// @param owner The executor the body's state belongs to.
42
/// @param onOwner Whether the component considers itself on its owner; what a
43
/// debug build asserts when no probe is installed.
44
inline
void
noteOwner(
char
const
* site, ::core::async::IExecutor
const
& owner,
bool
onOwner)
noexcept
{
45
if
(OwnerProbe
const
probe = ownerProbe().load(std::memory_order_acquire); probe !=
nullptr
) {
46
probe(site, owner);
47
return
;
48
}
49
#ifndef NDEBUG
50
// The assertion's text is fixed; the site says which misuse it was: off the owner, or another the owner's
51
// component reports through here, such as a duplicate row key.
52
if
(!onOwner) {
53
static_cast<
void
>
(std::fputs(
"morph: "
, stderr));
54
static_cast<
void
>
(std::fputs(site, stderr));
55
static_cast<
void
>
(std::fputs(
"\n"
, stderr));
56
}
57
#endif
58
assert(onOwner &&
"a loop-owned body ran off its owner's thread"
);
59
static_cast<
void
>
(onOwner);
60
}
61
62
}
// namespace morph::exec::detail
morph
core
detail
owner_probe.hpp
Generated by
1.17.0