|
1 /* |
|
2 * A type which wraps a pipe handle in message oriented mode |
|
3 * |
|
4 * pipe_connection.c |
|
5 * |
|
6 * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt |
|
7 */ |
|
8 |
|
9 #include "multiprocessing.h" |
|
10 |
|
11 #define CLOSE(h) CloseHandle(h) |
|
12 |
|
13 /* |
|
14 * Send string to the pipe; assumes in message oriented mode |
|
15 */ |
|
16 |
|
17 static Py_ssize_t |
|
18 conn_send_string(ConnectionObject *conn, char *string, size_t length) |
|
19 { |
|
20 DWORD amount_written; |
|
21 BOOL ret; |
|
22 |
|
23 Py_BEGIN_ALLOW_THREADS |
|
24 ret = WriteFile(conn->handle, string, length, &amount_written, NULL); |
|
25 Py_END_ALLOW_THREADS |
|
26 return ret ? MP_SUCCESS : MP_STANDARD_ERROR; |
|
27 } |
|
28 |
|
29 /* |
|
30 * Attempts to read into buffer, or if buffer too small into *newbuffer. |
|
31 * |
|
32 * Returns number of bytes read. Assumes in message oriented mode. |
|
33 */ |
|
34 |
|
35 static Py_ssize_t |
|
36 conn_recv_string(ConnectionObject *conn, char *buffer, |
|
37 size_t buflength, char **newbuffer, size_t maxlength) |
|
38 { |
|
39 DWORD left, length, full_length, err; |
|
40 BOOL ret; |
|
41 *newbuffer = NULL; |
|
42 |
|
43 Py_BEGIN_ALLOW_THREADS |
|
44 ret = ReadFile(conn->handle, buffer, MIN(buflength, maxlength), |
|
45 &length, NULL); |
|
46 Py_END_ALLOW_THREADS |
|
47 if (ret) |
|
48 return length; |
|
49 |
|
50 err = GetLastError(); |
|
51 if (err != ERROR_MORE_DATA) { |
|
52 if (err == ERROR_BROKEN_PIPE) |
|
53 return MP_END_OF_FILE; |
|
54 return MP_STANDARD_ERROR; |
|
55 } |
|
56 |
|
57 if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, NULL, &left)) |
|
58 return MP_STANDARD_ERROR; |
|
59 |
|
60 full_length = length + left; |
|
61 if (full_length > maxlength) |
|
62 return MP_BAD_MESSAGE_LENGTH; |
|
63 |
|
64 *newbuffer = PyMem_Malloc(full_length); |
|
65 if (*newbuffer == NULL) |
|
66 return MP_MEMORY_ERROR; |
|
67 |
|
68 memcpy(*newbuffer, buffer, length); |
|
69 |
|
70 Py_BEGIN_ALLOW_THREADS |
|
71 ret = ReadFile(conn->handle, *newbuffer+length, left, &length, NULL); |
|
72 Py_END_ALLOW_THREADS |
|
73 if (ret) { |
|
74 assert(length == left); |
|
75 return full_length; |
|
76 } else { |
|
77 PyMem_Free(*newbuffer); |
|
78 return MP_STANDARD_ERROR; |
|
79 } |
|
80 } |
|
81 |
|
82 /* |
|
83 * Check whether any data is available for reading |
|
84 */ |
|
85 |
|
86 #define conn_poll(conn, timeout) conn_poll_save(conn, timeout, _save) |
|
87 |
|
88 static int |
|
89 conn_poll_save(ConnectionObject *conn, double timeout, PyThreadState *_save) |
|
90 { |
|
91 DWORD bytes, deadline, delay; |
|
92 int difference, res; |
|
93 BOOL block = FALSE; |
|
94 |
|
95 if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL)) |
|
96 return MP_STANDARD_ERROR; |
|
97 |
|
98 if (timeout == 0.0) |
|
99 return bytes > 0; |
|
100 |
|
101 if (timeout < 0.0) |
|
102 block = TRUE; |
|
103 else |
|
104 /* XXX does not check for overflow */ |
|
105 deadline = GetTickCount() + (DWORD)(1000 * timeout + 0.5); |
|
106 |
|
107 Sleep(0); |
|
108 |
|
109 for (delay = 1 ; ; delay += 1) { |
|
110 if (!PeekNamedPipe(conn->handle, NULL, 0, NULL, &bytes, NULL)) |
|
111 return MP_STANDARD_ERROR; |
|
112 else if (bytes > 0) |
|
113 return TRUE; |
|
114 |
|
115 if (!block) { |
|
116 difference = deadline - GetTickCount(); |
|
117 if (difference < 0) |
|
118 return FALSE; |
|
119 if ((int)delay > difference) |
|
120 delay = difference; |
|
121 } |
|
122 |
|
123 if (delay > 20) |
|
124 delay = 20; |
|
125 |
|
126 Sleep(delay); |
|
127 |
|
128 /* check for signals */ |
|
129 Py_BLOCK_THREADS |
|
130 res = PyErr_CheckSignals(); |
|
131 Py_UNBLOCK_THREADS |
|
132 |
|
133 if (res) |
|
134 return MP_EXCEPTION_HAS_BEEN_SET; |
|
135 } |
|
136 } |
|
137 |
|
138 /* |
|
139 * "connection.h" defines the PipeConnection type using the definitions above |
|
140 */ |
|
141 |
|
142 #define CONNECTION_NAME "PipeConnection" |
|
143 #define CONNECTION_TYPE PipeConnectionType |
|
144 |
|
145 #include "connection.h" |