| 143 | } |
| 144 | |
| 145 | void ToggleQueue::enqueue(ObjectInstance* obj, ToggleQueue::Direction direction, |
| 146 | ToggleQueue::Handler handler) { |
| 147 | g_assert(owns_lock() && "Unsafe access to queue"); |
| 148 | |
| 149 | if (G_UNLIKELY(m_shutdown)) { |
| 150 | gjs_debug(GJS_DEBUG_GOBJECT, |
| 151 | "Enqueuing GObject %p to toggle %s after " |
| 152 | "shutdown, probably from another thread (%p).", |
| 153 | obj->ptr(), direction == UP ? "UP" : "DOWN", g_thread_self()); |
| 154 | return; |
| 155 | } |
| 156 | |
| 157 | auto other_item = find_operation_locked(obj, direction == UP ? DOWN : UP); |
| 158 | if (other_item != q.end()) { |
| 159 | if (direction == UP) { |
| 160 | debug("enqueue UP, dequeuing already DOWN object", obj); |
| 161 | } else { |
| 162 | debug("enqueue DOWN, dequeuing already UP object", obj); |
| 163 | } |
| 164 | q.erase(other_item); |
| 165 | return; |
| 166 | } |
| 167 | |
| 168 | /* Only keep an unowned reference on the object here, since if we're here, |
| 169 | * the JSObject wrapper already has a reference and we don't want to cause |
| 170 | * any weak notify in case it has lost one already in the main thread. So |
| 171 | * let's just save the pointer to keep track of the object till we don't |
| 172 | * handle this toggle. |
| 173 | * |
| 174 | * We rely on objects cancelling the queue in case an object gets finalized |
| 175 | * earlier than we've processed it. |
| 176 | */ |
| 177 | q.emplace_back(obj, direction); |
| 178 | |
| 179 | if (direction == UP) { |
| 180 | debug("enqueue UP", obj); |
| 181 | } else { |
| 182 | debug("enqueue DOWN", obj); |
| 183 | } |
| 184 | |
| 185 | if (m_idle_id) { |
| 186 | g_assert(m_toggle_handler == handler && |
| 187 | "Should always enqueue with the same handler"); |
| 188 | return; |
| 189 | } |
| 190 | |
| 191 | m_toggle_handler = handler; |
| 192 | m_idle_id = g_idle_add_full(G_PRIORITY_HIGH, idle_handle_toggle, this, |
| 193 | idle_destroy_notify); |
| 194 | } |