From 4f871cf9cf869da68560b6efbf19749a4828e9d2 Mon Sep 17 00:00:00 2001 From: pxin Date: Mon, 4 Mar 2019 10:59:27 +0800 Subject: [PATCH 1/7] add _vxwapi extension module --- Modules/_vxwapi.c | 520 ++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 5 +- 2 files changed, 524 insertions(+), 1 deletion(-) create mode 100644 Modules/_vxwapi.c diff --git a/Modules/_vxwapi.c b/Modules/_vxwapi.c new file mode 100644 index 00000000000000..110eba8dcfe541 --- /dev/null +++ b/Modules/_vxwapi.c @@ -0,0 +1,520 @@ +/* + * VxWorks Compatibility Wrapper + * + * Python interface to VxWorks methods + * + * Author: wenyan.xin@windriver.com + * + ************************************************/ +#include +#include + +#include +#include +#include +#include + +#include "clinic/_vxwapi.c.h" + +/*[clinic input] +module _vxwapi +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=6efcf3b26a262ef1]*/ + +/* Returns 1 if there is a problem with fd_sequence, 0 otherwise. */ +static int +_sanity_check_python_fd_sequence(PyObject *fd_sequence) +{ + Py_ssize_t seq_idx; + long prev_fd = -1; + for (seq_idx = 0; seq_idx < PyTuple_GET_SIZE(fd_sequence); ++seq_idx) { + PyObject* py_fd = PyTuple_GET_ITEM(fd_sequence, seq_idx); + long iter_fd; + if (!PyLong_Check(py_fd)) { + return 1; + } + iter_fd = PyLong_AsLong(py_fd); + if (iter_fd < 0 || iter_fd <= prev_fd || iter_fd > INT_MAX) { + /* Negative, overflow, unsorted, too big for a fd. */ + return 1; + } + prev_fd = iter_fd; + } + return 0; +} + +/* Is fd found in the sorted Python Sequence? */ +static int +_is_fd_in_sorted_fd_sequence(int fd, PyObject *fd_sequence) +{ + /* Binary search. */ + Py_ssize_t search_min = 0; + Py_ssize_t search_max = PyTuple_GET_SIZE(fd_sequence) - 1; + if (search_max < 0) + return 0; + do { + long middle = (search_min + search_max) / 2; + long middle_fd = PyLong_AsLong(PyTuple_GET_ITEM(fd_sequence, middle)); + if (fd == middle_fd) + return 1; + if (fd > middle_fd) + search_min = middle + 1; + else + search_max = middle - 1; + } while (search_min <= search_max); + return 0; +} + + +static void _close_open_fds(long start_fd, PyObject* py_fds_to_keep) +{ + int fd; + int ret; + + for (fd = start_fd; fd < FD_SETSIZE; ++fd) { + ret = fcntl (fd, F_GETFD); + if (ret < 0) + continue; + + if (_is_fd_in_sorted_fd_sequence(fd, py_fds_to_keep)) + continue; + + _Py_set_inheritable_async_safe(fd, 0, NULL); + } +} + + +static int +make_inheritable(PyObject *py_fds_to_keep, int errpipe_write) +{ + Py_ssize_t i, len; + + len = PyTuple_GET_SIZE(py_fds_to_keep); + for (i = 0; i < len; ++i) { + PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i); + long fd = PyLong_AsLong(fdobj); + assert(!PyErr_Occurred()); + assert(0 <= fd && fd <= INT_MAX); + if (fd == errpipe_write) { + /* errpipe_write is part of py_fds_to_keep. It must be closed at + exec(), but kept open in the child process until exec() is + called. */ + continue; + } + if (_Py_set_inheritable_async_safe((int)fd, 1, NULL) < 0) + return -1; + } + return 0; +} + +static PyObject * +rtp_spawn_impl( + PyObject *executable_list, + char *const argvp[], + char *const envpp[], + PyObject *cwd_obj, + int p2cread, int p2cwrite, + int c2pread, int c2pwrite, + int errread, int errwrite, + int errpipe_read, int errpipe_write, + int close_fds, int restore_signals, + PyObject *py_fds_to_keep) +{ + int priority = 0; + unsigned int uStackSize = 0; + int options = 0; + int taskOptions = VX_FP_TASK; + char pwdbuf[PATH_MAX]={0}; + const char *cwd = NULL; + PyObject *cwd_obj2; + char *const *exec_array; + + int p2cread_bk = -1; + int c2pwrite_bk = -1; + int errwrite_bk = -1; + + if (make_inheritable(py_fds_to_keep, errpipe_write) < 0) + goto error; + + /* When duping fds, if there arises a situation where one of the fds is + either 0, 1 or 2, it is possible that it is overwritten (#12607). */ + if (c2pwrite == 0) { + c2pwrite = dup(c2pwrite); + if (_Py_set_inheritable_async_safe(c2pwrite, 0, NULL) < 0) { + goto error; + } + c2pwrite_bk = c2pwrite; + } + + if (c2pwrite_bk == -1 && p2cread == 1) { + p2cread = dup(p2cread); + if (_Py_set_inheritable_async_safe(p2cread, 0, NULL) < 0) { + goto error; + } + p2cread_bk = p2cread; + } + + while (errwrite == 0 || errwrite == 1) { + errwrite = dup(errwrite); + if (_Py_set_inheritable_async_safe(errwrite, 0, NULL) < 0) { + goto error; + } + errwrite_bk = errwrite; + } + + exec_array = _PySequence_BytesToCharpArray(executable_list); + if (!exec_array) + goto error; + + if (cwd_obj != Py_None) { + if (PyUnicode_FSConverter(cwd_obj, &cwd_obj2) == 0) + goto error; + cwd = PyBytes_AsString(cwd_obj2); + } else { + cwd = NULL; + cwd_obj2 = NULL; + } + + int pid = RTP_ID_ERROR; + int stdin_bk = -1, stdout_bk = -1, stderr_bk = -1; + int saved_errno, reached_preexec = 0; + const char* err_msg = ""; + char hex_errno[sizeof(saved_errno)*2+1]; + + if (-1 != p2cwrite && + _Py_set_inheritable_async_safe(p2cwrite, 0, NULL) < 0) + goto error; + + if (-1 != c2pread && + _Py_set_inheritable_async_safe(c2pread, 0, NULL) < 0) + goto error; + + if (-1 != errread && + _Py_set_inheritable_async_safe(errread, 0, NULL) < 0) + goto error; + + if (-1 != errpipe_read && + _Py_set_inheritable_async_safe(errpipe_read, 0, NULL) < 0) + goto error; + + if (-1 != errpipe_write && + _Py_set_inheritable_async_safe(errpipe_write, 0, NULL) < 0) + goto error; + + if (p2cread == 0) { + if (_Py_set_inheritable_async_safe(p2cread, 1, NULL) < 0) + goto error; + } + else if (p2cread != -1) { + stdin_bk = dup(0); + if (dup2(p2cread, 0) == -1) /* stdin */ + goto error; + } + + if (c2pwrite == 1) { + if (_Py_set_inheritable_async_safe(c2pwrite, 1, NULL) < 0) + goto error; + } + else if (c2pwrite != -1) { + stdout_bk = dup(1); + if (dup2(c2pwrite, 1) == -1) /* stdout */ + goto error; + } + + if (errwrite == 2) { + if (_Py_set_inheritable_async_safe(errwrite, 1, NULL) < 0) + goto error; + } + else if (errwrite != -1) { + stderr_bk = dup(2); + if (dup2(errwrite, 2) == -1) /* stderr */ + goto error; + } + + char *cwd_bk = getcwd(pwdbuf, sizeof(pwdbuf)); + if (cwd) { + if (chdir(cwd) == -1) { + if (ENODEV == errno) { + errno = ENOENT; + } + goto error; + } + } + + reached_preexec = 1; + + /* close FDs after executing preexec_fn, which might open FDs */ + if (close_fds) { + _close_open_fds(3, py_fds_to_keep); + } + + (void)taskPriorityGet (taskIdSelf(), &priority); + (void)taskStackSizeGet (taskIdSelf(), &uStackSize); + + saved_errno = 0; + for (int i = 0; exec_array[i] != NULL; ++i) { + const char *executable = exec_array[i]; + pid = rtpSpawn (executable, (const char **)argvp, + (const char**)envpp, priority, uStackSize, options, taskOptions); + + if (RTP_ID_ERROR == pid && saved_errno == 0) { + if (ENODEV == errno) { + errno = ENOENT; + } + saved_errno = errno; + } + } + + if (p2cread_bk != -1 ) + close(p2cread_bk); + + if (c2pwrite_bk != -1 ) + close(c2pwrite_bk); + + if (errwrite_bk != -1 ) + close(errwrite_bk); + + if (exec_array) + _Py_FreeCharPArray(exec_array); + + if (stdin_bk >= 0) { + if (dup2(stdin_bk, 0) == -1) + goto error; + close(stdin_bk); + } + if (stdout_bk >= 0) { + if (dup2(stdout_bk, 1) == -1) + goto error; + close(stdout_bk); + } + if (stderr_bk >= 0) { + if (dup2(stderr_bk,2) == -1) + goto error; + close(stderr_bk); + } + + if (cwd && cwd_bk) + chdir(cwd_bk); + + if (RTP_ID_ERROR != pid) { + return Py_BuildValue("i", pid); + } + + /* Report the first exec error, not the last. */ + if (saved_errno) + errno = saved_errno; + +error: + saved_errno = errno; + /* Report the posix error to our parent process. */ + /* We ignore all write() return values as the total size of our writes is + less than PIPEBUF and we cannot do anything about an error anyways. + Use _Py_write_noraise() to retry write() if it is interrupted by a + signal (fails with EINTR). */ + if (saved_errno) { + char *cur; + _Py_write_noraise(errpipe_write, "OSError:", 8); + cur = hex_errno + sizeof(hex_errno); + while (saved_errno != 0 && cur != hex_errno) { + *--cur = Py_hexdigits[saved_errno % 16]; + saved_errno /= 16; + } + _Py_write_noraise(errpipe_write, cur, hex_errno + sizeof(hex_errno) - cur); + _Py_write_noraise(errpipe_write, ":", 1); + if (!reached_preexec) { + /* Indicate to the parent that the error happened before rtpSpawn(). */ + _Py_write_noraise(errpipe_write, "noexec", 6); + } + /* We can't call strerror(saved_errno). It is not async signal safe. + * The parent process will look the error message up. */ + } else { + _Py_write_noraise(errpipe_write, "SubprocessError:0:", 18); + _Py_write_noraise(errpipe_write, err_msg, strlen(err_msg)); + } + + return Py_BuildValue("i", pid); +} + + +static void _save_fds(int saved_fd[]) +{ + int fd; + int flags; + + if (!saved_fd) return; + + for (fd = 0; fd < FD_SETSIZE; ++fd) { + flags = fcntl (fd, F_GETFD); + if (flags < 0) + continue; + + saved_fd[fd] = !(flags & FD_CLOEXEC); + } +} + +static void _restore_fds(int saved_fd[]) +{ + int fd; + int flags; + + if (!saved_fd) return; + + for (fd = 0; fd < FD_SETSIZE; ++fd) { + flags = fcntl (fd, F_GETFD); + if (flags < 0) + continue; + + if (-1 != saved_fd[fd]) { + _Py_set_inheritable_async_safe(fd, saved_fd[fd], NULL); + } + } +} + +/*[clinic input] +_vxwapi.rtp_spawn + + process_args: object + executable_list: object + close_fds: int + py_fds_to_keep: object(subclass_of='&PyTuple_Type') + cwd_obj: object + env_list: object + p2cread: int + p2cwrite: int + c2pread: int + c2pwrite: int + errread: int + errwrite: int + errpipe_read: int + errpipe_write: int + restore_signals: int + call_setsid: int + preexec_fn: object + / + +Spawn a real time process in the vxWorks OS +[clinic start generated code]*/ + +static PyObject * +_vxwapi_rtp_spawn_impl(PyObject *module, PyObject *process_args, + PyObject *executable_list, int close_fds, + PyObject *py_fds_to_keep, PyObject *cwd_obj, + PyObject *env_list, int p2cread, int p2cwrite, + int c2pread, int c2pwrite, int errread, int errwrite, + int errpipe_read, int errpipe_write, + int restore_signals, int call_setsid, + PyObject *preexec_fn) +/*[clinic end generated code: output=5f98889b783df975 input=30419f3fea045213]*/ +{ + PyObject *converted_args = NULL, *fast_args = NULL; + char *const *argv = NULL, *const *envp = NULL; + int saved_fd[FD_SETSIZE] = {-1}; + + PyObject *return_value = NULL; + if (_PyInterpreterState_Get() != PyInterpreterState_Main()) { + PyErr_SetString(PyExc_RuntimeError, "fork not supported for subinterpreters"); + return NULL; + } + + if (close_fds && errpipe_write < 3) { /* precondition */ + PyErr_SetString(PyExc_ValueError, "errpipe_write must be >= 3"); + return NULL; + } + + if (_sanity_check_python_fd_sequence(py_fds_to_keep)) { + PyErr_SetString(PyExc_ValueError, "bad value(s) in fds_to_keep"); + return NULL; + } + + if (preexec_fn != Py_None) { + PyErr_SetString(PyExc_RuntimeError, "Preexecution function is not supported on VxWorks"); + return NULL; + } + + if (call_setsid != 0) { + PyErr_SetString(PyExc_RuntimeError, "VxWorks does not support sessions"); + return NULL; + } + + /* Convert args and env into appropriate arguments */ + /* These conversions are done in the parent process to avoid allocating + or freeing memory in the child process. */ + if (process_args != Py_None) { + Py_ssize_t num_args; + Py_ssize_t arg_num; + /* Equivalent to: */ + /* tuple(PyUnicode_FSConverter(arg) for arg in process_args) */ + fast_args = PySequence_Fast(process_args, "argv must be a tuple"); + if (fast_args == NULL) + goto cleanup; + num_args = PySequence_Fast_GET_SIZE(fast_args); + converted_args = PyTuple_New(num_args); + if (converted_args == NULL) + goto cleanup; + for (arg_num = 0; arg_num < num_args; ++arg_num) { + PyObject *borrowed_arg, *converted_arg; + if (PySequence_Fast_GET_SIZE(fast_args) != num_args) { + PyErr_SetString(PyExc_RuntimeError, + "args changed during iteration"); + goto cleanup; + } + borrowed_arg = PySequence_Fast_GET_ITEM(fast_args, arg_num); + if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0) + goto cleanup; + PyTuple_SET_ITEM(converted_args, arg_num, converted_arg); + } + + argv = _PySequence_BytesToCharpArray(converted_args); + Py_CLEAR(converted_args); + Py_CLEAR(fast_args); + if (!argv) + goto cleanup; + } + + if (env_list != Py_None) { + envp = _PySequence_BytesToCharpArray(env_list); + if (!envp) + goto cleanup; + } + + _save_fds(saved_fd); + + return_value = rtp_spawn_impl( + executable_list, argv, envp, cwd_obj, + p2cread, p2cwrite, c2pread, c2pwrite, + errread, errwrite, errpipe_read, errpipe_write, + close_fds, restore_signals, py_fds_to_keep); + + _restore_fds (saved_fd); + +cleanup: + if (envp) + _Py_FreeCharPArray(envp); + if (argv) + _Py_FreeCharPArray(argv); + Py_XDECREF(converted_args); + Py_XDECREF(fast_args); + return return_value; +} + + + +static PyMethodDef _vxwapiMethods[] = { + _VXWAPI_RTP_SPAWN_METHODDEF + { NULL, NULL } +}; + +static struct PyModuleDef _vxwapimodule = { + PyModuleDef_HEAD_INIT, + "_vxwapi", + NULL, + -1, + _vxwapiMethods +}; + +PyMODINIT_FUNC +PyInit__vxwapi(void) +{ + return PyModule_Create(&_vxwapimodule); +} + diff --git a/setup.py b/setup.py index c278f08b8e6d2f..bf54dbcb681a44 100644 --- a/setup.py +++ b/setup.py @@ -807,7 +807,10 @@ def detect_simple_extensions(self): self.add(Extension('_csv', ['_csv.c'])) # POSIX subprocess module helper. - self.add(Extension('_posixsubprocess', ['_posixsubprocess.c'])) + if VXWORKS: + self.add(Extension('_vxwapi', ['_vxwapi.c'])) + else: + self.add(Extension('_posixsubprocess', ['_posixsubprocess.c'])) def detect_test_extensions(self): # Python C API test module From 3ab9f6e642180c962c5aa04ec593edabe35b44e4 Mon Sep 17 00:00:00 2001 From: pxin Date: Mon, 4 Mar 2019 11:18:54 +0800 Subject: [PATCH 2/7] Port subprocess.py onto VxWorks --- Lib/subprocess.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 0496b447e8ea03..1260e8739a3ab6 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -66,7 +66,11 @@ _mswindows = True except ModuleNotFoundError: _mswindows = False - import _posixsubprocess + _vxworks = (sys.platform == "vxworks") + if _vxworks: + import _vxwapi + else: + import _posixsubprocess import select import selectors else: @@ -733,6 +737,14 @@ def __init__(self, args, bufsize=-1, executable=None, raise ValueError("preexec_fn is not supported on Windows " "platforms") else: + if _vxworks: + if shell: + raise ValueError("shell is not supported on VxWorks") + if preexec_fn is not None: + raise ValueError("Preexecution function is not supported" + "on VxWorks"); + if start_new_session: + raise ValueError("VxWorks does not support sessions"); # POSIX if pass_fds and not close_fds: warnings.warn("pass_fds overriding close_fds.", RuntimeWarning) @@ -1580,7 +1592,17 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, for dir in os.get_exec_path(env)) fds_to_keep = set(pass_fds) fds_to_keep.add(errpipe_write) - self.pid = _posixsubprocess.fork_exec( + if _vxworks: + self.pid = _vxwapi.rtp_spawn( + args, executable_list, + close_fds, tuple(sorted(map(int, fds_to_keep))), + cwd, env_list, + p2cread, p2cwrite, c2pread, c2pwrite, + errread, errwrite, + errpipe_read, errpipe_write, + restore_signals, start_new_session, preexec_fn) + else: + self.pid = _posixsubprocess.fork_exec( args, executable_list, close_fds, tuple(sorted(map(int, fds_to_keep))), cwd, env_list, @@ -1589,6 +1611,8 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, errpipe_read, errpipe_write, restore_signals, start_new_session, preexec_fn) self._child_created = True + if _vxworks and self.pid == -1: + self._child_created = False finally: # be sure the FD is closed no matter what os.close(errpipe_write) From 031a8c786b68aa250a98a29185431af3d116638f Mon Sep 17 00:00:00 2001 From: pxin Date: Mon, 4 Mar 2019 11:23:12 +0800 Subject: [PATCH 3/7] generate clinic for _vxwapi.c --- Modules/clinic/_vxwapi.c.h | 166 +++++++++++++++++++++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 Modules/clinic/_vxwapi.c.h diff --git a/Modules/clinic/_vxwapi.c.h b/Modules/clinic/_vxwapi.c.h new file mode 100644 index 00000000000000..0511936a8c27ea --- /dev/null +++ b/Modules/clinic/_vxwapi.c.h @@ -0,0 +1,166 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(_vxwapi_rtp_spawn__doc__, +"rtp_spawn($module, process_args, executable_list, close_fds,\n" +" py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite,\n" +" c2pread, c2pwrite, errread, errwrite, errpipe_read,\n" +" errpipe_write, restore_signals, call_setsid, preexec_fn, /)\n" +"--\n" +"\n" +"Spawn a real time process in the vxWorks OS"); + +#define _VXWAPI_RTP_SPAWN_METHODDEF \ + {"rtp_spawn", (PyCFunction)(void(*)(void))_vxwapi_rtp_spawn, METH_FASTCALL, _vxwapi_rtp_spawn__doc__}, + +static PyObject * +_vxwapi_rtp_spawn_impl(PyObject *module, PyObject *process_args, + PyObject *executable_list, int close_fds, + PyObject *py_fds_to_keep, PyObject *cwd_obj, + PyObject *env_list, int p2cread, int p2cwrite, + int c2pread, int c2pwrite, int errread, int errwrite, + int errpipe_read, int errpipe_write, + int restore_signals, int call_setsid, + PyObject *preexec_fn); + +static PyObject * +_vxwapi_rtp_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *process_args; + PyObject *executable_list; + int close_fds; + PyObject *py_fds_to_keep; + PyObject *cwd_obj; + PyObject *env_list; + int p2cread; + int p2cwrite; + int c2pread; + int c2pwrite; + int errread; + int errwrite; + int errpipe_read; + int errpipe_write; + int restore_signals; + int call_setsid; + PyObject *preexec_fn; + + if (!_PyArg_CheckPositional("rtp_spawn", nargs, 17, 17)) { + goto exit; + } + process_args = args[0]; + executable_list = args[1]; + if (PyFloat_Check(args[2])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + close_fds = _PyLong_AsInt(args[2]); + if (close_fds == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyTuple_Check(args[3])) { + _PyArg_BadArgument("rtp_spawn", 4, "tuple", args[3]); + goto exit; + } + py_fds_to_keep = args[3]; + cwd_obj = args[4]; + env_list = args[5]; + if (PyFloat_Check(args[6])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + p2cread = _PyLong_AsInt(args[6]); + if (p2cread == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[7])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + p2cwrite = _PyLong_AsInt(args[7]); + if (p2cwrite == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[8])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + c2pread = _PyLong_AsInt(args[8]); + if (c2pread == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[9])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + c2pwrite = _PyLong_AsInt(args[9]); + if (c2pwrite == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[10])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + errread = _PyLong_AsInt(args[10]); + if (errread == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[11])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + errwrite = _PyLong_AsInt(args[11]); + if (errwrite == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[12])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + errpipe_read = _PyLong_AsInt(args[12]); + if (errpipe_read == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[13])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + errpipe_write = _PyLong_AsInt(args[13]); + if (errpipe_write == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[14])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + restore_signals = _PyLong_AsInt(args[14]); + if (restore_signals == -1 && PyErr_Occurred()) { + goto exit; + } + if (PyFloat_Check(args[15])) { + PyErr_SetString(PyExc_TypeError, + "integer argument expected, got float" ); + goto exit; + } + call_setsid = _PyLong_AsInt(args[15]); + if (call_setsid == -1 && PyErr_Occurred()) { + goto exit; + } + preexec_fn = args[16]; + return_value = _vxwapi_rtp_spawn_impl(module, process_args, executable_list, close_fds, py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, call_setsid, preexec_fn); + +exit: + return return_value; +} +/*[clinic end generated code: output=216bc865460f7764 input=a9049054013a1b77]*/ From 4a5df1c8094fc5656401b69c2a4de81dcf09d132 Mon Sep 17 00:00:00 2001 From: wxin1 Date: Mon, 4 Mar 2019 15:05:13 +0800 Subject: [PATCH 4/7] adjust test_subprocess case for VxWorks --- Doc/library/subprocess.rst | 6 ++++ Lib/test/test_subprocess.py | 61 ++++++++++++++++++++++++++++++------- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst index e7844587e908b7..39abab6c24395c 100644 --- a/Doc/library/subprocess.rst +++ b/Doc/library/subprocess.rst @@ -394,6 +394,8 @@ functions. Popen(['/bin/sh', '-c', args[0], args[1], ...]) + VxWorks does not support shell argument. + On Windows with ``shell=True``, the :envvar:`COMSPEC` environment variable specifies the default shell. The only time you need to specify ``shell=True`` on Windows is when the command you wish to execute is built @@ -449,6 +451,8 @@ functions. child process just before the child is executed. (POSIX only) + VxWorks does not support preexec_fn argument. + .. warning:: The *preexec_fn* parameter is not safe to use in the presence of threads @@ -509,6 +513,8 @@ functions. If *start_new_session* is true the setsid() system call will be made in the child process prior to the execution of the subprocess. (POSIX only) + VxWorks does not support start_new_session argument. + .. versionchanged:: 3.2 *start_new_session* was added. diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index b0b6b06e92759e..932c54e8d9a67e 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -36,6 +36,24 @@ raise unittest.SkipTest("test is not helpful for PGO") mswindows = (sys.platform == "win32") +vxworks = (sys.platform == "vxworks") + +no_shell = False +no_preexec_fn = False + +if vxworks: + import _vxwapi + mock_modname = "subprocess._vxwapi.rtp_spawn" + mock_submod = subprocess._vxwapi + mock_func = _vxwapi.rtp_spawn + + no_shell = True + no_preexec_fn = True +elif not mswindows: + import _posixsubprocess + mock_modname = "subprocess._posixsubprocess.fork_exec" + mock_submod = subprocess._posixsubprocess + mock_func = _posixsubprocess.fork_exec # # Depends on the following external programs: Python @@ -315,6 +333,7 @@ def test_executable_takes_precedence(self): executable=NONEXISTING_CMD[0]) @unittest.skipIf(mswindows, "executable argument replaces shell") + @unittest.skipIf(no_shell, "shell argument is not supported") def test_executable_replaces_shell(self): # Check that the executable argument replaces the default shell # when shell=True. @@ -1581,8 +1600,8 @@ class PopenNoDestructor(subprocess.Popen): def __del__(self): pass - @mock.patch("subprocess._posixsubprocess.fork_exec") - def test_exception_errpipe_normal(self, fork_exec): + @mock.patch(mock_modname) + def test_exception_errpipe_normal(self, mock_func): """Test error passing done through errpipe_write in the good case""" def proper_error(*args): errpipe_write = args[13] @@ -1591,15 +1610,15 @@ def proper_error(*args): os.write(errpipe_write, b"OSError:" + err_code + b":") return 0 - fork_exec.side_effect = proper_error + mock_func.side_effect = proper_error with mock.patch("subprocess.os.waitpid", side_effect=ChildProcessError): with self.assertRaises(IsADirectoryError): self.PopenNoDestructor(["non_existent_command"]) - @mock.patch("subprocess._posixsubprocess.fork_exec") - def test_exception_errpipe_bad_data(self, fork_exec): + @mock.patch(mock_modname) + def test_exception_errpipe_bad_data(self, mock_func): """Test error passing done through errpipe_write where its not in the expected format""" error_data = b"\xFF\x00\xDE\xAD" @@ -1611,7 +1630,7 @@ def bad_error(*args): os.write(errpipe_write, error_data) return 0 - fork_exec.side_effect = bad_error + mock_func.side_effect = bad_error with mock.patch("subprocess.os.waitpid", side_effect=ChildProcessError): @@ -1644,6 +1663,8 @@ def test_restore_signals(self): msg="restore_signals=True should've unblocked " "SIGPIPE and friends.") + @unittest.skipUnless(os is not None and hasattr(os, 'setsid'), + 'need os.setsid') def test_start_new_session(self): # For code coverage of calling setsid(). We don't care if we get an # EPERM error from it depending on the test execution environment, that @@ -1690,6 +1711,7 @@ def test_CalledProcessError_str_non_zero(self): error_string = str(err) self.assertIn("non-zero exit status 2.", error_string) + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_preexec(self): # DISCLAIMER: Setting environment variables is *not* a good use # of a preexec_fn. This is merely a test. @@ -1701,6 +1723,7 @@ def test_preexec(self): with p: self.assertEqual(p.stdout.read(), b"apple") + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_preexec_exception(self): def raise_it(): raise ValueError("What if two swallows carried a coconut?") @@ -1709,7 +1732,7 @@ def raise_it(): preexec_fn=raise_it) except subprocess.SubprocessError as e: self.assertTrue( - subprocess._posixsubprocess, + mock_submod, "Expected a ValueError from the preexec_fn") except ValueError as e: self.assertIn("coconut", e.args[0]) @@ -1743,6 +1766,7 @@ def _execute_child(self, *args, **kwargs): os.close(fd) @unittest.skipIf(not os.path.exists("/dev/zero"), "/dev/zero required.") + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_preexec_errpipe_does_not_double_close_pipes(self): """Issue16140: Don't double close pipes on preexec error.""" @@ -1756,6 +1780,7 @@ def raise_it(): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=raise_it) + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_preexec_gc_module_failure(self): # This tests the code that disables garbage collection if the child # process will execute any Python. @@ -1795,6 +1820,7 @@ def raise_runtime_error(): @unittest.skipIf( sys.platform == 'darwin', 'setrlimit() seems to fail on OS X') + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_preexec_fork_failure(self): # The internal code did not preserve the previous exception when # re-enabling garbage collection @@ -1840,6 +1866,7 @@ def test_invalid_args(self): "import sys; sys.exit(47)"], creationflags=47) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_sequence(self): # Run command through the shell (sequence) newenv = os.environ.copy() @@ -1850,6 +1877,7 @@ def test_shell_sequence(self): with p: self.assertEqual(p.stdout.read().strip(b" \t\r\n\f"), b"apple") + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_string(self): # Run command through the shell (string) newenv = os.environ.copy() @@ -1873,6 +1901,7 @@ def test_call_string(self): os.remove(fname) self.assertEqual(rc, 47) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_specific_shell(self): # Issue #9265: Incorrect name passed as arg[0]. shells = [] @@ -2203,6 +2232,7 @@ def test_swap_std_fds_with_one_closed(self): for to_fds in itertools.permutations(range(3), 2): self._check_swap_std_fds_with_one_closed(from_fds, to_fds) + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_surrogates_error_message(self): def prepare(): raise ValueError("surrogate:\uDCff") @@ -2213,11 +2243,11 @@ def prepare(): preexec_fn=prepare) except ValueError as err: # Pure Python implementations keeps the message - self.assertIsNone(subprocess._posixsubprocess) + self.assertIsNone(mock_submod) self.assertEqual(str(err), "surrogate:\uDCff") except subprocess.SubprocessError as err: # _posixsubprocess uses a default message - self.assertIsNotNone(subprocess._posixsubprocess) + self.assertIsNotNone(mock_submod) self.assertEqual(str(err), "Exception occurred in preexec_fn.") else: self.fail("Expected ValueError or subprocess.SubprocessError") @@ -2251,6 +2281,7 @@ def test_undecodable_env(self): stdout = stdout.rstrip(b'\n\r') self.assertEqual(stdout.decode('ascii'), ascii(encoded_value)) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_bytes_program(self): abs_program = os.fsencode(sys.executable) path, program = os.path.split(sys.executable) @@ -2662,6 +2693,7 @@ def test_leak_fast_process_del_killed(self): self.assertRaises(OSError, os.waitpid, pid, 0) self.assertNotIn(ident, [id(o) for o in subprocess._active]) + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_close_fds_after_preexec(self): fd_status = support.findfile("fd_status.py", subdir="subprocessdata") @@ -2680,6 +2712,7 @@ def test_close_fds_after_preexec(self): self.assertNotIn(fd, remaining_fds) @support.cpython_only + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_fork_exec(self): # Issue #22290: fork_exec() must not crash on memory allocation failure # or other errors @@ -2712,7 +2745,6 @@ def test_fork_exec(self): @support.cpython_only def test_fork_exec_sorted_fd_sanity_check(self): # Issue #23564: sanity check the fork_exec() fds_to_keep sanity check. - import _posixsubprocess class BadInt: first = True def __init__(self, value): @@ -2738,7 +2770,7 @@ def __int__(self): with self.assertRaises( ValueError, msg='fds_to_keep={}'.format(fds_to_keep)) as c: - _posixsubprocess.fork_exec( + mock_func( [b"false"], [b"false"], True, fds_to_keep, None, [b"env"], -1, -1, -1, -1, @@ -2884,6 +2916,7 @@ def test_creationflags(self): ' -c "import time; time.sleep(0.25)"', creationflags=CREATE_NEW_CONSOLE) + @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_invalid_args(self): # invalid arguments should raise ValueError self.assertRaises(ValueError, subprocess.call, @@ -2968,6 +3001,7 @@ def test_empty_handle_list(self): subprocess.call([sys.executable, "-c", "import sys; sys.exit(0)"], startupinfo=startupinfo) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_sequence(self): # Run command through the shell (sequence) newenv = os.environ.copy() @@ -2978,6 +3012,7 @@ def test_shell_sequence(self): with p: self.assertIn(b"physalis", p.stdout.read()) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_string(self): # Run command through the shell (string) newenv = os.environ.copy() @@ -2988,6 +3023,7 @@ def test_shell_string(self): with p: self.assertIn(b"physalis", p.stdout.read()) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_encodings(self): # Run command through the shell (string) for enc in ['ansi', 'oem']: @@ -3134,6 +3170,7 @@ def popen_via_context_manager(*args, **kwargs): raise KeyboardInterrupt # Test how __exit__ handles ^C. self._test_keyboardinterrupt_no_kill(popen_via_context_manager) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_getoutput(self): self.assertEqual(subprocess.getoutput('echo xyzzy'), 'xyzzy') self.assertEqual(subprocess.getstatusoutput('echo xyzzy'), @@ -3206,11 +3243,13 @@ def with_spaces(self, *args, **kwargs): "2 [%r, 'ab cd']" % self.fname ) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_string_with_spaces(self): # call() function with string argument with spaces on Windows self.with_spaces('"%s" "%s" "%s"' % (sys.executable, self.fname, "ab cd"), shell=1) + @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_sequence_with_spaces(self): # call() function with sequence argument with spaces on Windows self.with_spaces([sys.executable, self.fname, "ab cd"], shell=1) From 1271bda8b824717f52ccccebaec9fd57ccf381fc Mon Sep 17 00:00:00 2001 From: pxin Date: Mon, 4 Mar 2019 15:20:31 +0800 Subject: [PATCH 5/7] add news file for subprocess module support --- .../NEWS.d/next/Library/2019-03-04-14-57-25.bpo-31904.28djD8.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2019-03-04-14-57-25.bpo-31904.28djD8.rst diff --git a/Misc/NEWS.d/next/Library/2019-03-04-14-57-25.bpo-31904.28djD8.rst b/Misc/NEWS.d/next/Library/2019-03-04-14-57-25.bpo-31904.28djD8.rst new file mode 100644 index 00000000000000..959b7a18a8f027 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-03-04-14-57-25.bpo-31904.28djD8.rst @@ -0,0 +1 @@ +Support subprocess module on VxWorks. From 5f46d31bc9c72172b9fbef180f1dc8eb9b2674c9 Mon Sep 17 00:00:00 2001 From: wxin1 Date: Mon, 4 Mar 2019 17:41:06 +0800 Subject: [PATCH 6/7] fix the test_subprocess failed issue on Windows --- Lib/test/test_subprocess.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 932c54e8d9a67e..70a0300e3136c9 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -49,7 +49,7 @@ no_shell = True no_preexec_fn = True -elif not mswindows: +else: import _posixsubprocess mock_modname = "subprocess._posixsubprocess.fork_exec" mock_submod = subprocess._posixsubprocess From eb6eb3190b8595dcd2946d68116c24fe70c32ffa Mon Sep 17 00:00:00 2001 From: wxin1 Date: Tue, 5 Mar 2019 17:08:34 +0800 Subject: [PATCH 7/7] fixed subprocess mode mock name for VxWorks --- Lib/subprocess.py | 15 +++++----- Lib/test/test_subprocess.py | 56 ++++++++++++++++++------------------- Modules/_vxwapi.c | 26 ++++------------- Modules/clinic/_vxwapi.c.h | 34 ++++------------------ 4 files changed, 44 insertions(+), 87 deletions(-) diff --git a/Lib/subprocess.py b/Lib/subprocess.py index 1260e8739a3ab6..aed765ae4130c5 100644 --- a/Lib/subprocess.py +++ b/Lib/subprocess.py @@ -741,10 +741,10 @@ def __init__(self, args, bufsize=-1, executable=None, if shell: raise ValueError("shell is not supported on VxWorks") if preexec_fn is not None: - raise ValueError("Preexecution function is not supported" - "on VxWorks"); + raise ValueError("preexec_fn is not supported on VxWorks") if start_new_session: - raise ValueError("VxWorks does not support sessions"); + raise ValueError("start_new_session is not supported" + "on VxWorks") # POSIX if pass_fds and not close_fds: warnings.warn("pass_fds overriding close_fds.", RuntimeWarning) @@ -1599,8 +1599,9 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, cwd, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, - errpipe_read, errpipe_write, - restore_signals, start_new_session, preexec_fn) + errpipe_read, errpipe_write) + if self.pid != -1: + self._child_created = True else: self.pid = _posixsubprocess.fork_exec( args, executable_list, @@ -1610,9 +1611,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, errread, errwrite, errpipe_read, errpipe_write, restore_signals, start_new_session, preexec_fn) - self._child_created = True - if _vxworks and self.pid == -1: - self._child_created = False + self._child_created = True finally: # be sure the FD is closed no matter what os.close(errpipe_write) diff --git a/Lib/test/test_subprocess.py b/Lib/test/test_subprocess.py index 70a0300e3136c9..88542ee145b3e6 100644 --- a/Lib/test/test_subprocess.py +++ b/Lib/test/test_subprocess.py @@ -42,18 +42,15 @@ no_preexec_fn = False if vxworks: - import _vxwapi - mock_modname = "subprocess._vxwapi.rtp_spawn" - mock_submod = subprocess._vxwapi - mock_func = _vxwapi.rtp_spawn + mock_fork_exec_or_spawn_fn_name = "subprocess._vxwapi.rtp_spawn" + platform_specific_fork_exec_or_spawn = subprocess._vxwapi.rtp_spawn no_shell = True no_preexec_fn = True else: - import _posixsubprocess - mock_modname = "subprocess._posixsubprocess.fork_exec" - mock_submod = subprocess._posixsubprocess - mock_func = _posixsubprocess.fork_exec + mock_fork_exec_or_spawn_fn_name = "subprocess._posixsubprocess.fork_exec" + if not mswindows: + platform_specific_fork_exec_or_spawn = subprocess._posixsubprocess.fork_exec # # Depends on the following external programs: Python @@ -1600,8 +1597,8 @@ class PopenNoDestructor(subprocess.Popen): def __del__(self): pass - @mock.patch(mock_modname) - def test_exception_errpipe_normal(self, mock_func): + @mock.patch(mock_fork_exec_or_spawn_fn_name) + def test_exception_errpipe_normal(self, platform_specific_fork_exec_or_spawn): """Test error passing done through errpipe_write in the good case""" def proper_error(*args): errpipe_write = args[13] @@ -1610,15 +1607,15 @@ def proper_error(*args): os.write(errpipe_write, b"OSError:" + err_code + b":") return 0 - mock_func.side_effect = proper_error + platform_specific_fork_exec_or_spawn.side_effect = proper_error with mock.patch("subprocess.os.waitpid", side_effect=ChildProcessError): with self.assertRaises(IsADirectoryError): self.PopenNoDestructor(["non_existent_command"]) - @mock.patch(mock_modname) - def test_exception_errpipe_bad_data(self, mock_func): + @mock.patch(mock_fork_exec_or_spawn_fn_name) + def test_exception_errpipe_bad_data(self, platform_specific_fork_exec_or_spawn): """Test error passing done through errpipe_write where its not in the expected format""" error_data = b"\xFF\x00\xDE\xAD" @@ -1630,7 +1627,7 @@ def bad_error(*args): os.write(errpipe_write, error_data) return 0 - mock_func.side_effect = bad_error + platform_specific_fork_exec_or_spawn.side_effect = bad_error with mock.patch("subprocess.os.waitpid", side_effect=ChildProcessError): @@ -1732,7 +1729,7 @@ def raise_it(): preexec_fn=raise_it) except subprocess.SubprocessError as e: self.assertTrue( - mock_submod, + subprocess._posixsubprocess, "Expected a ValueError from the preexec_fn") except ValueError as e: self.assertIn("coconut", e.args[0]) @@ -2243,11 +2240,11 @@ def prepare(): preexec_fn=prepare) except ValueError as err: # Pure Python implementations keeps the message - self.assertIsNone(mock_submod) + self.assertIsNone(subprocess._posixsubprocess) self.assertEqual(str(err), "surrogate:\uDCff") except subprocess.SubprocessError as err: # _posixsubprocess uses a default message - self.assertIsNotNone(mock_submod) + self.assertIsNotNone(subprocess._posixsubprocess) self.assertEqual(str(err), "Exception occurred in preexec_fn.") else: self.fail("Expected ValueError or subprocess.SubprocessError") @@ -2770,12 +2767,19 @@ def __int__(self): with self.assertRaises( ValueError, msg='fds_to_keep={}'.format(fds_to_keep)) as c: - mock_func( - [b"false"], [b"false"], - True, fds_to_keep, None, [b"env"], - -1, -1, -1, -1, - 1, 2, 3, 4, - True, True, None) + if vxworks: + platform_specific_fork_exec_or_spawn( + [b"false"], [b"false"], + True, fds_to_keep, None, [b"env"], + -1, -1, -1, -1, + 1, 2, 3, 4) + else: + platform_specific_fork_exec_or_spawn( + [b"false"], [b"false"], + True, fds_to_keep, None, [b"env"], + -1, -1, -1, -1, + 1, 2, 3, 4, + True, True, None) self.assertIn('fds_to_keep', str(c.exception)) finally: if not gc_enabled: @@ -2916,7 +2920,6 @@ def test_creationflags(self): ' -c "import time; time.sleep(0.25)"', creationflags=CREATE_NEW_CONSOLE) - @unittest.skipIf(no_preexec_fn, "preexec_fn argument is not supported") def test_invalid_args(self): # invalid arguments should raise ValueError self.assertRaises(ValueError, subprocess.call, @@ -3001,7 +3004,6 @@ def test_empty_handle_list(self): subprocess.call([sys.executable, "-c", "import sys; sys.exit(0)"], startupinfo=startupinfo) - @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_sequence(self): # Run command through the shell (sequence) newenv = os.environ.copy() @@ -3012,7 +3014,6 @@ def test_shell_sequence(self): with p: self.assertIn(b"physalis", p.stdout.read()) - @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_string(self): # Run command through the shell (string) newenv = os.environ.copy() @@ -3023,7 +3024,6 @@ def test_shell_string(self): with p: self.assertIn(b"physalis", p.stdout.read()) - @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_encodings(self): # Run command through the shell (string) for enc in ['ansi', 'oem']: @@ -3243,13 +3243,11 @@ def with_spaces(self, *args, **kwargs): "2 [%r, 'ab cd']" % self.fname ) - @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_string_with_spaces(self): # call() function with string argument with spaces on Windows self.with_spaces('"%s" "%s" "%s"' % (sys.executable, self.fname, "ab cd"), shell=1) - @unittest.skipIf(no_shell, "shell argument is not supported") def test_shell_sequence_with_spaces(self): # call() function with sequence argument with spaces on Windows self.with_spaces([sys.executable, self.fname, "ab cd"], shell=1) diff --git a/Modules/_vxwapi.c b/Modules/_vxwapi.c index 110eba8dcfe541..984ce6487657ea 100644 --- a/Modules/_vxwapi.c +++ b/Modules/_vxwapi.c @@ -117,8 +117,7 @@ rtp_spawn_impl( int c2pread, int c2pwrite, int errread, int errwrite, int errpipe_read, int errpipe_write, - int close_fds, int restore_signals, - PyObject *py_fds_to_keep) + int close_fds, PyObject *py_fds_to_keep) { int priority = 0; unsigned int uStackSize = 0; @@ -243,7 +242,6 @@ rtp_spawn_impl( reached_preexec = 1; - /* close FDs after executing preexec_fn, which might open FDs */ if (close_fds) { _close_open_fds(3, py_fds_to_keep); } @@ -387,9 +385,6 @@ _vxwapi.rtp_spawn errwrite: int errpipe_read: int errpipe_write: int - restore_signals: int - call_setsid: int - preexec_fn: object / Spawn a real time process in the vxWorks OS @@ -401,10 +396,9 @@ _vxwapi_rtp_spawn_impl(PyObject *module, PyObject *process_args, PyObject *py_fds_to_keep, PyObject *cwd_obj, PyObject *env_list, int p2cread, int p2cwrite, int c2pread, int c2pwrite, int errread, int errwrite, - int errpipe_read, int errpipe_write, - int restore_signals, int call_setsid, - PyObject *preexec_fn) -/*[clinic end generated code: output=5f98889b783df975 input=30419f3fea045213]*/ + int errpipe_read, int errpipe_write) +/*[clinic end generated code: output=e398e7eafdf8ce1e input=76a69d261378fad9]*/ + { PyObject *converted_args = NULL, *fast_args = NULL; char *const *argv = NULL, *const *envp = NULL; @@ -426,16 +420,6 @@ _vxwapi_rtp_spawn_impl(PyObject *module, PyObject *process_args, return NULL; } - if (preexec_fn != Py_None) { - PyErr_SetString(PyExc_RuntimeError, "Preexecution function is not supported on VxWorks"); - return NULL; - } - - if (call_setsid != 0) { - PyErr_SetString(PyExc_RuntimeError, "VxWorks does not support sessions"); - return NULL; - } - /* Convert args and env into appropriate arguments */ /* These conversions are done in the parent process to avoid allocating or freeing memory in the child process. */ @@ -483,7 +467,7 @@ _vxwapi_rtp_spawn_impl(PyObject *module, PyObject *process_args, executable_list, argv, envp, cwd_obj, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, - close_fds, restore_signals, py_fds_to_keep); + close_fds, py_fds_to_keep); _restore_fds (saved_fd); diff --git a/Modules/clinic/_vxwapi.c.h b/Modules/clinic/_vxwapi.c.h index 0511936a8c27ea..8c4029121f0042 100644 --- a/Modules/clinic/_vxwapi.c.h +++ b/Modules/clinic/_vxwapi.c.h @@ -6,7 +6,7 @@ PyDoc_STRVAR(_vxwapi_rtp_spawn__doc__, "rtp_spawn($module, process_args, executable_list, close_fds,\n" " py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite,\n" " c2pread, c2pwrite, errread, errwrite, errpipe_read,\n" -" errpipe_write, restore_signals, call_setsid, preexec_fn, /)\n" +" errpipe_write, /)\n" "--\n" "\n" "Spawn a real time process in the vxWorks OS"); @@ -20,9 +20,7 @@ _vxwapi_rtp_spawn_impl(PyObject *module, PyObject *process_args, PyObject *py_fds_to_keep, PyObject *cwd_obj, PyObject *env_list, int p2cread, int p2cwrite, int c2pread, int c2pwrite, int errread, int errwrite, - int errpipe_read, int errpipe_write, - int restore_signals, int call_setsid, - PyObject *preexec_fn); + int errpipe_read, int errpipe_write); static PyObject * _vxwapi_rtp_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs) @@ -42,11 +40,8 @@ _vxwapi_rtp_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs) int errwrite; int errpipe_read; int errpipe_write; - int restore_signals; - int call_setsid; - PyObject *preexec_fn; - if (!_PyArg_CheckPositional("rtp_spawn", nargs, 17, 17)) { + if (!_PyArg_CheckPositional("rtp_spawn", nargs, 14, 14)) { goto exit; } process_args = args[0]; @@ -139,28 +134,9 @@ _vxwapi_rtp_spawn(PyObject *module, PyObject *const *args, Py_ssize_t nargs) if (errpipe_write == -1 && PyErr_Occurred()) { goto exit; } - if (PyFloat_Check(args[14])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } - restore_signals = _PyLong_AsInt(args[14]); - if (restore_signals == -1 && PyErr_Occurred()) { - goto exit; - } - if (PyFloat_Check(args[15])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } - call_setsid = _PyLong_AsInt(args[15]); - if (call_setsid == -1 && PyErr_Occurred()) { - goto exit; - } - preexec_fn = args[16]; - return_value = _vxwapi_rtp_spawn_impl(module, process_args, executable_list, close_fds, py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, call_setsid, preexec_fn); + return_value = _vxwapi_rtp_spawn_impl(module, process_args, executable_list, close_fds, py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write); exit: return return_value; } -/*[clinic end generated code: output=216bc865460f7764 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=44ceb0e8de454bd6 input=a9049054013a1b77]*/