1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004-2007 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#if HAVE_CONFIG_H 37219820Sjeff# include <config.h> 38219820Sjeff#endif /* HAVE_CONFIG_H */ 39219820Sjeff 40219820Sjeff#include <math.h> 41219820Sjeff#include <stdlib.h> 42219820Sjeff#include <complib/cl_event_wheel.h> 43219820Sjeff#include <complib/cl_debug.h> 44219820Sjeff 45219820Sjeff#define CL_DBG(fmt, arg...) 46219820Sjeff 47219820Sjeffstatic cl_status_t 48219820Sjeff__event_will_age_before(IN const cl_list_item_t * const p_list_item, 49219820Sjeff IN void *context) 50219820Sjeff{ 51219820Sjeff uint64_t aging_time = *((uint64_t *) context); 52219820Sjeff cl_event_wheel_reg_info_t *p_event; 53219820Sjeff 54219820Sjeff p_event = 55219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item); 56219820Sjeff 57219820Sjeff if (p_event->aging_time < aging_time) 58219820Sjeff return CL_SUCCESS; 59219820Sjeff else 60219820Sjeff return CL_NOT_FOUND; 61219820Sjeff} 62219820Sjeff 63219820Sjeffstatic void __cl_event_wheel_callback(IN void *context) 64219820Sjeff{ 65219820Sjeff cl_event_wheel_t *p_event_wheel = (cl_event_wheel_t *) context; 66219820Sjeff cl_list_item_t *p_list_item, *p_prev_event_list_item; 67219820Sjeff cl_list_item_t *p_list_next_item; 68219820Sjeff cl_event_wheel_reg_info_t *p_event; 69219820Sjeff uint64_t current_time; 70219820Sjeff uint64_t next_aging_time; 71219820Sjeff uint32_t new_timeout; 72219820Sjeff cl_status_t cl_status; 73219820Sjeff 74219820Sjeff /* might be during closing ... */ 75219820Sjeff if (p_event_wheel->closing) 76219820Sjeff return; 77219820Sjeff 78219820Sjeff current_time = cl_get_time_stamp(); 79219820Sjeff 80219820Sjeff if (NULL != p_event_wheel->p_external_lock) 81219820Sjeff 82219820Sjeff /* Take care of the order of acquiring locks to avoid the deadlock! 83219820Sjeff * The external lock goes first. 84219820Sjeff */ 85219820Sjeff cl_spinlock_acquire(p_event_wheel->p_external_lock); 86219820Sjeff 87219820Sjeff cl_spinlock_acquire(&p_event_wheel->lock); 88219820Sjeff 89219820Sjeff p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); 90219820Sjeff if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel)) 91219820Sjeff /* the list is empty - nothing to do */ 92219820Sjeff goto Exit; 93219820Sjeff 94219820Sjeff /* we found such an item. get the p_event */ 95219820Sjeff p_event = 96219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item); 97219820Sjeff 98219820Sjeff while (p_event->aging_time <= current_time) { 99219820Sjeff /* this object has aged - invoke it's callback */ 100219820Sjeff if (p_event->pfn_aged_callback) 101219820Sjeff next_aging_time = 102219820Sjeff p_event->pfn_aged_callback(p_event->key, 103219820Sjeff p_event->num_regs, 104219820Sjeff p_event->context); 105219820Sjeff else 106219820Sjeff next_aging_time = 0; 107219820Sjeff 108219820Sjeff /* point to the next object in the wheel */ 109219820Sjeff p_list_next_item = cl_qlist_next(p_list_item); 110219820Sjeff 111219820Sjeff /* We need to retire the event if the next aging time passed */ 112219820Sjeff if (next_aging_time < current_time) { 113219820Sjeff /* remove it from the map */ 114219820Sjeff cl_qmap_remove_item(&p_event_wheel->events_map, 115219820Sjeff &(p_event->map_item)); 116219820Sjeff 117219820Sjeff /* pop p_event from the wheel */ 118219820Sjeff cl_qlist_remove_head(&p_event_wheel->events_wheel); 119219820Sjeff 120219820Sjeff /* delete the event info object - allocated by cl_event_wheel_reg */ 121219820Sjeff free(p_event); 122219820Sjeff } else { 123219820Sjeff /* update the required aging time */ 124219820Sjeff p_event->aging_time = next_aging_time; 125219820Sjeff p_event->num_regs++; 126219820Sjeff 127219820Sjeff /* do not remove from the map - but remove from the list head and 128219820Sjeff place in the correct position */ 129219820Sjeff 130219820Sjeff /* pop p_event from the wheel */ 131219820Sjeff cl_qlist_remove_head(&p_event_wheel->events_wheel); 132219820Sjeff 133219820Sjeff /* find the event that ages just before */ 134219820Sjeff p_prev_event_list_item = 135219820Sjeff cl_qlist_find_from_tail(&p_event_wheel-> 136219820Sjeff events_wheel, 137219820Sjeff __event_will_age_before, 138219820Sjeff &p_event->aging_time); 139219820Sjeff 140219820Sjeff /* insert just after */ 141219820Sjeff cl_qlist_insert_next(&p_event_wheel->events_wheel, 142219820Sjeff p_prev_event_list_item, 143219820Sjeff &p_event->list_item); 144219820Sjeff 145219820Sjeff /* as we have modified the list - restart from first item: */ 146219820Sjeff p_list_next_item = 147219820Sjeff cl_qlist_head(&p_event_wheel->events_wheel); 148219820Sjeff } 149219820Sjeff 150219820Sjeff /* advance to next event */ 151219820Sjeff p_list_item = p_list_next_item; 152219820Sjeff if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel)) 153219820Sjeff /* the list is empty - nothing to do */ 154219820Sjeff break; 155219820Sjeff 156219820Sjeff /* get the p_event */ 157219820Sjeff p_event = 158219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, 159219820Sjeff list_item); 160219820Sjeff } 161219820Sjeff 162219820Sjeff /* We need to restart the timer only if the list is not empty now */ 163219820Sjeff if (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { 164219820Sjeff /* get the p_event */ 165219820Sjeff p_event = 166219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, 167219820Sjeff list_item); 168219820Sjeff 169219820Sjeff /* start the timer to the timeout [msec] */ 170219820Sjeff new_timeout = 171219820Sjeff (uint32_t) (((p_event->aging_time - current_time) / 1000) + 172219820Sjeff 0.5); 173219820Sjeff CL_DBG("__cl_event_wheel_callback: Restart timer in: " 174219820Sjeff "%u [msec]\n", new_timeout); 175219820Sjeff cl_status = cl_timer_start(&p_event_wheel->timer, new_timeout); 176219820Sjeff if (cl_status != CL_SUCCESS) { 177219820Sjeff CL_DBG("__cl_event_wheel_callback : ERR 6100: " 178219820Sjeff "Failed to start timer\n"); 179219820Sjeff } 180219820Sjeff } 181219820Sjeff 182219820Sjeff /* release the lock */ 183219820SjeffExit: 184219820Sjeff cl_spinlock_release(&p_event_wheel->lock); 185219820Sjeff if (NULL != p_event_wheel->p_external_lock) 186219820Sjeff cl_spinlock_release(p_event_wheel->p_external_lock); 187219820Sjeff} 188219820Sjeff 189219820Sjeff/* 190219820Sjeff * Construct and Initialize 191219820Sjeff */ 192219820Sjeffvoid cl_event_wheel_construct(IN cl_event_wheel_t * const p_event_wheel) 193219820Sjeff{ 194219820Sjeff cl_spinlock_construct(&(p_event_wheel->lock)); 195219820Sjeff cl_timer_construct(&(p_event_wheel->timer)); 196219820Sjeff} 197219820Sjeff 198219820Sjeffcl_status_t 199219820Sjeffcl_event_wheel_init(IN cl_event_wheel_t * const p_event_wheel) 200219820Sjeff{ 201219820Sjeff cl_status_t cl_status = CL_SUCCESS; 202219820Sjeff 203219820Sjeff /* initialize */ 204219820Sjeff p_event_wheel->p_external_lock = NULL; 205219820Sjeff p_event_wheel->closing = FALSE; 206219820Sjeff cl_status = cl_spinlock_init(&(p_event_wheel->lock)); 207219820Sjeff if (cl_status != CL_SUCCESS) 208219820Sjeff return cl_status; 209219820Sjeff cl_qlist_init(&p_event_wheel->events_wheel); 210219820Sjeff cl_qmap_init(&p_event_wheel->events_map); 211219820Sjeff 212219820Sjeff /* init the timer with timeout */ 213219820Sjeff cl_status = cl_timer_init(&p_event_wheel->timer, __cl_event_wheel_callback, p_event_wheel); /* cb context */ 214219820Sjeff 215219820Sjeff return cl_status; 216219820Sjeff} 217219820Sjeff 218219820Sjeffcl_status_t 219219820Sjeffcl_event_wheel_init_ex(IN cl_event_wheel_t * const p_event_wheel, 220219820Sjeff IN cl_spinlock_t * p_external_lock) 221219820Sjeff{ 222219820Sjeff cl_status_t cl_status; 223219820Sjeff 224219820Sjeff cl_status = cl_event_wheel_init(p_event_wheel); 225219820Sjeff if (CL_SUCCESS != cl_status) 226219820Sjeff return cl_status; 227219820Sjeff 228219820Sjeff p_event_wheel->p_external_lock = p_external_lock; 229219820Sjeff return cl_status; 230219820Sjeff} 231219820Sjeff 232219820Sjeffvoid cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel) 233219820Sjeff{ 234219820Sjeff cl_list_item_t *p_list_item; 235219820Sjeff cl_event_wheel_reg_info_t *p_event; 236219820Sjeff 237219820Sjeff p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); 238219820Sjeff 239219820Sjeff while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { 240219820Sjeff p_event = 241219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, 242219820Sjeff list_item); 243219820Sjeff CL_DBG("cl_event_wheel_dump: Found event key:<0x%" 244219820Sjeff PRIx64 ">, aging time:%" PRIu64 "\n", 245219820Sjeff p_event->key, p_event->aging_time); 246219820Sjeff p_list_item = cl_qlist_next(p_list_item); 247219820Sjeff } 248219820Sjeff} 249219820Sjeff 250219820Sjeffvoid cl_event_wheel_destroy(IN cl_event_wheel_t * const p_event_wheel) 251219820Sjeff{ 252219820Sjeff cl_list_item_t *p_list_item; 253219820Sjeff cl_map_item_t *p_map_item; 254219820Sjeff cl_event_wheel_reg_info_t *p_event; 255219820Sjeff 256219820Sjeff /* we need to get a lock */ 257219820Sjeff cl_spinlock_acquire(&p_event_wheel->lock); 258219820Sjeff 259219820Sjeff cl_event_wheel_dump(p_event_wheel); 260219820Sjeff 261219820Sjeff /* go over all the items in the list and remove them */ 262219820Sjeff p_list_item = cl_qlist_remove_head(&p_event_wheel->events_wheel); 263219820Sjeff while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { 264219820Sjeff p_event = 265219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, 266219820Sjeff list_item); 267219820Sjeff 268219820Sjeff CL_DBG("cl_event_wheel_destroy: Found outstanding event" 269219820Sjeff " key:<0x%" PRIx64 ">\n", p_event->key); 270219820Sjeff 271219820Sjeff /* remove it from the map */ 272219820Sjeff p_map_item = &(p_event->map_item); 273219820Sjeff cl_qmap_remove_item(&p_event_wheel->events_map, p_map_item); 274219820Sjeff free(p_event); /* allocated by cl_event_wheel_reg */ 275219820Sjeff p_list_item = 276219820Sjeff cl_qlist_remove_head(&p_event_wheel->events_wheel); 277219820Sjeff } 278219820Sjeff 279219820Sjeff /* destroy the timer */ 280219820Sjeff cl_timer_destroy(&p_event_wheel->timer); 281219820Sjeff 282219820Sjeff /* destroy the lock (this should be done without releasing - we don't want 283219820Sjeff any other run to grab the lock at this point. */ 284219820Sjeff cl_spinlock_release(&p_event_wheel->lock); 285219820Sjeff cl_spinlock_destroy(&(p_event_wheel->lock)); 286219820Sjeff} 287219820Sjeff 288219820Sjeffcl_status_t 289219820Sjeffcl_event_wheel_reg(IN cl_event_wheel_t * const p_event_wheel, 290219820Sjeff IN const uint64_t key, 291219820Sjeff IN const uint64_t aging_time_usec, 292219820Sjeff IN cl_pfn_event_aged_cb_t pfn_callback, 293219820Sjeff IN void *const context) 294219820Sjeff{ 295219820Sjeff cl_event_wheel_reg_info_t *p_event; 296219820Sjeff uint64_t timeout; 297219820Sjeff uint32_t to; 298219820Sjeff cl_status_t cl_status = CL_SUCCESS; 299219820Sjeff cl_list_item_t *prev_event_list_item; 300219820Sjeff cl_map_item_t *p_map_item; 301219820Sjeff 302219820Sjeff /* Get the lock on the manager */ 303219820Sjeff cl_spinlock_acquire(&(p_event_wheel->lock)); 304219820Sjeff 305219820Sjeff cl_event_wheel_dump(p_event_wheel); 306219820Sjeff 307219820Sjeff /* Make sure such a key does not exists */ 308219820Sjeff p_map_item = cl_qmap_get(&p_event_wheel->events_map, key); 309219820Sjeff if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { 310219820Sjeff CL_DBG("cl_event_wheel_reg: Already exists key:0x%" 311219820Sjeff PRIx64 "\n", key); 312219820Sjeff 313219820Sjeff /* already there - remove it from the list as it is getting a new time */ 314219820Sjeff p_event = 315219820Sjeff PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, 316219820Sjeff map_item); 317219820Sjeff 318219820Sjeff /* remove the item from the qlist */ 319219820Sjeff cl_qlist_remove_item(&p_event_wheel->events_wheel, 320219820Sjeff &p_event->list_item); 321219820Sjeff /* and the qmap */ 322219820Sjeff cl_qmap_remove_item(&p_event_wheel->events_map, 323219820Sjeff &p_event->map_item); 324219820Sjeff } else { 325219820Sjeff /* make a new one */ 326219820Sjeff p_event = (cl_event_wheel_reg_info_t *) 327219820Sjeff malloc(sizeof(cl_event_wheel_reg_info_t)); 328219820Sjeff p_event->num_regs = 0; 329219820Sjeff } 330219820Sjeff 331219820Sjeff p_event->key = key; 332219820Sjeff p_event->aging_time = aging_time_usec; 333219820Sjeff p_event->pfn_aged_callback = pfn_callback; 334219820Sjeff p_event->context = context; 335219820Sjeff p_event->num_regs++; 336219820Sjeff 337219820Sjeff CL_DBG("cl_event_wheel_reg: Registering event key:0x%" PRIx64 338219820Sjeff " aging in %u [msec]\n", p_event->key, 339219820Sjeff (uint32_t) ((p_event->aging_time - 340219820Sjeff cl_get_time_stamp()) / 1000)); 341219820Sjeff 342219820Sjeff /* If the list is empty - need to start the timer */ 343219820Sjeff if (cl_is_qlist_empty(&p_event_wheel->events_wheel)) { 344219820Sjeff /* Edward Bortnikov 03/29/2003 345219820Sjeff * ++TBD Consider moving the timer manipulation behind the list manipulation. 346219820Sjeff */ 347219820Sjeff 348219820Sjeff /* calculate the new timeout */ 349219820Sjeff timeout = 350219820Sjeff (p_event->aging_time - cl_get_time_stamp() + 500) / 1000; 351219820Sjeff 352219820Sjeff /* stop the timer if it is running */ 353219820Sjeff 354219820Sjeff /* Edward Bortnikov 03/29/2003 355219820Sjeff * Don't call cl_timer_stop() because it spins forever. 356219820Sjeff * cl_timer_start() will invoke cl_timer_stop() by itself. 357219820Sjeff * 358219820Sjeff * The problematic scenario is when __cl_event_wheel_callback() 359219820Sjeff * is in race condition with this code. It sets timer.in_timer_cb 360219820Sjeff * to TRUE and then blocks on p_event_wheel->lock. Following this, 361219820Sjeff * the call to cl_timer_stop() hangs. Following this, the whole system 362219820Sjeff * enters into a deadlock. 363219820Sjeff * 364219820Sjeff * cl_timer_stop(&p_event_wheel->timer); 365219820Sjeff */ 366219820Sjeff 367219820Sjeff /* The timeout for the cl_timer_start should be given as uint32_t. 368219820Sjeff if there is an overflow - warn about it. */ 369219820Sjeff to = (uint32_t) timeout; 370219820Sjeff if (timeout > (uint32_t) timeout) { 371219820Sjeff to = 0xffffffff; /* max 32 bit timer */ 372219820Sjeff CL_DBG("cl_event_wheel_reg: timeout requested is " 373219820Sjeff "too large. Using timeout: %u\n", to); 374219820Sjeff } 375219820Sjeff 376219820Sjeff /* start the timer to the timeout [msec] */ 377219820Sjeff cl_status = cl_timer_start(&p_event_wheel->timer, to); 378219820Sjeff if (cl_status != CL_SUCCESS) { 379219820Sjeff CL_DBG("cl_event_wheel_reg : ERR 6103: " 380219820Sjeff "Failed to start timer\n"); 381219820Sjeff goto Exit; 382219820Sjeff } 383219820Sjeff } 384219820Sjeff 385219820Sjeff /* insert the object to the qlist and the qmap */ 386219820Sjeff 387219820Sjeff /* BUT WE MUST INSERT IT IN A SORTED MANNER */ 388219820Sjeff prev_event_list_item = 389219820Sjeff cl_qlist_find_from_tail(&p_event_wheel->events_wheel, 390219820Sjeff __event_will_age_before, 391219820Sjeff &p_event->aging_time); 392219820Sjeff 393219820Sjeff cl_qlist_insert_next(&p_event_wheel->events_wheel, 394219820Sjeff prev_event_list_item, &p_event->list_item); 395219820Sjeff 396219820Sjeff cl_qmap_insert(&p_event_wheel->events_map, key, &(p_event->map_item)); 397219820Sjeff 398219820SjeffExit: 399219820Sjeff cl_spinlock_release(&p_event_wheel->lock); 400219820Sjeff 401219820Sjeff return cl_status; 402219820Sjeff} 403219820Sjeff 404219820Sjeffvoid 405219820Sjeffcl_event_wheel_unreg(IN cl_event_wheel_t * const p_event_wheel, IN uint64_t key) 406219820Sjeff{ 407219820Sjeff cl_event_wheel_reg_info_t *p_event; 408219820Sjeff cl_map_item_t *p_map_item; 409219820Sjeff 410219820Sjeff CL_DBG("cl_event_wheel_unreg: " "Removing key:0x%" PRIx64 "\n", key); 411219820Sjeff 412219820Sjeff cl_spinlock_acquire(&p_event_wheel->lock); 413219820Sjeff p_map_item = cl_qmap_get(&p_event_wheel->events_map, key); 414219820Sjeff if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { 415219820Sjeff /* we found such an item. */ 416219820Sjeff p_event = 417219820Sjeff PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, 418219820Sjeff map_item); 419219820Sjeff 420219820Sjeff /* remove the item from the qlist */ 421219820Sjeff cl_qlist_remove_item(&p_event_wheel->events_wheel, 422219820Sjeff &(p_event->list_item)); 423219820Sjeff /* remove the item from the qmap */ 424219820Sjeff cl_qmap_remove_item(&p_event_wheel->events_map, 425219820Sjeff &(p_event->map_item)); 426219820Sjeff 427219820Sjeff CL_DBG("cl_event_wheel_unreg: Removed key:0x%" PRIx64 "\n", 428219820Sjeff key); 429219820Sjeff 430219820Sjeff /* free the item */ 431219820Sjeff free(p_event); 432219820Sjeff } else { 433219820Sjeff CL_DBG("cl_event_wheel_unreg: did not find key:0x%" PRIx64 434219820Sjeff "\n", key); 435219820Sjeff } 436219820Sjeff 437219820Sjeff cl_spinlock_release(&p_event_wheel->lock); 438219820Sjeff} 439219820Sjeff 440219820Sjeffuint32_t 441219820Sjeffcl_event_wheel_num_regs(IN cl_event_wheel_t * const p_event_wheel, 442219820Sjeff IN uint64_t key) 443219820Sjeff{ 444219820Sjeff 445219820Sjeff cl_event_wheel_reg_info_t *p_event; 446219820Sjeff cl_map_item_t *p_map_item; 447219820Sjeff uint32_t num_regs = 0; 448219820Sjeff 449219820Sjeff /* try to find the key in the map */ 450219820Sjeff CL_DBG("cl_event_wheel_num_regs: Looking for key:0x%" 451219820Sjeff PRIx64 "\n", key); 452219820Sjeff 453219820Sjeff cl_spinlock_acquire(&p_event_wheel->lock); 454219820Sjeff p_map_item = cl_qmap_get(&p_event_wheel->events_map, key); 455219820Sjeff if (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { 456219820Sjeff /* ok so we can simply return it's num_regs */ 457219820Sjeff p_event = 458219820Sjeff PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, 459219820Sjeff map_item); 460219820Sjeff num_regs = p_event->num_regs; 461219820Sjeff } 462219820Sjeff 463219820Sjeff cl_spinlock_release(&p_event_wheel->lock); 464219820Sjeff return (num_regs); 465219820Sjeff} 466219820Sjeff 467219820Sjeff#ifdef __CL_EVENT_WHEEL_TEST__ 468219820Sjeff 469219820Sjeff/* Dump out the complete state of the event wheel */ 470219820Sjeffvoid __cl_event_wheel_dump(IN cl_event_wheel_t * const p_event_wheel) 471219820Sjeff{ 472219820Sjeff cl_list_item_t *p_list_item; 473219820Sjeff cl_map_item_t *p_map_item; 474219820Sjeff cl_event_wheel_reg_info_t *p_event; 475219820Sjeff 476219820Sjeff printf("************** Event Wheel Dump ***********************\n"); 477219820Sjeff printf("Event Wheel List has %u items:\n", 478219820Sjeff cl_qlist_count(&p_event_wheel->events_wheel)); 479219820Sjeff 480219820Sjeff p_list_item = cl_qlist_head(&p_event_wheel->events_wheel); 481219820Sjeff while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel)) { 482219820Sjeff p_event = 483219820Sjeff PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, 484219820Sjeff list_item); 485219820Sjeff printf("Event key:0x%" PRIx64 " Context:%s NumRegs:%u\n", 486219820Sjeff p_event->key, (char *)p_event->context, 487219820Sjeff p_event->num_regs); 488219820Sjeff 489219820Sjeff /* next */ 490219820Sjeff p_list_item = cl_qlist_next(p_list_item); 491219820Sjeff } 492219820Sjeff 493219820Sjeff printf("Event Map has %u items:\n", 494219820Sjeff cl_qmap_count(&p_event_wheel->events_map)); 495219820Sjeff 496219820Sjeff p_map_item = cl_qmap_head(&p_event_wheel->events_map); 497219820Sjeff while (p_map_item != cl_qmap_end(&p_event_wheel->events_map)) { 498219820Sjeff p_event = 499219820Sjeff PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, 500219820Sjeff map_item); 501219820Sjeff printf("Event key:0x%" PRIx64 " Context:%s NumRegs:%u\n", 502219820Sjeff p_event->key, (char *)p_event->context, 503219820Sjeff p_event->num_regs); 504219820Sjeff 505219820Sjeff /* next */ 506219820Sjeff p_map_item = cl_qmap_next(p_map_item); 507219820Sjeff } 508219820Sjeff 509219820Sjeff} 510219820Sjeff 511219820Sjeff/* The callback for aging event */ 512219820Sjeff/* We assume we pass a text context */ 513219820Sjeffvoid __test_event_aging(uint64_t key, void *context) 514219820Sjeff{ 515219820Sjeff printf("*****************************************************\n"); 516219820Sjeff printf("Aged key: 0x%" PRIx64 " Context:%s\n", key, (char *)context); 517219820Sjeff} 518219820Sjeff 519219820Sjeffint main() 520219820Sjeff{ 521219820Sjeff cl_event_wheel_t event_wheel; 522219820Sjeff /* uint64_t key; */ 523219820Sjeff 524219820Sjeff /* construct */ 525219820Sjeff cl_event_wheel_construct(&event_wheel); 526219820Sjeff 527219820Sjeff /* init */ 528219820Sjeff cl_event_wheel_init(&event_wheel); 529219820Sjeff 530219820Sjeff /* Start Playing */ 531219820Sjeff cl_event_wheel_reg(&event_wheel, 1, /* key */ 532219820Sjeff cl_get_time_stamp() + 3000000, /* 3 sec lifetime */ 533219820Sjeff __test_event_aging, /* cb */ 534219820Sjeff "The first Aging Event"); 535219820Sjeff 536219820Sjeff cl_event_wheel_reg(&event_wheel, 2, /* key */ 537219820Sjeff cl_get_time_stamp() + 3000000, /* 3 sec lifetime */ 538219820Sjeff __test_event_aging, /* cb */ 539219820Sjeff "The Second Aging Event"); 540219820Sjeff 541219820Sjeff cl_event_wheel_reg(&event_wheel, 3, /* key */ 542219820Sjeff cl_get_time_stamp() + 3500000, /* 3 sec lifetime */ 543219820Sjeff __test_event_aging, /* cb */ 544219820Sjeff "The Third Aging Event"); 545219820Sjeff 546219820Sjeff __cl_event_wheel_dump(&event_wheel); 547219820Sjeff 548219820Sjeff sleep(2); 549219820Sjeff cl_event_wheel_reg(&event_wheel, 2, /* key */ 550219820Sjeff cl_get_time_stamp() + 8000000, /* 3 sec lifetime */ 551219820Sjeff __test_event_aging, /* cb */ 552219820Sjeff "The Second Aging Event Moved"); 553219820Sjeff 554219820Sjeff __cl_event_wheel_dump(&event_wheel); 555219820Sjeff 556219820Sjeff sleep(1); 557219820Sjeff /* remove the third event */ 558219820Sjeff cl_event_wheel_unreg(&event_wheel, 3); /* key */ 559219820Sjeff 560219820Sjeff /* get the number of registrations for the keys */ 561219820Sjeff printf("Event 1 Registered: %u\n", 562219820Sjeff cl_event_wheel_num_regs(&event_wheel, 1)); 563219820Sjeff printf("Event 2 Registered: %u\n", 564219820Sjeff cl_event_wheel_num_regs(&event_wheel, 2)); 565219820Sjeff 566219820Sjeff sleep(5); 567219820Sjeff /* destroy */ 568219820Sjeff cl_event_wheel_destroy(&event_wheel); 569219820Sjeff 570219820Sjeff return (0); 571219820Sjeff} 572219820Sjeff 573219820Sjeff#endif /* __CL_EVENT_WHEEL_TEST__ */ 574