Windows nonblocking write: 1 byte at a time to know when buffer fills.

This commit is contained in:
Martin Ling 2013-11-25 15:21:19 +00:00
parent a3cb91f5e1
commit 0765af5644
1 changed files with 23 additions and 26 deletions

View File

@ -64,7 +64,7 @@ struct sp_port {
#ifdef _WIN32
HANDLE hdl;
OVERLAPPED write_ovl;
BYTE *write_buf;
BYTE pending_byte;
BOOL writing;
#else
int fd;
@ -627,7 +627,6 @@ enum sp_return sp_open(struct sp_port *port, enum sp_mode flags)
sp_close(port);
RETURN_FAIL("CreateEvent() failed");
}
port->write_buf = NULL;
port->writing = FALSE;
}
@ -698,9 +697,6 @@ enum sp_return sp_close(struct sp_port *port)
RETURN_FAIL("CloseHandle() failed");
port->hdl = INVALID_HANDLE_VALUE;
if (port->nonblocking) {
if (port->writing)
/* Write should have been stopped by closing the port, so safe to free buffer. */
free(port->write_buf);
/* Close event handle created for overlapped writes. */
if (CloseHandle(port->write_ovl.hEvent) == 0)
RETURN_FAIL("CloseHandle() failed");
@ -791,6 +787,7 @@ enum sp_return sp_write(struct sp_port *port, const void *buf, size_t count)
#ifdef _WIN32
DWORD written = 0;
BYTE *ptr = (BYTE *) buf;
if (port->nonblocking) {
/* Non-blocking write. */
@ -800,8 +797,6 @@ enum sp_return sp_write(struct sp_port *port, const void *buf, size_t count)
if (HasOverlappedIoCompleted(&port->write_ovl)) {
DEBUG("Previous write completed");
port->writing = 0;
free(port->write_buf);
port->write_buf = NULL;
} else {
DEBUG("Previous write not complete");
/* Can't take a new write until the previous one finishes. */
@ -809,29 +804,31 @@ enum sp_return sp_write(struct sp_port *port, const void *buf, size_t count)
}
}
/* Copy user buffer. */
if (!(port->write_buf = malloc(count)))
RETURN_ERROR(SP_ERR_MEM, "buffer copy malloc failed");
memcpy(port->write_buf, buf, count);
/* Keep writing data until the OS has to actually start an async IO for it.
* At that point we know the buffer is full. */
while (written < count)
{
/* Copy first byte of user buffer. */
port->pending_byte = *ptr++;
/* Start asynchronous write. */
if (WriteFile(port->hdl, buf, count, NULL, &port->write_ovl) == 0) {
if (WriteFile(port->hdl, &port->pending_byte, 1, NULL, &port->write_ovl) == 0) {
if (GetLastError() == ERROR_IO_PENDING) {
DEBUG("Asynchronous write started");
port->writing = 1;
RETURN_VALUE("%d", count);
RETURN_VALUE("%d", ++written);
} else {
free(port->write_buf);
port->write_buf = NULL;
/* Actual failure of some kind. */
RETURN_FAIL("WriteFile() failed");
}
} else {
DEBUG("Write completed immediately");
free(port->write_buf);
port->write_buf = NULL;
RETURN_VALUE("%d", count);
DEBUG("Single byte written immediately.");
written++;
}
}
DEBUG("All bytes written immediately.");
} else {
/* Blocking write. */
if (WriteFile(port->hdl, buf, count, &written, NULL) == 0) {