{"record":{"id":"8a3c73c98683f4b1","repo":"gfx-rs/wgpu","slug":"could-not-lock-adapter-context-this-is-most-likel-8a3c73","errorCode":null,"errorMessage":"Could not lock adapter context. This is most-likely a deadlock.","messagePattern":"Could not lock adapter context\\. This is most-likely a deadlock\\.","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"wgpu-hal/src/gles/wgl.rs","lineNumber":70,"sourceCode":"    }\n\n    pub fn raw_context(&self) -> *mut c_void {\n        match self.inner.lock().context {\n            Some(ref wgl) => wgl.context.0,\n            None => ptr::null_mut(),\n        }\n    }\n\n    /// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to\n    /// do rendering.\n    #[track_caller]\n    pub fn lock(&self) -> AdapterContextLock<'_> {\n        let inner = self\n            .inner\n            // Don't lock forever. If it takes longer than 1 second to get the lock we've got a\n            // deadlock and should panic to show where we got stuck\n            .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))\n            .expect(\"Could not lock adapter context. This is most-likely a deadlock.\");\n\n        if let Some(wgl) = &inner.context {\n            wgl.make_current(inner.device.dc).unwrap()\n        };\n\n        AdapterContextLock { inner }\n    }\n\n    /// Obtain a lock to the WGL context and get handle to the [`glow::Context`] that can be used to\n    /// do rendering.\n    ///\n    /// Unlike [`lock`](Self::lock), this accepts a device to pass to `make_current` and exposes the error\n    /// when `make_current` fails.\n    #[track_caller]\n    fn lock_with_dc(&self, device: Gdi::HDC) -> windows::core::Result<AdapterContextLock<'_>> {\n        let inner = self\n            .inner\n            .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS))","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/gfx-rs/wgpu/blob/3e11ff59bf3f9795d285ecc045014089640d7248/wgpu-hal/src/gles/wgl.rs#L52-L88","documentation":"`AdapterContext::lock` on the WGL (Windows GL) backend tries to acquire the adapter's shared GL context mutex with a 1-second timeout (`try_lock_for`). If the lock cannot be acquired within `CONTEXT_LOCK_TIMEOUT_SECS`, it panics with this message to surface a suspected deadlock instead of hanging forever. The adapter context is shared between all devices/surfaces of one adapter, so any thread holding it longer than ~1 second triggers this in another thread.","triggerScenarios":"Any public API that needs the GL context (buffer/texture/queue operations, instance->adapter enumeration) while another thread holds `AdapterContextLock` for more than 1 second, or recursively locking the adapter context on the same thread (std sync RwLock/Mutex non-reentrant), or a lock leaked (not dropped) on another thread.","commonSituations":"Calling wgpu GL APIs from the same thread that already holds a lock (re-entrant call e.g. inside a winit callback that itself calls queue.submit); holding the lock across an await point; doing long GL work inside a closure that keeps `AdapterContextLock` alive; window teardown racing with rendering on another thread.","solutions":["Audit for recursive locking: never call another wgpu method that takes the context while you already hold `AdapterContextLock` (e.g. inside `lock()`-based accessors like `GlTexture::raw`).","Ensure every `AdapterContextLock` is dropped promptly; never hold it across `.await` or long-running GL calls.","Route all GL/wgpu calls for that adapter through a single thread or serialize them with your own synchronization so contention stays below the 1s timeout.","If contention is legitimately heavy, restructure to drop-and-reacquire frequently, or file an issue to raise `CONTEXT_LOCK_TIMEOUT_SECS` via a patched build."],"exampleFix":"// before: nested lock deadlocks (same thread, non-reentrant)\nlet tex = unsafe { texture.lock() };\nunsafe { queue.submit(...) }; // panics: submit locks the same context\n// after\nlet tex_raw = unsafe { texture.lock() }.raw().clone();\ndrop(tex_raw_owner); // ensure lock released before further wgpu calls\nunsafe { queue.submit(...) };","handlingStrategy":"validation","validationCode":"// Rust: detect re-entrant lock attempts before they deadlock\n// wgpu's AdapterContext uses a timed try_lock; emulate the guard discipline:\nfn assert_not_holding<T>(guard_slot: &Option<std::sync::MutexGuard<'_, T>>) {\n    assert!(guard_slot.is_none(), \"wgpu GL context lock already held on this thread: recursive call will deadlock\");\n}","typeGuard":"// Rust: structural guard - refuse to run wgpu calls while a lock guard exists\nstruct GlGuardScope<'a>(Option<wgpu_hal::gles::AdapterContextLock<'a>>);\nimpl<'a> GlGuardScope<'a> {\n    fn enter(&mut self, ctx: &'a wgpu_hal::gles::AdapterContext) {\n        assert!(self.0.is_none(), \"cannot nest AdapterContext locks on one thread\");\n        self.0 = Some(ctx.lock());\n    }\n}","tryCatchPattern":"// panic must be caught at the FFI/task boundary, not around every call\nlet result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    device_queue_do_work();\n}));\nmatch result {\n    Ok(v) => v,\n    Err(p) => {\n        let msg = p.downcast_ref::<String>().map(String::as_str)\n            .or_else(|| p.downcast_ref::<&str>().copied()).unwrap_or(\"\");\n        if msg.contains(\"Could not lock adapter context\") {\n            restart_gl_thread(); // rebuild device after suspected deadlock\n        } else { std::panic::resume_unwind(p); }\n    }\n}","preventionTips":["Never call wgpu methods that lock the AdapterContext while you already hold an AdapterContextLock / device.lock() guard on the same thread.","Never hold the GL context guard across an .await point; drop it before yielding.","Keep all GL work for one adapter on a dedicated thread so context acquisition is naturally serialized.","Review code that clones raw GL handles (GlTexture::raw etc.) and make sure the guard is scoped as tightly as possible."],"tags":["windows","wgl","opengl","deadlock","concurrency","panic"],"backgroundTag":"lock-timeout-deadlock","analyzedSha":"3e11ff59bf3f9795d285ecc045014089640d7248","analyzedAt":"2026-09-03T01:43:21.459Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}