| /* |
| * 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" |