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