Skip to content

Commit 3d4aaaa

Browse files
authored
thread.setname and context (#6726)
1 parent 81d89d1 commit 3d4aaaa

File tree

2 files changed

+84
-9
lines changed

2 files changed

+84
-9
lines changed

crates/stdlib/src/contextvars.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ thread_local! {
2424
mod _contextvars {
2525
use crate::vm::{
2626
AsObject, Py, PyObjectRef, PyPayload, PyRef, PyResult, VirtualMachine, atomic_func,
27-
builtins::{PyGenericAlias, PyStrRef, PyType, PyTypeRef},
27+
builtins::{PyGenericAlias, PyList, PyStrRef, PyType, PyTypeRef},
2828
class::StaticType,
2929
common::hash::PyHash,
3030
function::{ArgCallable, FuncArgs, OptionalArg},
3131
protocol::{PyMappingMethods, PySequenceMethods},
32-
types::{AsMapping, AsSequence, Constructor, Hashable, Representable},
32+
types::{AsMapping, AsSequence, Constructor, Hashable, Iterable, Representable},
3333
};
3434
use core::{
3535
cell::{Cell, RefCell, UnsafeCell},
@@ -163,7 +163,7 @@ mod _contextvars {
163163
}
164164
}
165165

166-
#[pyclass(with(Constructor, AsMapping, AsSequence))]
166+
#[pyclass(with(Constructor, AsMapping, AsSequence, Iterable))]
167167
impl PyContext {
168168
#[pymethod]
169169
fn run(
@@ -205,11 +205,6 @@ mod _contextvars {
205205
self.borrow_vars().len()
206206
}
207207

208-
#[pymethod]
209-
fn __iter__(&self) -> PyResult {
210-
unimplemented!("Context.__iter__ is currently under construction")
211-
}
212-
213208
#[pymethod]
214209
fn get(
215210
&self,
@@ -238,6 +233,15 @@ mod _contextvars {
238233
let vars = zelf.borrow_vars();
239234
vars.values().map(|value| value.to_owned()).collect()
240235
}
236+
237+
// TODO: wrong return type
238+
#[pymethod]
239+
fn items(zelf: PyRef<Self>, vm: &VirtualMachine) -> Vec<PyObjectRef> {
240+
let vars = zelf.borrow_vars();
241+
vars.iter()
242+
.map(|(k, v)| vm.ctx.new_tuple(vec![k.clone().into(), v.clone()]).into())
243+
.collect()
244+
}
241245
}
242246

243247
impl Constructor for PyContext {
@@ -281,6 +285,15 @@ mod _contextvars {
281285
}
282286
}
283287

288+
impl Iterable for PyContext {
289+
fn iter(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult {
290+
let vars = zelf.borrow_vars();
291+
let keys: Vec<PyObjectRef> = vars.keys().map(|k| k.clone().into()).collect();
292+
let list = vm.ctx.new_list(keys);
293+
<PyList as Iterable>::iter(list, vm)
294+
}
295+
}
296+
284297
#[pyattr]
285298
#[pyclass(name, traverse)]
286299
#[derive(PyPayload)]
@@ -574,6 +587,22 @@ mod _contextvars {
574587
) -> PyGenericAlias {
575588
PyGenericAlias::from_args(cls, args, vm)
576589
}
590+
591+
#[pymethod]
592+
fn __enter__(zelf: PyRef<Self>) -> PyRef<Self> {
593+
zelf
594+
}
595+
596+
#[pymethod]
597+
fn __exit__(
598+
zelf: &Py<Self>,
599+
_ty: PyObjectRef,
600+
_val: PyObjectRef,
601+
_tb: PyObjectRef,
602+
vm: &VirtualMachine,
603+
) -> PyResult<()> {
604+
ContextVar::reset(&zelf.var, zelf.to_owned(), vm)
605+
}
577606
}
578607

579608
impl Constructor for ContextToken {

crates/vm/src/stdlib/thread.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub(crate) use _thread::{
99
pub(crate) mod _thread {
1010
use crate::{
1111
AsObject, Py, PyPayload, PyRef, PyResult, VirtualMachine,
12-
builtins::{PyDictRef, PyStr, PyTupleRef, PyType, PyTypeRef},
12+
builtins::{PyDictRef, PyStr, PyStrRef, PyTupleRef, PyType, PyTypeRef},
1313
frame::FrameRef,
1414
function::{ArgCallable, Either, FuncArgs, KwArgs, OptionalArg, PySetterValue},
1515
types::{Constructor, GetAttr, Representable, SetAttr},
@@ -260,6 +260,11 @@ pub(crate) mod _thread {
260260
Ok(())
261261
}
262262

263+
#[pymethod]
264+
fn locked(&self) -> bool {
265+
self.mu.is_locked()
266+
}
267+
263268
#[pymethod]
264269
fn _is_owned(&self) -> bool {
265270
self.mu.is_owned_by_current_thread()
@@ -293,6 +298,47 @@ pub(crate) mod _thread {
293298
current_thread_id()
294299
}
295300

301+
/// Set the name of the current thread
302+
#[pyfunction]
303+
fn set_name(name: PyStrRef) {
304+
#[cfg(target_os = "linux")]
305+
{
306+
use std::ffi::CString;
307+
if let Ok(c_name) = CString::new(name.as_str()) {
308+
// pthread_setname_np on Linux has a 16-byte limit including null terminator
309+
// TODO: Potential UTF-8 boundary issue when truncating thread name on Linux.
310+
// https://github.com/RustPython/RustPython/pull/6726/changes#r2689379171
311+
let truncated = if c_name.as_bytes().len() > 15 {
312+
CString::new(&c_name.as_bytes()[..15]).unwrap_or(c_name)
313+
} else {
314+
c_name
315+
};
316+
unsafe {
317+
libc::pthread_setname_np(libc::pthread_self(), truncated.as_ptr());
318+
}
319+
}
320+
}
321+
#[cfg(target_os = "macos")]
322+
{
323+
use std::ffi::CString;
324+
if let Ok(c_name) = CString::new(name.as_str()) {
325+
unsafe {
326+
libc::pthread_setname_np(c_name.as_ptr());
327+
}
328+
}
329+
}
330+
#[cfg(windows)]
331+
{
332+
// Windows doesn't have a simple pthread_setname_np equivalent
333+
// SetThreadDescription requires Windows 10+
334+
let _ = name;
335+
}
336+
#[cfg(not(any(target_os = "linux", target_os = "macos", windows)))]
337+
{
338+
let _ = name;
339+
}
340+
}
341+
296342
/// Get OS-level thread ID (pthread_self on Unix)
297343
/// This is important for fork compatibility - the ID must remain stable after fork
298344
#[cfg(unix)]

0 commit comments

Comments
 (0)