2 * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38 * Abstraction of Timer create, destroy functions.
44 #endif /* HAVE_CONFIG_H */
48 #include <complib/cl_timer.h>
50 #include <sys/errno.h>
53 /* Timer provider (emulates timers in user mode). */
54 typedef struct _cl_timer_prov {
56 pthread_mutex_t mutex;
64 /* Global timer provider. */
65 static cl_timer_prov_t *gp_timer_prov = NULL;
67 static void *__cl_timer_prov_cb(IN void *const context);
70 * Creates the process global timer provider. Must be called by the shared
71 * object framework to solve all serialization issues.
73 cl_status_t __cl_timer_prov_create(void)
75 CL_ASSERT(gp_timer_prov == NULL);
77 gp_timer_prov = malloc(sizeof(cl_timer_prov_t));
79 return (CL_INSUFFICIENT_MEMORY);
81 memset(gp_timer_prov, 0, sizeof(cl_timer_prov_t));
83 cl_qlist_init(&gp_timer_prov->queue);
85 pthread_mutex_init(&gp_timer_prov->mutex, NULL);
86 pthread_cond_init(&gp_timer_prov->cond, NULL);
88 if (pthread_create(&gp_timer_prov->thread, NULL,
89 __cl_timer_prov_cb, NULL)) {
90 __cl_timer_prov_destroy();
97 void __cl_timer_prov_destroy(void)
104 tid = gp_timer_prov->thread;
105 pthread_mutex_lock(&gp_timer_prov->mutex);
106 gp_timer_prov->exit = TRUE;
107 pthread_cond_broadcast(&gp_timer_prov->cond);
108 pthread_mutex_unlock(&gp_timer_prov->mutex);
109 pthread_join(tid, NULL);
111 /* Destroy the mutex and condition variable. */
112 pthread_mutex_destroy(&gp_timer_prov->mutex);
113 pthread_cond_destroy(&gp_timer_prov->cond);
115 /* Free the memory and reset the global pointer. */
117 gp_timer_prov = NULL;
121 * This is the internal work function executed by the timer's thread.
123 static void *__cl_timer_prov_cb(IN void *const context)
128 pthread_mutex_lock(&gp_timer_prov->mutex);
129 while (!gp_timer_prov->exit) {
130 if (cl_is_qlist_empty(&gp_timer_prov->queue)) {
131 /* Wait until we exit or a timer is queued. */
133 * pthread_cond_wait atomically unlocks the mutex (as per
134 * pthread_unlock_mutex) and waits for the condition variable
135 * cond to be signaled. The thread execution is suspended and
136 * does not consume any CPU time until the condition variable is
137 * signaled. The mutex must be locked by the calling thread on
138 * entrance to pthread_cond_wait. Before RETURNING TO THE
139 * CALLING THREAD, PTHREAD_COND_WAIT RE-ACQUIRES MUTEX (as per
140 * pthread_lock_mutex).
142 ret = pthread_cond_wait(&gp_timer_prov->cond,
143 &gp_timer_prov->mutex);
146 * The timer elements are on the queue in expiration order.
147 * Get the first in the list to determine how long to wait.
151 (cl_timer_t *) cl_qlist_head(&gp_timer_prov->queue);
153 pthread_cond_timedwait(&gp_timer_prov->cond,
154 &gp_timer_prov->mutex,
158 Sleep again on every event other than timeout and invalid
159 Note: EINVAL means that we got behind. This can occur when
162 if (ret != ETIMEDOUT && ret != EINVAL)
166 * The timer expired. Check the state in case it was cancelled
167 * after it expired but before we got a chance to invoke the
170 if (p_timer->timer_state != CL_TIMER_QUEUED)
174 * Mark the timer as running to synchronize with its
175 * cancelation since we can't hold the mutex during the
178 p_timer->timer_state = CL_TIMER_RUNNING;
180 /* Remove the item from the timer queue. */
181 cl_qlist_remove_item(&gp_timer_prov->queue,
182 &p_timer->list_item);
183 pthread_mutex_unlock(&gp_timer_prov->mutex);
184 /* Invoke the callback. */
185 p_timer->pfn_callback((void *)p_timer->context);
187 /* Acquire the mutex again. */
188 pthread_mutex_lock(&gp_timer_prov->mutex);
190 * Only set the state to idle if the timer has not been accessed
193 if (p_timer->timer_state == CL_TIMER_RUNNING)
194 p_timer->timer_state = CL_TIMER_IDLE;
197 * Signal any thread trying to manipulate the timer
200 pthread_cond_signal(&p_timer->cond);
203 gp_timer_prov->thread = 0;
204 pthread_mutex_unlock(&gp_timer_prov->mutex);
208 /* Timer implementation. */
209 void cl_timer_construct(IN cl_timer_t * const p_timer)
211 memset(p_timer, 0, sizeof(cl_timer_t));
212 p_timer->state = CL_UNINITIALIZED;
216 cl_timer_init(IN cl_timer_t * const p_timer,
217 IN cl_pfn_timer_callback_t pfn_callback,
218 IN const void *const context)
221 CL_ASSERT(pfn_callback);
223 cl_timer_construct(p_timer);
228 /* Store timer parameters. */
229 p_timer->pfn_callback = pfn_callback;
230 p_timer->context = context;
232 /* Mark the timer as idle. */
233 p_timer->timer_state = CL_TIMER_IDLE;
235 /* Create the condition variable that is used when cancelling a timer. */
236 pthread_cond_init(&p_timer->cond, NULL);
238 p_timer->state = CL_INITIALIZED;
243 void cl_timer_destroy(IN cl_timer_t * const p_timer)
246 CL_ASSERT(cl_is_state_valid(p_timer->state));
248 if (p_timer->state == CL_INITIALIZED)
249 cl_timer_stop(p_timer);
251 p_timer->state = CL_UNINITIALIZED;
253 /* is it possible we have some threads waiting on the cond now? */
254 pthread_cond_broadcast(&p_timer->cond);
255 pthread_cond_destroy(&p_timer->cond);
260 * Return TRUE if timeout value 1 is earlier than timeout value 2.
262 static __inline boolean_t
263 __cl_timer_is_earlier(IN struct timespec *p_timeout1,
264 IN struct timespec *p_timeout2)
266 return ((p_timeout1->tv_sec < p_timeout2->tv_sec) ||
267 ((p_timeout1->tv_sec == p_timeout2->tv_sec) &&
268 (p_timeout1->tv_nsec < p_timeout2->tv_nsec)));
272 * Search for a timer with an earlier timeout than the one provided by
273 * the context. Both the list item and the context are pointers to
274 * a cl_timer_t structure with valid timeouts.
277 __cl_timer_find(IN const cl_list_item_t * const p_list_item,
278 IN void *const context)
280 cl_timer_t *p_in_list;
283 CL_ASSERT(p_list_item);
286 p_in_list = (cl_timer_t *) p_list_item;
287 p_new = (cl_timer_t *) context;
289 CL_ASSERT(p_in_list->state == CL_INITIALIZED);
290 CL_ASSERT(p_new->state == CL_INITIALIZED);
292 CL_ASSERT(p_in_list->timer_state == CL_TIMER_QUEUED);
294 if (__cl_timer_is_earlier(&p_in_list->timeout, &p_new->timeout))
297 return (CL_NOT_FOUND);
301 cl_timer_start(IN cl_timer_t * const p_timer, IN const uint32_t time_ms)
303 struct timeval curtime;
304 cl_list_item_t *p_list_item;
305 uint32_t delta_time = time_ms;
308 CL_ASSERT(p_timer->state == CL_INITIALIZED);
310 pthread_mutex_lock(&gp_timer_prov->mutex);
311 /* Signal the timer provider thread to wake up. */
312 pthread_cond_signal(&gp_timer_prov->cond);
314 /* Remove the timer from the queue if currently queued. */
315 if (p_timer->timer_state == CL_TIMER_QUEUED)
316 cl_qlist_remove_item(&gp_timer_prov->queue,
317 &p_timer->list_item);
319 /* Get the current time */
321 #define timerclear(tvp) (tvp)->tv_sec = (time_t)0, (tvp)->tv_usec = 0L
323 timerclear(&curtime);
324 gettimeofday(&curtime, NULL);
326 /* do not do 0 wait ! */
327 /* if (delta_time < 1000.0) {delta_time = 1000;} */
329 /* Calculate the timeout. */
330 p_timer->timeout.tv_sec = curtime.tv_sec + (delta_time / 1000);
331 p_timer->timeout.tv_nsec =
332 (curtime.tv_usec + ((delta_time % 1000) * 1000)) * 1000;
334 /* Add the timer to the queue. */
335 if (cl_is_qlist_empty(&gp_timer_prov->queue)) {
336 /* The timer list is empty. Add to the head. */
337 cl_qlist_insert_head(&gp_timer_prov->queue,
338 &p_timer->list_item);
340 /* Find the correct insertion place in the list for the timer. */
341 p_list_item = cl_qlist_find_from_tail(&gp_timer_prov->queue,
342 __cl_timer_find, p_timer);
344 /* Insert the timer. */
345 cl_qlist_insert_next(&gp_timer_prov->queue, p_list_item,
346 &p_timer->list_item);
349 p_timer->timer_state = CL_TIMER_QUEUED;
350 pthread_mutex_unlock(&gp_timer_prov->mutex);
355 void cl_timer_stop(IN cl_timer_t * const p_timer)
358 CL_ASSERT(p_timer->state == CL_INITIALIZED);
360 pthread_mutex_lock(&gp_timer_prov->mutex);
361 switch (p_timer->timer_state) {
362 case CL_TIMER_RUNNING:
363 /* Wait for the callback to complete. */
364 pthread_cond_wait(&p_timer->cond, &gp_timer_prov->mutex);
365 /* Timer could have been queued while we were waiting. */
366 if (p_timer->timer_state != CL_TIMER_QUEUED)
369 case CL_TIMER_QUEUED:
370 /* Change the state of the timer. */
371 p_timer->timer_state = CL_TIMER_IDLE;
372 /* Remove the timer from the queue. */
373 cl_qlist_remove_item(&gp_timer_prov->queue,
374 &p_timer->list_item);
376 * Signal the timer provider thread to move onto the
377 * next timer in the queue.
379 pthread_cond_signal(&gp_timer_prov->cond);
385 pthread_mutex_unlock(&gp_timer_prov->mutex);
389 cl_timer_trim(IN cl_timer_t * const p_timer, IN const uint32_t time_ms)
391 struct timeval curtime;
392 struct timespec newtime;
396 CL_ASSERT(p_timer->state == CL_INITIALIZED);
398 pthread_mutex_lock(&gp_timer_prov->mutex);
400 /* Get the current time */
401 timerclear(&curtime);
402 gettimeofday(&curtime, NULL);
404 /* Calculate the timeout. */
405 newtime.tv_sec = curtime.tv_sec + (time_ms / 1000);
406 newtime.tv_nsec = (curtime.tv_usec + ((time_ms % 1000) * 1000)) * 1000;
408 if (p_timer->timer_state == CL_TIMER_QUEUED) {
409 /* If the old time is earlier, do not trim it. Just return. */
410 if (__cl_timer_is_earlier(&p_timer->timeout, &newtime)) {
411 pthread_mutex_unlock(&gp_timer_prov->mutex);
416 /* Reset the timer to the new timeout value. */
418 pthread_mutex_unlock(&gp_timer_prov->mutex);
419 status = cl_timer_start(p_timer, time_ms);
424 uint64_t cl_get_time_stamp(void)
430 gettimeofday(&tv, NULL);
432 /* Convert the time of day into a microsecond timestamp. */
433 tstamp = ((uint64_t) tv.tv_sec * 1000000) + (uint64_t) tv.tv_usec;
438 uint32_t cl_get_time_stamp_sec(void)
443 gettimeofday(&tv, NULL);