Issue #11743: Rewrite multiprocessing connection classes in pure Python.
diff --git a/Modules/_multiprocessing/connection.h b/Modules/_multiprocessing/connection.h
deleted file mode 100644
index 002d5aa..0000000
--- a/Modules/_multiprocessing/connection.h
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Definition of a `Connection` type.
- * Used by `socket_connection.c` and `pipe_connection.c`.
- *
- * connection.h
- *
- * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
- */
-
-#ifndef CONNECTION_H
-#define CONNECTION_H
-
-/*
- * Read/write flags
- */
-
-#define READABLE 1
-#define WRITABLE 2
-
-#define CHECK_READABLE(self) \
-    if (!(self->flags & READABLE)) { \
-    PyErr_SetString(PyExc_IOError, "connection is write-only"); \
-    return NULL; \
-    }
-
-#define CHECK_WRITABLE(self) \
-    if (!(self->flags & WRITABLE)) { \
-    PyErr_SetString(PyExc_IOError, "connection is read-only"); \
-    return NULL; \
-    }
-
-/*
- * Allocation and deallocation
- */
-
-static PyObject *
-connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
-{
-    ConnectionObject *self;
-    HANDLE handle;
-    BOOL readable = TRUE, writable = TRUE;
-
-    static char *kwlist[] = {"handle", "readable", "writable", NULL};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "|ii", kwlist,
-                                     &handle, &readable, &writable))
-        return NULL;
-
-    if (handle == INVALID_HANDLE_VALUE || (Py_ssize_t)handle < 0) {
-        PyErr_Format(PyExc_IOError, "invalid handle %zd",
-                     (Py_ssize_t)handle);
-        return NULL;
-    }
-
-    if (!readable && !writable) {
-        PyErr_SetString(PyExc_ValueError,
-                        "either readable or writable must be true");
-        return NULL;
-    }
-
-    self = PyObject_New(ConnectionObject, type);
-    if (self == NULL)
-        return NULL;
-
-    self->weakreflist = NULL;
-    self->handle = handle;
-    self->flags = 0;
-
-    if (readable)
-        self->flags |= READABLE;
-    if (writable)
-        self->flags |= WRITABLE;
-    assert(self->flags >= 1 && self->flags <= 3);
-
-    return (PyObject*)self;
-}
-
-static void
-connection_dealloc(ConnectionObject* self)
-{
-    if (self->weakreflist != NULL)
-        PyObject_ClearWeakRefs((PyObject*)self);
-
-    if (self->handle != INVALID_HANDLE_VALUE) {
-        Py_BEGIN_ALLOW_THREADS
-        CLOSE(self->handle);
-        Py_END_ALLOW_THREADS
-    }
-    PyObject_Del(self);
-}
-
-/*
- * Functions for transferring buffers
- */
-
-static PyObject *
-connection_sendbytes(ConnectionObject *self, PyObject *args)
-{
-    Py_buffer pbuffer;
-    char *buffer;
-    Py_ssize_t length, offset=0, size=PY_SSIZE_T_MIN;
-    int res;
-
-    if (!PyArg_ParseTuple(args, F_RBUFFER "*|" F_PY_SSIZE_T F_PY_SSIZE_T,
-                          &pbuffer, &offset, &size))
-        return NULL;
-    buffer = pbuffer.buf;
-    length = pbuffer.len;
-
-    CHECK_WRITABLE(self); /* XXX release buffer in case of failure */
-
-    if (offset < 0) {
-        PyBuffer_Release(&pbuffer);
-        PyErr_SetString(PyExc_ValueError, "offset is negative");
-        return NULL;
-    }
-    if (length < offset) {
-        PyBuffer_Release(&pbuffer);
-        PyErr_SetString(PyExc_ValueError, "buffer length < offset");
-        return NULL;
-    }
-
-    if (size == PY_SSIZE_T_MIN) {
-        size = length - offset;
-    } else {
-        if (size < 0) {
-            PyBuffer_Release(&pbuffer);
-            PyErr_SetString(PyExc_ValueError, "size is negative");
-            return NULL;
-        }
-        if (offset + size > length) {
-            PyBuffer_Release(&pbuffer);
-            PyErr_SetString(PyExc_ValueError,
-                            "buffer length < offset + size");
-            return NULL;
-        }
-    }
-
-    res = conn_send_string(self, buffer + offset, size);
-
-    PyBuffer_Release(&pbuffer);
-    if (res < 0) {
-        if (PyErr_Occurred())
-            return NULL;
-        else
-            return mp_SetError(PyExc_IOError, res);
-    }
-
-    Py_RETURN_NONE;
-}
-
-static PyObject *
-connection_recvbytes(ConnectionObject *self, PyObject *args)
-{
-    char *freeme = NULL;
-    Py_ssize_t res, maxlength = PY_SSIZE_T_MAX;
-    PyObject *result = NULL;
-
-    if (!PyArg_ParseTuple(args, "|" F_PY_SSIZE_T, &maxlength))
-        return NULL;
-
-    CHECK_READABLE(self);
-
-    if (maxlength < 0) {
-        PyErr_SetString(PyExc_ValueError, "maxlength < 0");
-        return NULL;
-    }
-
-    res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE,
-                           &freeme, maxlength);
-
-    if (res < 0) {
-        if (res == MP_BAD_MESSAGE_LENGTH) {
-            if ((self->flags & WRITABLE) == 0) {
-                Py_BEGIN_ALLOW_THREADS
-                CLOSE(self->handle);
-                Py_END_ALLOW_THREADS
-                self->handle = INVALID_HANDLE_VALUE;
-            } else {
-                self->flags = WRITABLE;
-            }
-        }
-        mp_SetError(PyExc_IOError, res);
-    } else {
-        if (freeme == NULL) {
-            result = PyBytes_FromStringAndSize(self->buffer, res);
-        } else {
-            result = PyBytes_FromStringAndSize(freeme, res);
-            PyMem_Free(freeme);
-        }
-    }
-
-    return result;
-}
-
-static PyObject *
-connection_recvbytes_into(ConnectionObject *self, PyObject *args)
-{
-    char *freeme = NULL, *buffer = NULL;
-    Py_ssize_t res, length, offset = 0;
-    PyObject *result = NULL;
-    Py_buffer pbuf;
-
-    CHECK_READABLE(self);
-
-    if (!PyArg_ParseTuple(args, "w*|" F_PY_SSIZE_T,
-                          &pbuf, &offset))
-        return NULL;
-
-    buffer = pbuf.buf;
-    length = pbuf.len;
-
-    if (offset < 0) {
-        PyErr_SetString(PyExc_ValueError, "negative offset");
-        goto _error;
-    }
-
-    if (offset > length) {
-        PyErr_SetString(PyExc_ValueError, "offset too large");
-        goto _error;
-    }
-
-    res = conn_recv_string(self, buffer+offset, length-offset,
-                           &freeme, PY_SSIZE_T_MAX);
-
-    if (res < 0) {
-        if (res == MP_BAD_MESSAGE_LENGTH) {
-            if ((self->flags & WRITABLE) == 0) {
-                Py_BEGIN_ALLOW_THREADS
-                CLOSE(self->handle);
-                Py_END_ALLOW_THREADS
-                self->handle = INVALID_HANDLE_VALUE;
-            } else {
-                self->flags = WRITABLE;
-            }
-        }
-        mp_SetError(PyExc_IOError, res);
-    } else {
-        if (freeme == NULL) {
-            result = PyInt_FromSsize_t(res);
-        } else {
-            result = PyObject_CallFunction(BufferTooShort,
-                                           F_RBUFFER "#",
-                                           freeme, res);
-            PyMem_Free(freeme);
-            if (result) {
-                PyErr_SetObject(BufferTooShort, result);
-                Py_DECREF(result);
-            }
-            goto _error;
-        }
-    }
-
-_cleanup:
-    PyBuffer_Release(&pbuf);
-    return result;
-
-_error:
-    result = NULL;
-    goto _cleanup;
-}
-
-/*
- * Functions for transferring objects
- */
-
-static PyObject *
-connection_send_obj(ConnectionObject *self, PyObject *obj)
-{
-    char *buffer;
-    int res;
-    Py_ssize_t length;
-    PyObject *pickled_string = NULL;
-
-    CHECK_WRITABLE(self);
-
-    pickled_string = PyObject_CallFunctionObjArgs(pickle_dumps, obj,
-                                                  pickle_protocol, NULL);
-    if (!pickled_string)
-        goto failure;
-
-    if (PyBytes_AsStringAndSize(pickled_string, &buffer, &length) < 0)
-        goto failure;
-
-    res = conn_send_string(self, buffer, (int)length);
-
-    if (res < 0) {
-        mp_SetError(PyExc_IOError, res);
-        goto failure;
-    }
-
-    Py_XDECREF(pickled_string);
-    Py_RETURN_NONE;
-
-  failure:
-    Py_XDECREF(pickled_string);
-    return NULL;
-}
-
-static PyObject *
-connection_recv_obj(ConnectionObject *self)
-{
-    char *freeme = NULL;
-    Py_ssize_t res;
-    PyObject *temp = NULL, *result = NULL;
-
-    CHECK_READABLE(self);
-
-    res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE,
-                           &freeme, PY_SSIZE_T_MAX);
-
-    if (res < 0) {
-        if (res == MP_BAD_MESSAGE_LENGTH) {
-            if ((self->flags & WRITABLE) == 0) {
-                Py_BEGIN_ALLOW_THREADS
-                CLOSE(self->handle);
-                Py_END_ALLOW_THREADS
-                self->handle = INVALID_HANDLE_VALUE;
-            } else {
-                self->flags = WRITABLE;
-            }
-        }
-        mp_SetError(PyExc_IOError, res);
-    } else {
-        if (freeme == NULL) {
-            temp = PyBytes_FromStringAndSize(self->buffer, res);
-        } else {
-            temp = PyBytes_FromStringAndSize(freeme, res);
-            PyMem_Free(freeme);
-        }
-    }
-
-    if (temp)
-        result = PyObject_CallFunctionObjArgs(pickle_loads,
-                                              temp, NULL);
-    Py_XDECREF(temp);
-    return result;
-}
-
-/*
- * Other functions
- */
-
-static PyObject *
-connection_poll(ConnectionObject *self, PyObject *args)
-{
-    PyObject *timeout_obj = NULL;
-    double timeout = 0.0;
-    int res;
-
-    CHECK_READABLE(self);
-
-    if (!PyArg_ParseTuple(args, "|O", &timeout_obj))
-        return NULL;
-
-    if (timeout_obj == NULL) {
-        timeout = 0.0;
-    } else if (timeout_obj == Py_None) {
-        timeout = -1.0;                                 /* block forever */
-    } else {
-        timeout = PyFloat_AsDouble(timeout_obj);
-        if (PyErr_Occurred())
-            return NULL;
-        if (timeout < 0.0)
-            timeout = 0.0;
-    }
-
-    Py_BEGIN_ALLOW_THREADS
-    res = conn_poll(self, timeout, _save);
-    Py_END_ALLOW_THREADS
-
-    switch (res) {
-    case TRUE:
-        Py_RETURN_TRUE;
-    case FALSE:
-        Py_RETURN_FALSE;
-    default:
-        return mp_SetError(PyExc_IOError, res);
-    }
-}
-
-static PyObject *
-connection_fileno(ConnectionObject* self)
-{
-    if (self->handle == INVALID_HANDLE_VALUE) {
-        PyErr_SetString(PyExc_IOError, "handle is invalid");
-        return NULL;
-    }
-    return PyInt_FromLong((long)self->handle);
-}
-
-static PyObject *
-connection_close(ConnectionObject *self)
-{
-    if (self->handle != INVALID_HANDLE_VALUE) {
-        Py_BEGIN_ALLOW_THREADS
-        CLOSE(self->handle);
-        Py_END_ALLOW_THREADS
-        self->handle = INVALID_HANDLE_VALUE;
-    }
-
-    Py_RETURN_NONE;
-}
-
-static PyObject *
-connection_repr(ConnectionObject *self)
-{
-    static char *conn_type[] = {"read-only", "write-only", "read-write"};
-
-    assert(self->flags >= 1 && self->flags <= 3);
-    return FROM_FORMAT("<%s %s, handle %zd>",
-                       conn_type[self->flags - 1],
-                       CONNECTION_NAME, (Py_ssize_t)self->handle);
-}
-
-/*
- * Getters and setters
- */
-
-static PyObject *
-connection_closed(ConnectionObject *self, void *closure)
-{
-    return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE));
-}
-
-static PyObject *
-connection_readable(ConnectionObject *self, void *closure)
-{
-    return PyBool_FromLong((long)(self->flags & READABLE));
-}
-
-static PyObject *
-connection_writable(ConnectionObject *self, void *closure)
-{
-    return PyBool_FromLong((long)(self->flags & WRITABLE));
-}
-
-/*
- * Tables
- */
-
-static PyMethodDef connection_methods[] = {
-    {"send_bytes", (PyCFunction)connection_sendbytes, METH_VARARGS,
-     "send the byte data from a readable buffer-like object"},
-    {"recv_bytes", (PyCFunction)connection_recvbytes, METH_VARARGS,
-     "receive byte data as a string"},
-    {"recv_bytes_into",(PyCFunction)connection_recvbytes_into,METH_VARARGS,
-     "receive byte data into a writeable buffer-like object\n"
-     "returns the number of bytes read"},
-
-    {"send", (PyCFunction)connection_send_obj, METH_O,
-     "send a (picklable) object"},
-    {"recv", (PyCFunction)connection_recv_obj, METH_NOARGS,
-     "receive a (picklable) object"},
-
-    {"poll", (PyCFunction)connection_poll, METH_VARARGS,
-     "whether there is any input available to be read"},
-    {"fileno", (PyCFunction)connection_fileno, METH_NOARGS,
-     "file descriptor or handle of the connection"},
-    {"close", (PyCFunction)connection_close, METH_NOARGS,
-     "close the connection"},
-
-    {NULL}  /* Sentinel */
-};
-
-static PyGetSetDef connection_getset[] = {
-    {"closed", (getter)connection_closed, NULL,
-     "True if the connection is closed", NULL},
-    {"readable", (getter)connection_readable, NULL,
-     "True if the connection is readable", NULL},
-    {"writable", (getter)connection_writable, NULL,
-     "True if the connection is writable", NULL},
-    {NULL}
-};
-
-/*
- * Connection type
- */
-
-PyDoc_STRVAR(connection_doc,
-             "Connection type whose constructor signature is\n\n"
-             "    Connection(handle, readable=True, writable=True).\n\n"
-             "The constructor does *not* duplicate the handle.");
-
-PyTypeObject CONNECTION_TYPE = {
-    PyVarObject_HEAD_INIT(NULL, 0)
-    /* tp_name           */ "_multiprocessing." CONNECTION_NAME,
-    /* tp_basicsize      */ sizeof(ConnectionObject),
-    /* tp_itemsize       */ 0,
-    /* tp_dealloc        */ (destructor)connection_dealloc,
-    /* tp_print          */ 0,
-    /* tp_getattr        */ 0,
-    /* tp_setattr        */ 0,
-    /* tp_reserved       */ 0,
-    /* tp_repr           */ (reprfunc)connection_repr,
-    /* tp_as_number      */ 0,
-    /* tp_as_sequence    */ 0,
-    /* tp_as_mapping     */ 0,
-    /* tp_hash           */ 0,
-    /* tp_call           */ 0,
-    /* tp_str            */ 0,
-    /* tp_getattro       */ 0,
-    /* tp_setattro       */ 0,
-    /* tp_as_buffer      */ 0,
-    /* tp_flags          */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
-                            Py_TPFLAGS_HAVE_WEAKREFS,
-    /* tp_doc            */ connection_doc,
-    /* tp_traverse       */ 0,
-    /* tp_clear          */ 0,
-    /* tp_richcompare    */ 0,
-    /* tp_weaklistoffset */ offsetof(ConnectionObject, weakreflist),
-    /* tp_iter           */ 0,
-    /* tp_iternext       */ 0,
-    /* tp_methods        */ connection_methods,
-    /* tp_members        */ 0,
-    /* tp_getset         */ connection_getset,
-    /* tp_base           */ 0,
-    /* tp_dict           */ 0,
-    /* tp_descr_get      */ 0,
-    /* tp_descr_set      */ 0,
-    /* tp_dictoffset     */ 0,
-    /* tp_init           */ 0,
-    /* tp_alloc          */ 0,
-    /* tp_new            */ connection_new,
-};
-
-#endif /* CONNECTION_H */
diff --git a/Modules/_multiprocessing/multiprocessing.c b/Modules/_multiprocessing/multiprocessing.c
index 7c4f52d..5685517 100644
--- a/Modules/_multiprocessing/multiprocessing.c
+++ b/Modules/_multiprocessing/multiprocessing.c
@@ -49,16 +49,6 @@
     case MP_MEMORY_ERROR:
         PyErr_NoMemory();
         break;
-    case MP_END_OF_FILE:
-        PyErr_SetNone(PyExc_EOFError);
-        break;
-    case MP_EARLY_END_OF_FILE:
-        PyErr_SetString(PyExc_IOError,
-                        "got end of file during message");
-        break;
-    case MP_BAD_MESSAGE_LENGTH:
-        PyErr_SetString(PyExc_IOError, "bad message length");
-        break;
     case MP_EXCEPTION_HAS_BEEN_SET:
         break;
     default:
@@ -257,12 +247,6 @@
     BufferTooShort = PyObject_GetAttrString(temp, "BufferTooShort");
     Py_XDECREF(temp);
 
-    /* Add connection type to module */
-    if (PyType_Ready(&ConnectionType) < 0)
-        return NULL;
-    Py_INCREF(&ConnectionType);
-    PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
-
 #if defined(MS_WINDOWS) ||                                              \
   (defined(HAVE_SEM_OPEN) && !defined(POSIX_SEMAPHORES_NOT_ENABLED))
     /* Add SemLock type to module */
@@ -286,13 +270,6 @@
 #endif
 
 #ifdef MS_WINDOWS
-    /* Add PipeConnection to module */
-    if (PyType_Ready(&PipeConnectionType) < 0)
-        return NULL;
-    Py_INCREF(&PipeConnectionType);
-    PyModule_AddObject(module, "PipeConnection",
-                       (PyObject*)&PipeConnectionType);
-
     /* Initialize win32 class and add to multiprocessing */
     temp = create_win32_namespace();
     if (!temp)
diff --git a/Modules/_multiprocessing/multiprocessing.h b/Modules/_multiprocessing/multiprocessing.h
index b9917c3..02796c1 100644
--- a/Modules/_multiprocessing/multiprocessing.h
+++ b/Modules/_multiprocessing/multiprocessing.h
@@ -118,11 +118,8 @@
 #define MP_SUCCESS (0)
 #define MP_STANDARD_ERROR (-1)
 #define MP_MEMORY_ERROR (-1001)
-#define MP_END_OF_FILE (-1002)
-#define MP_EARLY_END_OF_FILE (-1003)
-#define MP_BAD_MESSAGE_LENGTH (-1004)
-#define MP_SOCKET_ERROR (-1005)
-#define MP_EXCEPTION_HAS_BEEN_SET (-1006)
+#define MP_SOCKET_ERROR (-1002)
+#define MP_EXCEPTION_HAS_BEEN_SET (-1003)
 
 PyObject *mp_SetError(PyObject *Type, int num);
 
@@ -135,7 +132,6 @@
 extern PyObject *pickle_protocol;
 extern PyObject *BufferTooShort;
 extern PyTypeObject SemLockType;
-extern PyTypeObject ConnectionType;
 extern PyTypeObject PipeConnectionType;
 extern HANDLE sigint_event;
 
@@ -162,25 +158,9 @@
 #endif
 
 /*
- * Connection definition
- */
-
-#define CONNECTION_BUFFER_SIZE 1024
-
-typedef struct {
-    PyObject_HEAD
-    HANDLE handle;
-    int flags;
-    PyObject *weakreflist;
-    char buffer[CONNECTION_BUFFER_SIZE];
-} ConnectionObject;
-
-/*
  * Miscellaneous
  */
 
-#define MAX_MESSAGE_LENGTH 0x7fffffff
-
 #ifndef MIN
 #  define MIN(x, y) ((x) < (y) ? x : y)
 #  define MAX(x, y) ((x) > (y) ? x : y)
diff --git a/Modules/_multiprocessing/pipe_connection.c b/Modules/_multiprocessing/pipe_connection.c
deleted file mode 100644
index 05dde0c..0000000
--- a/Modules/_multiprocessing/pipe_connection.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * A type which wraps a pipe handle in message oriented mode
- *
- * pipe_connection.c
- *
- * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
- */
-
-#include "multiprocessing.h"
-
-#define CLOSE(h) CloseHandle(h)
-
-/*
- * Send string to the pipe; assumes in message oriented mode
- */
-
-static Py_ssize_t
-conn_send_string(ConnectionObject *conn, char *string, size_t length)
-{
-    DWORD amount_written;
-    BOOL ret;
-
-    Py_BEGIN_ALLOW_THREADS
-    ret = WriteFile(conn->handle, string, length, &amount_written, NULL);
-    Py_END_ALLOW_THREADS
-
-    if (ret == 0 && GetLastError() == ERROR_NO_SYSTEM_RESOURCES) {
-        PyErr_Format(PyExc_ValueError, "Cannnot send %" PY_FORMAT_SIZE_T "d bytes over connection", length);
-        return MP_STANDARD_ERROR;
-    }
-
-    return ret ? MP_SUCCESS : MP_STANDARD_ERROR;
-}
-
-/*
- * Attempts to read into buffer, or if buffer too small into *newbuffer.
- *
- * Returns number of bytes read.  Assumes in message oriented mode.
- */
-
-static Py_ssize_t
-conn_recv_string(ConnectionObject *conn, char *buffer,
-                 size_t buflength, char **newbuffer, size_t maxlength)
-{
-    DWORD left, length, full_length, err;
-    BOOL ret;
-    *newbuffer = NULL;
-
-    Py_BEGIN_ALLOW_THREADS
-    ret = ReadFile(conn->handle, buffer, MIN(buflength, maxlength),
-                  &length, NULL);
-    Py_END_ALLOW_THREADS
-    if (ret)
-        return length;
-
-    err = GetLastError();
-    if (err != ERROR_MORE_DATA) {
-        if (err == ERROR_BROKEN_PIPE)
-            return MP_END_OF_FILE;
-        return MP_STANDARD_ERROR;
-    }
-
-    if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, NULL, &left))
-        return MP_STANDARD_ERROR;
-
-    full_length = length + left;
-    if (full_length > maxlength)
-        return MP_BAD_MESSAGE_LENGTH;
-
-    *newbuffer = PyMem_Malloc(full_length);
-    if (*newbuffer == NULL)
-        return MP_MEMORY_ERROR;
-
-    memcpy(*newbuffer, buffer, length);
-
-    Py_BEGIN_ALLOW_THREADS
-    ret = ReadFile(conn->handle, *newbuffer+length, left, &length, NULL);
-    Py_END_ALLOW_THREADS
-    if (ret) {
-        assert(length == left);
-        return full_length;
-    } else {
-        PyMem_Free(*newbuffer);
-        return MP_STANDARD_ERROR;
-    }
-}
-
-/*
- * Check whether any data is available for reading
- */
-
-static int
-conn_poll(ConnectionObject *conn, double timeout, PyThreadState *_save)
-{
-    DWORD bytes, deadline, delay;
-    int difference, res;
-    BOOL block = FALSE;
-
-    if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL))
-        return MP_STANDARD_ERROR;
-
-    if (timeout == 0.0)
-        return bytes > 0;
-
-    if (timeout < 0.0)
-        block = TRUE;
-    else
-        /* XXX does not check for overflow */
-        deadline = GetTickCount() + (DWORD)(1000 * timeout + 0.5);
-
-    Sleep(0);
-
-    for (delay = 1 ; ; delay += 1) {
-        if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL))
-            return MP_STANDARD_ERROR;
-        else if (bytes > 0)
-            return TRUE;
-
-        if (!block) {
-            difference = deadline - GetTickCount();
-            if (difference < 0)
-                return FALSE;
-            if ((int)delay > difference)
-                delay = difference;
-        }
-
-        if (delay > 20)
-            delay = 20;
-
-        Sleep(delay);
-
-        /* check for signals */
-        Py_BLOCK_THREADS
-        res = PyErr_CheckSignals();
-        Py_UNBLOCK_THREADS
-
-        if (res)
-            return MP_EXCEPTION_HAS_BEEN_SET;
-    }
-}
-
-/*
- * "connection.h" defines the PipeConnection type using the definitions above
- */
-
-#define CONNECTION_NAME "PipeConnection"
-#define CONNECTION_TYPE PipeConnectionType
-
-#include "connection.h"
diff --git a/Modules/_multiprocessing/socket_connection.c b/Modules/_multiprocessing/socket_connection.c
deleted file mode 100644
index 7ebf338..0000000
--- a/Modules/_multiprocessing/socket_connection.c
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * A type which wraps a socket
- *
- * socket_connection.c
- *
- * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
- */
-
-#include "multiprocessing.h"
-
-#ifdef MS_WINDOWS
-#  define WRITE(h, buffer, length) send((SOCKET)h, buffer, length, 0)
-#  define READ(h, buffer, length) recv((SOCKET)h, buffer, length, 0)
-#  define CLOSE(h) closesocket((SOCKET)h)
-#else
-#  define WRITE(h, buffer, length) write(h, buffer, length)
-#  define READ(h, buffer, length) read(h, buffer, length)
-#  define CLOSE(h) close(h)
-#endif
-
-/*
- * Send string to file descriptor
- */
-
-static Py_ssize_t
-_conn_sendall(HANDLE h, char *string, size_t length)
-{
-    char *p = string;
-    Py_ssize_t res;
-
-    while (length > 0) {
-        res = WRITE(h, p, length);
-        if (res < 0)
-            return MP_SOCKET_ERROR;
-        length -= res;
-        p += res;
-    }
-
-    return MP_SUCCESS;
-}
-
-/*
- * Receive string of exact length from file descriptor
- */
-
-static Py_ssize_t
-_conn_recvall(HANDLE h, char *buffer, size_t length)
-{
-    size_t remaining = length;
-    Py_ssize_t temp;
-    char *p = buffer;
-
-    while (remaining > 0) {
-        temp = READ(h, p, remaining);
-        if (temp <= 0) {
-            if (temp == 0)
-                return remaining == length ?
-                    MP_END_OF_FILE : MP_EARLY_END_OF_FILE;
-            else
-                return temp;
-        }
-        remaining -= temp;
-        p += temp;
-    }
-
-    return MP_SUCCESS;
-}
-
-/*
- * Send a string prepended by the string length in network byte order
- */
-
-static Py_ssize_t
-conn_send_string(ConnectionObject *conn, char *string, size_t length)
-{
-    Py_ssize_t res;
-    /* The "header" of the message is a 32 bit unsigned number (in
-       network order) which specifies the length of the "body".  If
-       the message is shorter than about 16kb then it is quicker to
-       combine the "header" and the "body" of the message and send
-       them at once. */
-    if (length < (16*1024)) {
-        char *message;
-
-        message = PyMem_Malloc(length+4);
-        if (message == NULL)
-            return MP_MEMORY_ERROR;
-
-        *(UINT32*)message = htonl((UINT32)length);
-        memcpy(message+4, string, length);
-        Py_BEGIN_ALLOW_THREADS
-        res = _conn_sendall(conn->handle, message, length+4);
-        Py_END_ALLOW_THREADS
-        PyMem_Free(message);
-    } else {
-        UINT32 lenbuff;
-
-        if (length > MAX_MESSAGE_LENGTH)
-            return MP_BAD_MESSAGE_LENGTH;
-
-        lenbuff = htonl((UINT32)length);
-        Py_BEGIN_ALLOW_THREADS
-        res = _conn_sendall(conn->handle, (char*)&lenbuff, 4) ||
-            _conn_sendall(conn->handle, string, length);
-        Py_END_ALLOW_THREADS
-    }
-    return res;
-}
-
-/*
- * Attempts to read into buffer, or failing that into *newbuffer
- *
- * Returns number of bytes read.
- */
-
-static Py_ssize_t
-conn_recv_string(ConnectionObject *conn, char *buffer,
-                 size_t buflength, char **newbuffer, size_t maxlength)
-{
-    int res;
-    UINT32 ulength;
-
-    *newbuffer = NULL;
-
-    Py_BEGIN_ALLOW_THREADS
-    res = _conn_recvall(conn->handle, (char*)&ulength, 4);
-    Py_END_ALLOW_THREADS
-    if (res < 0)
-        return res;
-
-    ulength = ntohl(ulength);
-    if (ulength > maxlength)
-        return MP_BAD_MESSAGE_LENGTH;
-
-    if (ulength <= buflength) {
-        Py_BEGIN_ALLOW_THREADS
-        res = _conn_recvall(conn->handle, buffer, (size_t)ulength);
-        Py_END_ALLOW_THREADS
-        return res < 0 ? res : ulength;
-    } else {
-        *newbuffer = PyMem_Malloc((size_t)ulength);
-        if (*newbuffer == NULL)
-            return MP_MEMORY_ERROR;
-        Py_BEGIN_ALLOW_THREADS
-        res = _conn_recvall(conn->handle, *newbuffer, (size_t)ulength);
-        Py_END_ALLOW_THREADS
-        return res < 0 ? (Py_ssize_t)res : (Py_ssize_t)ulength;
-    }
-}
-
-/*
- * Check whether any data is available for reading -- neg timeout blocks
- */
-
-static int
-conn_poll(ConnectionObject *conn, double timeout, PyThreadState *_save)
-{
-    int res;
-    fd_set rfds;
-
-    /*
-     * Verify the handle, issue 3321. Not required for windows.
-     */
-    #ifndef MS_WINDOWS
-        if (((int)conn->handle) < 0 || ((int)conn->handle) >= FD_SETSIZE) {
-            Py_BLOCK_THREADS
-            PyErr_SetString(PyExc_IOError, "handle out of range in select()");
-            Py_UNBLOCK_THREADS
-            return MP_EXCEPTION_HAS_BEEN_SET;
-        }
-    #endif
-
-    FD_ZERO(&rfds);
-    FD_SET((SOCKET)conn->handle, &rfds);
-
-    if (timeout < 0.0) {
-        res = select((int)conn->handle+1, &rfds, NULL, NULL, NULL);
-    } else {
-        struct timeval tv;
-        tv.tv_sec = (long)timeout;
-        tv.tv_usec = (long)((timeout - tv.tv_sec) * 1e6 + 0.5);
-        res = select((int)conn->handle+1, &rfds, NULL, NULL, &tv);
-    }
-
-    if (res < 0) {
-        return MP_SOCKET_ERROR;
-    } else if (FD_ISSET(conn->handle, &rfds)) {
-        return TRUE;
-    } else {
-        assert(res == 0);
-        return FALSE;
-    }
-}
-
-/*
- * "connection.h" defines the Connection type using defs above
- */
-
-#define CONNECTION_NAME "Connection"
-#define CONNECTION_TYPE ConnectionType
-
-#include "connection.h"
diff --git a/Modules/_multiprocessing/win32_functions.c b/Modules/_multiprocessing/win32_functions.c
index 452d608..12dc0cd 100644
--- a/Modules/_multiprocessing/win32_functions.c
+++ b/Modules/_multiprocessing/win32_functions.c
@@ -215,6 +215,164 @@
     Py_RETURN_NONE;
 }
 
+static PyObject *
+win32_closesocket(PyObject *self, PyObject *args)
+{
+    HANDLE handle;
+    int ret;
+
+    if (!PyArg_ParseTuple(args, F_HANDLE ":closesocket" , &handle))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    ret = closesocket((SOCKET) handle);
+    Py_END_ALLOW_THREADS
+
+    if (ret)
+        return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+win32_recv(PyObject *self, PyObject *args)
+{
+    HANDLE handle;
+    int size, nread;
+    PyObject *buf;
+
+    if (!PyArg_ParseTuple(args, F_HANDLE "i:recv" , &handle, &size))
+        return NULL;
+
+    buf = PyBytes_FromStringAndSize(NULL, size);
+    if (!buf)
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    nread = recv((SOCKET) handle, PyBytes_AS_STRING(buf), size, 0);
+    Py_END_ALLOW_THREADS
+
+    if (nread < 0) {
+        Py_DECREF(buf);
+        return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
+    }
+    _PyBytes_Resize(&buf, nread);
+    return buf;
+}
+
+static PyObject *
+win32_send(PyObject *self, PyObject *args)
+{
+    HANDLE handle;
+    Py_buffer buf;
+    int ret;
+
+    if (!PyArg_ParseTuple(args, F_HANDLE "y*:send" , &handle, &buf))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    ret = send((SOCKET) handle, buf.buf, buf.len, 0);
+    Py_END_ALLOW_THREADS
+
+    PyBuffer_Release(&buf);
+    if (ret < 0)
+        return PyErr_SetExcFromWindowsErr(PyExc_IOError, WSAGetLastError());
+    return PyLong_FromLong(ret);
+}
+
+static PyObject *
+win32_WriteFile(PyObject *self, PyObject *args)
+{
+    HANDLE handle;
+    Py_buffer buf;
+    int written;
+    BOOL ret;
+
+    if (!PyArg_ParseTuple(args, F_HANDLE "y*:WriteFile" , &handle, &buf))
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    ret = WriteFile(handle, buf.buf, buf.len, &written, NULL);
+    Py_END_ALLOW_THREADS
+
+    PyBuffer_Release(&buf);
+    if (!ret)
+        return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+    return PyLong_FromLong(written);
+}
+
+static PyObject *
+win32_ReadFile(PyObject *self, PyObject *args)
+{
+    HANDLE handle;
+    int size;
+    DWORD nread;
+    PyObject *buf;
+    BOOL ret;
+
+    if (!PyArg_ParseTuple(args, F_HANDLE "i:ReadFile" , &handle, &size))
+        return NULL;
+
+    buf = PyBytes_FromStringAndSize(NULL, size);
+    if (!buf)
+        return NULL;
+
+    Py_BEGIN_ALLOW_THREADS
+    ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread, NULL);
+    Py_END_ALLOW_THREADS
+
+    if (!ret && GetLastError() != ERROR_MORE_DATA) {
+        Py_DECREF(buf);
+        return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+    }
+    if (_PyBytes_Resize(&buf, nread))
+        return NULL;
+    return Py_BuildValue("NN", buf, PyBool_FromLong(ret));
+}
+
+static PyObject *
+win32_PeekNamedPipe(PyObject *self, PyObject *args)
+{
+    HANDLE handle;
+    int size = 0;
+    PyObject *buf = NULL;
+    DWORD nread, navail, nleft;
+    BOOL ret;
+
+    if (!PyArg_ParseTuple(args, F_HANDLE "|i:PeekNamedPipe" , &handle, &size))
+        return NULL;
+
+    if (size < 0) {
+        PyErr_SetString(PyExc_ValueError, "negative size");
+        return NULL;
+    }
+
+    if (size) {
+        buf = PyBytes_FromStringAndSize(NULL, size);
+        if (!buf)
+            return NULL;
+        Py_BEGIN_ALLOW_THREADS
+        ret = PeekNamedPipe(handle, PyBytes_AS_STRING(buf), size, &nread,
+                            &navail, &nleft);
+        Py_END_ALLOW_THREADS
+        if (!ret) {
+            Py_DECREF(buf);
+            return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+        }
+        if (_PyBytes_Resize(&buf, nread))
+            return NULL;
+        return Py_BuildValue("Nii", buf, navail, nleft);
+    }
+    else {
+        Py_BEGIN_ALLOW_THREADS
+        ret = PeekNamedPipe(handle, NULL, 0, NULL, &navail, &nleft);
+        Py_END_ALLOW_THREADS
+        if (!ret) {
+            return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+        }
+        return Py_BuildValue("ii", navail, nleft);
+    }
+}
+
 static PyMethodDef win32_methods[] = {
     WIN32_FUNCTION(CloseHandle),
     WIN32_FUNCTION(GetLastError),
@@ -223,8 +381,14 @@
     WIN32_FUNCTION(ConnectNamedPipe),
     WIN32_FUNCTION(CreateFile),
     WIN32_FUNCTION(CreateNamedPipe),
+    WIN32_FUNCTION(ReadFile),
+    WIN32_FUNCTION(PeekNamedPipe),
     WIN32_FUNCTION(SetNamedPipeHandleState),
     WIN32_FUNCTION(WaitNamedPipe),
+    WIN32_FUNCTION(WriteFile),
+    WIN32_FUNCTION(closesocket),
+    WIN32_FUNCTION(recv),
+    WIN32_FUNCTION(send),
     {NULL}
 };
 
@@ -244,6 +408,8 @@
     Py_INCREF(&Win32Type);
 
     WIN32_CONSTANT(F_DWORD, ERROR_ALREADY_EXISTS);
+    WIN32_CONSTANT(F_DWORD, ERROR_BROKEN_PIPE);
+    WIN32_CONSTANT(F_DWORD, ERROR_NO_SYSTEM_RESOURCES);
     WIN32_CONSTANT(F_DWORD, ERROR_PIPE_BUSY);
     WIN32_CONSTANT(F_DWORD, ERROR_PIPE_CONNECTED);
     WIN32_CONSTANT(F_DWORD, ERROR_SEM_TIMEOUT);