e23d51c2ee67b4b9631586b9d55ce86aa2fc4f3d
[mirror/winof/.git] / ulp / opensm / user / opensm / cl_event_wheel.c
1 /*
2  * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  *
6  * This software is available to you under the OpenIB.org BSD license
7  * below:
8  *
9  *     Redistribution and use in source and binary forms, with or
10  *     without modification, are permitted provided that the following
11  *     conditions are met:
12  *
13  *      - Redistributions of source code must retain the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer.
16  *
17  *      - Redistributions in binary form must reproduce the above
18  *        copyright notice, this list of conditions and the following
19  *        disclaimer in the documentation and/or other materials
20  *        provided with the distribution.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29  * SOFTWARE.
30  *
31  * $Id$
32  */
33
34
35 #if HAVE_CONFIG_H
36 #  include <config.h>
37 #endif /* HAVE_CONFIG_H */
38
39 #include <math.h>
40 #include <complib/cl_debug.h>
41 #include <opensm/cl_event_wheel.h>
42
43 cl_status_t
44 __event_will_age_before(
45   IN  const cl_list_item_t* const   p_list_item,
46   IN  void*                context )
47 {
48   uint64_t aging_time = *((uint64_t*)context);
49   cl_event_wheel_reg_info_t *p_event;
50
51   p_event =
52     PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
53
54   if (p_event->aging_time < aging_time)
55     return CL_SUCCESS;
56   else
57     return CL_NOT_FOUND;
58 }
59
60 void
61 __cl_event_wheel_callback( IN void* context )
62 {
63   cl_event_wheel_t *p_event_wheel = (cl_event_wheel_t *)context;
64   cl_list_item_t *p_list_item, *p_prev_event_list_item;
65   cl_list_item_t *p_list_next_item;
66   cl_event_wheel_reg_info_t *p_event;
67   uint64_t current_time;
68   uint64_t next_aging_time;
69   uint32_t new_timeout;
70   cl_status_t cl_status;
71
72   OSM_LOG_ENTER( p_event_wheel->p_log, __cl_event_wheel_callback);
73
74   /* might be during closing ...  */
75   if (p_event_wheel->closing)
76   {
77     goto JustExit;
78   }
79
80   current_time = cl_get_time_stamp();
81
82   if (NULL != p_event_wheel->p_external_lock) {
83
84     /* Take care of the order of acquiring locks to avoid the deadlock!
85      * The external lock goes first.
86      */
87     CL_SPINLOCK_ACQUIRE(p_event_wheel->p_external_lock);
88   }
89
90   CL_SPINLOCK_ACQUIRE(&p_event_wheel->lock);
91
92   p_list_item = cl_qlist_head(&p_event_wheel->events_wheel);
93   if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel))
94   {
95     /* the list is empty - nothing to do */
96     goto Exit;
97   }
98
99   /* we found such an item.  get the p_event */
100   p_event = PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
101
102   while (p_event->aging_time <= current_time)
103   {
104     /* this object has aged - invoke it's callback */
105     if (p_event->pfn_aged_callback)
106     {
107       next_aging_time =
108         p_event->pfn_aged_callback(
109           p_event->key, p_event->num_regs, p_event->context);
110     }
111     else
112     {
113       next_aging_time = 0;
114     }
115
116     /* point to the next object in the wheel */
117     p_list_next_item = cl_qlist_next(p_list_item);
118
119     /* We need to retire the event if the next aging time passed */
120     if (next_aging_time < current_time)
121     {
122       /* remove it from the map */
123       cl_qmap_remove_item(&p_event_wheel->events_map, &(p_event->map_item));
124
125       /* pop p_event from the wheel */
126       cl_qlist_remove_head(&p_event_wheel->events_wheel);
127
128       /* delete the event info object - allocated by cl_event_wheel_reg */
129       cl_free(p_event);
130     }
131     else
132     {
133       /* update the required aging time */
134       p_event->aging_time = next_aging_time;
135       p_event->num_regs++;
136
137       /* do not remove from the map  - but remove from the list head and
138          place in the correct position */
139
140       /* pop p_event from the wheel */
141       cl_qlist_remove_head(&p_event_wheel->events_wheel);
142
143       /* find the event that ages just before */
144       p_prev_event_list_item = cl_qlist_find_from_tail(
145         &p_event_wheel->events_wheel,
146         __event_will_age_before,
147         &p_event->aging_time);
148
149       /* insert just after */
150       cl_qlist_insert_next(
151         &p_event_wheel->events_wheel,
152         p_prev_event_list_item ,
153         &p_event->list_item);
154
155       /* as we have modified the list - restart from first item: */
156       p_list_next_item = cl_qlist_head(&p_event_wheel->events_wheel);
157     }
158
159     /* advance to next event */
160     p_list_item = p_list_next_item;
161     if (p_list_item == cl_qlist_end(&p_event_wheel->events_wheel))
162     {
163       /* the list is empty - nothing to do */
164       break;
165     }
166
167     /* get the p_event */
168     p_event =  PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
169   }
170
171   /* We need to restart the timer only if the list is not empty now */
172   if (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel))
173   {
174     /* get the p_event */
175     p_event = PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
176
177     /* start the timer to the timeout [msec] */
178     new_timeout = (uint32_t)(((p_event->aging_time - current_time)/1000)+0.5);
179     osm_log (p_event_wheel->p_log, OSM_LOG_DEBUG,
180                "__cl_event_wheel_callback : "
181                "Restart timer in : %u [msec]\n",
182              new_timeout);
183     cl_status = cl_timer_start(&p_event_wheel->timer, new_timeout);
184     if (cl_status != CL_SUCCESS)
185     {
186       osm_log (p_event_wheel->p_log, OSM_LOG_ERROR,
187                "__cl_event_wheel_callback : ERROR 1000: "
188                "Failed to start timer\n" );
189     }
190   }
191
192   /* release the lock */
193  Exit:
194   CL_SPINLOCK_RELEASE( &p_event_wheel->lock );
195   if (NULL != p_event_wheel->p_external_lock) {
196     CL_SPINLOCK_RELEASE(p_event_wheel->p_external_lock);
197   }
198  JustExit:
199   OSM_LOG_EXIT( p_event_wheel->p_log );
200 }
201
202 /*
203  * Construct and Initialize
204  */
205
206 void
207 cl_event_wheel_construct(
208   IN  cl_event_wheel_t* const p_event_wheel )
209 {
210   cl_spinlock_construct( &(p_event_wheel->lock) );
211   cl_timer_construct( &(p_event_wheel->timer) );
212 }
213
214 cl_status_t
215 cl_event_wheel_init(
216   IN  cl_event_wheel_t* const p_event_wheel,
217   IN  osm_log_t *p_log)
218 {
219   cl_status_t cl_status = CL_SUCCESS;
220
221   OSM_LOG_ENTER( p_log, cl_event_wheel_init );
222
223   /* initialize */
224   p_event_wheel->p_log = p_log;
225   p_event_wheel->p_external_lock = NULL;
226   p_event_wheel->closing = FALSE;
227   cl_status =  cl_spinlock_init( &(p_event_wheel->lock) );
228   if (cl_status != CL_SUCCESS)
229   {
230     osm_log (p_event_wheel->p_log, OSM_LOG_ERROR,
231              "cl_event_wheel_init : ERROR 1000: "
232              "Failed to initialize cl_spinlock\n" );
233     goto Exit;
234   }
235   cl_qlist_init( &p_event_wheel->events_wheel);
236   cl_qmap_init( &p_event_wheel->events_map );
237
238   /* init the timer with timeout */
239   cl_status = cl_timer_init(&p_event_wheel->timer,
240                             __cl_event_wheel_callback,
241                             p_event_wheel ); /* cb context */
242
243   if (cl_status != CL_SUCCESS)
244   {
245     osm_log (p_event_wheel->p_log, OSM_LOG_ERROR,
246              "cl_event_wheel_init : ERROR 1000: "
247              "Failed to initialize cl_timer\n" );
248     goto Exit;
249   }
250  Exit:
251   OSM_LOG_EXIT( p_event_wheel->p_log );
252   return(cl_status);
253 }
254
255 cl_status_t
256 cl_event_wheel_init_ex(
257   IN  cl_event_wheel_t* const p_event_wheel,
258   IN  osm_log_t       *p_log,
259   IN  cl_spinlock_t   *p_external_lock)
260 {
261   cl_status_t cl_status;
262
263   cl_status = cl_event_wheel_init(p_event_wheel, p_log);
264   if (CL_SUCCESS != cl_status)
265   {
266     return cl_status;
267   }
268
269   p_event_wheel->p_external_lock = p_external_lock;
270   return cl_status;
271 }
272
273 void
274 cl_event_wheel_dump(
275   IN cl_event_wheel_t* const p_event_wheel )
276 {
277   cl_list_item_t *p_list_item;
278   cl_event_wheel_reg_info_t *p_event;
279
280   OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_dump );
281
282   p_list_item = cl_qlist_head(&p_event_wheel->events_wheel);
283   osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
284            "cl_event_wheel_dump: "
285            "event_wheel ptr:%p \n",
286            p_event_wheel);
287
288   while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel) )
289   {
290     p_event = PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
291     osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
292              "cl_event_wheel_dump: "
293              "Found event key:<0x%"PRIx64">, aging time:%" PRIu64".\n",
294              p_event->key, p_event->aging_time );
295     p_list_item = cl_qlist_next( p_list_item );
296   }
297   OSM_LOG_EXIT( p_event_wheel->p_log );
298 }
299
300 void
301 cl_event_wheel_destroy(
302   IN cl_event_wheel_t* const p_event_wheel )
303 {
304   cl_list_item_t  *p_list_item;
305   cl_map_item_t   *p_map_item;
306   cl_event_wheel_reg_info_t *p_event;
307
308   OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_destroy );
309
310   /* we need to get a lock */
311   CL_SPINLOCK_ACQUIRE( &p_event_wheel->lock );
312
313   cl_event_wheel_dump( p_event_wheel);
314
315   /* go over all the items in the list and remove them */
316   p_list_item = cl_qlist_remove_head(&p_event_wheel->events_wheel);
317   while ( p_list_item != cl_qlist_end(&p_event_wheel->events_wheel) )
318   {
319     p_event = PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
320
321     osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
322              "cl_event_wheel_destroy: "
323              "Found outstanding event key:<0x%"PRIx64">.\n",
324              p_event->key );
325
326     /* remove it from the map */
327     p_map_item = &(p_event->map_item);
328     cl_qmap_remove_item(&p_event_wheel->events_map, p_map_item);
329     cl_free(p_event); /* allocated by cl_event_wheel_reg */
330     p_list_item = cl_qlist_remove_head(&p_event_wheel->events_wheel);
331   }
332
333   /* destroy the timer */
334   cl_timer_destroy( &p_event_wheel->timer );
335
336   /* destroy the lock (this should be done without releasing - we don't want
337      any other run to grab the lock at this point. */
338   CL_SPINLOCK_RELEASE( &p_event_wheel->lock );
339   cl_spinlock_destroy( &(p_event_wheel->lock) );
340
341   OSM_LOG_EXIT( p_event_wheel->p_log );
342 }
343
344 cl_status_t
345 cl_event_wheel_reg(
346   IN cl_event_wheel_t* const p_event_wheel,
347   IN const uint64_t          key,
348   IN const uint64_t          aging_time_usec,
349   IN cl_pfn_event_aged_cb_t  pfn_callback,
350   IN void* const       context )
351 {
352   cl_event_wheel_reg_info_t *p_event;
353   uint64_t timeout;
354   cl_status_t cl_status = CL_SUCCESS;
355   cl_list_item_t *prev_event_list_item;
356   cl_map_item_t  *p_map_item;
357
358   OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_reg );
359
360   /* Get the lock on the manager */
361   CL_SPINLOCK_ACQUIRE( &(p_event_wheel->lock) );
362
363   cl_event_wheel_dump( p_event_wheel);
364
365   /* Make sure such a key does not exists */
366   p_map_item = cl_qmap_get( &p_event_wheel->events_map, key );
367   if (p_map_item != cl_qmap_end( &p_event_wheel->events_map ))
368   {
369     osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
370              "cl_event_wheel_reg: "
371              "Already exists key:0x%"PRIx64"\n", key);
372
373     /* already there - remove it from the list as it is getting a new time */
374     p_event = PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, map_item);
375
376     /* remove the item from the qlist */
377     cl_qlist_remove_item( &p_event_wheel->events_wheel, &p_event->list_item );
378     /* and the qmap */
379     cl_qmap_remove_item( &p_event_wheel->events_map, &p_event->map_item );
380   }
381   else
382   {
383     /* make a new one */
384     p_event = (cl_event_wheel_reg_info_t *)
385       cl_malloc( sizeof (cl_event_wheel_reg_info_t) );
386     p_event->num_regs = 0;
387   }
388
389   p_event->key = key;
390   p_event->aging_time = aging_time_usec;
391   p_event->pfn_aged_callback = pfn_callback;
392   p_event->context = context;
393   p_event->num_regs++;
394
395   osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
396            "cl_event_wheel_reg: "
397            "Registering event key:0x%"PRIx64" aging in %u [msec].\n",
398            p_event->key,
399            (uint32_t)((p_event->aging_time - cl_get_time_stamp()) / 1000 ));
400
401   /* If the list is empty - need to start the timer */
402   if (cl_is_qlist_empty(&p_event_wheel->events_wheel))
403   {
404     /* Edward Bortnikov 03/29/2003
405      * ++TBD Consider moving the timer manipulation behind the list manipulation.
406      */
407
408     /* calculate the new timeout */
409     timeout = (p_event->aging_time - cl_get_time_stamp() + 500) / 1000;
410
411     /* stop the timer if it is running */
412
413     /* Edward Bortnikov 03/29/2003
414      * Don't call cl_timer_stop() because it spins forever.
415      * cl_timer_start() will invoke cl_timer_stop() by itself.
416      *
417      * The problematic scenario is when __cl_event_wheel_callback()
418      * is in race condition with this code. It sets timer.in_timer_cb
419      * to TRUE and then blocks on p_event_wheel->lock. Following this,
420      * the call to cl_timer_stop() hangs. Following this, the whole system
421      * enters into a deadlock.
422      *
423      * cl_timer_stop(&p_event_wheel->timer);
424      */
425
426     /* The timeout for the cl_timer_start should be given as uint32_t.
427        if there is an overflow - warn about it. */
428     if ( timeout > (uint32_t)timeout )
429     {
430       osm_log (p_event_wheel->p_log, OSM_LOG_INFO,
431                "cl_event_wheel_reg: "
432                "timeout requested is too large. Using timeout: %u \n",
433                (uint32_t)timeout );
434     }
435
436     /* start the timer to the timeout [msec] */
437     cl_status = cl_timer_start(&p_event_wheel->timer, (uint32_t)timeout);
438
439     if (cl_status != CL_SUCCESS)
440     {
441       osm_log (p_event_wheel->p_log, OSM_LOG_ERROR,
442                "cl_event_wheel_reg : ERROR 1000: "
443                "Failed to start timer\n" );
444       goto Exit;
445     }
446   }
447
448   /* insert the object to the qlist and the qmap */
449
450   /* BUT WE MUST INSERT IT IN A SORTED MANNER */
451   prev_event_list_item = cl_qlist_find_from_tail(
452     &p_event_wheel->events_wheel,
453     __event_will_age_before,
454     &p_event->aging_time);
455
456   cl_qlist_insert_next(
457     &p_event_wheel->events_wheel,
458     prev_event_list_item ,
459     &p_event->list_item);
460
461   cl_qmap_insert( &p_event_wheel->events_map, key, &(p_event->map_item));
462
463  Exit:
464   CL_SPINLOCK_RELEASE( &p_event_wheel->lock );
465   OSM_LOG_EXIT( p_event_wheel->p_log );
466
467   return cl_status;
468 }
469
470 void
471 cl_event_wheel_unreg(
472   IN cl_event_wheel_t* const p_event_wheel,
473   IN uint64_t key )
474 {
475   cl_event_wheel_reg_info_t *p_event;
476   cl_map_item_t* p_map_item;
477
478   OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_unreg );
479
480   osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
481            "cl_event_wheel_unreg: "
482            "Removing key:0x%"PRIx64".\n", key );
483
484   CL_SPINLOCK_ACQUIRE( &p_event_wheel->lock );
485   p_map_item = cl_qmap_get( &p_event_wheel->events_map, key );
486   if (p_map_item != cl_qmap_end( &p_event_wheel->events_map ))
487   {
488     /* we found such an item. */
489     p_event = PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, map_item);
490
491     /* remove the item from the qlist */
492     cl_qlist_remove_item( &p_event_wheel->events_wheel, &(p_event->list_item));
493     /* remove the item from the qmap */
494     cl_qmap_remove_item( &p_event_wheel->events_map, &(p_event->map_item) );
495
496     osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
497              "cl_event_wheel_unreg: "
498              "Removed key:0x%"PRIx64".\n", key );
499
500     /* free the item */
501     cl_free(p_event);
502   }
503   else
504   {
505     osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
506              "cl_event_wheel_unreg: "
507              "Did not find key:0x%"PRIx64"\n", key );
508   }
509
510   CL_SPINLOCK_RELEASE( &p_event_wheel->lock );
511   OSM_LOG_EXIT( p_event_wheel->p_log );
512
513 }
514
515 uint32_t
516 cl_event_wheel_num_regs(
517   IN cl_event_wheel_t* const p_event_wheel,
518   IN uint64_t key )
519 {
520
521   cl_event_wheel_reg_info_t *p_event;
522   cl_map_item_t* p_map_item;
523   uint32_t num_regs = 0;
524
525   OSM_LOG_ENTER( p_event_wheel->p_log, cl_event_wheel_num_regs );
526
527   /* try to find the key in the map */
528   osm_log( p_event_wheel->p_log, OSM_LOG_DEBUG,
529            "cl_event_wheel_num_regs: "
530            "Looking for key:0x%"PRIx64".\n", key );
531
532   CL_SPINLOCK_ACQUIRE( &p_event_wheel->lock );
533   p_map_item = cl_qmap_get( &p_event_wheel->events_map, key );
534   if (p_map_item != cl_qmap_end( &p_event_wheel->events_map ))
535   {
536     /* ok so we can simply return it's num_regs */
537     p_event = PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, map_item);
538     num_regs = p_event->num_regs;
539   }
540
541   CL_SPINLOCK_RELEASE( &p_event_wheel->lock );
542   OSM_LOG_EXIT( p_event_wheel->p_log );
543   return(num_regs);
544 }
545
546 #ifdef __CL_EVENT_WHEEL_TEST__
547
548 /* Dump out the complete state of the event wheel */
549 void __cl_event_wheel_dump(
550   IN cl_event_wheel_t* const p_event_wheel)
551 {
552   cl_list_item_t *p_list_item;
553   cl_map_item_t  *p_map_item;
554   cl_event_wheel_reg_info_t *p_event;
555
556   printf("************** Event Wheel Dump ***********************\n");
557   printf("Event Wheel List has %u items:\n",
558          cl_qlist_count( &p_event_wheel->events_wheel ));
559
560   p_list_item = cl_qlist_head(&p_event_wheel->events_wheel);
561   while (p_list_item != cl_qlist_end(&p_event_wheel->events_wheel))
562   {
563     p_event = PARENT_STRUCT(p_list_item, cl_event_wheel_reg_info_t, list_item);
564     printf("Event key:0x%"PRIx64" Conetxt:%s NumRegs:%u\n",
565            p_event->key, (char *)p_event->context, p_event->num_regs);
566
567     /* next */
568     p_list_item = cl_qlist_next(p_list_item);
569   }
570
571   printf("Event Map has %u items:\n",
572          cl_qmap_count( &p_event_wheel->events_map ));
573
574   p_map_item = cl_qmap_head(&p_event_wheel->events_map);
575   while (p_map_item != cl_qmap_end(&p_event_wheel->events_map))
576   {
577     p_event = PARENT_STRUCT(p_map_item, cl_event_wheel_reg_info_t, map_item);
578     printf("Event key:0x%"PRIx64" Conetxt:%s NumRegs:%u\n",
579            p_event->key, (char *)p_event->context, p_event->num_regs);
580
581     /* next */
582     p_map_item = cl_qmap_next(p_map_item);
583   }
584
585 }
586
587 /* The callback for aging event */
588 /* We assume we pass a text context */
589 void __test_event_aging(uint64_t key, void *context)
590 {
591   printf("*****************************************************\n");
592   printf("Aged key: 0x%"PRIx64" Conetxt:%s\n", key, (char *)context);
593 }
594
595 int
596 main ()
597 {
598   osm_log_t log;
599   cl_event_wheel_t event_wheel;
600   /*  uint64_t key; */
601
602   /* construct */
603   osm_log_construct( &log );
604   cl_event_wheel_construct( &event_wheel );
605
606   /* init */
607   osm_log_init( &log, TRUE, 0xff, NULL);
608   cl_event_wheel_init( &event_wheel, &log );
609
610   /* Start Playing */
611   cl_event_wheel_reg( &event_wheel,
612                       1, /*  key */
613                       cl_get_time_stamp() + 3000000, /*  3 sec lifetime */
614                       __test_event_aging, /*  cb */
615                       "The first Aging Event"
616                       );
617
618   cl_event_wheel_reg( &event_wheel,
619                       2, /*  key */
620                       cl_get_time_stamp() + 3000000, /*  3 sec lifetime */
621                       __test_event_aging, /*  cb */
622                       "The Second Aging Event"
623                       );
624
625   cl_event_wheel_reg( &event_wheel,
626                       3, /*  key */
627                       cl_get_time_stamp() + 3500000, /*  3 sec lifetime */
628                       __test_event_aging, /*  cb */
629                       "The Third Aging Event"
630                       );
631
632   __cl_event_wheel_dump(&event_wheel);
633
634   sleep(2);
635   cl_event_wheel_reg( &event_wheel,
636                       2, /*  key */
637                       cl_get_time_stamp() + 8000000, /*  3 sec lifetime */
638                       __test_event_aging, /*  cb */
639                       "The Second Aging Event Moved"
640                       );
641
642   __cl_event_wheel_dump(&event_wheel);
643
644   sleep(1);
645   /* remove the third event */
646   cl_event_wheel_unreg( &event_wheel,
647                         3); /*  key */
648
649   /* get the number of registrations for the keys */
650   printf("Event 1 Registred: %u\n", cl_event_wheel_num_regs(&event_wheel, 1));
651   printf("Event 2 Registred: %u\n", cl_event_wheel_num_regs(&event_wheel, 2));
652
653   sleep(5);
654   /* destroy */
655   cl_event_wheel_destroy( &event_wheel );
656
657   return(0);
658 }
659
660 #endif /* __CL_EVENT_WHEEL_TEST__ */