[ofw] [PATCH v2] complib/user: fix timer race conditions
Tzachi Dar
tzachid at mellanox.co.il
Tue Jun 29 00:48:30 PDT 2010
OK, a very nice trick to use a periodic timer.
I also believe that stop can be called from a callback since the criticalsections are re-entrant.
Indeed in that case you will not know if the callback is running until one will call cl_timer_destroy.
Thanks
Tzachi
> -----Original Message-----
> From: ofw-bounces at lists.openfabrics.org [mailto:ofw-
> bounces at lists.openfabrics.org] On Behalf Of Hefty, Sean
> Sent: Tuesday, June 29, 2010 12:51 AM
> To: ofw at lists.openfabrics.org
> Subject: [ofw] [PATCH v2] complib/user: fix timer race conditions
>
> This serializes the callbacks for a timer and provides synchronization
> for multi-threaded timer usage.
>
> cl_timer_stop is not allowed to be called from a timer callback, and
> will block until any callback has completed.
>
> cl_timer_start simply calls cl_timer_trim
>
> cl_timer_trim changes the timeout of a queued timer if the new timeout
> time is less than the last set timeout.
>
> Signed-off-by: Sean Hefty <sean.hefty at intel.com>
> ---
> Changes from v1:
> Eliminated TimerQueue. The default one is used.
> Replaced the one-shot timer with a periodic timer. This lets us use
> the ChangeTimerQueueTimer (who names these things, really) function to
> adjust the next timeout.
> Moved the calculation of the timeout time to inside the critical
> section to improve its accuracy in case an attempt to acquire the
> critical section blocks.
>
> trunk/core/complib/user/cl_timer.c | 83 ++++++++++++++++++-------
> --------
> trunk/inc/user/complib/cl_timer_osd.h | 5 +-
> 2 files changed, 47 insertions(+), 41 deletions(-)
>
> diff --git a/trunk/core/complib/user/cl_timer.c
> b/trunk/core/complib/user/cl_timer.c
> index 4f2ce0f..5cab378 100644
> --- a/trunk/core/complib/user/cl_timer.c
> +++ b/trunk/core/complib/user/cl_timer.c
> @@ -32,23 +32,31 @@
>
>
> #include "complib/cl_timer.h"
> +
>
> +#define CL_MAX_TIME 0xFFFFFFFF
>
> +
> +/*
> + * If timeout_time is 0, the timer has been stopped.
> + */
> static void CALLBACK
> __timer_callback(
> IN cl_timer_t* const p_timer,
> IN BOOLEAN timer_signalled )
> {
> - /* timer_signalled is always TRUE, and has no value. */
> - CL_ASSERT( timer_signalled );
> + uint64_t timeout;
> UNUSED_PARAM( timer_signalled );
>
> + EnterCriticalSection( &p_timer->cb_lock );
> + EnterCriticalSection( &p_timer->lock );
> + timeout = p_timer->timeout_time;
> p_timer->timeout_time = 0;
> - p_timer->thread_id = GetCurrentThreadId();
> + LeaveCriticalSection( &p_timer->lock );
>
> - (p_timer->pfn_callback)( (void*)p_timer->context );
> -
> - p_timer->thread_id = 0;
> + if( timeout )
> + (p_timer->pfn_callback)( (void*)p_timer->context );
> + LeaveCriticalSection( &p_timer->cb_lock );
> }
>
>
> @@ -56,9 +64,7 @@ void
> cl_timer_construct(
> IN cl_timer_t* const p_timer )
> {
> - p_timer->h_timer = NULL;
> - p_timer->timeout_time = 0;
> - p_timer->thread_id = 0;
> + memset(p_timer, 0, sizeof *p_timer);
> }
>
>
> @@ -76,6 +82,11 @@ cl_timer_init(
>
> p_timer->pfn_callback = pfn_callback;
> p_timer->context = context;
> + InitializeCriticalSection( &p_timer->lock );
> + InitializeCriticalSection( &p_timer->cb_lock );
> + if( !CreateTimerQueueTimer( &p_timer->h_timer, NULL,
> __timer_callback,
> + p_timer, CL_MAX_TIME, CL_MAX_TIME, WT_EXECUTEINIOTHREAD ) )
> + return CL_ERROR;
> return( CL_SUCCESS );
> }
>
> @@ -86,7 +97,9 @@ cl_timer_destroy(
> {
> CL_ASSERT( p_timer );
>
> - cl_timer_stop( p_timer );
> + DeleteTimerQueueTimer( NULL, p_timer->h_timer,
> INVALID_HANDLE_VALUE );
> + DeleteCriticalSection( &p_timer->lock );
> + DeleteCriticalSection( &p_timer->cb_lock );
> }
>
>
> @@ -95,19 +108,7 @@ cl_timer_start(
> IN cl_timer_t* const p_timer,
> IN const uint32_t time_ms )
> {
> - CL_ASSERT( p_timer );
> -
> - cl_timer_stop( p_timer );
> -
> - p_timer->timeout_time = cl_get_time_stamp() +
> (((uint64_t)time_ms) * 1000);
> -
> - if( !CreateTimerQueueTimer( &p_timer->h_timer, NULL,
> __timer_callback,
> - p_timer, time_ms, 0, WT_EXECUTEINIOTHREAD ) )
> - {
> - return( CL_ERROR );
> - }
> -
> - return( CL_SUCCESS );
> + return cl_timer_trim( p_timer, time_ms );
> }
>
>
> @@ -116,35 +117,41 @@ cl_timer_trim(
> IN cl_timer_t* const p_timer,
> IN const uint32_t time_ms )
> {
> - uint64_t timeout_time;
> + uint64_t timeout;
> + cl_status_t status = CL_SUCCESS;
>
> CL_ASSERT( p_timer );
> CL_ASSERT( p_timer->pfn_callback );
>
> - /* Calculate the timeout time in the timer object. */
> - timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) *
> 1000);
> -
> - /* Only pull in the timeout time. */
> - if( p_timer->timeout_time && p_timer->timeout_time < timeout_time
> )
> - return( CL_SUCCESS );
> -
> - return cl_timer_start( p_timer, time_ms );
> + EnterCriticalSection( &p_timer->lock );
> + timeout = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
> + if ( !p_timer->timeout_time || timeout < p_timer->timeout_time )
> + {
> + if( ChangeTimerQueueTimer( NULL, p_timer->h_timer, time_ms,
> CL_MAX_TIME ) )
> + p_timer->timeout_time = timeout;
> + else
> + status = CL_ERROR;
> + }
> + LeaveCriticalSection( &p_timer->lock );
> + return status;
> }
>
>
> +/*
> + * Acquire cb_lock to ensure that all callbacks have completed.
> + */
> void
> cl_timer_stop(
> IN cl_timer_t* const p_timer )
> {
> CL_ASSERT( p_timer );
>
> - if( p_timer->h_timer && p_timer->thread_id !=
> GetCurrentThreadId() )
> - {
> - /* Make sure we block until the timer is cancelled. */
> - DeleteTimerQueueTimer( NULL, p_timer->h_timer,
> INVALID_HANDLE_VALUE );
> - p_timer->h_timer = NULL;
> - }
> + EnterCriticalSection( &p_timer->cb_lock );
> + EnterCriticalSection( &p_timer->lock );
> p_timer->timeout_time = 0;
> + ChangeTimerQueueTimer( NULL, p_timer->h_timer, CL_MAX_TIME,
> CL_MAX_TIME );
> + LeaveCriticalSection( &p_timer->lock );
> + LeaveCriticalSection( &p_timer->cb_lock );
> }
>
>
> diff --git a/trunk/inc/user/complib/cl_timer_osd.h
> b/trunk/inc/user/complib/cl_timer_osd.h
> index 0a023ba..a4a1195 100644
> --- a/trunk/inc/user/complib/cl_timer_osd.h
> +++ b/trunk/inc/user/complib/cl_timer_osd.h
> @@ -38,15 +38,14 @@
>
> #include "cl_types.h"
>
> -
> -/* Timer object definition. */
> typedef struct _cl_timer
> {
> HANDLE h_timer;
> cl_pfn_timer_callback_t pfn_callback;
> const void *context;
> uint64_t timeout_time;
> - DWORD thread_id;
> + CRITICAL_SECTION lock;
> + CRITICAL_SECTION cb_lock;
>
> } cl_timer_t;
>
More information about the ofw
mailing list