@@ -350,7 +350,7 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self,
350350 }
351351
352352 // Validate that the debug offsets are valid
353- if (validate_debug_offsets (& self -> debug_offsets ) == -1 ) {
353+ if (validate_debug_offsets (& self -> debug_offsets ) == -1 ) {
354354 set_exception_cause (self , PyExc_RuntimeError , "Invalid debug offsets found" );
355355 return -1 ;
356356 }
@@ -933,7 +933,7 @@ RemoteUnwinder_dealloc(PyObject *op)
933933 _Py_hashtable_destroy (self -> code_object_cache );
934934 }
935935#ifdef MS_WINDOWS
936- if (self -> win_process_buffer != NULL ) {
936+ if (self -> win_process_buffer != NULL ) {
937937 PyMem_Free (self -> win_process_buffer );
938938 }
939939#endif
@@ -1122,7 +1122,129 @@ static PyModuleDef_Slot remote_debugging_slots[] = {
11221122 {0 , NULL },
11231123};
11241124
1125+ /* ============================================================================
1126+ * MODULE-LEVEL FUNCTIONS
1127+ * ============================================================================ */
1128+
1129+ /*[clinic input]
1130+ _remote_debugging.get_child_pids
1131+
1132+ pid: int
1133+ Process ID of the parent process
1134+ *
1135+ recursive: bool = True
1136+ If True, return all descendants (children, grandchildren, etc.).
1137+ If False, return only direct children.
1138+
1139+ Get all child process IDs of the given process.
1140+
1141+ Returns a list of child process IDs. Returns an empty list if no children
1142+ are found.
1143+
1144+ This function provides a snapshot of child processes at a moment in time.
1145+ Child processes may exit or new ones may be created after the list is returned.
1146+
1147+ Raises:
1148+ OSError: If unable to enumerate processes
1149+ NotImplementedError: If not supported on this platform
1150+ [clinic start generated code]*/
1151+
1152+ static PyObject *
1153+ _remote_debugging_get_child_pids_impl (PyObject * module , int pid , int recursive );
1154+
1155+ static PyObject *
1156+ _remote_debugging_get_child_pids (PyObject * module , PyObject * const * args , Py_ssize_t nargs , PyObject * kwnames )
1157+ {
1158+ PyObject * return_value = NULL ;
1159+ #if defined(Py_BUILD_CORE ) && !defined(Py_BUILD_CORE_MODULE )
1160+
1161+ #define NUM_KEYWORDS 2
1162+ static struct {
1163+ PyGC_Head _this_is_not_used ;
1164+ PyObject_VAR_HEAD
1165+ Py_hash_t ob_hash ;
1166+ PyObject * ob_item [NUM_KEYWORDS ];
1167+ } _kwtuple = {
1168+ .ob_base = PyVarObject_HEAD_INIT (& PyTuple_Type , NUM_KEYWORDS )
1169+ .ob_hash = -1 ,
1170+ .ob_item = { & _Py_ID (pid ), & _Py_ID (recursive ), },
1171+ };
1172+ #undef NUM_KEYWORDS
1173+ #define KWTUPLE (&_kwtuple.ob_base.ob_base)
1174+
1175+ #else // !Py_BUILD_CORE
1176+ # define KWTUPLE NULL
1177+ #endif // !Py_BUILD_CORE
1178+
1179+ static const char * const _keywords [] = {"pid" , "recursive" , NULL };
1180+ static _PyArg_Parser _parser = {
1181+ .keywords = _keywords ,
1182+ .fname = "get_child_pids" ,
1183+ .kwtuple = KWTUPLE ,
1184+ };
1185+ #undef KWTUPLE
1186+ PyObject * argsbuf [2 ];
1187+ Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE (kwnames ) : 0 ) - 1 ;
1188+ int pid ;
1189+ int recursive = 1 ;
1190+
1191+ args = _PyArg_UnpackKeywords (args , nargs , NULL , kwnames , & _parser ,
1192+ /*minpos*/ 1 , /*maxpos*/ 1 , /*minkw*/ 0 , /*varpos*/ 0 , argsbuf );
1193+ if (!args ) {
1194+ goto exit ;
1195+ }
1196+ pid = PyLong_AsInt (args [0 ]);
1197+ if (pid == -1 && PyErr_Occurred ()) {
1198+ goto exit ;
1199+ }
1200+ if (!noptargs ) {
1201+ goto skip_optional_kwonly ;
1202+ }
1203+ recursive = PyObject_IsTrue (args [1 ]);
1204+ if (recursive < 0 ) {
1205+ goto exit ;
1206+ }
1207+ skip_optional_kwonly :
1208+ return_value = _remote_debugging_get_child_pids_impl (module , pid , recursive );
1209+
1210+ exit :
1211+ return return_value ;
1212+ }
1213+
1214+ PyDoc_STRVAR (_remote_debugging_get_child_pids__doc__ ,
1215+ "get_child_pids($module, /, pid, *, recursive=True)\n"
1216+ "--\n"
1217+ "\n"
1218+ "Get all child process IDs of the given process.\n"
1219+ "\n"
1220+ " pid\n"
1221+ " Process ID of the parent process\n"
1222+ " recursive\n"
1223+ " If True, return all descendants (children, grandchildren, etc.).\n"
1224+ " If False, return only direct children.\n"
1225+ "\n"
1226+ "Returns a list of child process IDs. Returns an empty list if no children\n"
1227+ "are found.\n"
1228+ "\n"
1229+ "This function provides a snapshot of child processes at a moment in time.\n"
1230+ "Child processes may exit or new ones may be created after the list is returned.\n"
1231+ "\n"
1232+ "Raises:\n"
1233+ " OSError: If unable to enumerate processes\n"
1234+ " NotImplementedError: If not supported on this platform" );
1235+
1236+ #define _REMOTE_DEBUGGING_GET_CHILD_PIDS_METHODDEF \
1237+ {"get_child_pids", _PyCFunction_CAST(_remote_debugging_get_child_pids), METH_FASTCALL|METH_KEYWORDS, _remote_debugging_get_child_pids__doc__},
1238+ /*[clinic end generated code: output=b21aaa012edb5379 input=c445e924c6be29f2]*/
1239+
1240+ static PyObject *
1241+ _remote_debugging_get_child_pids_impl (PyObject * module , int pid , int recursive )
1242+ {
1243+ return enumerate_child_pids ((pid_t )pid , recursive );
1244+ }
1245+
11251246static PyMethodDef remote_debugging_methods [] = {
1247+ _REMOTE_DEBUGGING_GET_CHILD_PIDS_METHODDEF
11261248 {NULL , NULL , 0 , NULL },
11271249};
11281250
0 commit comments