From 9fe43bcbe98a591c0a45cc2416cf17923b91df41 Mon Sep 17 00:00:00 2001 From: Joseph Hickey Date: Wed, 6 Mar 2024 16:55:16 -0500 Subject: [PATCH] (Draft) Fix #1455, High-res timed stream ops Implement high-res timed operations for streams. This uses an absolute time via the OS_time_t value, which has a default resolution of 0.1usec but is configurable. --- src/os/inc/osapi-file.h | 81 +++++++++++++++++++++++++++++++++- src/os/shared/src/osapi-file.c | 49 +++++++++++++++++++- 2 files changed, 126 insertions(+), 4 deletions(-) diff --git a/src/os/inc/osapi-file.h b/src/os/inc/osapi-file.h index e039f2bfc..280482dcf 100644 --- a/src/os/inc/osapi-file.h +++ b/src/os/inc/osapi-file.h @@ -237,7 +237,49 @@ int32 OS_write(osal_id_t filedes, const void *buffer, size_t nbytes); * @param[in] filedes The handle ID to operate on * @param[out] buffer Storage location for file data @nonnull * @param[in] nbytes Maximum number of bytes to read @nonzero - * @param[in] timeout Maximum time to wait, in milliseconds (OS_PEND = forever) + * @param[in] abstime Absolute time at which this function should return, if no data is readable + * + * @returns Byte count on success or appropriate error code, see @ref OSReturnCodes + * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period + * @retval #OS_ERR_INVALID_ID if the file descriptor passed in is invalid + * @retval #OS_ERR_INVALID_SIZE if the passed-in size is not valid + * @retval #OS_INVALID_POINTER if the passed-in buffer is not valid + * @retval 0 if at end of file/stream data + */ +int32 OS_AbsTimedRead(osal_id_t filedes, void *buffer, size_t nbytes, OS_time_t abstime); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief File/Stream input read with a timeout + * + * This implements a time-limited read and is primarily intended for use with + * sockets but may also work with any other stream-like resource that the underlying + * OS supports, such as pipes or special devices. + * + * If data is immediately available on the file/socket, this will return that data + * along with the actual number of bytes that were immediately available. It will + * not block. + * + * If the file position is at the end of file or end of stream data (e.g. if the remote + * end has closed the connection), then this function will immediately return 0 without + * blocking for the timeout period. + * + * If no data is immediately available, but the underlying resource/stream is still + * connected to a peer, this will wait up to the given timeout for additional + * data to appear. If no data appears within the timeout period, then this returns + * the #OS_ERROR_TIMEOUT status code. This allows the caller to differentiate + * an open (but idle) socket connection from a connection which has been closed + * by the remote peer. + * + * In all cases this will return successfully as soon as at least 1 byte of actual + * data is available. It will not attempt to read the entire input buffer. + * + * If an EOF condition occurs prior to timeout, this function returns zero. + * + * @param[in] filedes The handle ID to operate on + * @param[out] buffer Storage location for file data @nonnull + * @param[in] nbytes Maximum number of bytes to read @nonzero + * @param[in] timeout Maximum time to wait, in milliseconds, relative to current time (OS_PEND = forever) * * @returns Byte count on success or appropriate error code, see @ref OSReturnCodes * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period @@ -272,7 +314,42 @@ int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout * @param[in] filedes The handle ID to operate on * @param[in] buffer Source location for file data @nonnull * @param[in] nbytes Maximum number of bytes to read @nonzero - * @param[in] timeout Maximum time to wait, in milliseconds (OS_PEND = forever) + * @param[in] abstime Absolute time at which this function should return, if no data is readable + * + * @return A non-negative byte count or appropriate error code, see @ref OSReturnCodes + * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period + * @retval #OS_ERR_INVALID_ID if the file descriptor passed in is invalid + * @retval #OS_ERR_INVALID_SIZE if the passed-in size is not valid + * @retval #OS_INVALID_POINTER if the passed-in buffer is not valid + * @retval 0 if file/stream cannot accept any more data + */ +int32 OS_AbsTimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, OS_time_t abstime); + +/*-------------------------------------------------------------------------------------*/ +/** + * @brief File/Stream output write with a timeout + * + * This implements a time-limited write and is primarily intended for use with + * sockets but may also work with any other stream-like resource that the underlying + * OS supports. + * + * If output buffer space is immediately available on the file/socket, this will + * place data into the buffer and return the actual number of bytes that were + * queued for output. It will not block. + * + * If no output buffer space is immediately available, this will wait up to the + * given timeout for space to become available. If no space becomes available within + * the timeout period, then this returns an error code (not zero). + * + * In all cases this will return successfully as soon as at least 1 byte of actual + * data is output. It will _not_ attempt to write the entire output buffer. + * + * If an EOF condition occurs prior to timeout, this function returns zero. + * + * @param[in] filedes The handle ID to operate on + * @param[in] buffer Source location for file data @nonnull + * @param[in] nbytes Maximum number of bytes to read @nonzero + * @param[in] timeout Maximum time to wait, in milliseconds, relative to current time (OS_PEND = forever) * * @return A non-negative byte count or appropriate error code, see @ref OSReturnCodes * @retval #OS_ERROR_TIMEOUT if no data became available during timeout period diff --git a/src/os/shared/src/osapi-file.c b/src/os/shared/src/osapi-file.c index da5eb7a05..08cf6eb8e 100644 --- a/src/os/shared/src/osapi-file.c +++ b/src/os/shared/src/osapi-file.c @@ -82,6 +82,29 @@ int32 OS_FileIteratorClose(osal_id_t filedes, void *arg) return OS_close(filedes); } +/*---------------------------------------------------------------- + * + * Helper function to convert a relative timeout to absolute time + * + *-----------------------------------------------------------------*/ +OS_time_t OS_TimeFromRelative(int32 relative_msec) +{ + OS_time_t AbsTime; + + if (relative_msec > 0) + { + OS_GetLocalTime(&AbsTime); + OS_TimeAdd(AbsTime, OS_TimeFromTotalMilliseconds(relative_msec)); + } + else + { + AbsTime = OS_TIME_MAX; + } + + return AbsTime; +} + + /**************************************************************************************** FILE API ***************************************************************************************/ @@ -182,7 +205,7 @@ int32 OS_close(osal_id_t filedes) * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout) +int32 OS_AbsTimedRead(osal_id_t filedes, void *buffer, size_t nbytes, OS_time_t abstime) { OS_object_token_t token; int32 return_code; @@ -208,7 +231,18 @@ int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout * See description in API and header file for detail * *-----------------------------------------------------------------*/ -int32 OS_TimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, int32 timeout) +int32 OS_TimedRead(osal_id_t filedes, void *buffer, size_t nbytes, int32 timeout) +{ + return OS_AbsTimedRead(filedes, buffer, nbytes, OS_TimeFromRelative(timeout)); +} + +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_AbsTimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, OS_time_t abstime) { OS_object_token_t token; int32 return_code; @@ -227,6 +261,17 @@ int32 OS_TimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, int32 return return_code; } +/*---------------------------------------------------------------- + * + * Purpose: Implemented per public OSAL API + * See description in API and header file for detail + * + *-----------------------------------------------------------------*/ +int32 OS_TimedWrite(osal_id_t filedes, const void *buffer, size_t nbytes, int32 timeout) +{ + return OS_AbsTimedWrite(filedes, buffer, nbytes, OS_TimeFromRelative(timeout)); +} + /*---------------------------------------------------------------- * * Purpose: Implemented per public OSAL API