Skip to content

Commit

Permalink
winpr-comm: fixed a regression about timeouts to block of first bytes…
Browse files Browse the repository at this point in the history
… when required. Added timeouts values in the DEBUG log.
  • Loading branch information
eledoux committed Mar 9, 2015
1 parent c9c8f8c commit a8fc5fc
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 17 deletions.
50 changes: 33 additions & 17 deletions winpr/libwinpr/comm/comm_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
UCHAR vmin = 0;
UCHAR vtime = 0;
ULONGLONG Tmax = 0;
struct timeval tmaxTimeout;
struct timeval tmaxTimeout, *pTmaxTimeout;
struct termios currentTermios;

EnterCriticalSection(&pComm->ReadLock); /* KISSer by the function's beginning */
Expand Down Expand Up @@ -144,13 +144,13 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439614%28v=vs.85%29.aspx
*
* ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME | TMAX |
* 0 | 0 | 0 | N | 0 | 0 | Blocks for N bytes available.
* 0< Ti <MAXULONG | 0 | 0 | N | Ti | 0 | Block on first byte, then use Ti between bytes.
* 0 | 0 | 0 | N | 0 | INDEF | Blocks for N bytes available.
* 0< Ti <MAXULONG | 0 | 0 | N | Ti | INDEF | Blocks on first byte, then use Ti between bytes.
* MAXULONG | 0 | 0 | 0 | 0 | 0 | Returns immediately with bytes available (don't block)
* MAXULONG | MAXULONG | 0< Tc <MAXULONG | N | 0 | Tc | Blocks on first byte during Tc or returns immediately whith bytes available
* MAXULONG | m | MAXULONG | | Invalid
* 0 | m | 0< Tc <MAXULONG | N | 0 | Tmax | Block on first byte during Tmax or returns immediately whith bytes available
* 0< Ti <MAXULONG | m | 0< Tc <MAXULONG | N | Ti | Tmax | Block on first byte, then use Ti between bytes. Tmax is use for the whole system call.
* 0 | m | 0< Tc <MAXULONG | N | 0 | Tmax | Blocks on first byte during Tmax or returns immediately whith bytes available
* 0< Ti <MAXULONG | m | 0< Tc <MAXULONG | N | Ti | Tmax | Blocks on first byte, then use Ti between bytes. Tmax is used for the whole system call.
*/

/* NB: timeouts are in milliseconds, VTIME are in deciseconds and is an unsigned char */
Expand Down Expand Up @@ -195,6 +195,8 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,

/* TMAX */

pTmaxTimeout = &tmaxTimeout;

if ((pTimeouts->ReadIntervalTimeout == MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == MAXULONG))
{
/* Tc */
Expand All @@ -204,6 +206,10 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
{
/* Tmax */
Tmax = nNumberOfBytesToRead * pTimeouts->ReadTotalTimeoutMultiplier + pTimeouts->ReadTotalTimeoutConstant;

/* INDEFinitely */
if((Tmax == 0) && (pTimeouts->ReadIntervalTimeout < MAXULONG) && (pTimeouts->ReadTotalTimeoutMultiplier == 0))
pTmaxTimeout = NULL;
}

if ((currentTermios.c_cc[VMIN] != vmin) || (currentTermios.c_cc[VTIME] != vtime))
Expand All @@ -219,11 +225,16 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
}
}

ZeroMemory(&tmaxTimeout, sizeof(struct timeval));
if (Tmax > 0) /* no timeout if Tmax == 0 */
/* wait indefinitely if pTmaxTimeout is NULL */

if(pTmaxTimeout != NULL)
{
tmaxTimeout.tv_sec = Tmax / 1000; /* s */
tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */
ZeroMemory(pTmaxTimeout, sizeof(struct timeval));
if (Tmax > 0) /* return immdiately if Tmax == 0 */
{
pTmaxTimeout->tv_sec = Tmax / 1000; /* s */
pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000; /* us */
}
}


Expand All @@ -244,7 +255,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
FD_SET(pComm->fd_read_event, &read_set);
FD_SET(pComm->fd_read, &read_set);

nbFds = select(biggestFd+1, &read_set, NULL, NULL, &tmaxTimeout);
nbFds = select(biggestFd+1, &read_set, NULL, NULL, pTmaxTimeout);
if (nbFds < 0)
{
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno, strerror(errno));
Expand Down Expand Up @@ -358,7 +369,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped)
{
WINPR_COMM* pComm = (WINPR_COMM*) hDevice;
struct timeval tmaxTimeout;
struct timeval tmaxTimeout, *pTmaxTimeout;

EnterCriticalSection(&pComm->WriteLock); /* KISSer by the function's beginning */

Expand Down Expand Up @@ -406,13 +417,18 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
* how much time was left. Keep the timeout variable out of
* the while() */


ZeroMemory(&tmaxTimeout, sizeof(struct timeval));
if (Tmax > 0) /* no timeout if Tmax == 0 */
pTmaxTimeout = &tmaxTimeout;
ZeroMemory(pTmaxTimeout, sizeof(struct timeval));
if (Tmax > 0)
{
pTmaxTimeout->tv_sec = Tmax / 1000; /* s */
pTmaxTimeout->tv_usec = (Tmax % 1000) * 1000; /* us */
}
else if ((pComm->timeouts.WriteTotalTimeoutMultiplier == 0) && (pComm->timeouts.WriteTotalTimeoutConstant == 0))
{
tmaxTimeout.tv_sec = Tmax / 1000; /* s */
tmaxTimeout.tv_usec = (Tmax % 1000) * 1000; /* us */
pTmaxTimeout = NULL;
}
/* else return immdiately */

while (*lpNumberOfBytesWritten < nNumberOfBytesToWrite)
{
Expand All @@ -433,7 +449,7 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite
FD_SET(pComm->fd_write_event, &event_set);
FD_SET(pComm->fd_write, &write_set);

nbFds = select(biggestFd+1, &event_set, &write_set, NULL, &tmaxTimeout);
nbFds = select(biggestFd+1, &event_set, &write_set, NULL, pTmaxTimeout);
if (nbFds < 0)
{
CommLog_Print(WLOG_WARN, "select() failure, errno=[%d] %s\n", errno, strerror(errno));
Expand Down
6 changes: 6 additions & 0 deletions winpr/libwinpr/comm/comm_serial_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,12 @@ static BOOL _set_timeouts(WINPR_COMM *pComm, const SERIAL_TIMEOUTS *pTimeouts)
pComm->timeouts.WriteTotalTimeoutMultiplier = pTimeouts->WriteTotalTimeoutMultiplier;
pComm->timeouts.WriteTotalTimeoutConstant = pTimeouts->WriteTotalTimeoutConstant;

CommLog_Print(WLOG_DEBUG, "ReadIntervalTimeout %d", pComm->timeouts.ReadIntervalTimeout);
CommLog_Print(WLOG_DEBUG, "ReadTotalTimeoutMultiplier %d", pComm->timeouts.ReadTotalTimeoutMultiplier);
CommLog_Print(WLOG_DEBUG, "ReadTotalTimeoutConstant %d", pComm->timeouts.ReadTotalTimeoutConstant);
CommLog_Print(WLOG_DEBUG, "WriteTotalTimeoutMultiplier %d", pComm->timeouts.WriteTotalTimeoutMultiplier);
CommLog_Print(WLOG_DEBUG, "WriteTotalTimeoutConstant %d", pComm->timeouts.WriteTotalTimeoutConstant);

return TRUE;
}

Expand Down

0 comments on commit a8fc5fc

Please sign in to comment.