Branch data Line data Source code
1 : : /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2 : : // SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
3 : : // SPDX-FileCopyrightText: 2021 Evan Welsh <contact@evanwelsh.com>
4 : :
5 : : #pragma once
6 : :
7 : : #include <config.h>
8 : :
9 : : #include <glib.h>
10 : :
11 : : #include "util/log.h"
12 : :
13 : : class GjsContextPrivate;
14 : :
15 : : namespace Gjs {
16 : :
17 : : class MainLoop {
18 : : // grefcounts start at one and become invalidated when they are decremented
19 : : // to zero. So the actual hold count is equal to the "ref" count minus 1.
20 : : // We nonetheless use grefcount here because it takes care of dealing with
21 : : // integer overflow for us.
22 : : grefcount m_hold_count;
23 : : bool m_exiting;
24 : :
25 : 1325 : void debug(const char* msg) {
26 : 1325 : gjs_debug(GJS_DEBUG_MAINLOOP, "Main loop instance %p: %s", this, msg);
27 : 1325 : }
28 : :
29 : 1401 : [[nodiscard]] bool can_block() {
30 : : // Don't block if exiting
31 [ - + ]: 1401 : if (m_exiting)
32 : 0 : return false;
33 : :
34 : 1401 : g_assert(!g_ref_count_compare(&m_hold_count, 0) &&
35 : : "main loop released too many times");
36 : :
37 : : // If the reference count is not zero or one, the loop is being held.
38 : 1401 : return !g_ref_count_compare(&m_hold_count, 1);
39 : : }
40 : :
41 : 4 : void exit() {
42 : 4 : m_exiting = true;
43 : :
44 : : // Reset the reference count to 1 to exit
45 : 4 : g_ref_count_init(&m_hold_count);
46 : 4 : }
47 : :
48 : : public:
49 : 235 : MainLoop() : m_exiting(false) { g_ref_count_init(&m_hold_count); }
50 : 233 : ~MainLoop() {
51 : 233 : g_assert(g_ref_count_compare(&m_hold_count, 1) &&
52 : : "mismatched hold/release on main loop");
53 : 233 : }
54 : :
55 : 387 : void hold() {
56 : : // Don't allow new holds after exit() is called
57 [ + + ]: 387 : if (m_exiting)
58 : 1 : return;
59 : :
60 : 386 : debug("hold");
61 : 386 : g_ref_count_inc(&m_hold_count);
62 : : }
63 : :
64 : 384 : void release() {
65 : : // Ignore releases after exit(), exit() resets the refcount
66 [ - + ]: 384 : if (m_exiting)
67 : 0 : return;
68 : :
69 : 384 : debug("release");
70 : 384 : bool zero [[maybe_unused]] = g_ref_count_dec(&m_hold_count);
71 : 384 : g_assert(!zero && "main loop released too many times");
72 : : }
73 : :
74 : : [[nodiscard]] bool spin(GjsContextPrivate*);
75 : : };
76 : :
77 : : }; // namespace Gjs
|