[ofw] [PATCH v2] complib/timer: fix race accessing timer fields

Hefty, Sean sean.hefty at intel.com
Wed Jun 23 16:48:07 PDT 2010


The timeout_time field of cl_timer_t is modified in the timer
callback function and also in calls to cl_timer_start, cl_timer_stop,
and cl_timer_trim.  The user cannot protect against the changes
made in the timer callback function, so the timer must provide
this protection itself.

Provide serialization to prevent multiple timer callbacks to
the user at once.

Signed-off-by: Sean Hefty <sean.hefty at intel.com>
---
changes from v1: used Windows spinlock calls rather than abstractions
compile tested only

 trunk/core/complib/kernel/cl_timer.c    |   41 +++++++++++++++++++++++--------
 trunk/inc/kernel/complib/cl_timer_osd.h |    2 ++
 2 files changed, 33 insertions(+), 10 deletions(-)

diff --git a/trunk/core/complib/kernel/cl_timer.c b/trunk/core/complib/kernel/cl_timer.c
index 34cae8e..e235642 100644
--- a/trunk/core/complib/kernel/cl_timer.c
+++ b/trunk/core/complib/kernel/cl_timer.c
@@ -41,13 +41,19 @@ __timer_callback(
 	IN	void*		arg1,
 	IN	void*		arg2 )
 {
+	KLOCK_QUEUE_HANDLE hlock;
+
 	UNUSED_PARAM( p_dpc );
 	UNUSED_PARAM( arg1 );
 	UNUSED_PARAM( arg2 );
 
+	KeAcquireInStackQueuedSpinLockAtDpcLevel( &p_timer->spinlock, &hlock );
 	p_timer->timeout_time = 0;
+	KeReleaseInStackQueuedSpinLockFromDpcLevel( &hlock );
 
+	KeAcquireInStackQueuedSpinLockAtDpcLevel( &p_timer->cb_lock, &hlock );
 	(p_timer->pfn_callback)( (void*)p_timer->context );
+	KeReleaseInStackQueuedSpinLockFromDpcLevel( &hlock );
 }
 
 
@@ -75,6 +81,8 @@ cl_timer_init(
 
 	KeInitializeTimer( &p_timer->timer );
 	KeInitializeDpc( &p_timer->dpc, __timer_callback, p_timer );
+	KeInitializeSpinLock( &p_timer->spinlock );
+	KeInitializeSpinLock( &p_timer->cb_lock );
 
 	return( CL_SUCCESS );
 }
@@ -108,6 +116,8 @@ cl_timer_start(
 	IN	const uint32_t		time_ms )
 {
 	LARGE_INTEGER	due_time;
+	uint64_t		timeout_time;
+	KLOCK_QUEUE_HANDLE hlock;
 
 	CL_ASSERT( p_timer );
 	CL_ASSERT( p_timer->pfn_callback );
@@ -115,11 +125,13 @@ cl_timer_start(
 
 	/* Due time is in 100 ns increments.  Negative for relative time. */
 	due_time.QuadPart = -(int64_t)(((uint64_t)time_ms) * 10000);
+	timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
 
-	/* Store the timeout time in the timer object. */
-	p_timer->timeout_time = cl_get_time_stamp() + (((uint64_t)time_ms) * 1000);
-
+	KeAcquireInStackQueuedSpinLock( &p_timer->spinlock, &hlock );
+	p_timer->timeout_time = timeout_time;
 	KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc );
+	KeReleaseInStackQueuedSpinLock( &hlock );
+
 	return( CL_SUCCESS );
 }
 
@@ -129,19 +141,25 @@ cl_timer_trim(
 	IN	cl_timer_t* const	p_timer,
 	IN	const uint32_t		time_ms )
 {
+	LARGE_INTEGER	due_time;
 	uint64_t		timeout_time;
+	KLOCK_QUEUE_HANDLE hlock;
 
 	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 );
+	KeAcquireInStackQueuedSpinLock( &p_timer->spinlock, &hlock );
+	if( !p_timer->timeout_time || p_timer->timeout_time > timeout_time )
+	{
+		p_timer->timeout_time = timeout_time;
+		due_time.QuadPart = -(int64_t)(((uint64_t)time_ms) * 10000);
+		KeSetTimer( &p_timer->timer, due_time, &p_timer->dpc );
+	}
+	KeReleaseInStackQueuedSpinLock( &hlock );
+	return( CL_SUCCESS );
 }
 
 
@@ -149,12 +167,15 @@ void
 cl_timer_stop(
 	IN	cl_timer_t* const	p_timer )
 {
+	KLOCK_QUEUE_HANDLE hlock;
+
 	CL_ASSERT( p_timer );
 	CL_ASSERT( p_timer->pfn_callback );
 	CL_ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL );
 	
 	/* Cancel the timer.  This also cancels any queued DPCs for the timer. */
-	KeCancelTimer( &p_timer->timer );
-
+	KeAcquireInStackQueuedSpinLock( &p_timer->spinlock, &hlock );
 	p_timer->timeout_time = 0;
+	KeCancelTimer( &p_timer->timer );
+	KeReleaseInStackQueuedSpinLock( &hlock );
 }
diff --git a/trunk/inc/kernel/complib/cl_timer_osd.h b/trunk/inc/kernel/complib/cl_timer_osd.h
index 4cb99b0..0935902 100644
--- a/trunk/inc/kernel/complib/cl_timer_osd.h
+++ b/trunk/inc/kernel/complib/cl_timer_osd.h
@@ -48,6 +48,8 @@ typedef struct _cl_timer
 	cl_pfn_timer_callback_t	pfn_callback;
 	const void				*context;
 	uint64_t				timeout_time;
+	KSPIN_LOCK				spinlock;
+	KSPIN_LOCK				cb_lock;
 
 } cl_timer_t;
 

-------------- next part --------------
A non-text attachment was scrubbed...
Name: cl_timer
Type: application/octet-stream
Size: 4501 bytes
Desc: cl_timer
URL: <http://lists.openfabrics.org/pipermail/ofw/attachments/20100623/b5b7e610/attachment.obj>


More information about the ofw mailing list