pyo3/src/pythonrun.rs

125 lines
5 KiB
Rust
Raw Normal View History

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};
use ffi;
2015-06-21 22:35:01 +00:00
use python::{Python, ToPythonPointer};
use objects::PyObject;
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-01-04 04:50:28 +00:00
/// Prepares the use of python in a free-threaded context.
2015-04-18 20:20:19 +00:00
///
/// If the python interpreter is not already initialized, this function
/// will initialize it with disabled signal handling
/// (python will not raise the `KeyboardInterrupt` exception).
/// Python signal handling depends on the notion of a 'main thread', which must be
/// the thread that initializes the python interpreter.
2015-01-04 04:50:28 +00:00
pub fn prepare_freethreaded_python() {
2015-01-04 19:11:18 +00:00
// Protect against race conditions when python is not yet initialized
// and multiple threads concurrently call 'prepare_freethreaded_python()'.
// 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 {
// 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.
assert!(ffi::PyEval_ThreadsInitialized() != 0);
} else {
// If python isn't initialized yet, we expect that python threading isn't initialized either.
assert!(ffi::PyEval_ThreadsInitialized() == 0);
// Initialize python.
// 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.
// Note that the 'main thread' notion in python isn't documented properly;
// and running python without one is not officially supported.
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();
// Note that the PyThreadState returned by PyEval_SaveThread is also held in TLS by the python runtime,
// and will be restored by PyGILState_Ensure.
2015-01-04 04:50:28 +00:00
}
});
2015-01-05 16:05:53 +00:00
}
/// RAII type that represents an acquired GIL.
#[must_use]
pub struct GILGuard {
2015-01-12 02:17:29 +00:00
gstate: ffi::PyGILState_STATE
}
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 {}
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.
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.
/// If the python runtime is not already initialized, this function will initialize it.
/// Note that in this case, the python runtime will not have any main thread, and will
/// not deliver signals like KeyboardInterrupt.
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-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]
pub fn python<'p>(&'p self) -> Python<'p> {
unsafe { Python::assume_gil_acquired() }
}
}
2015-06-21 22:35:01 +00:00
/// Mutex-like wrapper object for data that is protected by the python GIL.
pub struct GILProtected<T> {
data: T
}
unsafe impl<T: Send> Send for GILProtected<T> { }
unsafe impl<T: Send> Sync for GILProtected<T> { }
impl <T> GILProtected<T> {
#[inline]
pub fn new(data: T) -> GILProtected<T> {
2015-06-21 22:35:01 +00:00
GILProtected { data: data }
}
#[inline]
pub fn get<'p>(&'p self, py: Python<'p>) -> &'p T {
&self.data
}
#[inline]
pub fn into_inner(self) -> T {
self.data
}
}