- Timestamp:
- Dec 26, 2017, 10:43:44 PM (8 years ago)
- Location:
- python/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
python/trunk/Lib/subprocess.py
r1254 r1281 659 659 preexec_fn=None, close_fds=False, shell=False, 660 660 cwd=None, env=None, universal_newlines=False, 661 startupinfo=None, creationflags=0): 661 startupinfo=None, creationflags=0, 662 threadsafe=None): 662 663 """Create new Popen instance.""" 663 664 _cleanup() … … 683 684 raise ValueError("creationflags is only supported on Windows " 684 685 "platforms") 686 if os2: 687 if threadsafe is None: 688 threadsafe = False 689 else: 690 if threadsafe is not None: 691 raise ValueError("threadsafe is only supported on OS/2 " 692 "platforms") 685 693 686 694 self.stdin = None … … 713 721 self._execute_child(args, executable, preexec_fn, close_fds, 714 722 cwd, env, universal_newlines, 715 startupinfo, creationflags, shell, to_close,723 startupinfo, creationflags, threadsafe, shell, to_close, 716 724 p2cread, p2cwrite, 717 725 c2pread, c2pwrite, … … 912 920 def _execute_child(self, args, executable, preexec_fn, close_fds, 913 921 cwd, env, universal_newlines, 914 startupinfo, creationflags, shell, to_close,922 startupinfo, creationflags, threadsafe, shell, to_close, 915 923 p2cread, p2cwrite, 916 924 c2pread, c2pwrite, … … 1195 1203 def _execute_child(self, args, executable, preexec_fn, close_fds, 1196 1204 cwd, env, universal_newlines, 1197 startupinfo, creationflags, shell, to_close,1205 startupinfo, creationflags, threadsafe, shell, to_close, 1198 1206 p2cread, p2cwrite, 1199 1207 c2pread, c2pwrite, … … 1223 1231 # in the kernel). 1224 1232 mode = os.P_NOWAIT 1225 oldcwd = None 1226 dups = [ None, None, None ] 1227 cloexec_fds = set() 1228 1229 try: 1230 # Change the directory if asked 1231 if cwd is not None: 1232 oldcwd = os.getcwd() 1233 os.chdir(cwd) 1234 1235 # Duplicate stdio if needed 1236 if p2cread is not None: 1237 dups[0] = os.dup(0) 1238 os.dup2(p2cread, 0) 1239 self._set_cloexec_flag(dups[0]) 1240 if c2pwrite is not None: 1241 dups[1] = os.dup(1) 1242 os.dup2(c2pwrite, 1) 1243 self._set_cloexec_flag(dups[1]) 1244 if errwrite is not None: 1245 dups[2] = os.dup(2) 1246 os.dup2(errwrite, 2) 1247 self._set_cloexec_flag(dups[2]) 1248 1249 # Disable inheritance 1250 if close_fds: 1251 for i in xrange(3, MAXFD): 1252 try: 1253 f = fcntl.fcntl(i, fcntl.F_GETFD) 1254 if not (f & fcntl.FD_CLOEXEC): 1255 cloexec_fds.add(i) 1256 self._set_cloexec_flag(i) 1257 except: 1258 pass 1259 1260 if env is None: 1261 pid = os.spawnvp(mode, executable, args) 1262 else: 1263 pid = os.spawnvpe(mode, executable, args, env) 1264 finally: 1265 # Restore inheritance 1266 for i in cloexec_fds: 1267 self._set_cloexec_flag(i, False) 1268 1269 # Restore the parent stdio 1270 for i, fd in enumerate(dups): 1271 if fd is not None: 1272 os.dup2(fd, i) 1273 os.close(fd) 1274 1275 # Restore the current directory 1276 if oldcwd is not None: 1277 os.chdir(oldcwd) 1233 1234 if close_fds: 1235 mode |= os.P_2_NOINHERIT 1236 if threadsafe: 1237 mode |= os.P_2_THREADSAFE 1238 stdfds = [ p2cread, c2pwrite, errwrite ] 1239 1240 pid = os.spawn2(mode, executable, args, cwd, env, stdfds) 1278 1241 1279 1242 # Child is launched. Close the parent's copy of those pipe … … 1480 1443 data = _eintr_retry_call(file.read) 1481 1444 if data == "": 1482 file.close() 1445 try: 1446 file.close() 1447 except IOError as e: 1448 # kLIBC close may fail with EBADF or even Error 0, 1449 # ignore for now 1450 pass 1483 1451 break 1484 1452 buffer.append(data) … … 1504 1472 if input is not None: 1505 1473 try: 1506 self.stdin.write(input)1474 _eintr_retry_call(self.stdin.write, input) 1507 1475 except IOError as e: 1508 1476 if e.errno != errno.EPIPE: 1509 1477 raise 1510 self.stdin.close() 1478 try: 1479 self.stdin.close() 1480 except IOError as e: 1481 # kLIBC close may fail with EBADF or even Error 0, 1482 # ignore for now 1483 pass 1511 1484 1512 1485 if self.stdout: -
python/trunk/Modules/posixmodule.c
r1254 r1281 38 38 #if defined(__KLIBC__) 39 39 #include <sys/socket.h> 40 #include <libcx/spawn2.h> 40 41 #endif 41 42 … … 8804 8805 } 8805 8806 #endif 8807 8808 #if defined(PYOS_OS2) 8809 PyDoc_STRVAR(os2_spawn2__doc__, 8810 "spawn2(mode, file, args, cwd, env, stdfds)\n\n\ 8811 Execute the program 'name' in a new process,\n\ 8812 search path to find the file.\n\ 8813 \n\ 8814 mode: mode of process creation\n\ 8815 file: executable file name\n\ 8816 args: tuple or list of strings\n\ 8817 cwd: initial working directory for the new process\n\ 8818 env: dictionary of strings mapping to strings\n\ 8819 stdfds: tuple or list of 3 file descriptors for standard I/O"); 8820 8821 static PyObject * 8822 os2_spawn2(PyObject *self, PyObject *args) 8823 { 8824 char *path, *cwd = NULL; 8825 PyObject *argv, *env, *stdfds; 8826 char **argvlist; 8827 char **envlist; 8828 PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; 8829 int mode, i, pos, argc, envc, stdfdc; 8830 Py_intptr_t spawnval; 8831 PyObject *(*argv_getitem)(PyObject *, Py_ssize_t); 8832 int lastarg = 0; 8833 PyObject *(*stdfd_getitem)(PyObject *, Py_ssize_t); 8834 int stdfdlist[3] = {0}; 8835 8836 /* Note: no need in et and Py_FileSystemDefaultEncoding for path arguments 8837 * as on OS/2 this is always the same as the default encoding. */ 8838 if (!PyArg_ParseTuple(args, "isOzOO:spawn2", &mode, 8839 &path, &argv, &cwd, &env, &stdfds)) 8840 return NULL; 8841 if (PyList_Check(argv)) { 8842 argc = PyList_Size(argv); 8843 argv_getitem = PyList_GetItem; 8844 } 8845 else if (PyTuple_Check(argv)) { 8846 argc = PyTuple_Size(argv); 8847 argv_getitem = PyTuple_GetItem; 8848 } 8849 else { 8850 PyErr_SetString(PyExc_TypeError, 8851 "spawn2() arg 3 must be a tuple or list"); 8852 goto fail_0; 8853 } 8854 8855 if (env != Py_None && !PyMapping_Check(env)) { 8856 PyErr_SetString(PyExc_TypeError, 8857 "spawn2() arg 5 must be a mapping object"); 8858 goto fail_0; 8859 } 8860 8861 if (PyList_Check(stdfds)) { 8862 stdfdc = PyList_Size(stdfds); 8863 stdfd_getitem = PyList_GetItem; 8864 } 8865 else if (PyTuple_Check(stdfds)) { 8866 stdfdc = PyTuple_Size(stdfds); 8867 stdfd_getitem = PyTuple_GetItem; 8868 } 8869 else if (stdfds == Py_None) { 8870 stdfdc = -1; 8871 } 8872 else { 8873 PyErr_SetString(PyExc_TypeError, 8874 "spawn2() arg 6 must be a tuple or list or None"); 8875 goto fail_0; 8876 } 8877 if (stdfdc != -1 && stdfdc != 3) { 8878 PyErr_SetString(PyExc_TypeError, 8879 "spawn2() arg 6 must contain 3 elements"); 8880 goto fail_0; 8881 } 8882 8883 argvlist = PyMem_NEW(char *, argc+1); 8884 if (argvlist == NULL) { 8885 PyErr_NoMemory(); 8886 goto fail_0; 8887 } 8888 8889 for (i = 0; i < argc; i++) { 8890 if (!PyArg_Parse((*argv_getitem)(argv, i), "et", 8891 Py_FileSystemDefaultEncoding, &argvlist[i])) 8892 { 8893 PyErr_SetString(PyExc_TypeError, 8894 "spawn2() arg 3 must contain only strings"); 8895 lastarg = i; 8896 goto fail_1; 8897 } 8898 } 8899 lastarg = argc; 8900 argvlist[argc] = NULL; 8901 8902 if (env == Py_None) { 8903 envlist = NULL; 8904 envc = -1; 8905 } else { 8906 i = PyMapping_Size(env); 8907 if (i < 0) 8908 goto fail_1; 8909 envlist = PyMem_NEW(char *, i + 1); 8910 if (envlist == NULL) { 8911 PyErr_NoMemory(); 8912 goto fail_1; 8913 } 8914 envc = 0; 8915 keys = PyMapping_Keys(env); 8916 vals = PyMapping_Values(env); 8917 if (!keys || !vals) 8918 goto fail_2; 8919 if (!PyList_Check(keys) || !PyList_Check(vals)) { 8920 PyErr_SetString(PyExc_TypeError, 8921 "spawn2(): env.keys() or env.values() is not a list"); 8922 goto fail_2; 8923 } 8924 8925 for (pos = 0; pos < i; pos++) { 8926 char *p, *k, *v; 8927 size_t len; 8928 8929 key = PyList_GetItem(keys, pos); 8930 val = PyList_GetItem(vals, pos); 8931 if (!key || !val) 8932 goto fail_2; 8933 8934 if (!PyArg_Parse(key, "s", &k)) { 8935 PyErr_SetString(PyExc_TypeError, 8936 "spawn2() arg 5 contains a non-string key"); 8937 goto fail_2; 8938 } 8939 if (!PyArg_Parse(val, "s", &v)) { 8940 PyErr_SetString(PyExc_TypeError, 8941 "spawn2() arg 5 contains a non-string key"); 8942 goto fail_2; 8943 } 8944 len = PyString_Size(key) + PyString_Size(val) + 2; 8945 p = PyMem_NEW(char, len); 8946 if (p == NULL) { 8947 PyErr_NoMemory(); 8948 goto fail_2; 8949 } 8950 PyOS_snprintf(p, len, "%s=%s", k, v); 8951 envlist[envc++] = p; 8952 } 8953 envlist[envc] = 0; 8954 } 8955 8956 if (stdfdc != -1) { 8957 for (i = 0; i < stdfdc; i++) { 8958 PyObject *elem = (*stdfd_getitem)(stdfds, i); 8959 if (elem == Py_None) { 8960 stdfdlist[i] = 0; 8961 } else { 8962 if (!PyArg_Parse(elem, "i", &stdfdlist[i])) { 8963 PyErr_SetString(PyExc_TypeError, 8964 "spawn2() arg 6 must contain only integers"); 8965 goto fail_2; 8966 } 8967 } 8968 } 8969 } 8970 8971 Py_BEGIN_ALLOW_THREADS 8972 8973 spawnval = spawn2(mode, path, (const char * const *)argvlist, cwd, 8974 (const char * const *)envlist, 8975 stdfdc == -1 ? NULL : stdfdlist); 8976 8977 Py_END_ALLOW_THREADS 8978 8979 if (spawnval == -1) 8980 (void) posix_error(); 8981 else 8982 res = Py_BuildValue("l", (long) spawnval); 8983 8984 fail_2: 8985 if (envlist) { 8986 while (--envc >= 0) 8987 PyMem_DEL(envlist[envc]); 8988 PyMem_DEL(envlist); 8989 } 8990 fail_1: 8991 free_string_array(argvlist, lastarg); 8992 Py_XDECREF(vals); 8993 Py_XDECREF(keys); 8994 fail_0: 8995 return res; 8996 } 8997 #endif /* PYOS_OS2 */ 8806 8998 8807 8999 static PyMethodDef posix_methods[] = { … … 9127 9319 #endif 9128 9320 {"urandom", posix_urandom, METH_VARARGS, posix_urandom__doc__}, 9321 #ifdef PYOS_OS2 9322 {"spawn2", os2_spawn2, METH_VARARGS, os2_spawn2__doc__}, 9323 #endif 9129 9324 {NULL, NULL} /* Sentinel */ 9130 9325 }; … … 9395 9590 if (ins(d, "P_UNRELATED", (long)P_UNRELATED)) return -1; 9396 9591 if (ins(d, "P_DEBUGDESC", (long)P_DEBUGDESC)) return -1; 9592 if (ins(d, "P_2_NOINHERIT", (long)P_2_NOINHERIT)) return -1; 9593 if (ins(d, "P_2_THREADSAFE", (long)P_2_THREADSAFE)) return -1; 9594 if (ins(d, "P_2_MODE_MASK", (long)P_2_MODE_MASK)) return -1; 9397 9595 #else 9398 9596 if (ins(d, "P_WAIT", (long)_P_WAIT)) return -1;
Note:
See TracChangeset
for help on using the changeset viewer.