MCPcopy Create free account
hub / github.com/GNOME/gjs / wrapped_gobj_toggle_notify

Method wrapped_gobj_toggle_notify

gi/object.cpp:2269–2330  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

2267}
2268
2269void ObjectInstance::wrapped_gobj_toggle_notify(void* instance, GObject*,
2270 gboolean is_last_ref) {
2271 bool toggle_up_queued, toggle_down_queued;
2272 auto* self = static_cast<ObjectInstance*>(instance);
2273
2274 GjsContextPrivate* gjs = GjsContextPrivate::from_current_context();
2275 if (gjs->destroying()) {
2276 // Do nothing here - we're in the process of disassociating the objects.
2277 return;
2278 }
2279
2280 /* We only want to touch javascript from one thread. If we're not in that
2281 * thread, then we need to defer processing to it.
2282 *
2283 * In case we're toggling up (and thus rooting the JS object) we also need
2284 * to take care if GC is running. The marking side of it is taken care by
2285 * JS::Heap, which we use in GjsMaybeOwned, so we're safe. As for sweeping,
2286 * it is too late: the JS object is dead, and attempting to keep it alive
2287 * would soon crash the process. Plus, if we touch the JSAPI from another
2288 * thread, libmozjs aborts in most cases when in debug mode. Thus, we drain
2289 * the toggle queue when GC starts, in order to prevent this from happening.
2290 *
2291 * In practice, a toggle up during JS finalize can only happen for temporary
2292 * refs/unrefs of objects that are garbage anyway, because JS code is never
2293 * invoked while the finalizers run and C code needs to clean after itself
2294 * before it returns from dispose()/finalize(). On the other hand, toggling
2295 * down is a lot simpler, because we're creating more garbage. So we just
2296 * unroot the object, make it a weak pointer, and wait for the next GC
2297 * cycle.
2298 *
2299 * Note that one would think that toggling up only happens in the main
2300 * thread (because toggling up is the result of the JS object, previously
2301 * visible only to JS code, becoming visible to the refcounted C world), but
2302 * because of weird weak singletons like g_bus_get_sync() objects can see
2303 * toggle-ups from different threads too.
2304 */
2305 bool is_main_thread = gjs->is_owner_thread();
2306
2307 auto toggle_queue = ToggleQueue::get_default();
2308 std::tie(toggle_down_queued, toggle_up_queued) =
2309 toggle_queue->is_queued(self);
2310 bool anything_queued = toggle_up_queued || toggle_down_queued;
2311
2312 if (is_last_ref) {
2313 // We've transitioned from 2 -> 1 references. The JSObject is rooted and
2314 // we need to unroot it so it can be garbage collected
2315 if (is_main_thread && !anything_queued) {
2316 self->toggle_down();
2317 } else {
2318 toggle_queue->enqueue(self, ToggleQueue::DOWN, toggle_handler);
2319 }
2320 } else {
2321 // We've transitioned from 1 -> 2 references. The JSObject associated
2322 // with the GObject is not rooted, but it needs to be. We'll root it.
2323 if (is_main_thread && !anything_queued &&
2324 !JS::RuntimeHeapIsCollecting()) {
2325 self->toggle_up();
2326 } else {

Callers

nothing calls this directly

Calls 6

toggle_downMethod · 0.95
toggle_upMethod · 0.95
destroyingMethod · 0.80
is_owner_threadMethod · 0.80
is_queuedMethod · 0.80
enqueueMethod · 0.80

Tested by

no test coverage detected