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 <[email protected]>
---
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;
 

Attachment: cl_timer
Description: cl_timer

_______________________________________________
ofw mailing list
[email protected]
http://lists.openfabrics.org/cgi-bin/mailman/listinfo/ofw

Reply via email to