Skip to content

Commit

Permalink
Document interaction with GIL
Browse files Browse the repository at this point in the history
Closes #9.
  • Loading branch information
vorner committed Oct 23, 2021
1 parent 1785055 commit 5ef7ae0
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.4.1

* Docs: Point out the need to handle GIL in around threads.

# 0.4.0

* Upgrade to pyo3 0.14.
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pyo3-log"
version = "0.4.0"
version = "0.4.1"
authors = ["Michal 'vorner' Vaner <[email protected]>"]
description = "Logging bridge from pyo3 native extension to python"
documentation = "https://docs.rs/pyo3-log"
Expand Down
2 changes: 1 addition & 1 deletion examples/hello_world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ crate-type = ["cdylib"]

[dependencies]
log = "~0.4"
pyo3 = { version = "~0.13", features = ["extension-module"] }
pyo3 = { version = "~0.14", features = ["extension-module"] }
pyo3-log = { path = "../.." }
52 changes: 52 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,58 @@
//!
//! Log levels are mapped to the same-named ones. The [`Trace`][Level::Trace] doesn't exist on the
//! Python side, but is mapped to a level with value 5.
//!
//! # Interaction with Python GIL
//!
//! Under the hook, the logging routines call into Python. That means they need to acquire the
//! Global Interpreter Lock of Python.
//!
//! This has several consequences. One of them is the above mentioned performance considerations.
//!
//! The other is a risk of deadlocks if threads are used from within the extension code without
//! releasing the GIL.
//!
//! ```rust
//! use std::thread;
//! use log::info;
//! use pyo3::prelude::*;
//!
//! #[pyfunction]
//! fn deadlock() {
//! info!("This logs fine");
//!
//! let background_thread = thread::spawn(|| {
//! info!("This'll deadlock");
//! });
//!
//! background_thread.join().unwrap();
//! }
//! # let _ = deadlock;
//! ```
//!
//! The above code will deadlock, because the `info` call in the background thread needs the GIL
//! that's held by the deadlock function. One needs to give up the GIL to let the other threads
//! run, something like this:
//!
//! ```rust
//! use std::thread;
//! use log::info;
//! use pyo3::prelude::*;
//!
//! #[pyfunction]
//! fn dont_deadlock(py: Python<'_>) {
//! info!("This logs fine");
//!
//! py.allow_threads(|| {
//! let background_thread = thread::spawn(|| {
//! info!("This'll not deadlock");
//! });
//!
//! background_thread.join().unwrap();
//! });
//! }
//! # let _ = dont_deadlock;
//! ```
use std::cmp;
use std::collections::HashMap;
Expand Down

0 comments on commit 5ef7ae0

Please sign in to comment.