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: 2017 Endless Mobile, Inc.
4 : : // SPDX-FileCopyrightText: 2021 Canonical Ltd.
5 : : // SPDX-FileContributor: Authored by: Philip Chimento <philip@endlessm.com>
6 : : // SPDX-FileContributor: Philip Chimento <philip.chimento@gmail.com>
7 : : // SPDX-FileContributor: Marco Trevisan <marco.trevisan@canonical.com>
8 : :
9 : : #ifndef GI_TOGGLE_H_
10 : : #define GI_TOGGLE_H_
11 : :
12 : : #include <config.h>
13 : :
14 : : #include <atomic>
15 : : #include <deque>
16 : : #include <thread>
17 : : #include <utility> // for pair
18 : :
19 : : #include <glib.h> // for gboolean
20 : :
21 : : class ObjectInstance;
22 : : namespace Gjs {
23 : : namespace Test {
24 : : struct ToggleQueue;
25 : : }
26 : : }
27 : :
28 : : /* Thread-safe queue for enqueueing toggle-up or toggle-down events on GObjects
29 : : * from any thread. For more information, see object.cpp, comments near
30 : : * wrapped_gobj_toggle_notify(). */
31 : : class ToggleQueue {
32 : : public:
33 : : enum Direction {
34 : : DOWN,
35 : : UP
36 : : };
37 : :
38 : : using Handler = void (*)(ObjectInstance*, Direction);
39 : :
40 : : private:
41 : : friend Gjs::Test::ToggleQueue;
42 : : struct Item {
43 : : Item() {}
44 : 61 : Item(ObjectInstance* o, Direction d) : object(o), direction(d) {}
45 : : ObjectInstance* object;
46 : : ToggleQueue::Direction direction;
47 : : };
48 : :
49 : : struct Locked {
50 : 8462 : explicit Locked(ToggleQueue* queue) { queue->lock(); }
51 : 8462 : ~Locked() { get_default_unlocked().maybe_unlock(); }
52 : 8426 : ToggleQueue* operator->() { return &get_default_unlocked(); }
53 : : };
54 : :
55 : : std::deque<Item> q;
56 : : std::atomic_bool m_shutdown = ATOMIC_VAR_INIT(false);
57 : :
58 : : unsigned m_idle_id = 0;
59 : : Handler m_toggle_handler = nullptr;
60 : : std::atomic<std::thread::id> m_holder = std::thread::id();
61 : : unsigned m_holder_ref_count = 0;
62 : :
63 : : void lock();
64 : : void maybe_unlock();
65 : : [[nodiscard]] bool is_locked() const {
66 : : return m_holder != std::thread::id();
67 : : }
68 : 17218 : [[nodiscard]] bool owns_lock() const {
69 : 17218 : return m_holder == std::this_thread::get_id();
70 : : }
71 : :
72 : : [[nodiscard]] std::deque<Item>::iterator find_operation_locked(
73 : : const ObjectInstance* obj, Direction direction);
74 : :
75 : : [[nodiscard]] std::deque<Item>::const_iterator find_operation_locked(
76 : : const ObjectInstance* obj, Direction direction) const;
77 : :
78 : : static gboolean idle_handle_toggle(void *data);
79 : : static void idle_destroy_notify(void *data);
80 : :
81 : 25297 : [[nodiscard]] static ToggleQueue& get_default_unlocked() {
82 [ + + + - ]: 25297 : static ToggleQueue the_singleton;
83 : 25297 : return the_singleton;
84 : : }
85 : :
86 : : public:
87 : : /* These two functions return a pair DOWN, UP signifying whether toggles
88 : : * are / were queued. is_queued() just checks and does not modify. */
89 : : [[nodiscard]] std::pair<bool, bool> is_queued(ObjectInstance* obj) const;
90 : : /* Cancels pending toggles and returns whether any were queued. */
91 : : std::pair<bool, bool> cancel(ObjectInstance* obj);
92 : :
93 : : /* Pops a toggle from the queue and processes it. Call this if you don't
94 : : * want to wait for it to be processed in idle time. Returns false if queue
95 : : * is empty. */
96 : : bool handle_toggle(Handler handler);
97 : : void handle_all_toggles(Handler handler);
98 : :
99 : : /* After calling this, the toggle queue won't accept any more toggles. Only
100 : : * intended for use when destroying the JSContext and breaking the
101 : : * associations between C and JS objects. */
102 : : void shutdown(void);
103 : :
104 : : /* Queues a toggle to be processed in idle time. */
105 : : void enqueue(ObjectInstance* obj, Direction direction, Handler handler);
106 : :
107 : 8409 : [[nodiscard]] static Locked get_default() {
108 : 8409 : return Locked(&get_default_unlocked());
109 : : }
110 : : };
111 : :
112 : : #endif // GI_TOGGLE_H_
|