summaryrefslogtreecommitdiffstats
path: root/Modules/_multiprocessing
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_multiprocessing')
-rw-r--r--Modules/_multiprocessing/connection.h527
-rw-r--r--Modules/_multiprocessing/multiprocessing.c35
-rw-r--r--Modules/_multiprocessing/multiprocessing.h71
-rw-r--r--Modules/_multiprocessing/pipe_connection.c149
-rw-r--r--Modules/_multiprocessing/semaphore.c4
-rw-r--r--Modules/_multiprocessing/socket_connection.c202
-rw-r--r--Modules/_multiprocessing/win32_functions.c536
7 files changed, 536 insertions, 988 deletions
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 83df1eb..a1e6ed5 100644
--- a/Modules/_multiprocessing/multiprocessing.c
+++ b/Modules/_multiprocessing/multiprocessing.c
@@ -16,7 +16,6 @@
PyObject *create_win32_namespace(void);
-PyObject *pickle_dumps, *pickle_loads, *pickle_protocol;
PyObject *ProcessError, *BufferTooShort;
/*
@@ -49,16 +48,6 @@ mp_SetError(PyObject *Type, int num)
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:
@@ -210,7 +199,7 @@ multiprocessing_address_of_buffer(PyObject *self, PyObject *obj)
if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
return NULL;
- return Py_BuildValue("N" F_PY_SSIZE_T,
+ return Py_BuildValue("Nn",
PyLong_FromVoidPtr(buffer), buffer_len);
}
@@ -264,15 +253,6 @@ PyInit__multiprocessing(void)
if (!module)
return NULL;
- /* Get copy of objects from pickle */
- temp = PyImport_ImportModule(PICKLE_MODULE);
- if (!temp)
- return NULL;
- pickle_dumps = PyObject_GetAttrString(temp, "dumps");
- pickle_loads = PyObject_GetAttrString(temp, "loads");
- pickle_protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
- Py_XDECREF(temp);
-
/* Get copy of BufferTooShort */
temp = PyImport_ImportModule("multiprocessing");
if (!temp)
@@ -280,12 +260,6 @@ PyInit__multiprocessing(void)
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 */
@@ -309,13 +283,6 @@ PyInit__multiprocessing(void)
#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 14425de..c303447 100644
--- a/Modules/_multiprocessing/multiprocessing.h
+++ b/Modules/_multiprocessing/multiprocessing.h
@@ -4,7 +4,7 @@
#define PY_SSIZE_T_CLEAN
#ifdef __sun
-/* The control message API is only available on Solaris
+/* The control message API is only available on Solaris
if XPG 4.2 or later is requested. */
#define _XOPEN_SOURCE 500
#endif
@@ -64,20 +64,6 @@
/*
- * Make sure Py_ssize_t available
- */
-
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
- typedef int Py_ssize_t;
-# define PY_SSIZE_T_MAX INT_MAX
-# define PY_SSIZE_T_MIN INT_MIN
-# define F_PY_SSIZE_T "i"
-# define PyInt_FromSsize_t(n) PyInt_FromLong((long)n)
-#else
-# define F_PY_SSIZE_T "n"
-#endif
-
-/*
* Format codes
*/
@@ -105,12 +91,6 @@
# define T_SEM_HANDLE T_POINTER
#endif
-#if PY_VERSION_HEX >= 0x03000000
-# define F_RBUFFER "y"
-#else
-# define F_RBUFFER "s"
-#endif
-
/*
* Error codes which can be returned by functions called without GIL
*/
@@ -118,11 +98,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);
@@ -130,57 +107,15 @@ PyObject *mp_SetError(PyObject *Type, int num);
* Externs - not all will really exist on all platforms
*/
-extern PyObject *pickle_dumps;
-extern PyObject *pickle_loads;
-extern PyObject *pickle_protocol;
extern PyObject *BufferTooShort;
extern PyTypeObject SemLockType;
-extern PyTypeObject ConnectionType;
extern PyTypeObject PipeConnectionType;
extern HANDLE sigint_event;
/*
- * Py3k compatibility
- */
-
-#if PY_VERSION_HEX >= 0x03000000
-# define PICKLE_MODULE "pickle"
-# define FROM_FORMAT PyUnicode_FromFormat
-# define PyInt_FromLong PyLong_FromLong
-# define PyInt_FromSsize_t PyLong_FromSsize_t
-#else
-# define PICKLE_MODULE "cPickle"
-# define FROM_FORMAT PyString_FromFormat
-#endif
-
-#ifndef PyVarObject_HEAD_INIT
-# define PyVarObject_HEAD_INIT(type, size) PyObject_HEAD_INIT(type) size,
-#endif
-
-#ifndef Py_TPFLAGS_HAVE_WEAKREFS
-# define Py_TPFLAGS_HAVE_WEAKREFS 0
-#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/semaphore.c b/Modules/_multiprocessing/semaphore.c
index c2cd914..6749f23 100644
--- a/Modules/_multiprocessing/semaphore.c
+++ b/Modules/_multiprocessing/semaphore.c
@@ -481,7 +481,7 @@ semlock_dealloc(SemLockObject* self)
static PyObject *
semlock_count(SemLockObject *self)
{
- return PyInt_FromLong((long)self->count);
+ return PyLong_FromLong((long)self->count);
}
static PyObject *
@@ -505,7 +505,7 @@ semlock_getvalue(SemLockObject *self)
the number of waiting threads */
if (sval < 0)
sval = 0;
- return PyInt_FromLong((long)sval);
+ return PyLong_FromLong((long)sval);
#endif
}
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..c017b2a 100644
--- a/Modules/_multiprocessing/win32_functions.c
+++ b/Modules/_multiprocessing/win32_functions.c
@@ -12,10 +12,223 @@
#define WIN32_FUNCTION(func) \
{#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_STATIC, ""}
+#define WIN32_KWARGS_FUNCTION(func) \
+ {#func, (PyCFunction)win32_ ## func, METH_VARARGS | METH_KEYWORDS | METH_STATIC, ""}
+
#define WIN32_CONSTANT(fmt, con) \
PyDict_SetItemString(Win32Type.tp_dict, #con, Py_BuildValue(fmt, con))
+/* Grab CancelIoEx dynamically from kernel32 */
+static int has_CancelIoEx = -1;
+static BOOL (CALLBACK *Py_CancelIoEx)(HANDLE, LPOVERLAPPED);
+
+static int
+check_CancelIoEx()
+{
+ if (has_CancelIoEx == -1)
+ {
+ HINSTANCE hKernel32 = GetModuleHandle("KERNEL32");
+ * (FARPROC *) &Py_CancelIoEx = GetProcAddress(hKernel32,
+ "CancelIoEx");
+ has_CancelIoEx = (Py_CancelIoEx != NULL);
+ }
+ return has_CancelIoEx;
+}
+
+
+/*
+ * A Python object wrapping an OVERLAPPED structure and other useful data
+ * for overlapped I/O
+ */
+
+typedef struct {
+ PyObject_HEAD
+ OVERLAPPED overlapped;
+ /* For convenience, we store the file handle too */
+ HANDLE handle;
+ /* Whether there's I/O in flight */
+ int pending;
+ /* Whether I/O completed successfully */
+ int completed;
+ /* Buffer used for reading (optional) */
+ PyObject *read_buffer;
+ /* Buffer used for writing (optional) */
+ Py_buffer write_buffer;
+} OverlappedObject;
+
+static void
+overlapped_dealloc(OverlappedObject *self)
+{
+ int err = GetLastError();
+ if (self->pending) {
+ if (check_CancelIoEx())
+ Py_CancelIoEx(self->handle, &self->overlapped);
+ else {
+ PyErr_SetString(PyExc_RuntimeError,
+ "I/O operations still in flight while destroying "
+ "Overlapped object, the process may crash");
+ PyErr_WriteUnraisable(NULL);
+ }
+ }
+ CloseHandle(self->overlapped.hEvent);
+ SetLastError(err);
+ if (self->write_buffer.obj)
+ PyBuffer_Release(&self->write_buffer);
+ Py_CLEAR(self->read_buffer);
+ PyObject_Del(self);
+}
+
+static PyObject *
+overlapped_GetOverlappedResult(OverlappedObject *self, PyObject *waitobj)
+{
+ int wait;
+ BOOL res;
+ DWORD transferred = 0;
+
+ wait = PyObject_IsTrue(waitobj);
+ if (wait < 0)
+ return NULL;
+ Py_BEGIN_ALLOW_THREADS
+ res = GetOverlappedResult(self->handle, &self->overlapped, &transferred,
+ wait != 0);
+ Py_END_ALLOW_THREADS
+
+ if (!res) {
+ int err = GetLastError();
+ if (err == ERROR_IO_INCOMPLETE)
+ Py_RETURN_NONE;
+ if (err != ERROR_MORE_DATA) {
+ self->pending = 0;
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, err);
+ }
+ }
+ self->pending = 0;
+ self->completed = 1;
+ if (self->read_buffer) {
+ assert(PyBytes_CheckExact(self->read_buffer));
+ if (_PyBytes_Resize(&self->read_buffer, transferred))
+ return NULL;
+ }
+ return Py_BuildValue("lN", (long) transferred, PyBool_FromLong(res));
+}
+
+static PyObject *
+overlapped_getbuffer(OverlappedObject *self)
+{
+ PyObject *res;
+ if (!self->completed) {
+ PyErr_SetString(PyExc_ValueError,
+ "can't get read buffer before GetOverlappedResult() "
+ "signals the operation completed");
+ return NULL;
+ }
+ res = self->read_buffer ? self->read_buffer : Py_None;
+ Py_INCREF(res);
+ return res;
+}
+
+static PyObject *
+overlapped_cancel(OverlappedObject *self)
+{
+ BOOL res = TRUE;
+
+ if (self->pending) {
+ Py_BEGIN_ALLOW_THREADS
+ if (check_CancelIoEx())
+ res = Py_CancelIoEx(self->handle, &self->overlapped);
+ else
+ res = CancelIo(self->handle);
+ Py_END_ALLOW_THREADS
+ }
+
+ /* CancelIoEx returns ERROR_NOT_FOUND if the I/O completed in-between */
+ if (!res && GetLastError() != ERROR_NOT_FOUND)
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+ self->pending = 0;
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef overlapped_methods[] = {
+ {"GetOverlappedResult", (PyCFunction) overlapped_GetOverlappedResult,
+ METH_O, NULL},
+ {"getbuffer", (PyCFunction) overlapped_getbuffer, METH_NOARGS, NULL},
+ {"cancel", (PyCFunction) overlapped_cancel, METH_NOARGS, NULL},
+ {NULL}
+};
+
+static PyMemberDef overlapped_members[] = {
+ {"event", T_HANDLE,
+ offsetof(OverlappedObject, overlapped) + offsetof(OVERLAPPED, hEvent),
+ READONLY, "overlapped event handle"},
+ {NULL}
+};
+
+PyTypeObject OverlappedType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ /* tp_name */ "_multiprocessing.win32.Overlapped",
+ /* tp_basicsize */ sizeof(OverlappedObject),
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor) overlapped_dealloc,
+ /* tp_print */ 0,
+ /* tp_getattr */ 0,
+ /* tp_setattr */ 0,
+ /* tp_reserved */ 0,
+ /* tp_repr */ 0,
+ /* 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,
+ /* tp_doc */ "OVERLAPPED structure wrapper",
+ /* tp_traverse */ 0,
+ /* tp_clear */ 0,
+ /* tp_richcompare */ 0,
+ /* tp_weaklistoffset */ 0,
+ /* tp_iter */ 0,
+ /* tp_iternext */ 0,
+ /* tp_methods */ overlapped_methods,
+ /* tp_members */ overlapped_members,
+ /* tp_getset */ 0,
+ /* 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 */ 0,
+};
+
+static OverlappedObject *
+new_overlapped(HANDLE handle)
+{
+ OverlappedObject *self;
+
+ self = PyObject_New(OverlappedObject, &OverlappedType);
+ if (!self)
+ return NULL;
+ self->handle = handle;
+ self->read_buffer = NULL;
+ self->pending = 0;
+ self->completed = 0;
+ memset(&self->overlapped, 0, sizeof(OVERLAPPED));
+ memset(&self->write_buffer, 0, sizeof(Py_buffer));
+ /* Manual reset, initially non-signalled */
+ self->overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ return self;
+}
+
+
+/*
+ * Module functions
+ */
+
static PyObject *
win32_CloseHandle(PyObject *self, PyObject *args)
{
@@ -36,20 +249,44 @@ win32_CloseHandle(PyObject *self, PyObject *args)
}
static PyObject *
-win32_ConnectNamedPipe(PyObject *self, PyObject *args)
+win32_ConnectNamedPipe(PyObject *self, PyObject *args, PyObject *kwds)
{
HANDLE hNamedPipe;
- LPOVERLAPPED lpOverlapped;
+ int use_overlapped = 0;
BOOL success;
+ OverlappedObject *overlapped = NULL;
+ static char *kwlist[] = {"handle", "overlapped", NULL};
- if (!PyArg_ParseTuple(args, F_HANDLE F_POINTER,
- &hNamedPipe, &lpOverlapped))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ F_HANDLE "|i", kwlist,
+ &hNamedPipe, &use_overlapped))
return NULL;
+ if (use_overlapped) {
+ overlapped = new_overlapped(hNamedPipe);
+ if (!overlapped)
+ return NULL;
+ }
+
Py_BEGIN_ALLOW_THREADS
- success = ConnectNamedPipe(hNamedPipe, lpOverlapped);
+ success = ConnectNamedPipe(hNamedPipe,
+ overlapped ? &overlapped->overlapped : NULL);
Py_END_ALLOW_THREADS
+ if (overlapped) {
+ int err = GetLastError();
+ /* Overlapped ConnectNamedPipe never returns a success code */
+ assert(success == 0);
+ if (err == ERROR_IO_PENDING)
+ overlapped->pending = 1;
+ else if (err == ERROR_PIPE_CONNECTED)
+ SetEvent(overlapped->overlapped.hEvent);
+ else {
+ Py_DECREF(overlapped);
+ return PyErr_SetFromWindowsErr(err);
+ }
+ return (PyObject *) overlapped;
+ }
if (!success)
return PyErr_SetFromWindowsErr(0);
@@ -215,16 +452,295 @@ win32_WaitNamedPipe(PyObject *self, PyObject *args)
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, PyObject *kwds)
+{
+ HANDLE handle;
+ Py_buffer _buf, *buf;
+ PyObject *bufobj;
+ int written;
+ BOOL ret;
+ int use_overlapped = 0;
+ OverlappedObject *overlapped = NULL;
+ static char *kwlist[] = {"handle", "buffer", "overlapped", NULL};
+
+ /* First get handle and use_overlapped to know which Py_buffer to use */
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ F_HANDLE "O|i:WriteFile", kwlist,
+ &handle, &bufobj, &use_overlapped))
+ return NULL;
+
+ if (use_overlapped) {
+ overlapped = new_overlapped(handle);
+ if (!overlapped)
+ return NULL;
+ buf = &overlapped->write_buffer;
+ }
+ else
+ buf = &_buf;
+
+ if (!PyArg_Parse(bufobj, "y*", buf)) {
+ Py_XDECREF(overlapped);
+ return NULL;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = WriteFile(handle, buf->buf, buf->len, &written,
+ overlapped ? &overlapped->overlapped : NULL);
+ Py_END_ALLOW_THREADS
+
+ if (overlapped) {
+ int err = GetLastError();
+ if (!ret) {
+ if (err == ERROR_IO_PENDING)
+ overlapped->pending = 1;
+ else {
+ Py_DECREF(overlapped);
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+ }
+ }
+ return (PyObject *) overlapped;
+ }
+
+ PyBuffer_Release(buf);
+ if (!ret)
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+ return PyLong_FromLong(written);
+}
+
+static PyObject *
+win32_ReadFile(PyObject *self, PyObject *args, PyObject *kwds)
+{
+ HANDLE handle;
+ int size;
+ DWORD nread;
+ PyObject *buf;
+ BOOL ret;
+ int use_overlapped = 0;
+ OverlappedObject *overlapped = NULL;
+ static char *kwlist[] = {"handle", "size", "overlapped", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds,
+ F_HANDLE "i|i:ReadFile", kwlist,
+ &handle, &size, &use_overlapped))
+ return NULL;
+
+ buf = PyBytes_FromStringAndSize(NULL, size);
+ if (!buf)
+ return NULL;
+ if (use_overlapped) {
+ overlapped = new_overlapped(handle);
+ if (!overlapped) {
+ Py_DECREF(buf);
+ return NULL;
+ }
+ /* Steals reference to buf */
+ overlapped->read_buffer = buf;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ ret = ReadFile(handle, PyBytes_AS_STRING(buf), size, &nread,
+ overlapped ? &overlapped->overlapped : NULL);
+ Py_END_ALLOW_THREADS
+
+ if (overlapped) {
+ int err = GetLastError();
+ if (!ret) {
+ if (err == ERROR_IO_PENDING)
+ overlapped->pending = 1;
+ else if (err != ERROR_MORE_DATA) {
+ Py_DECREF(overlapped);
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+ }
+ }
+ return (PyObject *) overlapped;
+ }
+
+ 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 PyObject *
+win32_WaitForMultipleObjects(PyObject* self, PyObject* args)
+{
+ DWORD result;
+ PyObject *handle_seq;
+ HANDLE handles[MAXIMUM_WAIT_OBJECTS];
+ Py_ssize_t nhandles, i;
+ int wait_flag;
+ int milliseconds = INFINITE;
+
+ if (!PyArg_ParseTuple(args, "Oi|i:WaitForMultipleObjects",
+ &handle_seq, &wait_flag, &milliseconds))
+ return NULL;
+
+ if (!PySequence_Check(handle_seq)) {
+ PyErr_Format(PyExc_TypeError,
+ "sequence type expected, got '%s'",
+ Py_TYPE(handle_seq)->tp_doc);
+ return NULL;
+ }
+ nhandles = PySequence_Length(handle_seq);
+ if (nhandles == -1)
+ return NULL;
+ if (nhandles < 0 || nhandles >= MAXIMUM_WAIT_OBJECTS) {
+ PyErr_Format(PyExc_ValueError,
+ "need at most %zd handles, got a sequence of length %zd",
+ MAXIMUM_WAIT_OBJECTS, nhandles);
+ return NULL;
+ }
+ for (i = 0; i < nhandles; i++) {
+ HANDLE h;
+ PyObject *v = PySequence_GetItem(handle_seq, i);
+ if (v == NULL)
+ return NULL;
+ if (!PyArg_Parse(v, F_HANDLE, &h))
+ return NULL;
+ handles[i] = h;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ result = WaitForMultipleObjects((DWORD) nhandles, handles,
+ (BOOL) wait_flag, (DWORD) milliseconds);
+ Py_END_ALLOW_THREADS
+
+ if (result == WAIT_FAILED)
+ return PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
+
+ return PyLong_FromLong((int) result);
+}
+
+
static PyMethodDef win32_methods[] = {
WIN32_FUNCTION(CloseHandle),
WIN32_FUNCTION(GetLastError),
WIN32_FUNCTION(OpenProcess),
WIN32_FUNCTION(ExitProcess),
- WIN32_FUNCTION(ConnectNamedPipe),
+ WIN32_KWARGS_FUNCTION(ConnectNamedPipe),
WIN32_FUNCTION(CreateFile),
WIN32_FUNCTION(CreateNamedPipe),
+ WIN32_KWARGS_FUNCTION(ReadFile),
+ WIN32_FUNCTION(PeekNamedPipe),
WIN32_FUNCTION(SetNamedPipeHandleState),
+ WIN32_FUNCTION(WaitForMultipleObjects),
WIN32_FUNCTION(WaitNamedPipe),
+ WIN32_KWARGS_FUNCTION(WriteFile),
+ WIN32_FUNCTION(closesocket),
+ WIN32_FUNCTION(recv),
+ WIN32_FUNCTION(send),
{NULL}
};
@@ -243,10 +759,18 @@ create_win32_namespace(void)
return NULL;
Py_INCREF(&Win32Type);
+ if (PyType_Ready(&OverlappedType) < 0)
+ return NULL;
+ PyDict_SetItemString(Win32Type.tp_dict, "Overlapped",
+ (PyObject *) &OverlappedType);
+
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);
+ WIN32_CONSTANT(F_DWORD, FILE_FLAG_OVERLAPPED);
WIN32_CONSTANT(F_DWORD, GENERIC_READ);
WIN32_CONSTANT(F_DWORD, GENERIC_WRITE);
WIN32_CONSTANT(F_DWORD, INFINITE);