Browse code

- timer_del() returns now an int: 0 on success and <0 on error (e.g. timer already deleted or expired, or an attempt to self-delete from a timer handler) - added macros for ticks_t comparisons: TICKS_GTi(t1, t2), TICKS_GE(t1, t2), TICKS_LT (t1, t2) and TICKS_LE (t1, t2) - updated timer docs

Andrei Pelinescu-Onciul authored on 02/07/2007 15:27:39
Showing 4 changed files
... ...
@@ -106,6 +106,7 @@ The timer handler can be periodic, one shot or it can change from call to call.
106 106
 
107 107
 The timer becomes active after you add it with timer_add. timer_add takes as parameters a pointer to the corresponding timer_ln structure and an expire interval (in ticks, use the macros from timer_ticks.h to convert from s/ms).
108 108
 The timer must be intialized (with timer_init()) before adding it the first time.
109
+timer_add returns 0 on success and -1 on error (timer already active or timer not intialized).
109 110
 If you want to re-add a deleted timer (timer_del was called on it) or an expired one shot timer (the timer handlers returned 0 on the last run), you have to re-init it first, either by calling timer_reinit(t) or by calling again timer_init(...). If you don't re-initialize the timer, timer_add will refuse to add it and it will return -1. So if timer_add returns error (-1) it means that either you're trying to re-add a running timer or a deleted/expired timer that was not re-initialized.
110 111
 WARNING: do not initialize/re-initialize a running timer!
111 112
 
... ...
@@ -114,6 +115,7 @@ WARNING: do not initialize/re-initialize a running timer!
114 114
 
115 115
 To remove a timer from the active timer list call timer_del(struct timer_ln*).
116 116
 timer_del is the slowest of all the timer functions. If you are trying to delete a timer whose timer is executing. timer_del will wait until it finishes.
117
+timer_del returns 0 on success and a negative number on error (for now -1 if an attempt to delete and already removed or expired timer is made and -2 if timer_del is called from the timer handle it is supposed to delete).
117 118
 WARNING: - avoid deleting your own timer from its timer handle (if you try it, you'll get a BUG message in the log). If you _must_ have this, you have a broken design. If you still want it, look at  timer_allow_del().
118 119
          - if you have an one shot timer that frees its memory before exiting, make sure you don't call timer_del afterwards (e.g. use some reference counters and free the memory only if the counter is 0).
119 120
 
... ...
@@ -138,7 +140,7 @@ timer_add(&f->timer, rand());
138 138
 timer_del(&f->timer); /* if the timer is already expired => f is already
139 139
                          deleted => problems */
140 140
 
141
-The above timer_del/free_in_one_shot_timer race example is very simple, but consider that you can have much more complex scenarios, when timer_del can be called from different processes on some asynchronous events. If this looks like you're intended usage, make sure you use some  reference counters or some other protection mechanism to avoid the above race.
141
+The above timer_del/free_in_one_shot_timer race example is very simple, but consider that you can have much more complex scenarios, when timer_del can be called from different processes on some asynchronous events. If this looks like your intended usage, make sure you use some  reference counters or some other protection mechanism to avoid the above race.
142 142
 
143 143
 4.5 timer_allow_del
144 144
 -------------------
... ...
@@ -169,8 +171,20 @@ TICKS_TO_MS(t)  /* converts from ticks to milliseconds, can overflow for
169 169
                    that you'll deal with such large values */
170 170
 TICKS_TO_S(t)  /* converts from ticks to s, rounded down */
171 171
 
172
+4.8 Ticks value comparison
173
+---------------------------
172 174
 
173
-4.8 Backward compatibility
175
+The ticks value can (and will) overflow so ticks values should never be compared directly (e.g. ticks1<ticks2). To compare them include timer_ticks.h and use
176
+ one of the macros:
177
+
178
+TICKS_LT(t1, t2)  /*  t1 < t2 */
179
+TICKS_GT(t1, t2)  /*  t1 > t2 */
180
+TICKS_LE(t1, t2)  /*  t1 <= t2 */
181
+TICKS_GE(t1, t2)  /*  t1 >= t2 */
182
+
183
+These macros work as long as the difference between t1 and t2 is less then 2^(sizeof(ticks_t)*8-1). For the default TIMER_TICKS_HZ values, this means 4.25 years.
184
+
185
+4.9 Backward compatibility
174 186
 --------------------------
175 187
 
176 188
 The old  register_timer and get_ticks() are still supported for backward compatibility. This means that you don't have to change your existing working code.
... ...
@@ -33,6 +33,8 @@
33 33
  *              a timer handle; added timer_allow_del()  (andrei)
34 34
  *  2007-05-26  workaround for darwin sigwait() bug, see slow_timer_main() or
35 35
  *              grep __OS_darwin for more info (andrei)
36
+ *  2007-07-01  timer_del() returns <0 if the timer is not active or 
37
+ *               cannot be deleted (andrei)
36 38
  */
37 39
 
38 40
 
... ...
@@ -496,10 +498,11 @@ static inline int _timer_add(ticks_t t, struct timer_ln* tl)
496 496
 /* "public", safe timer add functions
497 497
  * adds a timer at delta ticks from the current time
498 498
  * returns -1 on error, 0 on success
499
- * WARNING: to re-add a deleted or expired timer you must call
499
+ * WARNING: to re-add an expired or deleted timer you must call
500 500
  *          timer_reinit(tl) prior to timer_add
501 501
  *          The default behaviour allows timer_add to add a timer only if it
502
- *          has never been added before.*/
502
+ *          has never been added before.
503
+ */
503 504
 #ifdef TIMER_DEBUG
504 505
 int timer_add_safe(struct timer_ln* tl, ticks_t delta,
505 506
 					const char* file, const char* func, unsigned line)
... ...
@@ -553,18 +556,19 @@ error:
553 553
 
554 554
 /* safe timer delete
555 555
  * deletes tl and inits the list pointer to 0
556
- * WARNING: to be able to reuse a deleted timer you must call
557
- *          timer_reinit(tl) on it
558
- * 
556
+ * returns  <0 on error (-1 if timer not active/already deleted and -2 if 
557
+ *           delete attempted from the timer handler) and 0 on success
559 558
  */
560 559
 #ifdef TIMER_DEBUG
561
-void timer_del_safe(struct timer_ln* tl,
560
+int timer_del_safe(struct timer_ln* tl,
562 561
 					const char* file, const char* func, unsigned line)
563 562
 #else
564
-void timer_del_safe(struct timer_ln* tl)
563
+int timer_del_safe(struct timer_ln* tl)
565 564
 #endif
566 565
 {
566
+	int ret;
567 567
 	
568
+	ret=-1;
568 569
 again:
569 570
 	/* quick exit if timer inactive */
570 571
 	if ( !(tl->flags & F_TIMER_ACTIVE)){
... ...
@@ -580,10 +584,12 @@ again:
580 580
 					tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
581 581
 					tl->init, tl->expires_no);
582 582
 #else
583
+/*
583 584
 		DBG("timer_del called on an inactive timer %p (%p, %p),"
584 585
 					" flags %x\n", tl, tl->next, tl->prev, tl->flags);
586
+*/
585 587
 #endif
586
-		return;
588
+		return -1;
587 589
 	}
588 590
 #ifdef USE_SLOW_TIMER
589 591
 		if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
... ...
@@ -609,7 +615,7 @@ again:
609 609
 						tl->add_line, tl->del_calls, tl->del_func, 
610 610
 						tl->del_file, tl->del_line, tl->init, tl->expires_no);
611 611
 #endif
612
-					return; /* do nothing */
612
+					return -2; /* do nothing */
613 613
 				}
614 614
 				sched_yield(); /* wait for it to complete */
615 615
 				goto again;
... ...
@@ -617,6 +623,7 @@ again:
617 617
 			if (tl->next!=0){
618 618
 				_timer_rm_list(tl); /* detach */
619 619
 				tl->next=tl->prev=0;
620
+				ret=0;
620 621
 #ifdef TIMER_DEBUG
621 622
 				tl->del_file=file;
622 623
 				tl->del_func=func;
... ...
@@ -643,10 +650,13 @@ again:
643 643
 						tl->del_func, tl->del_file, tl->del_line,
644 644
 						tl->init, tl->expires_no);
645 645
 #else
646
+/*
646 647
 				DBG("timer_del: (s) timer %p (%p, %p) flags %x "
647 648
 							"already detached\n",
648 649
 							tl, tl->next, tl->prev, tl->flags);
650
+*/
649 651
 #endif
652
+				ret=-1;
650 653
 			}
651 654
 			UNLOCK_SLOW_TIMER_LIST();
652 655
 		}else{
... ...
@@ -675,7 +685,7 @@ again:
675 675
 						tl->add_line, tl->del_calls, tl->del_func, 
676 676
 						tl->del_file, tl->del_line, tl->init, tl->expires_no);
677 677
 #endif
678
-					return; /* do nothing */
678
+					return -2; /* do nothing */
679 679
 				}
680 680
 				sched_yield(); /* wait for it to complete */
681 681
 				goto again;
... ...
@@ -683,6 +693,7 @@ again:
683 683
 			if ((tl->next!=0)&&(tl->prev!=0)){
684 684
 				_timer_rm_list(tl); /* detach */
685 685
 				tl->next=tl->prev=0;
686
+				ret=0;
686 687
 #ifdef TIMER_DEBUG
687 688
 				tl->del_file=file;
688 689
 				tl->del_func=func;
... ...
@@ -709,15 +720,19 @@ again:
709 709
 						tl->del_func, tl->del_file, tl->del_line,
710 710
 						tl->init, tl->expires_no);
711 711
 #else
712
+/*
712 713
 				DBG("timer_del: (f) timer %p (%p, %p) flags %x "
713 714
 							"already detached\n",
714 715
 							tl, tl->next, tl->prev, tl->flags);
716
+*/
715 717
 #endif
718
+				ret=-1;
716 719
 			}
717 720
 			UNLOCK_TIMER_LIST();
718 721
 #ifdef USE_SLOW_TIMER
719 722
 		}
720 723
 #endif
724
+return ret;
721 725
 }
722 726
 
723 727
 
... ...
@@ -749,7 +764,10 @@ void timer_allow_del()
749 749
 }
750 750
 
751 751
 
752
-/* called from timer_handle, must be called with the timer lock held */
752
+/* called from timer_handle, must be called with the timer lock held
753
+ * WARNING: expired one shot timers are _not_ automatically reinit
754
+ *          (because they could have been already freed from the timer
755
+ *           handler so a reinit would not be safe!) */
753 756
 inline static void timer_list_expire(ticks_t t, struct timer_head* h
754 757
 #ifdef USE_SLOW_TIMER
755 758
 										, struct timer_head* slow_l,
... ...
@@ -161,7 +161,7 @@ void timer_free(struct timer_ln* t);
161 161
 #ifdef TIMER_DEBUG
162 162
 int timer_add_safe(struct timer_ln *tl, ticks_t delta, 
163 163
 					const char*, const char*, unsigned);
164
-void timer_del_safe(struct timer_ln *tl,
164
+int timer_del_safe(struct timer_ln *tl,
165 165
 					const char*, const char*, unsigned);
166 166
 #define timer_add(tl, d) \
167 167
 	timer_add_safe((tl), (d), __FILE__, __FUNCTION__, __LINE__)
... ...
@@ -169,7 +169,7 @@ void timer_del_safe(struct timer_ln *tl,
169 169
 	timer_del_safe((tl), __FILE__, __FUNCTION__, __LINE__)
170 170
 #else
171 171
 int timer_add_safe(struct timer_ln *tl, ticks_t delta);
172
-void timer_del_safe(struct timer_ln *tl);
172
+int timer_del_safe(struct timer_ln *tl);
173 173
 #define timer_add timer_add_safe
174 174
 #define timer_del timer_del_safe
175 175
 #endif
... ...
@@ -30,6 +30,7 @@
30 30
 /* History:
31 31
  * --------
32 32
  *  2005-07-27  complete re-design/re-implemnetation (andrei)
33
+ *  2007-07-02  added ticks comparison macros (andrei)
33 34
  */
34 35
 
35 36
 #ifndef _timer_ticks_h
... ...
@@ -54,6 +55,19 @@
54 54
 #define TICKS_TO_MS(t) (((t)*1000U)/TIMER_TICKS_HZ)
55 55
 
56 56
 
57
+/* ticks comparison operations: t1 OP t2, where OP can be <, >, <=, >= */
58
+#define TICKS_CMP_OP(t1, t2, OP) \
59
+	(((s_ticks_t)((ticks_t)(t1)-(ticks_t)(t2))) OP (s_ticks_t)0)
60
+/* t1 < t2 */
61
+#define TICKS_LT(t1, t2)  TICKS_CMP_OP(t1, t2, <)
62
+/* t1 <= t2 */
63
+#define TICKS_LE(t1, t2)  TICKS_CMP_OP(t1, t2, <=)
64
+/* t1 > t2 */
65
+#define TICKS_GT(t1, t2)  TICKS_CMP_OP(t1, t2, >)
66
+/* t1 >= t2 */
67
+#define TICKS_GE(t1, t2)  TICKS_CMP_OP(t1, t2, >=)
68
+
69
+
57 70
 typedef unsigned int ticks_t;/* type used to keep the ticks (must be 32 bits)*/
58 71
 typedef signed   int s_ticks_t; /* signed ticks type */
59 72