1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. 3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5219820Sjeff * 6219820Sjeff * This software is available to you under a choice of one of two 7219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 8219820Sjeff * General Public License (GPL) Version 2, available from the file 9219820Sjeff * COPYING in the main directory of this source tree, or the 10219820Sjeff * OpenIB.org BSD license below: 11219820Sjeff * 12219820Sjeff * Redistribution and use in source and binary forms, with or 13219820Sjeff * without modification, are permitted provided that the following 14219820Sjeff * conditions are met: 15219820Sjeff * 16219820Sjeff * - Redistributions of source code must retain the above 17219820Sjeff * copyright notice, this list of conditions and the following 18219820Sjeff * disclaimer. 19219820Sjeff * 20219820Sjeff * - Redistributions in binary form must reproduce the above 21219820Sjeff * copyright notice, this list of conditions and the following 22219820Sjeff * disclaimer in the documentation and/or other materials 23219820Sjeff * provided with the distribution. 24219820Sjeff * 25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32219820Sjeff * SOFTWARE. 33219820Sjeff * 34219820Sjeff */ 35219820Sjeff 36219820Sjeff/* 37219820Sjeff * Abstract: 38219820Sjeff * Abstraction of Timer create, destroy functions. 39219820Sjeff * 40219820Sjeff */ 41219820Sjeff 42219820Sjeff#if HAVE_CONFIG_H 43219820Sjeff# include <config.h> 44219820Sjeff#endif /* HAVE_CONFIG_H */ 45219820Sjeff 46219820Sjeff#include <stdlib.h> 47219820Sjeff#include <string.h> 48219820Sjeff#include <complib/cl_timer.h> 49219820Sjeff#include <sys/time.h> 50219820Sjeff#include <sys/errno.h> 51219820Sjeff#include <stdio.h> 52219820Sjeff 53219820Sjeff/* Timer provider (emulates timers in user mode). */ 54219820Sjefftypedef struct _cl_timer_prov { 55219820Sjeff pthread_t thread; 56219820Sjeff pthread_mutex_t mutex; 57219820Sjeff pthread_cond_t cond; 58219820Sjeff cl_qlist_t queue; 59219820Sjeff 60219820Sjeff boolean_t exit; 61219820Sjeff 62219820Sjeff} cl_timer_prov_t; 63219820Sjeff 64219820Sjeff/* Global timer provider. */ 65219820Sjeffstatic cl_timer_prov_t *gp_timer_prov = NULL; 66219820Sjeff 67219820Sjeffstatic void *__cl_timer_prov_cb(IN void *const context); 68219820Sjeff 69219820Sjeff/* 70219820Sjeff * Creates the process global timer provider. Must be called by the shared 71219820Sjeff * object framework to solve all serialization issues. 72219820Sjeff */ 73219820Sjeffcl_status_t __cl_timer_prov_create(void) 74219820Sjeff{ 75219820Sjeff CL_ASSERT(gp_timer_prov == NULL); 76219820Sjeff 77219820Sjeff gp_timer_prov = malloc(sizeof(cl_timer_prov_t)); 78219820Sjeff if (!gp_timer_prov) 79219820Sjeff return (CL_INSUFFICIENT_MEMORY); 80219820Sjeff else 81219820Sjeff memset(gp_timer_prov, 0, sizeof(cl_timer_prov_t)); 82219820Sjeff 83219820Sjeff cl_qlist_init(&gp_timer_prov->queue); 84219820Sjeff 85219820Sjeff pthread_mutex_init(&gp_timer_prov->mutex, NULL); 86219820Sjeff pthread_cond_init(&gp_timer_prov->cond, NULL); 87219820Sjeff 88219820Sjeff if (pthread_create(&gp_timer_prov->thread, NULL, 89219820Sjeff __cl_timer_prov_cb, NULL)) { 90219820Sjeff __cl_timer_prov_destroy(); 91219820Sjeff return (CL_ERROR); 92219820Sjeff } 93219820Sjeff 94219820Sjeff return (CL_SUCCESS); 95219820Sjeff} 96219820Sjeff 97219820Sjeffvoid __cl_timer_prov_destroy(void) 98219820Sjeff{ 99219820Sjeff pthread_t tid; 100219820Sjeff 101219820Sjeff if (!gp_timer_prov) 102219820Sjeff return; 103219820Sjeff 104219820Sjeff tid = gp_timer_prov->thread; 105219820Sjeff pthread_mutex_lock(&gp_timer_prov->mutex); 106219820Sjeff gp_timer_prov->exit = TRUE; 107219820Sjeff pthread_cond_broadcast(&gp_timer_prov->cond); 108219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 109219820Sjeff pthread_join(tid, NULL); 110219820Sjeff 111219820Sjeff /* Destroy the mutex and condition variable. */ 112219820Sjeff pthread_mutex_destroy(&gp_timer_prov->mutex); 113219820Sjeff pthread_cond_destroy(&gp_timer_prov->cond); 114219820Sjeff 115219820Sjeff /* Free the memory and reset the global pointer. */ 116219820Sjeff free(gp_timer_prov); 117219820Sjeff gp_timer_prov = NULL; 118219820Sjeff} 119219820Sjeff 120219820Sjeff/* 121219820Sjeff * This is the internal work function executed by the timer's thread. 122219820Sjeff */ 123219820Sjeffstatic void *__cl_timer_prov_cb(IN void *const context) 124219820Sjeff{ 125219820Sjeff int ret; 126219820Sjeff cl_timer_t *p_timer; 127219820Sjeff 128219820Sjeff pthread_mutex_lock(&gp_timer_prov->mutex); 129219820Sjeff while (!gp_timer_prov->exit) { 130219820Sjeff if (cl_is_qlist_empty(&gp_timer_prov->queue)) { 131219820Sjeff /* Wait until we exit or a timer is queued. */ 132219820Sjeff /* cond wait does: 133219820Sjeff * pthread_cond_wait atomically unlocks the mutex (as per 134219820Sjeff * pthread_unlock_mutex) and waits for the condition variable 135219820Sjeff * cond to be signaled. The thread execution is suspended and 136219820Sjeff * does not consume any CPU time until the condition variable is 137219820Sjeff * signaled. The mutex must be locked by the calling thread on 138219820Sjeff * entrance to pthread_cond_wait. Before RETURNING TO THE 139219820Sjeff * CALLING THREAD, PTHREAD_COND_WAIT RE-ACQUIRES MUTEX (as per 140219820Sjeff * pthread_lock_mutex). 141219820Sjeff */ 142219820Sjeff ret = pthread_cond_wait(&gp_timer_prov->cond, 143219820Sjeff &gp_timer_prov->mutex); 144219820Sjeff } else { 145219820Sjeff /* 146219820Sjeff * The timer elements are on the queue in expiration order. 147219820Sjeff * Get the first in the list to determine how long to wait. 148219820Sjeff */ 149219820Sjeff 150219820Sjeff p_timer = 151219820Sjeff (cl_timer_t *) cl_qlist_head(&gp_timer_prov->queue); 152219820Sjeff ret = 153219820Sjeff pthread_cond_timedwait(&gp_timer_prov->cond, 154219820Sjeff &gp_timer_prov->mutex, 155219820Sjeff &p_timer->timeout); 156219820Sjeff 157219820Sjeff /* 158219820Sjeff Sleep again on every event other than timeout and invalid 159219820Sjeff Note: EINVAL means that we got behind. This can occur when 160219820Sjeff we are very busy... 161219820Sjeff */ 162219820Sjeff if (ret != ETIMEDOUT && ret != EINVAL) 163219820Sjeff continue; 164219820Sjeff 165219820Sjeff /* 166219820Sjeff * The timer expired. Check the state in case it was cancelled 167219820Sjeff * after it expired but before we got a chance to invoke the 168219820Sjeff * callback. 169219820Sjeff */ 170219820Sjeff if (p_timer->timer_state != CL_TIMER_QUEUED) 171219820Sjeff continue; 172219820Sjeff 173219820Sjeff /* 174219820Sjeff * Mark the timer as running to synchronize with its 175219820Sjeff * cancelation since we can't hold the mutex during the 176219820Sjeff * callback. 177219820Sjeff */ 178219820Sjeff p_timer->timer_state = CL_TIMER_RUNNING; 179219820Sjeff 180219820Sjeff /* Remove the item from the timer queue. */ 181219820Sjeff cl_qlist_remove_item(&gp_timer_prov->queue, 182219820Sjeff &p_timer->list_item); 183219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 184219820Sjeff /* Invoke the callback. */ 185219820Sjeff p_timer->pfn_callback((void *)p_timer->context); 186219820Sjeff 187219820Sjeff /* Acquire the mutex again. */ 188219820Sjeff pthread_mutex_lock(&gp_timer_prov->mutex); 189219820Sjeff /* 190219820Sjeff * Only set the state to idle if the timer has not been accessed 191219820Sjeff * from the callback 192219820Sjeff */ 193219820Sjeff if (p_timer->timer_state == CL_TIMER_RUNNING) 194219820Sjeff p_timer->timer_state = CL_TIMER_IDLE; 195219820Sjeff 196219820Sjeff /* 197219820Sjeff * Signal any thread trying to manipulate the timer 198219820Sjeff * that expired. 199219820Sjeff */ 200219820Sjeff pthread_cond_signal(&p_timer->cond); 201219820Sjeff } 202219820Sjeff } 203219820Sjeff gp_timer_prov->thread = 0; 204219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 205219820Sjeff pthread_exit(NULL); 206219820Sjeff} 207219820Sjeff 208219820Sjeff/* Timer implementation. */ 209219820Sjeffvoid cl_timer_construct(IN cl_timer_t * const p_timer) 210219820Sjeff{ 211219820Sjeff memset(p_timer, 0, sizeof(cl_timer_t)); 212219820Sjeff p_timer->state = CL_UNINITIALIZED; 213219820Sjeff} 214219820Sjeff 215219820Sjeffcl_status_t 216219820Sjeffcl_timer_init(IN cl_timer_t * const p_timer, 217219820Sjeff IN cl_pfn_timer_callback_t pfn_callback, 218219820Sjeff IN const void *const context) 219219820Sjeff{ 220219820Sjeff CL_ASSERT(p_timer); 221219820Sjeff CL_ASSERT(pfn_callback); 222219820Sjeff 223219820Sjeff cl_timer_construct(p_timer); 224219820Sjeff 225219820Sjeff if (!gp_timer_prov) 226219820Sjeff return (CL_ERROR); 227219820Sjeff 228219820Sjeff /* Store timer parameters. */ 229219820Sjeff p_timer->pfn_callback = pfn_callback; 230219820Sjeff p_timer->context = context; 231219820Sjeff 232219820Sjeff /* Mark the timer as idle. */ 233219820Sjeff p_timer->timer_state = CL_TIMER_IDLE; 234219820Sjeff 235219820Sjeff /* Create the condition variable that is used when cancelling a timer. */ 236219820Sjeff pthread_cond_init(&p_timer->cond, NULL); 237219820Sjeff 238219820Sjeff p_timer->state = CL_INITIALIZED; 239219820Sjeff 240219820Sjeff return (CL_SUCCESS); 241219820Sjeff} 242219820Sjeff 243219820Sjeffvoid cl_timer_destroy(IN cl_timer_t * const p_timer) 244219820Sjeff{ 245219820Sjeff CL_ASSERT(p_timer); 246219820Sjeff CL_ASSERT(cl_is_state_valid(p_timer->state)); 247219820Sjeff 248219820Sjeff if (p_timer->state == CL_INITIALIZED) 249219820Sjeff cl_timer_stop(p_timer); 250219820Sjeff 251219820Sjeff p_timer->state = CL_UNINITIALIZED; 252219820Sjeff 253219820Sjeff /* is it possible we have some threads waiting on the cond now? */ 254219820Sjeff pthread_cond_broadcast(&p_timer->cond); 255219820Sjeff pthread_cond_destroy(&p_timer->cond); 256219820Sjeff 257219820Sjeff} 258219820Sjeff 259219820Sjeff/* 260219820Sjeff * Return TRUE if timeout value 1 is earlier than timeout value 2. 261219820Sjeff */ 262219820Sjeffstatic __inline boolean_t 263219820Sjeff__cl_timer_is_earlier(IN struct timespec *p_timeout1, 264219820Sjeff IN struct timespec *p_timeout2) 265219820Sjeff{ 266219820Sjeff return ((p_timeout1->tv_sec < p_timeout2->tv_sec) || 267219820Sjeff ((p_timeout1->tv_sec == p_timeout2->tv_sec) && 268219820Sjeff (p_timeout1->tv_nsec < p_timeout2->tv_nsec))); 269219820Sjeff} 270219820Sjeff 271219820Sjeff/* 272219820Sjeff * Search for a timer with an earlier timeout than the one provided by 273219820Sjeff * the context. Both the list item and the context are pointers to 274219820Sjeff * a cl_timer_t structure with valid timeouts. 275219820Sjeff */ 276219820Sjeffstatic cl_status_t 277219820Sjeff__cl_timer_find(IN const cl_list_item_t * const p_list_item, 278219820Sjeff IN void *const context) 279219820Sjeff{ 280219820Sjeff cl_timer_t *p_in_list; 281219820Sjeff cl_timer_t *p_new; 282219820Sjeff 283219820Sjeff CL_ASSERT(p_list_item); 284219820Sjeff CL_ASSERT(context); 285219820Sjeff 286219820Sjeff p_in_list = (cl_timer_t *) p_list_item; 287219820Sjeff p_new = (cl_timer_t *) context; 288219820Sjeff 289219820Sjeff CL_ASSERT(p_in_list->state == CL_INITIALIZED); 290219820Sjeff CL_ASSERT(p_new->state == CL_INITIALIZED); 291219820Sjeff 292219820Sjeff CL_ASSERT(p_in_list->timer_state == CL_TIMER_QUEUED); 293219820Sjeff 294219820Sjeff if (__cl_timer_is_earlier(&p_in_list->timeout, &p_new->timeout)) 295219820Sjeff return (CL_SUCCESS); 296219820Sjeff 297219820Sjeff return (CL_NOT_FOUND); 298219820Sjeff} 299219820Sjeff 300219820Sjeffcl_status_t 301219820Sjeffcl_timer_start(IN cl_timer_t * const p_timer, IN const uint32_t time_ms) 302219820Sjeff{ 303219820Sjeff struct timeval curtime; 304219820Sjeff cl_list_item_t *p_list_item; 305219820Sjeff uint32_t delta_time = time_ms; 306219820Sjeff 307219820Sjeff CL_ASSERT(p_timer); 308219820Sjeff CL_ASSERT(p_timer->state == CL_INITIALIZED); 309219820Sjeff 310219820Sjeff pthread_mutex_lock(&gp_timer_prov->mutex); 311219820Sjeff /* Signal the timer provider thread to wake up. */ 312219820Sjeff pthread_cond_signal(&gp_timer_prov->cond); 313219820Sjeff 314219820Sjeff /* Remove the timer from the queue if currently queued. */ 315219820Sjeff if (p_timer->timer_state == CL_TIMER_QUEUED) 316219820Sjeff cl_qlist_remove_item(&gp_timer_prov->queue, 317219820Sjeff &p_timer->list_item); 318219820Sjeff 319219820Sjeff /* Get the current time */ 320219820Sjeff#ifndef timerclear 321219820Sjeff#define timerclear(tvp) (tvp)->tv_sec = (time_t)0, (tvp)->tv_usec = 0L 322219820Sjeff#endif 323219820Sjeff timerclear(&curtime); 324219820Sjeff gettimeofday(&curtime, NULL); 325219820Sjeff 326219820Sjeff /* do not do 0 wait ! */ 327219820Sjeff /* if (delta_time < 1000.0) {delta_time = 1000;} */ 328219820Sjeff 329219820Sjeff /* Calculate the timeout. */ 330219820Sjeff p_timer->timeout.tv_sec = curtime.tv_sec + (delta_time / 1000); 331219820Sjeff p_timer->timeout.tv_nsec = 332219820Sjeff (curtime.tv_usec + ((delta_time % 1000) * 1000)) * 1000; 333219820Sjeff 334219820Sjeff /* Add the timer to the queue. */ 335219820Sjeff if (cl_is_qlist_empty(&gp_timer_prov->queue)) { 336219820Sjeff /* The timer list is empty. Add to the head. */ 337219820Sjeff cl_qlist_insert_head(&gp_timer_prov->queue, 338219820Sjeff &p_timer->list_item); 339219820Sjeff } else { 340219820Sjeff /* Find the correct insertion place in the list for the timer. */ 341219820Sjeff p_list_item = cl_qlist_find_from_tail(&gp_timer_prov->queue, 342219820Sjeff __cl_timer_find, p_timer); 343219820Sjeff 344219820Sjeff /* Insert the timer. */ 345219820Sjeff cl_qlist_insert_next(&gp_timer_prov->queue, p_list_item, 346219820Sjeff &p_timer->list_item); 347219820Sjeff } 348219820Sjeff /* Set the state. */ 349219820Sjeff p_timer->timer_state = CL_TIMER_QUEUED; 350219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 351219820Sjeff 352219820Sjeff return (CL_SUCCESS); 353219820Sjeff} 354219820Sjeff 355219820Sjeffvoid cl_timer_stop(IN cl_timer_t * const p_timer) 356219820Sjeff{ 357219820Sjeff CL_ASSERT(p_timer); 358219820Sjeff CL_ASSERT(p_timer->state == CL_INITIALIZED); 359219820Sjeff 360219820Sjeff pthread_mutex_lock(&gp_timer_prov->mutex); 361219820Sjeff switch (p_timer->timer_state) { 362219820Sjeff case CL_TIMER_RUNNING: 363219820Sjeff /* Wait for the callback to complete. */ 364219820Sjeff pthread_cond_wait(&p_timer->cond, &gp_timer_prov->mutex); 365219820Sjeff /* Timer could have been queued while we were waiting. */ 366219820Sjeff if (p_timer->timer_state != CL_TIMER_QUEUED) 367219820Sjeff break; 368219820Sjeff 369219820Sjeff case CL_TIMER_QUEUED: 370219820Sjeff /* Change the state of the timer. */ 371219820Sjeff p_timer->timer_state = CL_TIMER_IDLE; 372219820Sjeff /* Remove the timer from the queue. */ 373219820Sjeff cl_qlist_remove_item(&gp_timer_prov->queue, 374219820Sjeff &p_timer->list_item); 375219820Sjeff /* 376219820Sjeff * Signal the timer provider thread to move onto the 377219820Sjeff * next timer in the queue. 378219820Sjeff */ 379219820Sjeff pthread_cond_signal(&gp_timer_prov->cond); 380219820Sjeff break; 381219820Sjeff 382219820Sjeff case CL_TIMER_IDLE: 383219820Sjeff break; 384219820Sjeff } 385219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 386219820Sjeff} 387219820Sjeff 388219820Sjeffcl_status_t 389219820Sjeffcl_timer_trim(IN cl_timer_t * const p_timer, IN const uint32_t time_ms) 390219820Sjeff{ 391219820Sjeff struct timeval curtime; 392219820Sjeff struct timespec newtime; 393219820Sjeff cl_status_t status; 394219820Sjeff 395219820Sjeff CL_ASSERT(p_timer); 396219820Sjeff CL_ASSERT(p_timer->state == CL_INITIALIZED); 397219820Sjeff 398219820Sjeff pthread_mutex_lock(&gp_timer_prov->mutex); 399219820Sjeff 400219820Sjeff /* Get the current time */ 401219820Sjeff timerclear(&curtime); 402219820Sjeff gettimeofday(&curtime, NULL); 403219820Sjeff 404219820Sjeff /* Calculate the timeout. */ 405219820Sjeff newtime.tv_sec = curtime.tv_sec + (time_ms / 1000); 406219820Sjeff newtime.tv_nsec = (curtime.tv_usec + ((time_ms % 1000) * 1000)) * 1000; 407219820Sjeff 408219820Sjeff if (p_timer->timer_state == CL_TIMER_QUEUED) { 409219820Sjeff /* If the old time is earlier, do not trim it. Just return. */ 410219820Sjeff if (__cl_timer_is_earlier(&p_timer->timeout, &newtime)) { 411219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 412219820Sjeff return (CL_SUCCESS); 413219820Sjeff } 414219820Sjeff } 415219820Sjeff 416219820Sjeff /* Reset the timer to the new timeout value. */ 417219820Sjeff 418219820Sjeff pthread_mutex_unlock(&gp_timer_prov->mutex); 419219820Sjeff status = cl_timer_start(p_timer, time_ms); 420219820Sjeff 421219820Sjeff return (status); 422219820Sjeff} 423219820Sjeff 424219820Sjeffuint64_t cl_get_time_stamp(void) 425219820Sjeff{ 426219820Sjeff uint64_t tstamp; 427219820Sjeff struct timeval tv; 428219820Sjeff 429219820Sjeff timerclear(&tv); 430219820Sjeff gettimeofday(&tv, NULL); 431219820Sjeff 432219820Sjeff /* Convert the time of day into a microsecond timestamp. */ 433219820Sjeff tstamp = ((uint64_t) tv.tv_sec * 1000000) + (uint64_t) tv.tv_usec; 434219820Sjeff 435219820Sjeff return (tstamp); 436219820Sjeff} 437219820Sjeff 438219820Sjeffuint32_t cl_get_time_stamp_sec(void) 439219820Sjeff{ 440219820Sjeff struct timeval tv; 441219820Sjeff 442219820Sjeff timerclear(&tv); 443219820Sjeff gettimeofday(&tv, NULL); 444219820Sjeff 445219820Sjeff return (tv.tv_sec); 446219820Sjeff} 447