[ofw] [PATCH] complib/user: fix timer race conditions
Fab Tillier
ftillier at microsoft.com
Thu Jun 24 18:02:21 PDT 2010
Why the per-timer timer queue? The only time you take advantage of it is in cl_timer_destroy, but at that point the timer should no longer be in the process of being queued. You could just as easily call __clear_timer_handle, and then do a blocking cancel of the timer.
-Fab
> -----Original Message-----
> From: Hefty, Sean [mailto:sean.hefty at intel.com]
> Sent: Thursday, June 24, 2010 5:56 PM
> To: Hefty, Sean; Smith, Stan; Fab Tillier; Tzachi Dar;
> ofw at lists.openfabrics.org
> Cc: Uri Habusha; Yevgeny Kliteynik
> Subject: [PATCH] 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.
>
> cl_timer_start simply calls cl_timer_trim
>
> cl_timer_trim cancels any queued timer and inserts a new one if the
> timeout
> time is less than the last last set timeout.
>
> This eliminates the need to track the callback thread ID and any races
> associated
> with trying to do so. The synchronization provided is straightforward.
>
> Signed-off-by: Sean Hefty <sean.hefty at intel.com>
> ---
> trunk/core/complib/user/cl_timer.c | 95 ++++++++++++++++++++-----
> --------
> trunk/inc/user/complib/cl_timer_osd.h | 4 +
> 2 files changed, 60 insertions(+), 39 deletions(-)
>
> diff --git a/trunk/core/complib/user/cl_timer.c
> b/trunk/core/complib/user/cl_timer.c
> index 4f2ce0f..37c5448 100644
> --- a/trunk/core/complib/user/cl_timer.c
> +++ b/trunk/core/complib/user/cl_timer.c
> @@ -34,21 +34,33 @@
> #include "complib/cl_timer.h"
>
>
> +static HANDLE
> +__clear_timer_handle(
> + IN cl_timer_t* const p_timer )
> +{
> + HANDLE timer;
> +
> + EnterCriticalSection( &p_timer->lock );
> + timer = p_timer->h_timer;
> + p_timer->h_timer = NULL;
> + LeaveCriticalSection( &p_timer->lock );
> +
> + return timer;
> +}
> +
> 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 );
> UNUSED_PARAM( timer_signalled );
>
> - p_timer->timeout_time = 0;
> - p_timer->thread_id = GetCurrentThreadId();
> + if( !__clear_timer_handle( p_timer ))
> + return;
>
> + EnterCriticalSection( &p_timer->cb_lock );
> (p_timer->pfn_callback)( (void*)p_timer->context );
> -
> - p_timer->thread_id = 0;
> + LeaveCriticalSection( &p_timer->cb_lock );
> }
>
>
> @@ -56,9 +68,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 +86,12 @@ cl_timer_init(
>
> p_timer->pfn_callback = pfn_callback;
> p_timer->context = context;
> + p_timer->h_timer_queue = CreateTimerQueue();
> + if( !p_timer->h_timer_queue )
> + return CL_ERROR;
> +
> + InitializeCriticalSection( &p_timer->lock );
> + InitializeCriticalSection( &p_timer->cb_lock );
> return( CL_SUCCESS );
> }
>
> @@ -86,7 +102,12 @@ cl_timer_destroy(
> {
> CL_ASSERT( p_timer );
>
> - cl_timer_stop( p_timer );
> + if( p_timer->h_timer_queue )
> + {
> + DeleteTimerQueueEx( p_timer->h_timer_queue,
> INVALID_HANDLE_VALUE );
> + DeleteCriticalSection( &p_timer->lock );
> + DeleteCriticalSection( &p_timer->cb_lock );
> + }
> }
>
>
> @@ -95,19 +116,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,19 +125,30 @@ 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 );
> + timeout = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
>
> - return cl_timer_start( p_timer, time_ms );
> + EnterCriticalSection( &p_timer->lock );
> + if ( !p_timer->h_timer || timeout < p_timer->timeout_time )
> + {
> + if( p_timer->h_timer )
> + DeleteTimerQueueTimer( p_timer->h_timer_queue,
> p_timer->h_timer, NULL );
> +
> + p_timer->timeout_time = timeout;
> + if( !CreateTimerQueueTimer( &p_timer->h_timer, p_timer-
> >h_timer_queue,
> + __timer_callback, p_timer, time_ms, 0,
> WT_EXECUTEINIOTHREAD ) )
> + {
> + p_timer->h_timer = NULL;
> + status = CL_ERROR;
> + }
> + }
> + LeaveCriticalSection( &p_timer->lock );
> + return status;
> }
>
>
> @@ -136,15 +156,14 @@ void
> cl_timer_stop(
> IN cl_timer_t* const p_timer )
> {
> + HANDLE 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;
> - }
> - p_timer->timeout_time = 0;
> + timer = __clear_timer_handle( p_timer );
> +
> + if( timer )
> + DeleteTimerQueueTimer( p_timer->h_timer_queue, timer,
> INVALID_HANDLE_VALUE );
> }
>
>
> diff --git a/trunk/inc/user/complib/cl_timer_osd.h
> b/trunk/inc/user/complib/cl_timer_osd.h
> index 0a023ba..370a175 100644
> --- a/trunk/inc/user/complib/cl_timer_osd.h
> +++ b/trunk/inc/user/complib/cl_timer_osd.h
> @@ -42,11 +42,13 @@
> /* Timer object definition. */
> typedef struct _cl_timer
> {
> + HANDLE h_timer_queue;
> 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