소스 검색

- 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 18 년 전
부모
커밋
7fc49b59b6
4개의 변경된 파일61개의 추가작업 그리고 15개의 파일을 삭제
  1. 16 2
      doc/timers.txt
  2. 29 11
      timer.c
  3. 2 2
      timer.h
  4. 14 0
      timer_ticks.h

+ 16 - 2
doc/timers.txt

@@ -106,6 +106,7 @@ The timer handler can be periodic, one shot or it can change from call to call.
 
 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).
 The timer must be intialized (with timer_init()) before adding it the first time.
+timer_add returns 0 on success and -1 on error (timer already active or timer not intialized).
 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.
 WARNING: do not initialize/re-initialize a running timer!
 
@@ -114,6 +115,7 @@ WARNING: do not initialize/re-initialize a running timer!
 
 To remove a timer from the active timer list call timer_del(struct timer_ln*).
 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.
+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).
 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().
          - 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).
 
@@ -138,7 +140,7 @@ timer_add(&f->timer, rand());
 timer_del(&f->timer); /* if the timer is already expired => f is already
                          deleted => problems */
 
-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.
+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.
 
 4.5 timer_allow_del
 -------------------
@@ -169,8 +171,20 @@ TICKS_TO_MS(t)  /* converts from ticks to milliseconds, can overflow for
                    that you'll deal with such large values */
 TICKS_TO_S(t)  /* converts from ticks to s, rounded down */
 
+4.8 Ticks value comparison
+---------------------------
 
-4.8 Backward compatibility
+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
+ one of the macros:
+
+TICKS_LT(t1, t2)  /*  t1 < t2 */
+TICKS_GT(t1, t2)  /*  t1 > t2 */
+TICKS_LE(t1, t2)  /*  t1 <= t2 */
+TICKS_GE(t1, t2)  /*  t1 >= t2 */
+
+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.
+
+4.9 Backward compatibility
 --------------------------
 
 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.

+ 29 - 11
timer.c

@@ -33,6 +33,8 @@
  *              a timer handle; added timer_allow_del()  (andrei)
  *  2007-05-26  workaround for darwin sigwait() bug, see slow_timer_main() or
  *              grep __OS_darwin for more info (andrei)
+ *  2007-07-01  timer_del() returns <0 if the timer is not active or 
+ *               cannot be deleted (andrei)
  */
 
 
@@ -496,10 +498,11 @@ static inline int _timer_add(ticks_t t, struct timer_ln* tl)
 /* "public", safe timer add functions
  * adds a timer at delta ticks from the current time
  * returns -1 on error, 0 on success
- * WARNING: to re-add a deleted or expired timer you must call
+ * WARNING: to re-add an expired or deleted timer you must call
  *          timer_reinit(tl) prior to timer_add
  *          The default behaviour allows timer_add to add a timer only if it
- *          has never been added before.*/
+ *          has never been added before.
+ */
 #ifdef TIMER_DEBUG
 int timer_add_safe(struct timer_ln* tl, ticks_t delta,
 					const char* file, const char* func, unsigned line)
@@ -553,18 +556,19 @@ error:
 
 /* safe timer delete
  * deletes tl and inits the list pointer to 0
- * WARNING: to be able to reuse a deleted timer you must call
- *          timer_reinit(tl) on it
- * 
+ * returns  <0 on error (-1 if timer not active/already deleted and -2 if 
+ *           delete attempted from the timer handler) and 0 on success
  */
 #ifdef TIMER_DEBUG
-void timer_del_safe(struct timer_ln* tl,
+int timer_del_safe(struct timer_ln* tl,
 					const char* file, const char* func, unsigned line)
 #else
-void timer_del_safe(struct timer_ln* tl)
+int timer_del_safe(struct timer_ln* tl)
 #endif
 {
+	int ret;
 	
+	ret=-1;
 again:
 	/* quick exit if timer inactive */
 	if ( !(tl->flags & F_TIMER_ACTIVE)){
@@ -580,10 +584,12 @@ again:
 					tl->del_calls, tl->del_func, tl->del_file, tl->del_line,
 					tl->init, tl->expires_no);
 #else
+/*
 		DBG("timer_del called on an inactive timer %p (%p, %p),"
 					" flags %x\n", tl, tl->next, tl->prev, tl->flags);
+*/
 #endif
-		return;
+		return -1;
 	}
 #ifdef USE_SLOW_TIMER
 		if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){
@@ -609,7 +615,7 @@ again:
 						tl->add_line, tl->del_calls, tl->del_func, 
 						tl->del_file, tl->del_line, tl->init, tl->expires_no);
 #endif
-					return; /* do nothing */
+					return -2; /* do nothing */
 				}
 				sched_yield(); /* wait for it to complete */
 				goto again;
@@ -617,6 +623,7 @@ again:
 			if (tl->next!=0){
 				_timer_rm_list(tl); /* detach */
 				tl->next=tl->prev=0;
+				ret=0;
 #ifdef TIMER_DEBUG
 				tl->del_file=file;
 				tl->del_func=func;
@@ -643,10 +650,13 @@ again:
 						tl->del_func, tl->del_file, tl->del_line,
 						tl->init, tl->expires_no);
 #else
+/*
 				DBG("timer_del: (s) timer %p (%p, %p) flags %x "
 							"already detached\n",
 							tl, tl->next, tl->prev, tl->flags);
+*/
 #endif
+				ret=-1;
 			}
 			UNLOCK_SLOW_TIMER_LIST();
 		}else{
@@ -675,7 +685,7 @@ again:
 						tl->add_line, tl->del_calls, tl->del_func, 
 						tl->del_file, tl->del_line, tl->init, tl->expires_no);
 #endif
-					return; /* do nothing */
+					return -2; /* do nothing */
 				}
 				sched_yield(); /* wait for it to complete */
 				goto again;
@@ -683,6 +693,7 @@ again:
 			if ((tl->next!=0)&&(tl->prev!=0)){
 				_timer_rm_list(tl); /* detach */
 				tl->next=tl->prev=0;
+				ret=0;
 #ifdef TIMER_DEBUG
 				tl->del_file=file;
 				tl->del_func=func;
@@ -709,15 +720,19 @@ again:
 						tl->del_func, tl->del_file, tl->del_line,
 						tl->init, tl->expires_no);
 #else
+/*
 				DBG("timer_del: (f) timer %p (%p, %p) flags %x "
 							"already detached\n",
 							tl, tl->next, tl->prev, tl->flags);
+*/
 #endif
+				ret=-1;
 			}
 			UNLOCK_TIMER_LIST();
 #ifdef USE_SLOW_TIMER
 		}
 #endif
+return ret;
 }
 
 
@@ -749,7 +764,10 @@ void timer_allow_del()
 }
 
 
-/* called from timer_handle, must be called with the timer lock held */
+/* called from timer_handle, must be called with the timer lock held
+ * WARNING: expired one shot timers are _not_ automatically reinit
+ *          (because they could have been already freed from the timer
+ *           handler so a reinit would not be safe!) */
 inline static void timer_list_expire(ticks_t t, struct timer_head* h
 #ifdef USE_SLOW_TIMER
 										, struct timer_head* slow_l,

+ 2 - 2
timer.h

@@ -161,7 +161,7 @@ void timer_free(struct timer_ln* t);
 #ifdef TIMER_DEBUG
 int timer_add_safe(struct timer_ln *tl, ticks_t delta, 
 					const char*, const char*, unsigned);
-void timer_del_safe(struct timer_ln *tl,
+int timer_del_safe(struct timer_ln *tl,
 					const char*, const char*, unsigned);
 #define timer_add(tl, d) \
 	timer_add_safe((tl), (d), __FILE__, __FUNCTION__, __LINE__)
@@ -169,7 +169,7 @@ void timer_del_safe(struct timer_ln *tl,
 	timer_del_safe((tl), __FILE__, __FUNCTION__, __LINE__)
 #else
 int timer_add_safe(struct timer_ln *tl, ticks_t delta);
-void timer_del_safe(struct timer_ln *tl);
+int timer_del_safe(struct timer_ln *tl);
 #define timer_add timer_add_safe
 #define timer_del timer_del_safe
 #endif

+ 14 - 0
timer_ticks.h

@@ -30,6 +30,7 @@
 /* History:
  * --------
  *  2005-07-27  complete re-design/re-implemnetation (andrei)
+ *  2007-07-02  added ticks comparison macros (andrei)
  */
 
 #ifndef _timer_ticks_h
@@ -54,6 +55,19 @@
 #define TICKS_TO_MS(t) (((t)*1000U)/TIMER_TICKS_HZ)
 
 
+/* ticks comparison operations: t1 OP t2, where OP can be <, >, <=, >= */
+#define TICKS_CMP_OP(t1, t2, OP) \
+	(((s_ticks_t)((ticks_t)(t1)-(ticks_t)(t2))) OP (s_ticks_t)0)
+/* t1 < t2 */
+#define TICKS_LT(t1, t2)  TICKS_CMP_OP(t1, t2, <)
+/* t1 <= t2 */
+#define TICKS_LE(t1, t2)  TICKS_CMP_OP(t1, t2, <=)
+/* t1 > t2 */
+#define TICKS_GT(t1, t2)  TICKS_CMP_OP(t1, t2, >)
+/* t1 >= t2 */
+#define TICKS_GE(t1, t2)  TICKS_CMP_OP(t1, t2, >=)
+
+
 typedef unsigned int ticks_t;/* type used to keep the ticks (must be 32 bits)*/
 typedef signed   int s_ticks_t; /* signed ticks type */