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 */
__cl_timer_prov_create(void)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
__cl_timer_prov_destroy(void)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 */
__cl_timer_prov_cb(IN void * const context)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. */
cl_timer_construct(IN cl_timer_t * const p_timer)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
cl_timer_init(IN cl_timer_t * const p_timer,IN cl_pfn_timer_callback_t pfn_callback,IN const void * const context)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
cl_timer_destroy(IN cl_timer_t * const p_timer)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 */
__cl_timer_is_earlier(IN struct timespec * p_timeout1,IN struct timespec * p_timeout2)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 */
__cl_timer_find(IN const cl_list_item_t * const p_list_item,IN void * const context)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 */
__cl_timer_calculate(IN const uint32_t time_ms,OUT struct timespec * const p_timer)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
cl_timer_start(IN cl_timer_t * const p_timer,IN const uint32_t time_ms)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
cl_timer_stop(IN cl_timer_t * const p_timer)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
cl_timer_trim(IN cl_timer_t * const p_timer,IN const uint32_t time_ms)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
cl_get_time_stamp(void)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
cl_get_time_stamp_sec(void)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