/Modules/_multiprocessing/pipe_connection.c

http://unladen-swallow.googlecode.com/ · C · 143 lines · 91 code · 29 blank · 23 comment · 25 complexity · a608d152a11d9f27356b536c5750072d MD5 · raw file

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