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 115
 
115 116
 To remove a timer from the active timer list call timer_del(struct timer_ln*).
116 117
 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.
118
+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 119
 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 120
          - 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 121
 
... ...
@@ -138,7 +140,7 @@ timer_add(&f->timer, rand());
138 140
 timer_del(&f->timer); /* if the timer is already expired => f is already
139 141
                          deleted => problems */
140 142
 
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.
143
+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 144
 
143 145
 4.5 timer_allow_del
144 146
 -------------------
... ...
@@ -169,8 +171,20 @@ TICKS_TO_MS(t)  /* converts from ticks to milliseconds, can overflow for
169 171
                    that you'll deal with such large values */
170 172
 TICKS_TO_S(t)  /* converts from ticks to s, rounded down */
171 173
 
174
+4.8 Ticks value comparison
175
+---------------------------
172 176
 
173
-4.8 Backward compatibility
177
+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
178
+ one of the macros:
179
+
180
+TICKS_LT(t1, t2)  /*  t1 < t2 */
181
+TICKS_GT(t1, t2)  /*  t1 > t2 */
182
+TICKS_LE(t1, t2)  /*  t1 <= t2 */
183
+TICKS_GE(t1, t2)  /*  t1 >= t2 */
184
+
185
+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.
186
+
187
+4.9 Backward compatibility
174 188
 --------------------------
175 189
 
176 190
 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 498
 /* "public", safe timer add functions
497 499
  * adds a timer at delta ticks from the current time
498 500
  * returns -1 on error, 0 on success
499
- * WARNING: to re-add a deleted or expired timer you must call
501
+ * WARNING: to re-add an expired or deleted timer you must call
500 502
  *          timer_reinit(tl) prior to timer_add
501 503
  *          The default behaviour allows timer_add to add a timer only if it
502
- *          has never been added before.*/
504
+ *          has never been added before.
505
+ */
503 506
 #ifdef TIMER_DEBUG
504 507
 int timer_add_safe(struct timer_ln* tl, ticks_t delta,
505 508
 					const char* file, const char* func, unsigned line)
... ...
@@ -553,18 +556,19 @@ error:
553 556
 
554 557
 /* safe timer delete
555 558
  * 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
- * 
559
+ * returns  <0 on error (-1 if timer not active/already deleted and -2 if 
560
+ *           delete attempted from the timer handler) and 0 on success
559 561
  */
560 562
 #ifdef TIMER_DEBUG
561
-void timer_del_safe(struct timer_ln* tl,
563
+int timer_del_safe(struct timer_ln* tl,
562 564
 					const char* file, const char* func, unsigned line)
563 565
 #else
564
-void timer_del_safe(struct timer_ln* tl)
566
+int timer_del_safe(struct timer_ln* tl)
565 567
 #endif
566 568
 {
569
+	int ret;
567 570
 	
571
+	ret=-1;
568 572
 again:
569 573
 	/* quick exit if timer inactive */
570 574
 	if ( !(tl->flags & F_TIMER_ACTIVE)){
... ...
@@ -580,10 +584,12 @@ again:
580 584
 					tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
581 585
 					tl->init, tl->expires_no);
582 586
 #else
587
+/*
583 588
 		DBG("timer_del called on an inactive timer %p (%p, %p),"
584 589
 					" flags %x\n", tl, tl->next, tl->prev, tl->flags);
590
+*/
585 591
 #endif
586
-		return;
592
+		return -1;
587 593
 	}
588 594
 #ifdef USE_SLOW_TIMER
589 595
 		if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
... ...
@@ -609,7 +615,7 @@ again:
609 615
 						tl->add_line, tl->del_calls, tl->del_func, 
610 616
 						tl->del_file, tl->del_line, tl->init, tl->expires_no);
611 617
 #endif
612
-					return; /* do nothing */
618
+					return -2; /* do nothing */
613 619
 				}
614 620
 				sched_yield(); /* wait for it to complete */
615 621
 				goto again;
... ...
@@ -617,6 +623,7 @@ again:
617 623
 			if (tl->next!=0){
618 624
 				_timer_rm_list(tl); /* detach */
619 625
 				tl->next=tl->prev=0;
626
+				ret=0;
620 627
 #ifdef TIMER_DEBUG
621 628
 				tl->del_file=file;
622 629
 				tl->del_func=func;
... ...
@@ -643,10 +650,13 @@ again:
643 650
 						tl->del_func, tl->del_file, tl->del_line,
644 651
 						tl->init, tl->expires_no);
645 652
 #else
653
+/*
646 654
 				DBG("timer_del: (s) timer %p (%p, %p) flags %x "
647 655
 							"already detached\n",
648 656
 							tl, tl->next, tl->prev, tl->flags);
657
+*/
649 658
 #endif
659
+				ret=-1;
650 660
 			}
651 661
 			UNLOCK_SLOW_TIMER_LIST();
652 662
 		}else{
... ...
@@ -675,7 +685,7 @@ again:
675 685
 						tl->add_line, tl->del_calls, tl->del_func, 
676 686
 						tl->del_file, tl->del_line, tl->init, tl->expires_no);
677 687
 #endif
678
-					return; /* do nothing */
688
+					return -2; /* do nothing */
679 689
 				}
680 690
 				sched_yield(); /* wait for it to complete */
681 691
 				goto again;
... ...
@@ -683,6 +693,7 @@ again:
683 693
 			if ((tl->next!=0)&&(tl->prev!=0)){
684 694
 				_timer_rm_list(tl); /* detach */
685 695
 				tl->next=tl->prev=0;
696
+				ret=0;
686 697
 #ifdef TIMER_DEBUG
687 698
 				tl->del_file=file;
688 699
 				tl->del_func=func;
... ...
@@ -709,15 +720,19 @@ again:
709 720
 						tl->del_func, tl->del_file, tl->del_line,
710 721
 						tl->init, tl->expires_no);
711 722
 #else
723
+/*
712 724
 				DBG("timer_del: (f) timer %p (%p, %p) flags %x "
713 725
 							"already detached\n",
714 726
 							tl, tl->next, tl->prev, tl->flags);
727
+*/
715 728
 #endif
729
+				ret=-1;
716 730
 			}
717 731
 			UNLOCK_TIMER_LIST();
718 732
 #ifdef USE_SLOW_TIMER
719 733
 		}
720 734
 #endif
735
+return ret;
721 736
 }
722 737
 
723 738
 
... ...
@@ -749,7 +764,10 @@ void timer_allow_del()
749 764
 }
750 765
 
751 766
 
752
-/* called from timer_handle, must be called with the timer lock held */
767
+/* called from timer_handle, must be called with the timer lock held
768
+ * WARNING: expired one shot timers are _not_ automatically reinit
769
+ *          (because they could have been already freed from the timer
770
+ *           handler so a reinit would not be safe!) */
753 771
 inline static void timer_list_expire(ticks_t t, struct timer_head* h
754 772
 #ifdef USE_SLOW_TIMER
755 773
 										, 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 55
 #define TICKS_TO_MS(t) (((t)*1000U)/TIMER_TICKS_HZ)
55 56
 
56 57
 
58
+/* ticks comparison operations: t1 OP t2, where OP can be <, >, <=, >= */
59
+#define TICKS_CMP_OP(t1, t2, OP) \
60
+	(((s_ticks_t)((ticks_t)(t1)-(ticks_t)(t2))) OP (s_ticks_t)0)
61
+/* t1 < t2 */
62
+#define TICKS_LT(t1, t2)  TICKS_CMP_OP(t1, t2, <)
63
+/* t1 <= t2 */
64
+#define TICKS_LE(t1, t2)  TICKS_CMP_OP(t1, t2, <=)
65
+/* t1 > t2 */
66
+#define TICKS_GT(t1, t2)  TICKS_CMP_OP(t1, t2, >)
67
+/* t1 >= t2 */
68
+#define TICKS_GE(t1, t2)  TICKS_CMP_OP(t1, t2, >=)
69
+
70
+
57 71
 typedef unsigned int ticks_t;/* type used to keep the ticks (must be 32 bits)*/
58 72
 typedef signed   int s_ticks_t; /* signed ticks type */
59 73