cl_event_wheel.c revision 285830
167754Smsmith/*
267754Smsmith * Copyright (c) 2004-2007 Voltaire, Inc. All rights reserved.
377424Smsmith * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
467754Smsmith * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
567754Smsmith *
667754Smsmith * This software is available to you under a choice of one of two
7217365Sjkim * licenses.  You may choose to be licensed under the terms of the GNU
8281075Sdim * General Public License (GPL) Version 2, available from the file
970243Smsmith * COPYING in the main directory of this source tree, or the
1067754Smsmith * OpenIB.org BSD license below:
11217365Sjkim *
12217365Sjkim *     Redistribution and use in source and binary forms, with or
13217365Sjkim *     without modification, are permitted provided that the following
14217365Sjkim *     conditions are met:
15217365Sjkim *
16217365Sjkim *      - Redistributions of source code must retain the above
17217365Sjkim *        copyright notice, this list of conditions and the following
18217365Sjkim *        disclaimer.
19217365Sjkim *
20217365Sjkim *      - Redistributions in binary form must reproduce the above
21217365Sjkim *        copyright notice, this list of conditions and the following
22217365Sjkim *        disclaimer in the documentation and/or other materials
23217365Sjkim *        provided with the distribution.
24217365Sjkim *
2567754Smsmith * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26217365Sjkim * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27217365Sjkim * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28217365Sjkim * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2967754Smsmith * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30217365Sjkim * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31217365Sjkim * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32217365Sjkim * SOFTWARE.
33217365Sjkim *
34217365Sjkim */
35217365Sjkim
36217365Sjkim#if HAVE_CONFIG_H
37217365Sjkim#  include <config.h>
38217365Sjkim#endif				/* HAVE_CONFIG_H */
39217365Sjkim
40217365Sjkim#include <math.h>
41217365Sjkim#include <stdlib.h>
42217365Sjkim#include <complib/cl_event_wheel.h>
4367754Smsmith#include <complib/cl_debug.h>
44193341Sjkim
45193341Sjkim#define CL_DBG(fmt, arg...)
46193341Sjkim
4767754Smsmithstatic cl_status_t
4877424Smsmith__event_will_age_before(IN const cl_list_item_t * const p_list_item,
4991116Smsmith			IN void *context)
5067754Smsmith{
5167754Smsmith	uint64_t aging_time = *((uint64_t *) context);
52281075Sdim	cl_event_wheel_reg_info_t *p_event;
5383174Smsmith
54151937Sjkim	p_event =
5567754Smsmith	    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
56151937Sjkim
57151937Sjkim	if (p_event->aging_time < aging_time)
58151937Sjkim		return CL_SUCCESS;
59151937Sjkim	else
6067754Smsmith		return CL_NOT_FOUND;
61151937Sjkim}
62151937Sjkim
63151937Sjkimstatic void __cl_event_wheel_callback(IN void *context)
64151937Sjkim{
6567754Smsmith	cl_event_wheel_t *p_event_wheel = (cl_event_wheel_t *) context;
66151937Sjkim	cl_list_item_t *p_list_item, *p_prev_event_list_item;
67151937Sjkim	cl_list_item_t *p_list_next_item;
68151937Sjkim	cl_event_wheel_reg_info_t *p_event;
69151937Sjkim	uint64_t current_time;
7083174Smsmith	uint64_t next_aging_time;
71151937Sjkim	uint32_t new_timeout;
72151937Sjkim	cl_status_t cl_status;
73151937Sjkim
74151937Sjkim	/* might be during closing ...  */
7583174Smsmith	if (p_event_wheel->closing)
76151937Sjkim		return;
77151937Sjkim
78151937Sjkim	current_time = cl_get_time_stamp();
79151937Sjkim
8067754Smsmith	if (NULL != p_event_wheel->p_external_lock)
81151937Sjkim
82151937Sjkim		/* Take care of the order of acquiring locks to avoid the deadlock!
83151937Sjkim		 * The external lock goes first.
8467754Smsmith		 */
85151937Sjkim		cl_spinlock_acquire(p_event_wheel->p_external_lock);
86151937Sjkim
87151937Sjkim	cl_spinlock_acquire(&p_event_wheel->lock);
88151937Sjkim
8967754Smsmith	p_list_item = cl_qlist_head(&p_event_wheel->events_wheel);
90151937Sjkim	if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel))
91228110Sjkim		/* the list is empty - nothing to do */
92228110Sjkim		goto Exit;
93228110Sjkim
94228110Sjkim	/* we found such an item.  get the p_event */
95228110Sjkim	p_event =
96151937Sjkim	    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
97151937Sjkim
98151937Sjkim	while (p_event->aging_time <= current_time) {
9967754Smsmith		/* this object has aged - invoke it's callback */
100151937Sjkim		if (p_event->pfn_aged_callback)
101151937Sjkim			next_aging_time =
102151937Sjkim			    p_event->pfn_aged_callback(p_event->key,
103151937Sjkim						       p_event->num_regs,
10467754Smsmith						       p_event->context);
105151937Sjkim		else
106151937Sjkim			next_aging_time = 0;
107151937Sjkim
10867754Smsmith		/* point to the next object in the wheel */
109151937Sjkim		p_list_next_item = cl_qlist_next(p_list_item);
110151937Sjkim
111151937Sjkim		/* We need to retire the event if the next aging time passed */
11267754Smsmith		if (next_aging_time < current_time) {
113151937Sjkim			/* remove it from the map */
114151937Sjkim			cl_qmap_remove_item(&p_event_wheel->events_map,
115151937Sjkim					    &(p_event->map_item));
116151937Sjkim
11767754Smsmith			/* pop p_event from the wheel */
11867754Smsmith			cl_qlist_remove_head(&p_event_wheel->events_wheel);
11967754Smsmith
12067754Smsmith			/* delete the event info object - allocated by cl_event_wheel_reg */
121151937Sjkim			free(p_event);
12267754Smsmith		} else {
123245582Sjkim			/* update the required aging time */
124245582Sjkim			p_event->aging_time = next_aging_time;
12567754Smsmith			p_event->num_regs++;
12677424Smsmith
12767754Smsmith			/* do not remove from the map  - but remove from the list head and
128245582Sjkim			   place in the correct position */
12967754Smsmith
13067754Smsmith			/* pop p_event from the wheel */
13167754Smsmith			cl_qlist_remove_head(&p_event_wheel->events_wheel);
132151937Sjkim
133151937Sjkim			/* find the event that ages just before */
134151937Sjkim			p_prev_event_list_item =
135151937Sjkim			    cl_qlist_find_from_tail(&p_event_wheel->
13667754Smsmith						    events_wheel,
137167802Sjkim						    __event_will_age_before,
138167802Sjkim						    &p_event->aging_time);
139151937Sjkim
140151937Sjkim			/* insert just after */
14167754Smsmith			cl_qlist_insert_next(&p_event_wheel->events_wheel,
14267754Smsmith					     p_prev_event_list_item,
143151937Sjkim					     &p_event->list_item);
14483174Smsmith
145151937Sjkim			/* as we have modified the list - restart from first item: */
14683174Smsmith			p_list_next_item =
147151937Sjkim			    cl_qlist_head(&p_event_wheel->events_wheel);
14867754Smsmith		}
149151937Sjkim
150167802Sjkim		/* advance to next event */
151151937Sjkim		p_list_item = p_list_next_item;
15267754Smsmith		if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel))
153151937Sjkim			/* the list is empty - nothing to do */
154151937Sjkim			break;
155151937Sjkim
156151937Sjkim		/* get the p_event */
157151937Sjkim		p_event =
158151937Sjkim		    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t,
159151937Sjkim				  list_item);
160151937Sjkim	}
161151937Sjkim
162151937Sjkim	/* We need to restart the timer only if the list is not empty now */
163151937Sjkim	if (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) {
16467754Smsmith		/* get the p_event */
165151937Sjkim		p_event =
16667754Smsmith		    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t,
167151937Sjkim				  list_item);
168250838Sjkim
169167802Sjkim		/* start the timer to the timeout [msec] */
170151937Sjkim		new_timeout =
17167754Smsmith		    (uint32_t) (((p_event->aging_time - current_time) / 1000) +
172151937Sjkim				0.5);
173250838Sjkim		CL_DBG("__cl_event_wheel_callback: Restart timer in: "
174167802Sjkim		       "%u [msec]\n", new_timeout);
175151937Sjkim		cl_status = cl_timer_start(&p_event_wheel->timer, new_timeout);
17667754Smsmith		if (cl_status != CL_SUCCESS) {
177151937Sjkim			CL_DBG("__cl_event_wheel_callback : ERR 6100: "
17867754Smsmith			       "Failed to start timer\n");
179151937Sjkim		}
180250838Sjkim	}
181228110Sjkim
182228110Sjkim	/* release the lock */
183228110SjkimExit:
184228110Sjkim	cl_spinlock_release(&p_event_wheel->lock);
185228110Sjkim	if (NULL != p_event_wheel->p_external_lock)
186228110Sjkim		cl_spinlock_release(p_event_wheel->p_external_lock);
187228110Sjkim}
188228110Sjkim
189228110Sjkim/*
190151937Sjkim * Construct and Initialize
19183174Smsmith */
192151937Sjkimvoid cl_event_wheel_construct(IN cl_event_wheel_t * const p_event_wheel)
193250838Sjkim{
194167802Sjkim	cl_spinlock_construct(&(p_event_wheel->lock));
195151937Sjkim	cl_timer_construct(&(p_event_wheel->timer));
19683174Smsmith}
197151937Sjkim
198250838Sjkimcl_status_t
199167802Sjkimcl_event_wheel_init(IN cl_event_wheel_t * const p_event_wheel)
200151937Sjkim{
20167754Smsmith	cl_status_t cl_status = CL_SUCCESS;
202151937Sjkim
203252279Sjkim	/* initialize */
204167802Sjkim	p_event_wheel->p_external_lock = NULL;
205151937Sjkim	p_event_wheel->closing = FALSE;
20667754Smsmith	cl_status = cl_spinlock_init(&(p_event_wheel->lock));
207151937Sjkim	if (cl_status != CL_SUCCESS)
20867754Smsmith		return cl_status;
209151937Sjkim	cl_qlist_init(&p_event_wheel->events_wheel);
210250838Sjkim	cl_qmap_init(&p_event_wheel->events_map);
211167802Sjkim
212167802Sjkim	/* init the timer with timeout */
213151937Sjkim	cl_status = cl_timer_init(&p_event_wheel->timer, __cl_event_wheel_callback, p_event_wheel);	/* cb context */
21467754Smsmith
215151937Sjkim	return cl_status;
216250838Sjkim}
217167802Sjkim
218167802Sjkimcl_status_t
219151937Sjkimcl_event_wheel_init_ex(IN cl_event_wheel_t * const p_event_wheel,
22067754Smsmith		       IN cl_spinlock_t * p_external_lock)
221228110Sjkim{
222250838Sjkim	cl_status_t cl_status;
223228110Sjkim
224228110Sjkim	cl_status = cl_event_wheel_init(p_event_wheel);
225228110Sjkim	if (CL_SUCCESS != cl_status)
226228110Sjkim		return cl_status;
227151937Sjkim
228151937Sjkim	p_event_wheel->p_external_lock = p_external_lock;
229151937Sjkim	return cl_status;
230151937Sjkim}
231151937Sjkim
232151937Sjkimvoid cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel)
233151937Sjkim{
234151937Sjkim	cl_list_item_t *p_list_item;
235167802Sjkim	cl_event_wheel_reg_info_t *p_event;
236151937Sjkim
237151937Sjkim	p_list_item = cl_qlist_head(&p_event_wheel->events_wheel);
23867754Smsmith
239228110Sjkim	while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) {
240228110Sjkim		p_event =
241228110Sjkim		    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t,
242228110Sjkim				  list_item);
243228110Sjkim		CL_DBG("cl_event_wheel_dump: Found event key:<0x%"
244228110Sjkim		       PRIx64 ">, aging time:%" PRIu64 "\n",
245228110Sjkim		       p_event->key, p_event->aging_time);
246228110Sjkim		p_list_item = cl_qlist_next(p_list_item);
247228110Sjkim	}
248228110Sjkim}
249228110Sjkim
250228110Sjkimvoid cl_event_wheel_destroy(IN cl_event_wheel_t * const p_event_wheel)
251228110Sjkim{
252151937Sjkim	cl_list_item_t *p_list_item;
253151937Sjkim	cl_map_item_t *p_map_item;
254151937Sjkim	cl_event_wheel_reg_info_t *p_event;
255151937Sjkim
256151937Sjkim	/* we need to get a lock */
257151937Sjkim	cl_spinlock_acquire(&p_event_wheel->lock);
258151937Sjkim
259167802Sjkim	cl_event_wheel_dump(p_event_wheel);
260151937Sjkim
261151937Sjkim	/* go over all the items in the list and remove them */
26267754Smsmith	p_list_item = cl_qlist_remove_head(&p_event_wheel->events_wheel);
263151937Sjkim	while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) {
264151937Sjkim		p_event =
265151937Sjkim		    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t,
266151937Sjkim				  list_item);
267151937Sjkim
268151937Sjkim		CL_DBG("cl_event_wheel_destroy: Found outstanding event"
269151937Sjkim		       " key:<0x%" PRIx64 ">\n", p_event->key);
270167802Sjkim
271167802Sjkim		/* remove it from the map */
272151937Sjkim		p_map_item = &(p_event->map_item);
273151937Sjkim		cl_qmap_remove_item(&p_event_wheel->events_map, p_map_item);
27467754Smsmith		free(p_event);	/* allocated by cl_event_wheel_reg */
275228110Sjkim		p_list_item =
276228110Sjkim		    cl_qlist_remove_head(&p_event_wheel->events_wheel);
277228110Sjkim	}
278228110Sjkim
279228110Sjkim	/* destroy the timer */
280228110Sjkim	cl_timer_destroy(&p_event_wheel->timer);
281228110Sjkim
282228110Sjkim	/* destroy the lock (this should be done without releasing - we don't want
283228110Sjkim	   any other run to grab the lock at this point. */
284228110Sjkim	cl_spinlock_release(&p_event_wheel->lock);
285228110Sjkim	cl_spinlock_destroy(&(p_event_wheel->lock));
286228110Sjkim}
287151937Sjkim
288151937Sjkimcl_status_t
289151937Sjkimcl_event_wheel_reg(IN cl_event_wheel_t * const p_event_wheel,
290151937Sjkim		   IN const uint64_t key,
291167802Sjkim		   IN const uint64_t aging_time_usec,
292151937Sjkim		   IN cl_pfn_event_aged_cb_t pfn_callback,
29367754Smsmith		   IN void *const context)
294151937Sjkim{
295151937Sjkim	cl_event_wheel_reg_info_t *p_event;
296151937Sjkim	uint64_t timeout;
297151937Sjkim	uint32_t to;
298167802Sjkim	cl_status_t cl_status = CL_SUCCESS;
299151937Sjkim	cl_list_item_t *prev_event_list_item;
30067754Smsmith	cl_map_item_t *p_map_item;
301151937Sjkim
302250838Sjkim	/* Get the lock on the manager */
303151937Sjkim	cl_spinlock_acquire(&(p_event_wheel->lock));
304151937Sjkim
305151937Sjkim	cl_event_wheel_dump(p_event_wheel);
306151937Sjkim
30767754Smsmith	/* Make sure such a key does not exists */
308151937Sjkim	p_map_item = cl_qmap_get(&p_event_wheel->events_map, key);
309151937Sjkim	if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) {
310151937Sjkim		CL_DBG("cl_event_wheel_reg: Already exists key:0x%"
31167754Smsmith		       PRIx64 "\n", key);
31267754Smsmith
31367754Smsmith		/* already there - remove it from the list as it is getting a new time */
31467754Smsmith		p_event =
31567754Smsmith		    PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t,
316151937Sjkim				  map_item);
31767754Smsmith
318151937Sjkim		/* remove the item from the qlist */
31967754Smsmith		cl_qlist_remove_item(&p_event_wheel->events_wheel,
320151937Sjkim				     &p_event->list_item);
32167754Smsmith		/* and the qmap */
322151937Sjkim		cl_qmap_remove_item(&p_event_wheel->events_map,
323151937Sjkim				    &p_event->map_item);
32467754Smsmith	} else {
32567754Smsmith		/* make a new one */
32667754Smsmith		p_event = (cl_event_wheel_reg_info_t *)
327151937Sjkim		    malloc(sizeof(cl_event_wheel_reg_info_t));
328151937Sjkim		p_event->num_regs = 0;
329151937Sjkim	}
33067754Smsmith
33191116Smsmith	p_event->key = key;
33283174Smsmith	p_event->aging_time = aging_time_usec;
33383174Smsmith	p_event->pfn_aged_callback = pfn_callback;
334151937Sjkim	p_event->context = context;
335151937Sjkim	p_event->num_regs++;
336151937Sjkim
337151937Sjkim	CL_DBG("cl_event_wheel_reg: Registering event key:0x%" PRIx64
33867754Smsmith	       " aging in %u [msec]\n", p_event->key,
339151937Sjkim	       (uint32_t) ((p_event->aging_time -
340151937Sjkim			    cl_get_time_stamp()) / 1000));
34167754Smsmith
342151937Sjkim	/* If the list is empty - need to start the timer */
343151937Sjkim	if (cl_is_qlist_empty(&p_event_wheel->events_wheel)) {
344151937Sjkim		/* Edward Bortnikov 03/29/2003
34567754Smsmith		 * ++TBD Consider moving the timer manipulation behind the list manipulation.
34667754Smsmith		 */
34767754Smsmith
34867754Smsmith		/* calculate the new timeout */
34967754Smsmith		timeout =
350151937Sjkim		    (p_event->aging_time - cl_get_time_stamp() + 500) / 1000;
35167754Smsmith
352151937Sjkim		/* stop the timer if it is running */
35367754Smsmith
35477424Smsmith		/* Edward Bortnikov 03/29/2003
35567754Smsmith		 * Don't call cl_timer_stop() because it spins forever.
356151937Sjkim		 * cl_timer_start() will invoke cl_timer_stop() by itself.
357151937Sjkim		 *
35867754Smsmith		 * The problematic scenario is when __cl_event_wheel_callback()
35967754Smsmith		 * is in race condition with this code. It sets timer.in_timer_cb
36067754Smsmith		 * to TRUE and then blocks on p_event_wheel->lock. Following this,
361151937Sjkim		 * the call to cl_timer_stop() hangs. Following this, the whole system
362151937Sjkim		 * enters into a deadlock.
363151937Sjkim		 *
36467754Smsmith		 * cl_timer_stop(&p_event_wheel->timer);
36591116Smsmith		 */
36683174Smsmith
36783174Smsmith		/* The timeout for the cl_timer_start should be given as uint32_t.
368151937Sjkim		   if there is an overflow - warn about it. */
36967754Smsmith		to = (uint32_t) timeout;
370151937Sjkim		if (timeout > (uint32_t) timeout) {
37167754Smsmith			to = 0xffffffff;	/* max 32 bit timer */
37291116Smsmith			CL_DBG("cl_event_wheel_reg: timeout requested is "
37367754Smsmith			       "too large. Using timeout: %u\n", to);
374151937Sjkim		}
37567754Smsmith
37667754Smsmith		/* start the timer to the timeout [msec] */
37791116Smsmith		cl_status = cl_timer_start(&p_event_wheel->timer, to);
37867754Smsmith		if (cl_status != CL_SUCCESS) {
379151937Sjkim			CL_DBG("cl_event_wheel_reg : ERR 6103: "
38067754Smsmith			       "Failed to start timer\n");
38167754Smsmith			goto Exit;
38291116Smsmith		}
38367754Smsmith	}
384151937Sjkim
38567754Smsmith	/* insert the object to the qlist and the qmap */
38667754Smsmith
38767754Smsmith	/* BUT WE MUST INSERT IT IN A SORTED MANNER */
38867754Smsmith	prev_event_list_item =
389151937Sjkim	    cl_qlist_find_from_tail(&p_event_wheel->events_wheel,
390151937Sjkim				    __event_will_age_before,
391151937Sjkim				    &p_event->aging_time);
39267754Smsmith
39367754Smsmith	cl_qlist_insert_next(&p_event_wheel->events_wheel,
394151937Sjkim			     prev_event_list_item, &p_event->list_item);
39567754Smsmith
396151937Sjkim	cl_qmap_insert(&p_event_wheel->events_map, key, &(p_event->map_item));
39767754Smsmith
39867754SmsmithExit:
39967754Smsmith	cl_spinlock_release(&p_event_wheel->lock);
40067754Smsmith
40167754Smsmith	return cl_status;
402151937Sjkim}
40367754Smsmith
404151937Sjkimvoid
40567754Smsmithcl_event_wheel_unreg(IN cl_event_wheel_t * const p_event_wheel, IN uint64_t key)
40677424Smsmith{
40767754Smsmith	cl_event_wheel_reg_info_t *p_event;
408151937Sjkim	cl_map_item_t *p_map_item;
40967754Smsmith
41067754Smsmith	CL_DBG("cl_event_wheel_unreg: " "Removing key:0x%" PRIx64 "\n", key);
41167754Smsmith
41267754Smsmith	cl_spinlock_acquire(&p_event_wheel->lock);
413151937Sjkim	p_map_item = cl_qmap_get(&p_event_wheel->events_map, key);
414151937Sjkim	if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) {
41567754Smsmith		/* we found such an item. */
416151937Sjkim		p_event =
417151937Sjkim		    PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t,
41867754Smsmith				  map_item);
41967754Smsmith
42091116Smsmith		/* remove the item from the qlist */
42183174Smsmith		cl_qlist_remove_item(&p_event_wheel->events_wheel,
42283174Smsmith				     &(p_event->list_item));
423245582Sjkim		/* remove the item from the qmap */
424245582Sjkim		cl_qmap_remove_item(&p_event_wheel->events_map,
425245582Sjkim				    &(p_event->map_item));
42667754Smsmith
427151937Sjkim		CL_DBG("cl_event_wheel_unreg: Removed key:0x%" PRIx64 "\n",
428151937Sjkim		       key);
42967754Smsmith
430151937Sjkim		/* free the item */
43167754Smsmith		free(p_event);
432151937Sjkim	} else {
433151937Sjkim		CL_DBG("cl_event_wheel_unreg: did not find key:0x%" PRIx64
434151937Sjkim		       "\n", key);
435151937Sjkim	}
43667754Smsmith
437151937Sjkim	cl_spinlock_release(&p_event_wheel->lock);
43867754Smsmith}
439151937Sjkim
440151937Sjkimuint32_t
441114237Snjlcl_event_wheel_num_regs(IN cl_event_wheel_t * const p_event_wheel,
442151937Sjkim			IN uint64_t key)
443151937Sjkim{
444151937Sjkim
445151937Sjkim	cl_event_wheel_reg_info_t *p_event;
446114237Snjl	cl_map_item_t *p_map_item;
447114237Snjl	uint32_t num_regs = 0;
448246849Sjkim
449246849Sjkim	/* try to find the key in the map */
450246849Sjkim	CL_DBG("cl_event_wheel_num_regs: Looking for key:0x%"
451246849Sjkim	       PRIx64 "\n", key);
452246849Sjkim
453246849Sjkim	cl_spinlock_acquire(&p_event_wheel->lock);
454246849Sjkim	p_map_item = cl_qmap_get(&p_event_wheel->events_map, key);
455246849Sjkim	if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) {
456246849Sjkim		/* ok so we can simply return it's num_regs */
457151937Sjkim		p_event =
45867754Smsmith		    PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t,
459228110Sjkim				  map_item);
460228110Sjkim		num_regs = p_event->num_regs;
461228110Sjkim	}
462228110Sjkim
463228110Sjkim	cl_spinlock_release(&p_event_wheel->lock);
464228110Sjkim	return (num_regs);
465228110Sjkim}
466228110Sjkim
467228110Sjkim#ifdef __CL_EVENT_WHEEL_TEST__
468228110Sjkim
46967754Smsmith/* Dump out the complete state of the event wheel */
470151937Sjkimvoid __cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel)
47167754Smsmith{
472228110Sjkim	cl_list_item_t *p_list_item;
47367754Smsmith	cl_map_item_t *p_map_item;
474151937Sjkim	cl_event_wheel_reg_info_t *p_event;
47567754Smsmith
476151937Sjkim	printf("************** Event Wheel Dump ***********************\n");
47767754Smsmith	printf("Event Wheel List has %u items:\n",
47867754Smsmith	       cl_qlist_count(&p_event_wheel->events_wheel));
47967754Smsmith
48067754Smsmith	p_list_item = cl_qlist_head(&p_event_wheel->events_wheel);
48167754Smsmith	while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) {
482151937Sjkim		p_event =
48377424Smsmith		    PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t,
484151937Sjkim				  list_item);
48577424Smsmith		printf("Event key:0x%" PRIx64 " Context:%s NumRegs:%u\n",
48677424Smsmith		       p_event->key, (char *)p_event->context,
48777424Smsmith		       p_event->num_regs);
488151937Sjkim
48977424Smsmith		/* next */
49077424Smsmith		p_list_item = cl_qlist_next(p_list_item);
49177424Smsmith	}
49277424Smsmith
493151937Sjkim	printf("Event Map has %u items:\n",
494151937Sjkim	       cl_qmap_count(&p_event_wheel->events_map));
49577424Smsmith
496151937Sjkim	p_map_item = cl_qmap_head(&p_event_wheel->events_map);
497151937Sjkim	while (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) {
49877424Smsmith		p_event =
49977424Smsmith		    PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t,
50091116Smsmith				  map_item);
50183174Smsmith		printf("Event key:0x%" PRIx64 " Context:%s NumRegs:%u\n",
50283174Smsmith		       p_event->key, (char *)p_event->context,
503245582Sjkim		       p_event->num_regs);
504245582Sjkim
505245582Sjkim		/* next */
50677424Smsmith		p_map_item = cl_qmap_next(p_map_item);
50777424Smsmith	}
50877424Smsmith
50977424Smsmith}
510151937Sjkim
51177424Smsmith/* The callback for aging event */
512151937Sjkim/* We assume we pass a text context */
51377424Smsmithvoid __test_event_aging(uint64_t key, void *context)
514151937Sjkim{
515151937Sjkim	printf("*****************************************************\n");
516151937Sjkim	printf("Aged key: 0x%" PRIx64 " Context:%s\n", key, (char *)context);
517151937Sjkim}
51877424Smsmith
519167802Sjkimint main()
520167802Sjkim{
52177424Smsmith	cl_event_wheel_t event_wheel;
52277424Smsmith	/*  uint64_t key; */
52377424Smsmith
52477424Smsmith	/* construct */
52577424Smsmith	cl_event_wheel_construct(&event_wheel);
52677424Smsmith
527151937Sjkim	/* init */
52867754Smsmith	cl_event_wheel_init(&event_wheel);
529151937Sjkim
530151937Sjkim	/* Start Playing */
53167754Smsmith	cl_event_wheel_reg(&event_wheel, 1,	/*  key */
53277424Smsmith			   cl_get_time_stamp() + 3000000,	/*  3 sec lifetime */
53367754Smsmith			   __test_event_aging,	/*  cb */
534151937Sjkim			   "The first Aging Event");
535151937Sjkim
53667754Smsmith	cl_event_wheel_reg(&event_wheel, 2,	/*  key */
53767754Smsmith			   cl_get_time_stamp() + 3000000,	/*  3 sec lifetime */
53867754Smsmith			   __test_event_aging,	/*  cb */
539151937Sjkim			   "The Second Aging Event");
540151937Sjkim
541151937Sjkim	cl_event_wheel_reg(&event_wheel, 3,	/*  key */
542151937Sjkim			   cl_get_time_stamp() + 3500000,	/*  3 sec lifetime */
54367754Smsmith			   __test_event_aging,	/*  cb */
544167802Sjkim			   "The Third Aging Event");
545167802Sjkim
546167802Sjkim	__cl_event_wheel_dump(&event_wheel);
547167802Sjkim
548167802Sjkim	sleep(2);
549167802Sjkim	cl_event_wheel_reg(&event_wheel, 2,	/*  key */
550151937Sjkim			   cl_get_time_stamp() + 8000000,	/*  3 sec lifetime */
55167754Smsmith			   __test_event_aging,	/*  cb */
552151937Sjkim			   "The Second Aging Event Moved");
553151937Sjkim
554151937Sjkim	__cl_event_wheel_dump(&event_wheel);
555151937Sjkim
556151937Sjkim	sleep(1);
557151937Sjkim	/* remove the third event */
558151937Sjkim	cl_event_wheel_unreg(&event_wheel, 3);	/*  key */
55967754Smsmith
560151937Sjkim	/* get the number of registrations for the keys */
561151937Sjkim	printf("Event 1 Registered: %u\n",
562151937Sjkim	       cl_event_wheel_num_regs(&event_wheel, 1));
563151937Sjkim	printf("Event 2 Registered: %u\n",
564151937Sjkim	       cl_event_wheel_num_regs(&event_wheel, 2));
565151937Sjkim
566151937Sjkim	sleep(5);
56783174Smsmith	/* destroy */
568151937Sjkim	cl_event_wheel_destroy(&event_wheel);
569151937Sjkim
570151937Sjkim	return (0);
571151937Sjkim}
572151937Sjkim
573151937Sjkim#endif				/* __CL_EVENT_WHEEL_TEST__ */
574151937Sjkim