2015-04-19 03:22:03 +00:00
|
|
|
// Copyright (c) 2015 Daniel Grunwald
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
|
|
// software and associated documentation files (the "Software"), to deal in the Software
|
|
|
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
|
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
|
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be included in all copies or
|
|
|
|
// substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
|
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
|
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
// DEALINGS IN THE SOFTWARE.
|
|
|
|
|
2015-01-04 04:50:28 +00:00
|
|
|
use std::sync::{Once, ONCE_INIT};
|
2015-01-04 23:07:31 +00:00
|
|
|
use ffi;
|
2015-06-27 21:49:53 +00:00
|
|
|
use python::Python;
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2015-01-04 04:50:28 +00:00
|
|
|
static START: Once = ONCE_INIT;
|
2015-01-05 16:05:53 +00:00
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Prepares the use of Python in a free-threaded context.
|
2015-04-18 20:20:19 +00:00
|
|
|
///
|
2015-06-27 20:45:35 +00:00
|
|
|
/// If the Python interpreter is not already initialized, this function
|
2015-04-18 20:20:19 +00:00
|
|
|
/// will initialize it with disabled signal handling
|
2015-06-27 20:45:35 +00:00
|
|
|
/// (Python will not raise the `KeyboardInterrupt` exception).
|
2015-04-18 20:20:19 +00:00
|
|
|
/// Python signal handling depends on the notion of a 'main thread', which must be
|
2015-06-27 20:45:35 +00:00
|
|
|
/// the thread that initializes the Python interpreter.
|
|
|
|
///
|
|
|
|
/// If both the Python interpreter and Python threading are already initialized,
|
|
|
|
/// this function has no effect.
|
|
|
|
///
|
|
|
|
/// # Panic
|
|
|
|
/// If the Python interpreter is initialized but Python threading is not,
|
|
|
|
/// a panic occurs.
|
|
|
|
/// It is not possible to safely access the Python runtime unless the main
|
|
|
|
/// thread (the thread which originally initialized Python) also initializes
|
|
|
|
/// threading.
|
|
|
|
///
|
|
|
|
/// When writing an extension module, the `py_module_initializer!` macro
|
|
|
|
/// will ensure that Python threading is initialized.
|
|
|
|
///
|
2015-01-04 04:50:28 +00:00
|
|
|
pub fn prepare_freethreaded_python() {
|
2015-06-27 20:45:35 +00:00
|
|
|
// Protect against race conditions when Python is not yet initialized
|
2015-01-04 19:11:18 +00:00
|
|
|
// and multiple threads concurrently call 'prepare_freethreaded_python()'.
|
2015-06-27 20:45:35 +00:00
|
|
|
// Note that we do not protect against concurrent initialization of the Python runtime
|
|
|
|
// by other users of the Python C API.
|
2015-01-04 04:50:28 +00:00
|
|
|
START.call_once(|| unsafe {
|
2015-01-04 19:11:18 +00:00
|
|
|
if ffi::Py_IsInitialized() != 0 {
|
2015-06-27 20:45:35 +00:00
|
|
|
// If Python is already initialized, we expect Python threading to also be initialized,
|
|
|
|
// as we can't make the existing Python main thread acquire the GIL.
|
2015-01-04 19:11:18 +00:00
|
|
|
assert!(ffi::PyEval_ThreadsInitialized() != 0);
|
|
|
|
} else {
|
2015-06-27 20:45:35 +00:00
|
|
|
// If Python isn't initialized yet, we expect that Python threading isn't initialized either.
|
2015-01-04 19:11:18 +00:00
|
|
|
assert!(ffi::PyEval_ThreadsInitialized() == 0);
|
2015-06-27 20:45:35 +00:00
|
|
|
// Initialize Python.
|
2015-01-04 19:11:18 +00:00
|
|
|
// We use Py_InitializeEx() with initsigs=0 to disable Python signal handling.
|
|
|
|
// Signal handling depends on the notion of a 'main thread', which doesn't exist in this case.
|
2015-06-27 20:45:35 +00:00
|
|
|
// Note that the 'main thread' notion in Python isn't documented properly;
|
|
|
|
// and running Python without one is not officially supported.
|
2015-01-04 19:11:18 +00:00
|
|
|
ffi::Py_InitializeEx(0);
|
|
|
|
ffi::PyEval_InitThreads();
|
|
|
|
// PyEval_InitThreads() will acquire the GIL,
|
|
|
|
// but we don't want to hold it at this point
|
2015-01-04 04:50:28 +00:00
|
|
|
// (it's not acquired in the other code paths)
|
2015-01-04 19:11:18 +00:00
|
|
|
// So immediately release the GIL:
|
|
|
|
let _thread_state = ffi::PyEval_SaveThread();
|
2015-06-27 20:45:35 +00:00
|
|
|
// Note that the PyThreadState returned by PyEval_SaveThread is also held in TLS by the Python runtime,
|
2015-01-04 19:11:18 +00:00
|
|
|
// and will be restored by PyGILState_Ensure.
|
2015-01-04 04:50:28 +00:00
|
|
|
}
|
|
|
|
});
|
2015-01-05 16:05:53 +00:00
|
|
|
}
|
|
|
|
|
2015-01-04 23:07:31 +00:00
|
|
|
/// RAII type that represents an acquired GIL.
|
2015-06-27 20:45:35 +00:00
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// use cpython::Python;
|
|
|
|
///
|
|
|
|
/// {
|
|
|
|
/// let gil_guard = Python::acquire_gil();
|
|
|
|
/// let py = gil_guard.python();
|
|
|
|
/// } // GIL is released when gil_guard is dropped
|
|
|
|
/// ```
|
2015-01-04 23:07:31 +00:00
|
|
|
#[must_use]
|
|
|
|
pub struct GILGuard {
|
2015-01-12 02:17:29 +00:00
|
|
|
gstate: ffi::PyGILState_STATE
|
2015-01-04 23:07:31 +00:00
|
|
|
}
|
|
|
|
|
2015-04-18 20:20:19 +00:00
|
|
|
/// GILGuard is not Send because the GIL must be released
|
|
|
|
/// by the same thread that acquired it.
|
2015-01-12 02:17:29 +00:00
|
|
|
impl !Send for GILGuard {}
|
2015-06-27 20:45:35 +00:00
|
|
|
|
|
|
|
/// GILGuard is not Sync because only the thread that
|
|
|
|
/// acquired the GIL may access the Python interpreter.
|
2015-06-24 22:02:56 +00:00
|
|
|
impl !Sync for GILGuard {}
|
2015-01-11 03:21:05 +00:00
|
|
|
|
2015-04-18 20:20:19 +00:00
|
|
|
/// The Drop implementation for GILGuard will release the GIL.
|
2015-01-04 23:07:31 +00:00
|
|
|
impl Drop for GILGuard {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe { ffi::PyGILState_Release(self.gstate) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl GILGuard {
|
|
|
|
/// Acquires the global interpreter lock, which allows access to the Python runtime.
|
2015-06-27 20:45:35 +00:00
|
|
|
///
|
|
|
|
/// If the Python runtime is not already initialized, this function will initialize it.
|
|
|
|
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
|
2015-01-04 23:07:31 +00:00
|
|
|
pub fn acquire() -> GILGuard {
|
|
|
|
::pythonrun::prepare_freethreaded_python();
|
|
|
|
let gstate = unsafe { ffi::PyGILState_Ensure() }; // acquire GIL
|
2015-01-12 02:17:29 +00:00
|
|
|
GILGuard { gstate: gstate }
|
2015-01-04 23:07:31 +00:00
|
|
|
}
|
2015-04-18 20:20:19 +00:00
|
|
|
|
|
|
|
/// Retrieves the marker type that proves that the GIL was acquired.
|
2015-06-21 22:35:01 +00:00
|
|
|
#[inline]
|
2015-01-04 23:07:31 +00:00
|
|
|
pub fn python<'p>(&'p self) -> Python<'p> {
|
|
|
|
unsafe { Python::assume_gil_acquired() }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Mutex-like wrapper object for data that is protected by the Python GIL.
|
|
|
|
///
|
|
|
|
/// # Example
|
|
|
|
/// ```
|
|
|
|
/// use std::cell::Cell;
|
|
|
|
/// use cpython::{Python, GILProtected};
|
|
|
|
///
|
|
|
|
/// let data = GILProtected::new(Cell::new(0));
|
|
|
|
///
|
|
|
|
/// {
|
|
|
|
/// let gil_guard = Python::acquire_gil();
|
|
|
|
/// let cell = data.get(gil_guard.python());
|
|
|
|
/// cell.set(cell.get() + 1);
|
|
|
|
/// }
|
|
|
|
/// ```
|
2015-06-21 22:35:01 +00:00
|
|
|
pub struct GILProtected<T> {
|
|
|
|
data: T
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe impl<T: Send> Send for GILProtected<T> { }
|
2015-06-27 20:45:35 +00:00
|
|
|
|
|
|
|
/// Because `GILProtected` ensures that the contained data
|
|
|
|
/// is only accessed while the GIL is acquired,
|
|
|
|
/// it can implement `Sync` even if the contained data
|
|
|
|
/// does not.
|
2015-06-21 22:35:01 +00:00
|
|
|
unsafe impl<T: Send> Sync for GILProtected<T> { }
|
|
|
|
|
|
|
|
impl <T> GILProtected<T> {
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Creates a new instance of `GILProtected`.
|
2015-06-21 22:35:01 +00:00
|
|
|
#[inline]
|
2016-03-05 00:16:54 +00:00
|
|
|
pub const fn new(data: T) -> GILProtected<T> {
|
2015-06-21 22:35:01 +00:00
|
|
|
GILProtected { data: data }
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Returns a shared reference to the data stored in the `GILProtected`.
|
|
|
|
///
|
|
|
|
/// Requires a `Python` instance as proof that the GIL is acquired.
|
2015-06-21 22:35:01 +00:00
|
|
|
#[inline]
|
2015-06-27 21:49:53 +00:00
|
|
|
pub fn get<'a>(&'a self, _py: Python<'a>) -> &'a T {
|
2015-06-21 22:35:01 +00:00
|
|
|
&self.data
|
|
|
|
}
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
/// Consumes the `GILProtected`, returning the wrapped value.
|
2015-06-21 22:35:01 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn into_inner(self) -> T {
|
|
|
|
self.data
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|