@@ -1308,20 +1308,33 @@ pub mod module {
13081308 env : crate :: function:: ArgMapping ,
13091309 vm : & VirtualMachine ,
13101310 ) -> PyResult < Vec < CString > > {
1311- let keys = env. mapping ( ) . keys ( vm) ?;
1312- let values = env. mapping ( ) . values ( vm) ?;
1311+ let items = env. mapping ( ) . items ( vm) ?;
13131312
1314- let keys = PyListRef :: try_from_object ( vm, keys)
1315- . map_err ( |_| vm. new_type_error ( "env.keys() is not a list" . to_owned ( ) ) ) ?
1316- . borrow_vec ( )
1317- . to_vec ( ) ;
1318- let values = PyListRef :: try_from_object ( vm, values)
1319- . map_err ( |_| vm. new_type_error ( "env.values() is not a list" . to_owned ( ) ) ) ?
1320- . borrow_vec ( )
1321- . to_vec ( ) ;
1313+ // Convert items to list if it isn't already
1314+ let items = vm. ctx . new_list (
1315+ items
1316+ . get_iter ( vm) ?
1317+ . iter ( vm) ?
1318+ . collect :: < PyResult < Vec < _ > > > ( ) ?,
1319+ ) ;
13221320
1323- keys. into_iter ( )
1324- . zip ( values)
1321+ items
1322+ . borrow_vec ( )
1323+ . iter ( )
1324+ . map ( |item| {
1325+ let tuple = item
1326+ . downcast_ref :: < crate :: builtins:: PyTuple > ( )
1327+ . ok_or_else ( || vm. new_type_error ( "items() should return tuples" . to_owned ( ) ) ) ?;
1328+ let tuple_items = tuple. as_slice ( ) ;
1329+ if tuple_items. len ( ) != 2 {
1330+ return Err ( vm. new_value_error (
1331+ "items() tuples should have exactly 2 elements" . to_owned ( ) ,
1332+ ) ) ;
1333+ }
1334+ Ok ( ( tuple_items[ 0 ] . clone ( ) , tuple_items[ 1 ] . clone ( ) ) )
1335+ } )
1336+ . collect :: < PyResult < Vec < _ > > > ( ) ?
1337+ . into_iter ( )
13251338 . map ( |( k, v) | {
13261339 let k = OsPath :: try_from_object ( vm, k) ?. into_bytes ( ) ;
13271340 let v = OsPath :: try_from_object ( vm, v) ?. into_bytes ( ) ;
@@ -1361,6 +1374,16 @@ pub mod module {
13611374 file_actions : Option < crate :: function:: ArgIterable < PyTupleRef > > ,
13621375 #[ pyarg( named, default ) ]
13631376 setsigdef : Option < crate :: function:: ArgIterable < i32 > > ,
1377+ #[ pyarg( named, default ) ]
1378+ setpgroup : Option < libc:: pid_t > ,
1379+ #[ pyarg( named, default ) ]
1380+ resetids : bool ,
1381+ #[ pyarg( named, default ) ]
1382+ setsid : bool ,
1383+ #[ pyarg( named, default ) ]
1384+ setsigmask : Option < crate :: function:: ArgIterable < i32 > > ,
1385+ #[ pyarg( named, default ) ]
1386+ scheduler : Option < PyTupleRef > ,
13641387 }
13651388
13661389 #[ cfg( any( target_os = "linux" , target_os = "freebsd" , target_os = "macos" ) ) ]
@@ -1459,6 +1482,74 @@ pub mod module {
14591482 ) ;
14601483 }
14611484
1485+ // Handle new posix_spawn attributes
1486+ let mut flags = 0i32 ;
1487+
1488+ if let Some ( pgid) = self . setpgroup {
1489+ let ret = unsafe { libc:: posix_spawnattr_setpgroup ( & mut attrp, pgid) } ;
1490+ if ret != 0 {
1491+ return Err ( vm. new_os_error ( format ! ( "posix_spawnattr_setpgroup failed: {ret}" ) ) ) ;
1492+ }
1493+ flags |= libc:: POSIX_SPAWN_SETPGROUP ;
1494+ }
1495+
1496+ if self . resetids {
1497+ flags |= libc:: POSIX_SPAWN_RESETIDS ;
1498+ }
1499+
1500+ if self . setsid {
1501+ // Note: POSIX_SPAWN_SETSID may not be available on all platforms
1502+ #[ cfg( target_os = "linux" ) ]
1503+ {
1504+ flags |= 0x0080 ; // POSIX_SPAWN_SETSID value on Linux
1505+ }
1506+ #[ cfg( not( target_os = "linux" ) ) ]
1507+ {
1508+ return Err ( vm. new_not_implemented_error (
1509+ "setsid parameter is not supported on this platform" . to_owned ( ) ,
1510+ ) ) ;
1511+ }
1512+ }
1513+
1514+ if let Some ( sigs) = self . setsigmask {
1515+ use nix:: sys:: signal;
1516+ let mut set = signal:: SigSet :: empty ( ) ;
1517+ for sig in sigs. iter ( vm) ? {
1518+ let sig = sig?;
1519+ let sig = signal:: Signal :: try_from ( sig) . map_err ( |_| {
1520+ vm. new_value_error ( format ! ( "signal number {sig} out of range" ) )
1521+ } ) ?;
1522+ set. add ( sig) ;
1523+ }
1524+ let ret = unsafe { libc:: posix_spawnattr_setsigmask ( & mut attrp, set. as_ref ( ) ) } ;
1525+ if ret != 0 {
1526+ return Err (
1527+ vm. new_os_error ( format ! ( "posix_spawnattr_setsigmask failed: {ret}" ) )
1528+ ) ;
1529+ }
1530+ flags |= libc:: POSIX_SPAWN_SETSIGMASK ;
1531+ }
1532+
1533+ if let Some ( _scheduler) = self . scheduler {
1534+ // TODO: Implement scheduler parameter handling
1535+ // This requires platform-specific sched_param struct handling
1536+ return Err ( vm. new_not_implemented_error (
1537+ "scheduler parameter is not yet implemented" . to_owned ( ) ,
1538+ ) ) ;
1539+ }
1540+
1541+ if flags != 0 {
1542+ // Check for potential overflow when casting to c_short
1543+ if flags > libc:: c_short:: MAX as i32 {
1544+ return Err ( vm. new_value_error ( "Too many flags set for posix_spawn" . to_owned ( ) ) ) ;
1545+ }
1546+ let ret =
1547+ unsafe { libc:: posix_spawnattr_setflags ( & mut attrp, flags as libc:: c_short ) } ;
1548+ if ret != 0 {
1549+ return Err ( vm. new_os_error ( format ! ( "posix_spawnattr_setflags failed: {ret}" ) ) ) ;
1550+ }
1551+ }
1552+
14621553 let mut args: Vec < CString > = self
14631554 . args
14641555 . iter ( vm) ?
0 commit comments