46 unsigned char *rw_buf;
48 OVERLAPPED overlapped;
51 BOOL use_thread_fallback;
53 DWORD bytes_transferred;
68struct _PipeWriteHandle
74 PipeReadHandle *prh_out,
77 PipeWriteHandle *pwh_out,
84 PipeReadHandle prh = malloc(
sizeof(
struct _PipeReadHandle));
85 PipeWriteHandle pwh = malloc(
sizeof(
struct _PipeWriteHandle));
87 if(prh == NULL || pwh == NULL)
92 return ERROR_OUTOFMEMORY;
95 prh->data.pipe = INVALID_HANDLE_VALUE;
96 prh->data.rw_buf = malloc(read_size);
97 prh->data.rw_buf_size = read_size;
98 prh->data.overlapped.hEvent = NULL;
99 prh->data.pending = FALSE;
100 prh->data.use_thread_fallback = FALSE;
101 prh->data.io_thread = NULL;
103 pwh->data.pipe = INVALID_HANDLE_VALUE;
104 pwh->data.rw_buf = malloc(read_size);
105 pwh->data.rw_buf_size = read_size;
106 pwh->data.overlapped.hEvent = NULL;
107 pwh->data.pending = FALSE;
108 pwh->data.use_thread_fallback = FALSE;
109 pwh->data.io_thread = NULL;
111 if(prh->data.rw_buf == NULL || pwh->data.rw_buf == NULL)
116 return ERROR_OUTOFMEMORY;
121 prh->data.overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
122 if(prh->data.overlapped.hEvent == NULL)
124 DWORD error = GetLastError();
132 pwh->data.overlapped.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
133 if(pwh->data.overlapped.hEvent == NULL)
135 DWORD error = GetLastError();
151 while(prh->data.pipe == INVALID_HANDLE_VALUE)
153 strcpy(pipename,
"\\\\.\\pipe\\tmp_");
154 int pnlen = strlen(pipename);
156 while(pnlen < (
sizeof(pipename) - 1))
158 char rndchar =
'A' + (rand() % 26);
159 pipename[pnlen++] = rndchar;
162 pipename[pnlen] =
'\0';
164 SECURITY_ATTRIBUTES r_secattrs = {
sizeof(SECURITY_ATTRIBUTES), NULL, read_inherit };
166 prh->data.pipe = CreateNamedPipe(
168 (PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED),
169 (PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT),
176 if(prh->data.pipe == INVALID_HANDLE_VALUE)
178 DWORD error = GetLastError();
180 if(error == ERROR_FILE_EXISTS)
184 else if(error == ERROR_CALL_NOT_IMPLEMENTED)
194 if(!CreatePipe(&(prh->data.pipe), &(pwh->data.pipe), &r_secattrs, read_size))
196 error = GetLastError();
204 if(read_inherit != write_inherit)
206 fprintf(stderr,
"replacing write handle (%d)\n", (
int)(write_inherit));
207 HANDLE new_write_handle;
216 DUPLICATE_SAME_ACCESS))
218 error = GetLastError();
226 CloseHandle(pwh->data.pipe);
227 pwh->data.pipe = new_write_handle;
230 prh->data.use_thread_fallback = TRUE;
231 pwh->data.use_thread_fallback = TRUE;
236 return ERROR_SUCCESS;
247 if(!ConnectNamedPipe(prh->data.pipe, &(prh->data.overlapped)))
249 DWORD error = GetLastError();
251 if(error != ERROR_IO_PENDING)
262 SECURITY_ATTRIBUTES w_secattrs = {
sizeof(SECURITY_ATTRIBUTES), NULL, write_inherit };
264 pwh->data.pipe = CreateFile(
270 FILE_FLAG_OVERLAPPED,
273 if(pwh->data.pipe == INVALID_HANDLE_VALUE)
275 DWORD error = GetLastError();
285 DWORD transferred_bytes;
286 if(!GetOverlappedResult(prh->data.pipe, &(prh->data.overlapped), &transferred_bytes, TRUE))
288 DWORD error = GetLastError();
299 return ERROR_SUCCESS;
302static void _pipe9x_cleanup(
struct PipeData *pd)
304 if(pd->pipe != INVALID_HANDLE_VALUE)
306 CloseHandle(pd->pipe);
312 if(pd->use_thread_fallback)
314 assert(pd->io_thread != NULL);
316 WaitForSingleObject(pd->io_thread, INFINITE);
317 CloseHandle(pd->io_thread);
319 pd->io_thread = NULL;
322 assert(pd->overlapped.hEvent != NULL);
323 WaitForSingleObject(pd->overlapped.hEvent, INFINITE);
327 if(pd->overlapped.hEvent != NULL)
329 CloseHandle(pd->overlapped.hEvent);
330 pd->overlapped.hEvent = NULL;
344 _pipe9x_cleanup(&(prh->data));
348static DWORD WINAPI _pipe9x_read_thread(LPVOID lpParameter)
350 PipeReadHandle prh = (PipeReadHandle)(lpParameter);
355 prh->data.rw_buf_size,
356 &(prh->data.bytes_transferred),
359 prh->data.io_result = ERROR_SUCCESS;
362 prh->data.io_result = GetLastError();
365 SetEvent(prh->data.overlapped.hEvent);
374 if(prh->data.pending)
376 return ERROR_IO_INCOMPLETE;
379 if(prh->data.use_thread_fallback)
381 assert(prh->data.io_thread == NULL);
383 ResetEvent(prh->data.overlapped.hEvent);
386 prh->data.io_thread = CreateThread(NULL, 0, &_pipe9x_read_thread, prh, 0, &io_thread_id);
388 if(prh->data.io_thread == NULL)
390 return GetLastError();
393 prh->data.pending = TRUE;
395 return ERROR_IO_PENDING;
401 prh->data.rw_buf_size,
402 &(prh->data.bytes_transferred),
403 &(prh->data.overlapped)))
409 prh->data.pending = TRUE;
410 return ERROR_IO_PENDING;
413 DWORD error = GetLastError();
415 if(error == ERROR_IO_PENDING)
417 prh->data.pending = TRUE;
418 return ERROR_IO_PENDING;
431 if(!prh->data.pending)
433 return ERROR_INVALID_PARAMETER;
436 if(prh->data.use_thread_fallback)
438 assert(prh->data.io_thread != NULL);
440 DWORD wait_result = WaitForSingleObject(prh->data.overlapped.hEvent, (wait ? INFINITE : 0));
441 if(wait_result == WAIT_OBJECT_0)
443 wait_result = WaitForSingleObject(prh->data.io_thread, INFINITE);
444 assert(wait_result == WAIT_OBJECT_0);
446 prh->data.pending = FALSE;
448 CloseHandle(prh->data.io_thread);
449 prh->data.io_thread = NULL;
451 if(prh->data.io_result == ERROR_SUCCESS)
453 *data_out = prh->data.rw_buf;
454 *data_size_out = prh->data.bytes_transferred;
457 return prh->data.io_result;
459 else if(wait_result == WAIT_TIMEOUT)
461 return ERROR_IO_INCOMPLETE;
469 DWORD bytes_transferred;
470 if(GetOverlappedResult(prh->data.pipe, &(prh->data.overlapped), &bytes_transferred, wait))
472 prh->data.pending = FALSE;
474 *data_out = prh->data.rw_buf;
475 *data_size_out = bytes_transferred;
477 return ERROR_SUCCESS;
480 DWORD error = GetLastError();
483 if(error != ERROR_IO_INCOMPLETE)
485 prh->data.pending = FALSE;
495 return prh->data.pending;
501 return prh->data.pipe;
507 return prh->data.overlapped.hEvent;
510static DWORD WINAPI _pipe9x_write_thread(LPVOID lpParameter)
512 PipeWriteHandle pwh = (PipeWriteHandle)(lpParameter);
517 pwh->data.bytes_transferred,
518 &(pwh->data.bytes_transferred),
521 pwh->data.io_result = ERROR_SUCCESS;
524 pwh->data.io_result = GetLastError();
527 SetEvent(pwh->data.overlapped.hEvent);
536 if(pwh->data.pending)
538 return ERROR_IO_INCOMPLETE;
541 if(data_size > pwh->data.rw_buf_size)
543 return ERROR_FILE_TOO_LARGE;
546 memcpy(pwh->data.rw_buf, data, data_size);
548 if(pwh->data.use_thread_fallback)
550 assert(pwh->data.io_thread == NULL);
552 ResetEvent(pwh->data.overlapped.hEvent);
554 pwh->data.bytes_transferred = data_size;
557 pwh->data.io_thread = CreateThread(NULL, 0, &_pipe9x_write_thread, pwh, 0, &io_thread_id);
559 if(pwh->data.io_thread == NULL)
561 return GetLastError();
564 pwh->data.pending = TRUE;
566 return ERROR_IO_PENDING;
573 &(pwh->data.bytes_transferred),
574 &(pwh->data.overlapped)))
580 pwh->data.pending = TRUE;
581 return ERROR_IO_PENDING;
584 DWORD error = GetLastError();
586 if(error == ERROR_IO_PENDING)
588 pwh->data.pending = TRUE;
589 return ERROR_IO_PENDING;
602 if(!pwh->data.pending)
604 return ERROR_INVALID_PARAMETER;
607 if(pwh->data.use_thread_fallback)
609 assert(pwh->data.io_thread != NULL);
611 DWORD wait_result = WaitForSingleObject(pwh->data.overlapped.hEvent, (wait ? INFINITE : 0));
612 if(wait_result == WAIT_OBJECT_0)
614 wait_result = WaitForSingleObject(pwh->data.io_thread, INFINITE);
615 assert(wait_result == WAIT_OBJECT_0);
617 pwh->data.pending = FALSE;
619 CloseHandle(pwh->data.io_thread);
620 pwh->data.io_thread = NULL;
622 if(pwh->data.io_result == ERROR_SUCCESS)
624 *data_written_out = pwh->data.bytes_transferred;
627 return pwh->data.io_result;
629 else if(wait_result == WAIT_TIMEOUT)
631 return ERROR_IO_INCOMPLETE;
639 DWORD bytes_transferred;
640 if(GetOverlappedResult(pwh->data.pipe, &(pwh->data.overlapped), &bytes_transferred, wait))
642 pwh->data.pending = FALSE;
644 *data_written_out = bytes_transferred;
646 return ERROR_SUCCESS;
649 DWORD error = GetLastError();
652 if(error != ERROR_IO_INCOMPLETE)
654 pwh->data.pending = FALSE;
668 _pipe9x_cleanup(&(pwh->data));
675 return pwh->data.pending;
681 return pwh->data.pipe;
687 return pwh->data.overlapped.hEvent;
DWORD pipe9x_write_result(PipeWriteHandle pwh, size_t *data_written_out, BOOL wait)
Get the result from a write operation.
BOOL pipe9x_write_pending(PipeWriteHandle pwh)
Check if a write operation is pending.
void pipe9x_read_close(PipeReadHandle prh)
Closes the read end of a pipe created by pipe9x_create().
DWORD pipe9x_read_result(PipeReadHandle prh, void **data_out, size_t *data_size_out, BOOL wait)
Get the result from a read operation.
DWORD pipe9x_create(PipeReadHandle *prh_out, size_t read_size, BOOL read_inherit, PipeWriteHandle *pwh_out, size_t write_size, BOOL write_inherit)
Create a pair of connected pipe handles.
void pipe9x_write_close(PipeWriteHandle pwh)
Closes the write end of a pipe created by pipe9x_create().
HANDLE pipe9x_write_pipe(PipeWriteHandle pwh)
Get the underlying Windows HANDLE of the pipe.
DWORD pipe9x_write_initiate(PipeWriteHandle prh, const void *data, size_t data_size)
Start a write in the background.
HANDLE pipe9x_read_pipe(PipeReadHandle prh)
Get the underlying Windows HANDLE of the pipe.
HANDLE pipe9x_write_event(PipeWriteHandle prh)
Get an event object for detecting I/O completion.
HANDLE pipe9x_read_event(PipeReadHandle prh)
Get an event object for detecting I/O completion.
DWORD pipe9x_read_initiate(PipeReadHandle prh)
Start a read in the background.
BOOL pipe9x_read_pending(PipeReadHandle prh)
Check if a read operation is pending.