Ignore:
Timestamp:
Dec 26, 2017, 10:43:44 PM (8 years ago)
Author:
dmik
Message:

python: Implement subprocess.Popen using LIBCx spawn2.

Closes #280.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • python/trunk/Modules/posixmodule.c

    r1254 r1281  
    3838#if defined(__KLIBC__)
    3939#include <sys/socket.h>
     40#include <libcx/spawn2.h>
    4041#endif
    4142
     
    88048805}
    88058806#endif
     8807
     8808#if defined(PYOS_OS2)
     8809PyDoc_STRVAR(os2_spawn2__doc__,
     8810"spawn2(mode, file, args, cwd, env, stdfds)\n\n\
     8811Execute the program 'name' in a new process,\n\
     8812search 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
     8821static PyObject *
     8822os2_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 */
    88068998
    88078999static PyMethodDef posix_methods[] = {
     
    91279319#endif
    91289320    {"urandom",         posix_urandom,   METH_VARARGS, posix_urandom__doc__},
     9321#ifdef PYOS_OS2
     9322    {"spawn2",          os2_spawn2, METH_VARARGS, os2_spawn2__doc__},
     9323#endif
    91299324    {NULL,              NULL}            /* Sentinel */
    91309325};
     
    93959590    if (ins(d, "P_UNRELATED", (long)P_UNRELATED)) return -1;
    93969591    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;
    93979595#else
    93989596    if (ins(d, "P_WAIT", (long)_P_WAIT)) return -1;
Note: See TracChangeset for help on using the changeset viewer.