1*d6b92ffaSHans Petter Selasky /* 2*d6b92ffaSHans Petter Selasky * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. 3*d6b92ffaSHans Petter Selasky * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4*d6b92ffaSHans Petter Selasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5*d6b92ffaSHans Petter Selasky * 6*d6b92ffaSHans Petter Selasky * This software is available to you under a choice of one of two 7*d6b92ffaSHans Petter Selasky * licenses. You may choose to be licensed under the terms of the GNU 8*d6b92ffaSHans Petter Selasky * General Public License (GPL) Version 2, available from the file 9*d6b92ffaSHans Petter Selasky * COPYING in the main directory of this source tree, or the 10*d6b92ffaSHans Petter Selasky * OpenIB.org BSD license below: 11*d6b92ffaSHans Petter Selasky * 12*d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or 13*d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following 14*d6b92ffaSHans Petter Selasky * conditions are met: 15*d6b92ffaSHans Petter Selasky * 16*d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above 17*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following 18*d6b92ffaSHans Petter Selasky * disclaimer. 19*d6b92ffaSHans Petter Selasky * 20*d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above 21*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following 22*d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials 23*d6b92ffaSHans Petter Selasky * provided with the distribution. 24*d6b92ffaSHans Petter Selasky * 25*d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26*d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27*d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28*d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29*d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30*d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31*d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32*d6b92ffaSHans Petter Selasky * SOFTWARE. 33*d6b92ffaSHans Petter Selasky * 34*d6b92ffaSHans Petter Selasky */ 35*d6b92ffaSHans Petter Selasky 36*d6b92ffaSHans Petter Selasky /* 37*d6b92ffaSHans Petter Selasky * Abstract: 38*d6b92ffaSHans Petter Selasky * Abstraction of Timer create, destroy functions. 39*d6b92ffaSHans Petter Selasky * 40*d6b92ffaSHans Petter Selasky */ 41*d6b92ffaSHans Petter Selasky 42*d6b92ffaSHans Petter Selasky #if HAVE_CONFIG_H 43*d6b92ffaSHans Petter Selasky # include <config.h> 44*d6b92ffaSHans Petter Selasky #endif /* HAVE_CONFIG_H */ 45*d6b92ffaSHans Petter Selasky 46*d6b92ffaSHans Petter Selasky #include <stdlib.h> 47*d6b92ffaSHans Petter Selasky #include <string.h> 48*d6b92ffaSHans Petter Selasky #include <complib/cl_timer.h> 49*d6b92ffaSHans Petter Selasky #include <sys/time.h> 50*d6b92ffaSHans Petter Selasky #include <sys/errno.h> 51*d6b92ffaSHans Petter Selasky #include <stdio.h> 52*d6b92ffaSHans Petter Selasky 53*d6b92ffaSHans Petter Selasky /* Timer provider (emulates timers in user mode). */ 54*d6b92ffaSHans Petter Selasky typedef struct _cl_timer_prov { 55*d6b92ffaSHans Petter Selasky pthread_t thread; 56*d6b92ffaSHans Petter Selasky pthread_mutex_t mutex; 57*d6b92ffaSHans Petter Selasky pthread_cond_t cond; 58*d6b92ffaSHans Petter Selasky cl_qlist_t queue; 59*d6b92ffaSHans Petter Selasky 60*d6b92ffaSHans Petter Selasky boolean_t exit; 61*d6b92ffaSHans Petter Selasky 62*d6b92ffaSHans Petter Selasky } cl_timer_prov_t; 63*d6b92ffaSHans Petter Selasky 64*d6b92ffaSHans Petter Selasky /* Global timer provider. */ 65*d6b92ffaSHans Petter Selasky static cl_timer_prov_t *gp_timer_prov = NULL; 66*d6b92ffaSHans Petter Selasky 67*d6b92ffaSHans Petter Selasky static void *__cl_timer_prov_cb(IN void *const context); 68*d6b92ffaSHans Petter Selasky 69*d6b92ffaSHans Petter Selasky /* 70*d6b92ffaSHans Petter Selasky * Creates the process global timer provider. Must be called by the shared 71*d6b92ffaSHans Petter Selasky * object framework to solve all serialization issues. 72*d6b92ffaSHans Petter Selasky */ 73*d6b92ffaSHans Petter Selasky cl_status_t __cl_timer_prov_create(void) 74*d6b92ffaSHans Petter Selasky { 75*d6b92ffaSHans Petter Selasky CL_ASSERT(gp_timer_prov == NULL); 76*d6b92ffaSHans Petter Selasky 77*d6b92ffaSHans Petter Selasky gp_timer_prov = malloc(sizeof(cl_timer_prov_t)); 78*d6b92ffaSHans Petter Selasky if (!gp_timer_prov) 79*d6b92ffaSHans Petter Selasky return (CL_INSUFFICIENT_MEMORY); 80*d6b92ffaSHans Petter Selasky else 81*d6b92ffaSHans Petter Selasky memset(gp_timer_prov, 0, sizeof(cl_timer_prov_t)); 82*d6b92ffaSHans Petter Selasky 83*d6b92ffaSHans Petter Selasky cl_qlist_init(&gp_timer_prov->queue); 84*d6b92ffaSHans Petter Selasky 85*d6b92ffaSHans Petter Selasky pthread_mutex_init(&gp_timer_prov->mutex, NULL); 86*d6b92ffaSHans Petter Selasky pthread_cond_init(&gp_timer_prov->cond, NULL); 87*d6b92ffaSHans Petter Selasky 88*d6b92ffaSHans Petter Selasky if (pthread_create(&gp_timer_prov->thread, NULL, 89*d6b92ffaSHans Petter Selasky __cl_timer_prov_cb, NULL)) { 90*d6b92ffaSHans Petter Selasky __cl_timer_prov_destroy(); 91*d6b92ffaSHans Petter Selasky return (CL_ERROR); 92*d6b92ffaSHans Petter Selasky } 93*d6b92ffaSHans Petter Selasky 94*d6b92ffaSHans Petter Selasky return (CL_SUCCESS); 95*d6b92ffaSHans Petter Selasky } 96*d6b92ffaSHans Petter Selasky 97*d6b92ffaSHans Petter Selasky void __cl_timer_prov_destroy(void) 98*d6b92ffaSHans Petter Selasky { 99*d6b92ffaSHans Petter Selasky pthread_t tid; 100*d6b92ffaSHans Petter Selasky 101*d6b92ffaSHans Petter Selasky if (!gp_timer_prov) 102*d6b92ffaSHans Petter Selasky return; 103*d6b92ffaSHans Petter Selasky 104*d6b92ffaSHans Petter Selasky tid = gp_timer_prov->thread; 105*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&gp_timer_prov->mutex); 106*d6b92ffaSHans Petter Selasky gp_timer_prov->exit = TRUE; 107*d6b92ffaSHans Petter Selasky pthread_cond_broadcast(&gp_timer_prov->cond); 108*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 109*d6b92ffaSHans Petter Selasky pthread_join(tid, NULL); 110*d6b92ffaSHans Petter Selasky 111*d6b92ffaSHans Petter Selasky /* Destroy the mutex and condition variable. */ 112*d6b92ffaSHans Petter Selasky pthread_mutex_destroy(&gp_timer_prov->mutex); 113*d6b92ffaSHans Petter Selasky pthread_cond_destroy(&gp_timer_prov->cond); 114*d6b92ffaSHans Petter Selasky 115*d6b92ffaSHans Petter Selasky /* Free the memory and reset the global pointer. */ 116*d6b92ffaSHans Petter Selasky free(gp_timer_prov); 117*d6b92ffaSHans Petter Selasky gp_timer_prov = NULL; 118*d6b92ffaSHans Petter Selasky } 119*d6b92ffaSHans Petter Selasky 120*d6b92ffaSHans Petter Selasky /* 121*d6b92ffaSHans Petter Selasky * This is the internal work function executed by the timer's thread. 122*d6b92ffaSHans Petter Selasky */ 123*d6b92ffaSHans Petter Selasky static void *__cl_timer_prov_cb(IN void *const context) 124*d6b92ffaSHans Petter Selasky { 125*d6b92ffaSHans Petter Selasky int ret; 126*d6b92ffaSHans Petter Selasky cl_timer_t *p_timer; 127*d6b92ffaSHans Petter Selasky 128*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&gp_timer_prov->mutex); 129*d6b92ffaSHans Petter Selasky while (!gp_timer_prov->exit) { 130*d6b92ffaSHans Petter Selasky if (cl_is_qlist_empty(&gp_timer_prov->queue)) { 131*d6b92ffaSHans Petter Selasky /* Wait until we exit or a timer is queued. */ 132*d6b92ffaSHans Petter Selasky /* cond wait does: 133*d6b92ffaSHans Petter Selasky * pthread_cond_wait atomically unlocks the mutex (as per 134*d6b92ffaSHans Petter Selasky * pthread_unlock_mutex) and waits for the condition variable 135*d6b92ffaSHans Petter Selasky * cond to be signaled. The thread execution is suspended and 136*d6b92ffaSHans Petter Selasky * does not consume any CPU time until the condition variable is 137*d6b92ffaSHans Petter Selasky * signaled. The mutex must be locked by the calling thread on 138*d6b92ffaSHans Petter Selasky * entrance to pthread_cond_wait. Before RETURNING TO THE 139*d6b92ffaSHans Petter Selasky * CALLING THREAD, PTHREAD_COND_WAIT RE-ACQUIRES MUTEX (as per 140*d6b92ffaSHans Petter Selasky * pthread_lock_mutex). 141*d6b92ffaSHans Petter Selasky */ 142*d6b92ffaSHans Petter Selasky ret = pthread_cond_wait(&gp_timer_prov->cond, 143*d6b92ffaSHans Petter Selasky &gp_timer_prov->mutex); 144*d6b92ffaSHans Petter Selasky } else { 145*d6b92ffaSHans Petter Selasky /* 146*d6b92ffaSHans Petter Selasky * The timer elements are on the queue in expiration order. 147*d6b92ffaSHans Petter Selasky * Get the first in the list to determine how long to wait. 148*d6b92ffaSHans Petter Selasky */ 149*d6b92ffaSHans Petter Selasky 150*d6b92ffaSHans Petter Selasky p_timer = 151*d6b92ffaSHans Petter Selasky (cl_timer_t *) cl_qlist_head(&gp_timer_prov->queue); 152*d6b92ffaSHans Petter Selasky ret = 153*d6b92ffaSHans Petter Selasky pthread_cond_timedwait(&gp_timer_prov->cond, 154*d6b92ffaSHans Petter Selasky &gp_timer_prov->mutex, 155*d6b92ffaSHans Petter Selasky &p_timer->timeout); 156*d6b92ffaSHans Petter Selasky 157*d6b92ffaSHans Petter Selasky /* 158*d6b92ffaSHans Petter Selasky Sleep again on every event other than timeout and invalid 159*d6b92ffaSHans Petter Selasky Note: EINVAL means that we got behind. This can occur when 160*d6b92ffaSHans Petter Selasky we are very busy... 161*d6b92ffaSHans Petter Selasky */ 162*d6b92ffaSHans Petter Selasky if (ret != ETIMEDOUT && ret != EINVAL) 163*d6b92ffaSHans Petter Selasky continue; 164*d6b92ffaSHans Petter Selasky 165*d6b92ffaSHans Petter Selasky /* 166*d6b92ffaSHans Petter Selasky * The timer expired. Check the state in case it was cancelled 167*d6b92ffaSHans Petter Selasky * after it expired but before we got a chance to invoke the 168*d6b92ffaSHans Petter Selasky * callback. 169*d6b92ffaSHans Petter Selasky */ 170*d6b92ffaSHans Petter Selasky if (p_timer->timer_state != CL_TIMER_QUEUED) 171*d6b92ffaSHans Petter Selasky continue; 172*d6b92ffaSHans Petter Selasky 173*d6b92ffaSHans Petter Selasky /* 174*d6b92ffaSHans Petter Selasky * Mark the timer as running to synchronize with its 175*d6b92ffaSHans Petter Selasky * cancelation since we can't hold the mutex during the 176*d6b92ffaSHans Petter Selasky * callback. 177*d6b92ffaSHans Petter Selasky */ 178*d6b92ffaSHans Petter Selasky p_timer->timer_state = CL_TIMER_RUNNING; 179*d6b92ffaSHans Petter Selasky 180*d6b92ffaSHans Petter Selasky /* Remove the item from the timer queue. */ 181*d6b92ffaSHans Petter Selasky cl_qlist_remove_item(&gp_timer_prov->queue, 182*d6b92ffaSHans Petter Selasky &p_timer->list_item); 183*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 184*d6b92ffaSHans Petter Selasky /* Invoke the callback. */ 185*d6b92ffaSHans Petter Selasky p_timer->pfn_callback((void *)p_timer->context); 186*d6b92ffaSHans Petter Selasky 187*d6b92ffaSHans Petter Selasky /* Acquire the mutex again. */ 188*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&gp_timer_prov->mutex); 189*d6b92ffaSHans Petter Selasky /* 190*d6b92ffaSHans Petter Selasky * Only set the state to idle if the timer has not been accessed 191*d6b92ffaSHans Petter Selasky * from the callback 192*d6b92ffaSHans Petter Selasky */ 193*d6b92ffaSHans Petter Selasky if (p_timer->timer_state == CL_TIMER_RUNNING) 194*d6b92ffaSHans Petter Selasky p_timer->timer_state = CL_TIMER_IDLE; 195*d6b92ffaSHans Petter Selasky 196*d6b92ffaSHans Petter Selasky /* 197*d6b92ffaSHans Petter Selasky * Signal any thread trying to manipulate the timer 198*d6b92ffaSHans Petter Selasky * that expired. 199*d6b92ffaSHans Petter Selasky */ 200*d6b92ffaSHans Petter Selasky pthread_cond_signal(&p_timer->cond); 201*d6b92ffaSHans Petter Selasky } 202*d6b92ffaSHans Petter Selasky } 203*d6b92ffaSHans Petter Selasky gp_timer_prov->thread = 0; 204*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 205*d6b92ffaSHans Petter Selasky pthread_exit(NULL); 206*d6b92ffaSHans Petter Selasky } 207*d6b92ffaSHans Petter Selasky 208*d6b92ffaSHans Petter Selasky /* Timer implementation. */ 209*d6b92ffaSHans Petter Selasky void cl_timer_construct(IN cl_timer_t * const p_timer) 210*d6b92ffaSHans Petter Selasky { 211*d6b92ffaSHans Petter Selasky memset(p_timer, 0, sizeof(cl_timer_t)); 212*d6b92ffaSHans Petter Selasky p_timer->state = CL_UNINITIALIZED; 213*d6b92ffaSHans Petter Selasky } 214*d6b92ffaSHans Petter Selasky 215*d6b92ffaSHans Petter Selasky cl_status_t cl_timer_init(IN cl_timer_t * const p_timer, 216*d6b92ffaSHans Petter Selasky IN cl_pfn_timer_callback_t pfn_callback, 217*d6b92ffaSHans Petter Selasky IN const void *const context) 218*d6b92ffaSHans Petter Selasky { 219*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer); 220*d6b92ffaSHans Petter Selasky CL_ASSERT(pfn_callback); 221*d6b92ffaSHans Petter Selasky 222*d6b92ffaSHans Petter Selasky cl_timer_construct(p_timer); 223*d6b92ffaSHans Petter Selasky 224*d6b92ffaSHans Petter Selasky if (!gp_timer_prov) 225*d6b92ffaSHans Petter Selasky return (CL_ERROR); 226*d6b92ffaSHans Petter Selasky 227*d6b92ffaSHans Petter Selasky /* Store timer parameters. */ 228*d6b92ffaSHans Petter Selasky p_timer->pfn_callback = pfn_callback; 229*d6b92ffaSHans Petter Selasky p_timer->context = context; 230*d6b92ffaSHans Petter Selasky 231*d6b92ffaSHans Petter Selasky /* Mark the timer as idle. */ 232*d6b92ffaSHans Petter Selasky p_timer->timer_state = CL_TIMER_IDLE; 233*d6b92ffaSHans Petter Selasky 234*d6b92ffaSHans Petter Selasky /* Create the condition variable that is used when cancelling a timer. */ 235*d6b92ffaSHans Petter Selasky pthread_cond_init(&p_timer->cond, NULL); 236*d6b92ffaSHans Petter Selasky 237*d6b92ffaSHans Petter Selasky p_timer->state = CL_INITIALIZED; 238*d6b92ffaSHans Petter Selasky 239*d6b92ffaSHans Petter Selasky return (CL_SUCCESS); 240*d6b92ffaSHans Petter Selasky } 241*d6b92ffaSHans Petter Selasky 242*d6b92ffaSHans Petter Selasky void cl_timer_destroy(IN cl_timer_t * const p_timer) 243*d6b92ffaSHans Petter Selasky { 244*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer); 245*d6b92ffaSHans Petter Selasky CL_ASSERT(cl_is_state_valid(p_timer->state)); 246*d6b92ffaSHans Petter Selasky 247*d6b92ffaSHans Petter Selasky if (p_timer->state == CL_INITIALIZED) 248*d6b92ffaSHans Petter Selasky cl_timer_stop(p_timer); 249*d6b92ffaSHans Petter Selasky 250*d6b92ffaSHans Petter Selasky p_timer->state = CL_UNINITIALIZED; 251*d6b92ffaSHans Petter Selasky 252*d6b92ffaSHans Petter Selasky /* is it possible we have some threads waiting on the cond now? */ 253*d6b92ffaSHans Petter Selasky pthread_cond_broadcast(&p_timer->cond); 254*d6b92ffaSHans Petter Selasky pthread_cond_destroy(&p_timer->cond); 255*d6b92ffaSHans Petter Selasky 256*d6b92ffaSHans Petter Selasky } 257*d6b92ffaSHans Petter Selasky 258*d6b92ffaSHans Petter Selasky /* 259*d6b92ffaSHans Petter Selasky * Return TRUE if timeout value 1 is earlier than timeout value 2. 260*d6b92ffaSHans Petter Selasky */ 261*d6b92ffaSHans Petter Selasky static __inline boolean_t __cl_timer_is_earlier(IN struct timespec *p_timeout1, 262*d6b92ffaSHans Petter Selasky IN struct timespec *p_timeout2) 263*d6b92ffaSHans Petter Selasky { 264*d6b92ffaSHans Petter Selasky return ((p_timeout1->tv_sec < p_timeout2->tv_sec) || 265*d6b92ffaSHans Petter Selasky ((p_timeout1->tv_sec == p_timeout2->tv_sec) && 266*d6b92ffaSHans Petter Selasky (p_timeout1->tv_nsec < p_timeout2->tv_nsec))); 267*d6b92ffaSHans Petter Selasky } 268*d6b92ffaSHans Petter Selasky 269*d6b92ffaSHans Petter Selasky /* 270*d6b92ffaSHans Petter Selasky * Search for a timer with an earlier timeout than the one provided by 271*d6b92ffaSHans Petter Selasky * the context. Both the list item and the context are pointers to 272*d6b92ffaSHans Petter Selasky * a cl_timer_t structure with valid timeouts. 273*d6b92ffaSHans Petter Selasky */ 274*d6b92ffaSHans Petter Selasky static cl_status_t __cl_timer_find(IN const cl_list_item_t * const p_list_item, 275*d6b92ffaSHans Petter Selasky IN void *const context) 276*d6b92ffaSHans Petter Selasky { 277*d6b92ffaSHans Petter Selasky cl_timer_t *p_in_list; 278*d6b92ffaSHans Petter Selasky cl_timer_t *p_new; 279*d6b92ffaSHans Petter Selasky 280*d6b92ffaSHans Petter Selasky CL_ASSERT(p_list_item); 281*d6b92ffaSHans Petter Selasky CL_ASSERT(context); 282*d6b92ffaSHans Petter Selasky 283*d6b92ffaSHans Petter Selasky p_in_list = (cl_timer_t *) p_list_item; 284*d6b92ffaSHans Petter Selasky p_new = (cl_timer_t *) context; 285*d6b92ffaSHans Petter Selasky 286*d6b92ffaSHans Petter Selasky CL_ASSERT(p_in_list->state == CL_INITIALIZED); 287*d6b92ffaSHans Petter Selasky CL_ASSERT(p_new->state == CL_INITIALIZED); 288*d6b92ffaSHans Petter Selasky 289*d6b92ffaSHans Petter Selasky CL_ASSERT(p_in_list->timer_state == CL_TIMER_QUEUED); 290*d6b92ffaSHans Petter Selasky 291*d6b92ffaSHans Petter Selasky if (__cl_timer_is_earlier(&p_in_list->timeout, &p_new->timeout)) 292*d6b92ffaSHans Petter Selasky return (CL_SUCCESS); 293*d6b92ffaSHans Petter Selasky 294*d6b92ffaSHans Petter Selasky return (CL_NOT_FOUND); 295*d6b92ffaSHans Petter Selasky } 296*d6b92ffaSHans Petter Selasky 297*d6b92ffaSHans Petter Selasky /* 298*d6b92ffaSHans Petter Selasky * Calculate 'struct timespec' value that is the 299*d6b92ffaSHans Petter Selasky * current time plus the 'time_ms' milliseconds. 300*d6b92ffaSHans Petter Selasky */ 301*d6b92ffaSHans Petter Selasky static __inline void __cl_timer_calculate(IN const uint32_t time_ms, 302*d6b92ffaSHans Petter Selasky OUT struct timespec * const p_timer) 303*d6b92ffaSHans Petter Selasky { 304*d6b92ffaSHans Petter Selasky struct timeval curtime, deltatime, endtime; 305*d6b92ffaSHans Petter Selasky 306*d6b92ffaSHans Petter Selasky gettimeofday(&curtime, NULL); 307*d6b92ffaSHans Petter Selasky 308*d6b92ffaSHans Petter Selasky deltatime.tv_sec = time_ms / 1000; 309*d6b92ffaSHans Petter Selasky deltatime.tv_usec = (time_ms % 1000) * 1000; 310*d6b92ffaSHans Petter Selasky timeradd(&curtime, &deltatime, &endtime); 311*d6b92ffaSHans Petter Selasky p_timer->tv_sec = endtime.tv_sec; 312*d6b92ffaSHans Petter Selasky p_timer->tv_nsec = endtime.tv_usec * 1000; 313*d6b92ffaSHans Petter Selasky } 314*d6b92ffaSHans Petter Selasky 315*d6b92ffaSHans Petter Selasky cl_status_t cl_timer_start(IN cl_timer_t * const p_timer, 316*d6b92ffaSHans Petter Selasky IN const uint32_t time_ms) 317*d6b92ffaSHans Petter Selasky { 318*d6b92ffaSHans Petter Selasky cl_list_item_t *p_list_item; 319*d6b92ffaSHans Petter Selasky 320*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer); 321*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer->state == CL_INITIALIZED); 322*d6b92ffaSHans Petter Selasky 323*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&gp_timer_prov->mutex); 324*d6b92ffaSHans Petter Selasky /* Signal the timer provider thread to wake up. */ 325*d6b92ffaSHans Petter Selasky pthread_cond_signal(&gp_timer_prov->cond); 326*d6b92ffaSHans Petter Selasky 327*d6b92ffaSHans Petter Selasky /* Remove the timer from the queue if currently queued. */ 328*d6b92ffaSHans Petter Selasky if (p_timer->timer_state == CL_TIMER_QUEUED) 329*d6b92ffaSHans Petter Selasky cl_qlist_remove_item(&gp_timer_prov->queue, 330*d6b92ffaSHans Petter Selasky &p_timer->list_item); 331*d6b92ffaSHans Petter Selasky 332*d6b92ffaSHans Petter Selasky __cl_timer_calculate(time_ms, &p_timer->timeout); 333*d6b92ffaSHans Petter Selasky 334*d6b92ffaSHans Petter Selasky /* Add the timer to the queue. */ 335*d6b92ffaSHans Petter Selasky if (cl_is_qlist_empty(&gp_timer_prov->queue)) { 336*d6b92ffaSHans Petter Selasky /* The timer list is empty. Add to the head. */ 337*d6b92ffaSHans Petter Selasky cl_qlist_insert_head(&gp_timer_prov->queue, 338*d6b92ffaSHans Petter Selasky &p_timer->list_item); 339*d6b92ffaSHans Petter Selasky } else { 340*d6b92ffaSHans Petter Selasky /* Find the correct insertion place in the list for the timer. */ 341*d6b92ffaSHans Petter Selasky p_list_item = cl_qlist_find_from_tail(&gp_timer_prov->queue, 342*d6b92ffaSHans Petter Selasky __cl_timer_find, p_timer); 343*d6b92ffaSHans Petter Selasky 344*d6b92ffaSHans Petter Selasky /* Insert the timer. */ 345*d6b92ffaSHans Petter Selasky cl_qlist_insert_next(&gp_timer_prov->queue, p_list_item, 346*d6b92ffaSHans Petter Selasky &p_timer->list_item); 347*d6b92ffaSHans Petter Selasky } 348*d6b92ffaSHans Petter Selasky /* Set the state. */ 349*d6b92ffaSHans Petter Selasky p_timer->timer_state = CL_TIMER_QUEUED; 350*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 351*d6b92ffaSHans Petter Selasky 352*d6b92ffaSHans Petter Selasky return (CL_SUCCESS); 353*d6b92ffaSHans Petter Selasky } 354*d6b92ffaSHans Petter Selasky 355*d6b92ffaSHans Petter Selasky void cl_timer_stop(IN cl_timer_t * const p_timer) 356*d6b92ffaSHans Petter Selasky { 357*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer); 358*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer->state == CL_INITIALIZED); 359*d6b92ffaSHans Petter Selasky 360*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&gp_timer_prov->mutex); 361*d6b92ffaSHans Petter Selasky switch (p_timer->timer_state) { 362*d6b92ffaSHans Petter Selasky case CL_TIMER_RUNNING: 363*d6b92ffaSHans Petter Selasky /* Wait for the callback to complete. */ 364*d6b92ffaSHans Petter Selasky pthread_cond_wait(&p_timer->cond, &gp_timer_prov->mutex); 365*d6b92ffaSHans Petter Selasky /* Timer could have been queued while we were waiting. */ 366*d6b92ffaSHans Petter Selasky if (p_timer->timer_state != CL_TIMER_QUEUED) 367*d6b92ffaSHans Petter Selasky break; 368*d6b92ffaSHans Petter Selasky 369*d6b92ffaSHans Petter Selasky case CL_TIMER_QUEUED: 370*d6b92ffaSHans Petter Selasky /* Change the state of the timer. */ 371*d6b92ffaSHans Petter Selasky p_timer->timer_state = CL_TIMER_IDLE; 372*d6b92ffaSHans Petter Selasky /* Remove the timer from the queue. */ 373*d6b92ffaSHans Petter Selasky cl_qlist_remove_item(&gp_timer_prov->queue, 374*d6b92ffaSHans Petter Selasky &p_timer->list_item); 375*d6b92ffaSHans Petter Selasky /* 376*d6b92ffaSHans Petter Selasky * Signal the timer provider thread to move onto the 377*d6b92ffaSHans Petter Selasky * next timer in the queue. 378*d6b92ffaSHans Petter Selasky */ 379*d6b92ffaSHans Petter Selasky pthread_cond_signal(&gp_timer_prov->cond); 380*d6b92ffaSHans Petter Selasky break; 381*d6b92ffaSHans Petter Selasky 382*d6b92ffaSHans Petter Selasky case CL_TIMER_IDLE: 383*d6b92ffaSHans Petter Selasky break; 384*d6b92ffaSHans Petter Selasky } 385*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 386*d6b92ffaSHans Petter Selasky } 387*d6b92ffaSHans Petter Selasky 388*d6b92ffaSHans Petter Selasky cl_status_t cl_timer_trim(IN cl_timer_t * const p_timer, 389*d6b92ffaSHans Petter Selasky IN const uint32_t time_ms) 390*d6b92ffaSHans Petter Selasky { 391*d6b92ffaSHans Petter Selasky struct timespec newtime; 392*d6b92ffaSHans Petter Selasky cl_status_t status; 393*d6b92ffaSHans Petter Selasky 394*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer); 395*d6b92ffaSHans Petter Selasky CL_ASSERT(p_timer->state == CL_INITIALIZED); 396*d6b92ffaSHans Petter Selasky 397*d6b92ffaSHans Petter Selasky pthread_mutex_lock(&gp_timer_prov->mutex); 398*d6b92ffaSHans Petter Selasky 399*d6b92ffaSHans Petter Selasky __cl_timer_calculate(time_ms, &newtime); 400*d6b92ffaSHans Petter Selasky 401*d6b92ffaSHans Petter Selasky if (p_timer->timer_state == CL_TIMER_QUEUED) { 402*d6b92ffaSHans Petter Selasky /* If the old time is earlier, do not trim it. Just return. */ 403*d6b92ffaSHans Petter Selasky if (__cl_timer_is_earlier(&p_timer->timeout, &newtime)) { 404*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 405*d6b92ffaSHans Petter Selasky return (CL_SUCCESS); 406*d6b92ffaSHans Petter Selasky } 407*d6b92ffaSHans Petter Selasky } 408*d6b92ffaSHans Petter Selasky 409*d6b92ffaSHans Petter Selasky /* Reset the timer to the new timeout value. */ 410*d6b92ffaSHans Petter Selasky 411*d6b92ffaSHans Petter Selasky pthread_mutex_unlock(&gp_timer_prov->mutex); 412*d6b92ffaSHans Petter Selasky status = cl_timer_start(p_timer, time_ms); 413*d6b92ffaSHans Petter Selasky 414*d6b92ffaSHans Petter Selasky return (status); 415*d6b92ffaSHans Petter Selasky } 416*d6b92ffaSHans Petter Selasky 417*d6b92ffaSHans Petter Selasky uint64_t cl_get_time_stamp(void) 418*d6b92ffaSHans Petter Selasky { 419*d6b92ffaSHans Petter Selasky uint64_t tstamp; 420*d6b92ffaSHans Petter Selasky struct timeval tv; 421*d6b92ffaSHans Petter Selasky 422*d6b92ffaSHans Petter Selasky gettimeofday(&tv, NULL); 423*d6b92ffaSHans Petter Selasky 424*d6b92ffaSHans Petter Selasky /* Convert the time of day into a microsecond timestamp. */ 425*d6b92ffaSHans Petter Selasky tstamp = ((uint64_t) tv.tv_sec * 1000000) + (uint64_t) tv.tv_usec; 426*d6b92ffaSHans Petter Selasky 427*d6b92ffaSHans Petter Selasky return (tstamp); 428*d6b92ffaSHans Petter Selasky } 429*d6b92ffaSHans Petter Selasky 430*d6b92ffaSHans Petter Selasky uint32_t cl_get_time_stamp_sec(void) 431*d6b92ffaSHans Petter Selasky { 432*d6b92ffaSHans Petter Selasky struct timeval tv; 433*d6b92ffaSHans Petter Selasky 434*d6b92ffaSHans Petter Selasky gettimeofday(&tv, NULL); 435*d6b92ffaSHans Petter Selasky 436*d6b92ffaSHans Petter Selasky return (tv.tv_sec); 437*d6b92ffaSHans Petter Selasky } 438