xref: /freebsd/contrib/ofed/opensm/complib/cl_timer.c (revision 87181516ef48be852d5e5fee53c6e0dbfc62f21e)
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