Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit dfc5c41

Browse filesBrowse files
arhadthedevgpshead
andauthored
gh-94518: Port 23-argument _posixsubprocess.fork_exec to Argument Clinic (#94519)
Convert fork_exec to pre-inlined-argparser Argument Clinic Co-authored-by: Gregory P. Smith <greg@krypto.org>
1 parent 0421ed4 commit dfc5c41
Copy full SHA for dfc5c41

File tree

Expand file treeCollapse file tree

3 files changed

+256
-66
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+256
-66
lines changed
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Convert private :meth:`_posixsubprocess.fork_exec` to use Argument Clinic.

‎Modules/_posixsubprocess.c

Copy file name to clipboardExpand all lines: Modules/_posixsubprocess.c
+93-66Lines changed: 93 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,28 @@
7575

7676
static struct PyModuleDef _posixsubprocessmodule;
7777

78+
/*[clinic input]
79+
module _posixsubprocess
80+
[clinic start generated code]*/
81+
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c62211df27cf7334]*/
82+
83+
/*[python input]
84+
class pid_t_converter(CConverter):
85+
type = 'pid_t'
86+
format_unit = '" _Py_PARSE_PID "'
87+
88+
def parse_arg(self, argname, displayname):
89+
return """
90+
{paramname} = PyLong_AsPid({argname});
91+
if ({paramname} == -1 && PyErr_Occurred()) {{{{
92+
goto exit;
93+
}}}}
94+
""".format(argname=argname, paramname=self.parser_name)
95+
[python start generated code]*/
96+
/*[python end generated code: output=da39a3ee5e6b4b0d input=5af1c116d56cbb5a]*/
97+
98+
#include "clinic/_posixsubprocess.c.h"
99+
78100
/* Convert ASCII to a positive int, no libc call. no overflow. -1 on error. */
79101
static int
80102
_pos_int_from_ascii(const char *name)
@@ -744,7 +766,7 @@ do_fork_exec(char *const exec_array[],
744766
assert(preexec_fn == Py_None);
745767

746768
pid = vfork();
747-
if (pid == -1) {
769+
if (pid == (pid_t)-1) {
748770
/* If vfork() fails, fall back to using fork(). When it isn't
749771
* allowed in a process by the kernel, vfork can return -1
750772
* with errno EINVAL. https://bugs.python.org/issue47151. */
@@ -784,44 +806,81 @@ do_fork_exec(char *const exec_array[],
784806
return 0; /* Dead code to avoid a potential compiler warning. */
785807
}
786808

809+
/*[clinic input]
810+
_posixsubprocess.fork_exec as subprocess_fork_exec
811+
args as process_args: object
812+
executable_list: object
813+
close_fds: bool
814+
pass_fds as py_fds_to_keep: object(subclass_of='&PyTuple_Type')
815+
cwd as cwd_obj: object
816+
env as env_list: object
817+
p2cread: int
818+
p2cwrite: int
819+
c2pread: int
820+
c2pwrite: int
821+
errread: int
822+
errwrite: int
823+
errpipe_read: int
824+
errpipe_write: int
825+
restore_signals: bool
826+
call_setsid: bool
827+
pgid_to_set: pid_t
828+
gid as gid_object: object
829+
extra_groups as extra_groups_packed: object
830+
uid as uid_object: object
831+
child_umask: int
832+
preexec_fn: object
833+
allow_vfork: bool
834+
/
835+
836+
Spawn a fresh new child process.
837+
838+
Fork a child process, close parent file descriptors as appropriate in the
839+
child and duplicate the few that are needed before calling exec() in the
840+
child process.
841+
842+
If close_fds is True, close file descriptors 3 and higher, except those listed
843+
in the sorted tuple pass_fds.
844+
845+
The preexec_fn, if supplied, will be called immediately before closing file
846+
descriptors and exec.
847+
848+
WARNING: preexec_fn is NOT SAFE if your application uses threads.
849+
It may trigger infrequent, difficult to debug deadlocks.
850+
851+
If an error occurs in the child process before the exec, it is
852+
serialized and written to the errpipe_write fd per subprocess.py.
853+
854+
Returns: the child process's PID.
855+
856+
Raises: Only on an error in the parent process.
857+
[clinic start generated code]*/
787858

788859
static PyObject *
789-
subprocess_fork_exec(PyObject *module, PyObject *args)
860+
subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
861+
PyObject *executable_list, int close_fds,
862+
PyObject *py_fds_to_keep, PyObject *cwd_obj,
863+
PyObject *env_list, int p2cread, int p2cwrite,
864+
int c2pread, int c2pwrite, int errread,
865+
int errwrite, int errpipe_read, int errpipe_write,
866+
int restore_signals, int call_setsid,
867+
pid_t pgid_to_set, PyObject *gid_object,
868+
PyObject *extra_groups_packed,
869+
PyObject *uid_object, int child_umask,
870+
PyObject *preexec_fn, int allow_vfork)
871+
/*[clinic end generated code: output=7ee4f6ee5cf22b5b input=51757287ef266ffa]*/
790872
{
791-
PyObject *gc_module = NULL;
792-
PyObject *executable_list, *py_fds_to_keep;
793-
PyObject *env_list, *preexec_fn;
794-
PyObject *process_args, *converted_args = NULL, *fast_args = NULL;
873+
PyObject *converted_args = NULL, *fast_args = NULL;
795874
PyObject *preexec_fn_args_tuple = NULL;
796-
PyObject *extra_groups_packed;
797-
PyObject *uid_object, *gid_object;
798-
int p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite;
799-
int errpipe_read, errpipe_write, close_fds, restore_signals;
800-
int call_setsid;
801-
pid_t pgid_to_set = -1;
802875
gid_t *extra_groups = NULL;
803-
int child_umask;
804-
PyObject *cwd_obj, *cwd_obj2 = NULL;
805-
const char *cwd;
876+
PyObject *cwd_obj2 = NULL;
877+
const char *cwd = NULL;
806878
pid_t pid = -1;
807879
int need_to_reenable_gc = 0;
808-
char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
809-
Py_ssize_t arg_num, extra_group_size = 0;
880+
char *const *argv = NULL, *const *envp = NULL;
881+
Py_ssize_t extra_group_size = 0;
810882
int need_after_fork = 0;
811883
int saved_errno = 0;
812-
int allow_vfork;
813-
814-
if (!PyArg_ParseTuple(
815-
args, "OOpO!OOiiiiiiiipp" _Py_PARSE_PID "OOOiOp:fork_exec",
816-
&process_args, &executable_list,
817-
&close_fds, &PyTuple_Type, &py_fds_to_keep,
818-
&cwd_obj, &env_list,
819-
&p2cread, &p2cwrite, &c2pread, &c2pwrite,
820-
&errread, &errwrite, &errpipe_read, &errpipe_write,
821-
&restore_signals, &call_setsid, &pgid_to_set,
822-
&gid_object, &extra_groups_packed, &uid_object, &child_umask,
823-
&preexec_fn, &allow_vfork))
824-
return NULL;
825884

826885
PyInterpreterState *interp = PyInterpreterState_Get();
827886
if ((preexec_fn != Py_None) && (interp != PyInterpreterState_Main())) {
@@ -844,7 +903,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
844903
need_to_reenable_gc = PyGC_Disable();
845904
}
846905

847-
exec_array = _PySequence_BytesToCharpArray(executable_list);
906+
char *const *exec_array = _PySequence_BytesToCharpArray(executable_list);
848907
if (!exec_array)
849908
goto cleanup;
850909

@@ -862,7 +921,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
862921
converted_args = PyTuple_New(num_args);
863922
if (converted_args == NULL)
864923
goto cleanup;
865-
for (arg_num = 0; arg_num < num_args; ++arg_num) {
924+
for (Py_ssize_t arg_num = 0; arg_num < num_args; ++arg_num) {
866925
PyObject *borrowed_arg, *converted_arg;
867926
if (PySequence_Fast_GET_SIZE(fast_args) != num_args) {
868927
PyErr_SetString(PyExc_RuntimeError, "args changed during iteration");
@@ -891,8 +950,6 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
891950
if (PyUnicode_FSConverter(cwd_obj, &cwd_obj2) == 0)
892951
goto cleanup;
893952
cwd = PyBytes_AsString(cwd_obj2);
894-
} else {
895-
cwd = NULL;
896953
}
897954

898955
if (extra_groups_packed != Py_None) {
@@ -1019,7 +1076,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
10191076
py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
10201077

10211078
/* Parent (original) process */
1022-
if (pid == -1) {
1079+
if (pid == (pid_t)-1) {
10231080
/* Capture errno for the exception. */
10241081
saved_errno = errno;
10251082
}
@@ -1068,47 +1125,17 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
10681125
if (need_to_reenable_gc) {
10691126
PyGC_Enable();
10701127
}
1071-
Py_XDECREF(gc_module);
10721128

10731129
return pid == -1 ? NULL : PyLong_FromPid(pid);
10741130
}
10751131

1076-
1077-
PyDoc_STRVAR(subprocess_fork_exec_doc,
1078-
"fork_exec(args, executable_list, close_fds, pass_fds, cwd, env,\n\
1079-
p2cread, p2cwrite, c2pread, c2pwrite,\n\
1080-
errread, errwrite, errpipe_read, errpipe_write,\n\
1081-
restore_signals, call_setsid, pgid_to_set,\n\
1082-
gid, extra_groups, uid,\n\
1083-
preexec_fn)\n\
1084-
\n\
1085-
Forks a child process, closes parent file descriptors as appropriate in the\n\
1086-
child and dups the few that are needed before calling exec() in the child\n\
1087-
process.\n\
1088-
\n\
1089-
If close_fds is true, close file descriptors 3 and higher, except those listed\n\
1090-
in the sorted tuple pass_fds.\n\
1091-
\n\
1092-
The preexec_fn, if supplied, will be called immediately before closing file\n\
1093-
descriptors and exec.\n\
1094-
WARNING: preexec_fn is NOT SAFE if your application uses threads.\n\
1095-
It may trigger infrequent, difficult to debug deadlocks.\n\
1096-
\n\
1097-
If an error occurs in the child process before the exec, it is\n\
1098-
serialized and written to the errpipe_write fd per subprocess.py.\n\
1099-
\n\
1100-
Returns: the child process's PID.\n\
1101-
\n\
1102-
Raises: Only on an error in the parent process.\n\
1103-
");
1104-
11051132
/* module level code ********************************************************/
11061133

11071134
PyDoc_STRVAR(module_doc,
11081135
"A POSIX helper for the subprocess module.");
11091136

11101137
static PyMethodDef module_methods[] = {
1111-
{"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc},
1138+
SUBPROCESS_FORK_EXEC_METHODDEF
11121139
{NULL, NULL} /* sentinel */
11131140
};
11141141

‎Modules/clinic/_posixsubprocess.c.h

Copy file name to clipboardExpand all lines: Modules/clinic/_posixsubprocess.c.h
+162Lines changed: 162 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.