... | ... |
@@ -61,7 +61,7 @@ MAIN_NAME=ser |
61 | 61 |
VERSION = 0 |
62 | 62 |
PATCHLEVEL = 10 |
63 | 63 |
SUBLEVEL = 99 |
64 |
-EXTRAVERSION = -dev24 |
|
64 |
+EXTRAVERSION = -dev25-timers |
|
65 | 65 |
|
66 | 66 |
RELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) |
67 | 67 |
OS = $(shell uname -s | sed -e s/SunOS/solaris/ | tr "[A-Z]" "[a-z]") |
68 | 68 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,111 @@ |
1 |
+/* |
|
2 |
+ * $Id$ |
|
3 |
+ * |
|
4 |
+ * circular list maintenance macros |
|
5 |
+ * |
|
6 |
+ * Copyright (C) 2005 iptelorg GmbH |
|
7 |
+ * |
|
8 |
+ * This file is part of ser, a free SIP server. |
|
9 |
+ * |
|
10 |
+ * ser is free software; you can redistribute it and/or modify |
|
11 |
+ * it under the terms of the GNU General Public License as published by |
|
12 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
13 |
+ * (at your option) any later version |
|
14 |
+ * |
|
15 |
+ * For a license to use the ser software under conditions |
|
16 |
+ * other than those described here, or to purchase support for this |
|
17 |
+ * software, please contact iptel.org by e-mail at the following addresses: |
|
18 |
+ * info@iptel.org |
|
19 |
+ * |
|
20 |
+ * ser is distributed in the hope that it will be useful, |
|
21 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
22 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
23 |
+ * GNU General Public License for more details. |
|
24 |
+ * |
|
25 |
+ * You should have received a copy of the GNU General Public License |
|
26 |
+ * along with this program; if not, write to the Free Software |
|
27 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
28 |
+ */ |
|
29 |
+ |
|
30 |
+/* History: |
|
31 |
+ * -------- |
|
32 |
+ * 2005-08-08 created by andrei |
|
33 |
+ */ |
|
34 |
+ |
|
35 |
+#ifndef _clist_h |
|
36 |
+#define _clist_h |
|
37 |
+ |
|
38 |
+/* circular list */ |
|
39 |
+#define clist_init(c, next, prev) \ |
|
40 |
+ do{ \ |
|
41 |
+ (c)->next=(void*)(c); \ |
|
42 |
+ (c)->prev=(void*)(c); \ |
|
43 |
+ } while(0) |
|
44 |
+ |
|
45 |
+ |
|
46 |
+ |
|
47 |
+/* adds an entire sublist { s,e } (including s & e ) |
|
48 |
+ * after head |
|
49 |
+ */ |
|
50 |
+#define clist_insert_sublist(head, s, e, next, prev) \ |
|
51 |
+ do{ \ |
|
52 |
+ (s)->prev=(head); \ |
|
53 |
+ (e)->next=(head)->next; \ |
|
54 |
+ (e)->next->prev=(e); \ |
|
55 |
+ (head)->next=s; \ |
|
56 |
+ }while(0) |
|
57 |
+ |
|
58 |
+ |
|
59 |
+ |
|
60 |
+/* appends an entire sublist { s,e } (including s & e ) |
|
61 |
+ * at the end of the list |
|
62 |
+ */ |
|
63 |
+#define clist_append_sublist(head, s, e, next, prev) \ |
|
64 |
+ do{ \ |
|
65 |
+ (s)->prev=(head)->prev; \ |
|
66 |
+ (e)->next=(void*)(head); \ |
|
67 |
+ (s)->prev->next=(s); \ |
|
68 |
+ (head)->prev=(e); \ |
|
69 |
+ }while(0) |
|
70 |
+ |
|
71 |
+ |
|
72 |
+ |
|
73 |
+/* remove sublist { s,e } (including s & e ) |
|
74 |
+ * always, if start is the beginning of the list use |
|
75 |
+ * clist_rm_sublist(head->next, e, next, prev ) */ |
|
76 |
+#define clist_rm_sublist(s, e, next, prev) \ |
|
77 |
+ do{\ |
|
78 |
+ (s)->prev->next=(e)->next; \ |
|
79 |
+ (e)->next->prev=(s)->prev ; \ |
|
80 |
+ }while(0) |
|
81 |
+ |
|
82 |
+ |
|
83 |
+ |
|
84 |
+/* insert after (head) */ |
|
85 |
+#define clist_insert(head, c, next, prev) \ |
|
86 |
+ clist_insert_sublist(head, c, c, next, prev) |
|
87 |
+ |
|
88 |
+ |
|
89 |
+ |
|
90 |
+/* append at the end of the list (head->prev) */ |
|
91 |
+#define clist_append(head, c, next, prev) \ |
|
92 |
+ clist_append_sublist(head, c, c, next, prev) |
|
93 |
+ |
|
94 |
+ |
|
95 |
+ |
|
96 |
+/* remove and element */ |
|
97 |
+#define clist_rm(c, next, prev) \ |
|
98 |
+ clist_rm_sublist(c, c, next, prev) |
|
99 |
+ |
|
100 |
+ |
|
101 |
+ |
|
102 |
+/* iterate on a clist */ |
|
103 |
+#define clist_foreach(head, v, dir) \ |
|
104 |
+ for((v)=(head)->dir; (v)!=(void*)(head); (v)=(v)->dir) |
|
105 |
+ |
|
106 |
+/* iterate on a clist, safe version (requires an extra bak. var) |
|
107 |
+ * (it allows removing of the current element) */ |
|
108 |
+#define clist_foreach_safe(head, v, bak, dir) \ |
|
109 |
+ for((v)=(head)->dir, (bak)=(v)->dir; (v)!=(void*)(head); \ |
|
110 |
+ (v)=(bak), (bak)=(v)->dir) |
|
111 |
+#endif |
131 | 130 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,174 @@ |
1 |
+# $Id$ |
|
2 |
+# |
|
3 |
+# History: |
|
4 |
+# -------- |
|
5 |
+# 2005-11-30 created by andrei |
|
6 |
+ |
|
7 |
+ |
|
8 |
+New timer interface |
|
9 |
+ |
|
10 |
+ |
|
11 |
+1. Introduction |
|
12 |
+--------------- |
|
13 |
+ |
|
14 |
+ ser's new timer interface is based on a 3 level hierarchical timing wheel |
|
15 |
+(see [1]). Most timeouts will go in the first "wheel" (all timeouts < 1<<14 |
|
16 |
+ ticks, which by default mean 1024 s). Each wheel acts as a circular buffer. |
|
17 |
+ The big advantage of this scheme is that most of the time you just run all the timer handlers from the current entry in the first wheel (no comparisons necessary). Each 2^14 ticks, all the timers in the second wheel's current entry are redistributed and each 2^23 ticks all the timers in the third wheel's current entry are redistributed. |
|
18 |
+ |
|
19 |
+ The new timer interfaces allows adding timers dynamically, supports one shot |
|
20 |
+ and periodic timers, is precise and fast (very low overhead) and supports |
|
21 |
+"fast" and "slow" timers. For now it uses setitimer to "generate" the ticks and form time to time it re-adjusts them based on the real system time. |
|
22 |
+ |
|
23 |
+ |
|
24 |
+[1] - G. Varghese, T. Lauck, Hashed and Hierarchical Timing Wheels: Efficient |
|
25 |
+ Data Structures for Implementing a Timer Facility, 1996 |
|
26 |
+ |
|
27 |
+ |
|
28 |
+2. include files |
|
29 |
+----------------- |
|
30 |
+ |
|
31 |
+All the public functions are defined in timer.h. timer_ticks.h contains |
|
32 |
+ ticks conversion related macros (ticks to seconds, ms or viceversa). |
|
33 |
+ |
|
34 |
+ |
|
35 |
+3. Example usage |
|
36 |
+---------------- |
|
37 |
+ |
|
38 |
+#include "../../timer.h" |
|
39 |
+#include "../../timer_ticks.h" |
|
40 |
+ |
|
41 |
+/* simple periodic timer handler */ |
|
42 |
+static ticks_t timer_h(ticks_t ticks, struct timer_ln* tl, void* data) |
|
43 |
+{ |
|
44 |
+ DBG("timer habdler called at %d ticks, foo is %d \n", ticks, *(int*)data); |
|
45 |
+ return (ticks_t)(-1); /* periodical */ |
|
46 |
+} |
|
47 |
+ |
|
48 |
+struct timer_ln *t; |
|
49 |
+int foo; |
|
50 |
+ |
|
51 |
+t=timer_alloc(); |
|
52 |
+if (t==0) |
|
53 |
+ goto error; |
|
54 |
+timer_init(t, timer_handle, &foo, 0); |
|
55 |
+foo=0; |
|
56 |
+timer_add(t, MS_TO_TICKS(1500)); /* start it after 1500ms */ |
|
57 |
+/* .... */ |
|
58 |
+/* remove it and change the period to 2 s */ |
|
59 |
+timer_del(t); |
|
60 |
+timer_reinit(t); /* without init or reinit timer_add will refuse to re-add it*/ |
|
61 |
+timer_add(t, S_TO_TICKS(2)); |
|
62 |
+/* .... */ |
|
63 |
+/* remove it at the end (optional) */ |
|
64 |
+timer_del(t); |
|
65 |
+timer_free(t); |
|
66 |
+ |
|
67 |
+ |
|
68 |
+4. Notes |
|
69 |
+--------- |
|
70 |
+ |
|
71 |
+4.1 alloc & init |
|
72 |
+---------------- |
|
73 |
+ |
|
74 |
+To use a timer you need a timer_ln structure. This structure must be stored |
|
75 |
+ in shared memory. |
|
76 |
+You can either use timer_alloc() which will return a pointer to a shared memory allocated timer_ln structure or you can "attach" timer_ln as a member to one |
|
77 |
+ of your structures which is already stored in the shared memory. |
|
78 |
+ |
|
79 |
+The timer_ln structure must be always initialized. Use the timer_init(...) macro for this. To the timer_init macro takes as parameters a pointer to the timer_ln structure, a pointer to a timer_handler_f function, a void* parameter for this |
|
80 |
+ function and some timer flags. |
|
81 |
+Example: |
|
82 |
+ |
|
83 |
+struct foo{ |
|
84 |
+ int bar; |
|
85 |
+ struct timer_ln timer; |
|
86 |
+}; |
|
87 |
+ |
|
88 |
+struct foo* f; |
|
89 |
+f=shm_malloc(sizeof(struct foo)); |
|
90 |
+ |
|
91 |
+time_init(&f->timer, timer_handle, &f->bar, 0); |
|
92 |
+ |
|
93 |
+ |
|
94 |
+The timer flags can be either 0 (if it's a "slow" timer) or F_TIMER_FAST if |
|
95 |
+ this is a "fast" timer. |
|
96 |
+A "fast" timer is a timer that does very little work in its timer handler (it always exits fast). You should use a "slow" timer if you don't care so much if your timer call is a little bit delayed or if you do dns lookups, query databases, blocking sends/writes. If you don't know which one to choose, choose "slow". |
|
97 |
+ |
|
98 |
+ |
|
99 |
+4.2 timer handlers |
|
100 |
+------------------ |
|
101 |
+ |
|
102 |
+The timer handler can be periodic, one shot or it can change from call to call. It all depends on what value you return from it. If you always return (ticks_t)(-1) or timer_ln->initial_timeout you have a periodic timer. If you return 0 you have an one shot timer (the timer will be removed when your timer handler function exits). For any other value v, your timer will be automatically re-added with the next expire set to v (expressed in ticks). |
|
103 |
+ |
|
104 |
+4.3 timer_add |
|
105 |
+------------- |
|
106 |
+ |
|
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 |
+The timer must be intialized (with timer_init()) before adding it the first time. |
|
109 |
+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 |
+WARNING: do not initialize/re-initialize a running timer! |
|
111 |
+ |
|
112 |
+4.4 timer_del |
|
113 |
+------------- |
|
114 |
+ |
|
115 |
+To remove a timer from the active timer list call timer_del(struct timer_ln*). |
|
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 |
+WARNING: 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). |
|
118 |
+ |
|
119 |
+Race example (using the struct foo defined above): |
|
120 |
+ |
|
121 |
+/* simple one shot timer handler */ |
|
122 |
+static ticks_t timer_h(ticks_t ticks, struct timer_ln* tl, void* data) |
|
123 |
+{ |
|
124 |
+ |
|
125 |
+ /* free the mem. */ |
|
126 |
+ shm_free(data); |
|
127 |
+ return 0; |
|
128 |
+} |
|
129 |
+ |
|
130 |
+struct foo* f; |
|
131 |
+f=shm_malloc(sizeof(struct foo)); |
|
132 |
+ |
|
133 |
+time_init(&f->timer, timer_handle, f, 0); |
|
134 |
+timer_add(&f->timer, rand()); |
|
135 |
+/* ... */ |
|
136 |
+/* random amount of time spent doing other things */ |
|
137 |
+timer_del(&f->timer); /* if the timer is already expired => f is already |
|
138 |
+ deleted => problems */ |
|
139 |
+ |
|
140 |
+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 |
+ |
|
142 |
+ |
|
143 |
+4.5 Getting the ticks value |
|
144 |
+---------------------------- |
|
145 |
+ |
|
146 |
+If you need the current ticks value you can get with get_ticks_raw(). |
|
147 |
+WARNING: don't use get_ticks(). get_ticks() returns the number of ticks converted to seconds and it was kept only for compatibility reasons with the existing code. |
|
148 |
+ |
|
149 |
+4.6 Conversion |
|
150 |
+--------------- |
|
151 |
+ |
|
152 |
+To convert between ticks & time and viceversa, include timer_ticks.h and use |
|
153 |
+one of the following macros: |
|
154 |
+ |
|
155 |
+MS_TO_TICKS(ms) /* converts from milliseconds to ticks, rounds up */ |
|
156 |
+S_TO_TICKS(s) /* convert from seconds to ticks */ |
|
157 |
+TICKS_TO_MS(t) /* converts from ticks to milliseconds, can overflow for |
|
158 |
+ very large values (use long long and |
|
159 |
+ TICKS_TO_MS((long long)t) to try to avoid it if you know |
|
160 |
+ that you'll deal with such large values */ |
|
161 |
+TICKS_TO_S(t) /* converts from ticks to s, rounded down */ |
|
162 |
+ |
|
163 |
+ |
|
164 |
+4.7 Backward compatibility |
|
165 |
+-------------------------- |
|
166 |
+ |
|
167 |
+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. |
|
168 |
+ |
|
169 |
+ |
|
170 |
+ |
|
171 |
+[Todo]: |
|
172 |
+- SLOW, DRIFT, RESYNC, FREQUENCY |
|
173 |
+ |
|
174 |
+ |
... | ... |
@@ -150,6 +150,9 @@ extern int is_main; |
150 | 150 |
/* debugging level for dumping memory status */ |
151 | 151 |
extern int memlog; |
152 | 152 |
|
153 |
+/* debugging level for timer debugging (see -DTIMER_DEBUG) */ |
|
154 |
+extern int timerlog; |
|
155 |
+ |
|
153 | 156 |
/* looking up outbound interface ? */ |
154 | 157 |
extern int mhomed; |
155 | 158 |
|
... | ... |
@@ -119,6 +119,7 @@ |
119 | 119 |
#include "pt.h" |
120 | 120 |
#include "script_cb.h" |
121 | 121 |
#include "ut.h" |
122 |
+#include "signals.h" |
|
122 | 123 |
#ifdef USE_TCP |
123 | 124 |
#include "poll_types.h" |
124 | 125 |
#include "tcp_init.h" |
... | ... |
@@ -255,6 +256,8 @@ int check_via = 0; |
255 | 256 |
int syn_branch = 1; |
256 | 257 |
/* debugging level for memory stats */ |
257 | 258 |
int memlog = L_DBG; |
259 |
+/* debugging level for timer debugging */ |
|
260 |
+int timerlog = L_WARN; |
|
258 | 261 |
/* should replies include extensive warnings? by default yes, |
259 | 262 |
good for trouble-shooting |
260 | 263 |
*/ |
... | ... |
@@ -424,28 +427,6 @@ static void kill_all_children(int signum) |
424 | 427 |
|
425 | 428 |
|
426 | 429 |
|
427 |
-#ifdef USE_SIGACTION |
|
428 |
-static void (*set_sig_h(int sig, void (*handler) (int) ))(int) |
|
429 |
-{ |
|
430 |
- struct sigaction act; |
|
431 |
- struct sigaction old; |
|
432 |
- |
|
433 |
- memset(&act, 0, sizeof(act)); |
|
434 |
- act.sa_handler=handler; |
|
435 |
- /* |
|
436 |
- sigemptyset(&act.sa_mask); |
|
437 |
- act.sa_flags=0; |
|
438 |
- */ |
|
439 |
- LOG(L_CRIT, "setting signal %d to %p\n", sig, handler); |
|
440 |
- /* sa_sigaction not set, we use sa_hanlder instead */ |
|
441 |
- return (sigaction (sig, &act, &old)==-1)?SIG_ERR:old.sa_handler; |
|
442 |
-} |
|
443 |
-#else |
|
444 |
-#define set_sig_h signal |
|
445 |
-#endif |
|
446 |
- |
|
447 |
- |
|
448 |
- |
|
449 | 430 |
/* if this handler is called, a critical timeout has occured while |
450 | 431 |
* waiting for the children to finish => we should kill everything and exit */ |
451 | 432 |
static void sig_alarm_kill(int signo) |
... | ... |
@@ -842,7 +823,7 @@ int main_loop() |
842 | 823 |
#ifdef USE_TCP |
843 | 824 |
int sockfd[2]; |
844 | 825 |
#endif |
845 |
-#ifdef DEBUG |
|
826 |
+#ifdef EXTRA_DEBUG |
|
846 | 827 |
int r; |
847 | 828 |
#endif |
848 | 829 |
|
... | ... |
@@ -884,23 +865,38 @@ int main_loop() |
884 | 865 |
as new processes are forked (while skipping 0 reserved for main |
885 | 866 |
*/ |
886 | 867 |
|
887 |
- /* we need another process to act as the timer*/ |
|
888 |
-#ifdef USE_TCP |
|
889 |
- /* if we are using tcp we always need a timer process, |
|
890 |
- * we cannot count on select timeout to measure time |
|
891 |
- * (it works only on linux) |
|
892 |
- */ |
|
893 |
- if ((!tcp_disable)||(timer_list)) |
|
894 |
-#else |
|
895 |
- if (timer_list) |
|
868 |
+#ifdef USE_SLOW_TIMER |
|
869 |
+ /* we need another process to act as the "slow" timer*/ |
|
870 |
+ process_no++; |
|
871 |
+ if ((pid=fork())<0){ |
|
872 |
+ LOG(L_CRIT, "ERROR: main_loop: Cannot fork\n"); |
|
873 |
+ goto error; |
|
874 |
+ } |
|
875 |
+ if (pid==0){ |
|
876 |
+ /* child */ |
|
877 |
+ pt[process_no].pid=getpid(); |
|
878 |
+ /* timer!*/ |
|
879 |
+ /* process_bit = 0; */ |
|
880 |
+ if (init_child(PROC_TIMER) < 0) { |
|
881 |
+ LOG(L_ERR, "slow timer: init_child failed\n"); |
|
882 |
+ goto error; |
|
883 |
+ } |
|
884 |
+ |
|
885 |
+ if (arm_slow_timer()<0) goto error; |
|
886 |
+ slow_timer_main(); |
|
887 |
+ }else{ |
|
888 |
+ pt[process_no].pid=pid; /*should be shared mem anyway*/ |
|
889 |
+ strncpy(pt[process_no].desc, "slow timer", MAX_PT_DESC ); |
|
890 |
+ slow_timer_pid=pid; |
|
891 |
+ |
|
892 |
+ } |
|
896 | 893 |
#endif |
897 |
- { |
|
894 |
+ /* we need another process to act as the "main" timer*/ |
|
898 | 895 |
process_no++; |
899 | 896 |
if ((pid=fork())<0){ |
900 | 897 |
LOG(L_CRIT, "ERROR: main_loop: Cannot fork\n"); |
901 | 898 |
goto error; |
902 | 899 |
} |
903 |
- |
|
904 | 900 |
if (pid==0){ |
905 | 901 |
/* child */ |
906 | 902 |
/* record pid twice to avoid the child using it, before |
... | ... |
@@ -912,15 +908,13 @@ int main_loop() |
912 | 908 |
LOG(L_ERR, "timer: init_child failed\n"); |
913 | 909 |
goto error; |
914 | 910 |
} |
915 |
- for(;;){ |
|
916 |
- sleep(TIMER_TICK); |
|
917 |
- timer_ticker(); |
|
918 |
- } |
|
911 |
+ |
|
912 |
+ if (arm_timer()<0) goto error; |
|
913 |
+ timer_main(); |
|
919 | 914 |
}else{ |
920 | 915 |
pt[process_no].pid=pid; /*should be shared mem anyway*/ |
921 | 916 |
strncpy(pt[process_no].desc, "timer", MAX_PT_DESC ); |
922 | 917 |
} |
923 |
- } |
|
924 | 918 |
|
925 | 919 |
/* if configured, start a server for accepting FIFO commands, |
926 | 920 |
* we need to do it after all the sockets are initialized, to |
... | ... |
@@ -1101,13 +1095,55 @@ int main_loop() |
1101 | 1095 |
bind_address=0; /* main proc -> it shouldn't send anything, */ |
1102 | 1096 |
|
1103 | 1097 |
|
1098 |
+ { |
|
1099 |
+#ifdef USE_SLOW_TIMER |
|
1104 | 1100 |
#ifdef USE_TCP |
1105 |
- /* if we are using tcp we always need the timer */ |
|
1106 |
- if ((!tcp_disable)||(timer_list)) |
|
1107 |
-#else |
|
1108 |
- if (timer_list) |
|
1101 |
+ if (!tcp_disable){ |
|
1102 |
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){ |
|
1103 |
+ LOG(L_ERR, "ERROR: main_loop: socketpair failed: %s\n", |
|
1104 |
+ strerror(errno)); |
|
1105 |
+ goto error; |
|
1106 |
+ } |
|
1107 |
+ } |
|
1109 | 1108 |
#endif |
1110 |
- { |
|
1109 |
+ /* fork again for the "slow" timer process*/ |
|
1110 |
+ process_no++; |
|
1111 |
+ if ((pid=fork())<0){ |
|
1112 |
+ LOG(L_CRIT, "main_loop: cannot fork \"slow\" timer process\n"); |
|
1113 |
+ goto error; |
|
1114 |
+ }else if (pid==0){ |
|
1115 |
+ /* child */ |
|
1116 |
+ /* is_main=0; */ |
|
1117 |
+#ifdef USE_TCP |
|
1118 |
+ if (!tcp_disable){ |
|
1119 |
+ close(sockfd[0]); |
|
1120 |
+ unix_tcp_sock=sockfd[1]; |
|
1121 |
+ } |
|
1122 |
+#endif |
|
1123 |
+ /* record pid twice to avoid the child using it, before |
|
1124 |
+ * parent gets a chance to set it*/ |
|
1125 |
+ pt[process_no].pid=getpid(); |
|
1126 |
+ if (init_child(PROC_TIMER) < 0) { |
|
1127 |
+ LOG(L_ERR, "slow timer: init_child failed\n"); |
|
1128 |
+ goto error; |
|
1129 |
+ } |
|
1130 |
+ if (arm_slow_timer()<0) goto error; |
|
1131 |
+ slow_timer_main(); |
|
1132 |
+ }else{ |
|
1133 |
+ pt[process_no].pid=pid; |
|
1134 |
+ strncpy(pt[process_no].desc, "slow timer", MAX_PT_DESC ); |
|
1135 |
+ slow_timer_pid=pid; |
|
1136 |
+#ifdef USE_TCP |
|
1137 |
+ if(!tcp_disable){ |
|
1138 |
+ close(sockfd[1]); |
|
1139 |
+ pt[process_no].unix_sock=sockfd[0]; |
|
1140 |
+ pt[process_no].idx=-1; /* this is not a "tcp" process*/ |
|
1141 |
+ } |
|
1142 |
+#endif |
|
1143 |
+ } |
|
1144 |
+#endif /* USE_SLOW_TIMER */ |
|
1145 |
+ |
|
1146 |
+ /* fork again for the "main" timer process*/ |
|
1111 | 1147 |
#ifdef USE_TCP |
1112 | 1148 |
if (!tcp_disable){ |
1113 | 1149 |
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd)<0){ |
... | ... |
@@ -1117,7 +1153,6 @@ int main_loop() |
1117 | 1153 |
} |
1118 | 1154 |
} |
1119 | 1155 |
#endif |
1120 |
- /* fork again for the attendant process*/ |
|
1121 | 1156 |
process_no++; |
1122 | 1157 |
if ((pid=fork())<0){ |
1123 | 1158 |
LOG(L_CRIT, "main_loop: cannot fork timer process\n"); |
... | ... |
@@ -1138,14 +1173,8 @@ int main_loop() |
1138 | 1173 |
LOG(L_ERR, "timer: init_child failed\n"); |
1139 | 1174 |
goto error; |
1140 | 1175 |
} |
1141 |
- |
|
1142 |
- for(;;){ |
|
1143 |
- /* debug: instead of doing something useful */ |
|
1144 |
- /* (placeholder for timers, etc.) */ |
|
1145 |
- sleep(TIMER_TICK); |
|
1146 |
- /* if we received a signal => TIMER_TICK may have not elapsed*/ |
|
1147 |
- timer_ticker(); |
|
1148 |
- } |
|
1176 |
+ if (arm_timer()<0) goto error; |
|
1177 |
+ timer_main(); |
|
1149 | 1178 |
}else{ |
1150 | 1179 |
pt[process_no].pid=pid; |
1151 | 1180 |
strncpy(pt[process_no].desc, "timer", MAX_PT_DESC ); |
... | ... |
@@ -1198,11 +1227,14 @@ int main_loop() |
1198 | 1227 |
} |
1199 | 1228 |
#endif |
1200 | 1229 |
/*DEBUG- remove it*/ |
1201 |
-#ifdef DEBUG |
|
1230 |
+#ifdef EXTRA_DEBUG |
|
1202 | 1231 |
fprintf(stderr, "\n% 3d processes (%3d), % 3d children * " |
1203 | 1232 |
"listening addresses + tcp listeners + tls listeners" |
1204 |
- "+ main + fifo %s\n", process_no+1, process_count(), children_no, |
|
1205 |
- (timer_list)?"+ timer":""); |
|
1233 |
+ "+ main + fifo + timer" |
|
1234 |
+# ifdef USE_SLOW_TIMER |
|
1235 |
+ " + slow_timer" |
|
1236 |
+# endif |
|
1237 |
+ "\n", process_no+1, process_count(), children_no); |
|
1206 | 1238 |
for (r=0; r<=process_no; r++){ |
1207 | 1239 |
fprintf(stderr, "% 3d % 5d - %s\n", r, pt[r].pid, pt[r].desc); |
1208 | 1240 |
} |
... | ... |
@@ -74,6 +74,9 @@ inline static int process_count() |
74 | 74 |
/* timer process */ |
75 | 75 |
+ 1 /* always, we need it in most cases, and we can't tell here |
76 | 76 |
& now if we don't need it */ |
77 |
+#ifdef USE_SLOW_TIMER |
|
78 |
+ + 1 /* slow timer process */ |
|
79 |
+#endif |
|
77 | 80 |
/* fifo server */ |
78 | 81 |
+((fifo==NULL || strlen(fifo)==0) ? 0 : 1 ) |
79 | 82 |
/* unixsock server*/ |
80 | 83 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,54 @@ |
1 |
+/* |
|
2 |
+ * $Id$ |
|
3 |
+ * |
|
4 |
+ * Copyright (C) 2001-2003 FhG Fokus |
|
5 |
+ * |
|
6 |
+ * This file is part of ser, a free SIP server. |
|
7 |
+ * |
|
8 |
+ * ser is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License as published by |
|
10 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
11 |
+ * (at your option) any later version |
|
12 |
+ * |
|
13 |
+ * For a license to use the ser software under conditions |
|
14 |
+ * other than those described here, or to purchase support for this |
|
15 |
+ * software, please contact iptel.org by e-mail at the following addresses: |
|
16 |
+ * info@iptel.org |
|
17 |
+ * |
|
18 |
+ * ser is distributed in the hope that it will be useful, |
|
19 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
20 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
21 |
+ * GNU General Public License for more details. |
|
22 |
+ * |
|
23 |
+ * You should have received a copy of the GNU General Public License |
|
24 |
+ * along with this program; if not, write to the Free Software |
|
25 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
26 |
+ */ |
|
27 |
+/* |
|
28 |
+ * Handle the signals |
|
29 |
+ * |
|
30 |
+ * History: |
|
31 |
+ * -------- |
|
32 |
+ * 2005-10-05 split from main.c (andrei) |
|
33 |
+ */ |
|
34 |
+ |
|
35 |
+#include "signals.h" |
|
36 |
+#include <signal.h> |
|
37 |
+ |
|
38 |
+#ifdef USE_SIGACTION |
|
39 |
+void (*set_sig_h(int sig, void (*handler) (int) ))(int) |
|
40 |
+{ |
|
41 |
+ struct sigaction act; |
|
42 |
+ struct sigaction old; |
|
43 |
+ |
|
44 |
+ memset(&act, 0, sizeof(act)); |
|
45 |
+ act.sa_handler=handler; |
|
46 |
+ /* |
|
47 |
+ sigemptyset(&act.sa_mask); |
|
48 |
+ act.sa_flags=0; |
|
49 |
+ */ |
|
50 |
+ LOG(L_CRIT, "setting signal %d to %p\n", sig, handler); |
|
51 |
+ /* sa_sigaction not set, we use sa_hanlder instead */ |
|
52 |
+ return (sigaction (sig, &act, &old)==-1)?SIG_ERR:old.sa_handler; |
|
53 |
+} |
|
54 |
+#endif |
0 | 55 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,46 @@ |
1 |
+/* |
|
2 |
+ * $Id$ |
|
3 |
+ * |
|
4 |
+ * Copyright (C) 2001-2003 FhG Fokus |
|
5 |
+ * |
|
6 |
+ * This file is part of ser, a free SIP server. |
|
7 |
+ * |
|
8 |
+ * ser is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License as published by |
|
10 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
11 |
+ * (at your option) any later version |
|
12 |
+ * |
|
13 |
+ * For a license to use the ser software under conditions |
|
14 |
+ * other than those described here, or to purchase support for this |
|
15 |
+ * software, please contact iptel.org by e-mail at the following addresses: |
|
16 |
+ * info@iptel.org |
|
17 |
+ * |
|
18 |
+ * ser is distributed in the hope that it will be useful, |
|
19 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
20 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
21 |
+ * GNU General Public License for more details. |
|
22 |
+ * |
|
23 |
+ * You should have received a copy of the GNU General Public License |
|
24 |
+ * along with this program; if not, write to the Free Software |
|
25 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
26 |
+ */ |
|
27 |
+/* |
|
28 |
+ * Handle the signals |
|
29 |
+ * |
|
30 |
+ * History: |
|
31 |
+ * -------- |
|
32 |
+ * 2005-10-05 split from main.c (andrei) |
|
33 |
+ */ |
|
34 |
+ |
|
35 |
+ |
|
36 |
+#ifndef _signals_h |
|
37 |
+#define _signals_h |
|
38 |
+ |
|
39 |
+#ifdef USE_SIGACTION |
|
40 |
+void (*set_sig_h(int sig, void (*handler) (int) ))(int); |
|
41 |
+#else |
|
42 |
+#define set_sig_h signal |
|
43 |
+#endif |
|
44 |
+ |
|
45 |
+ |
|
46 |
+#endif |
... | ... |
@@ -28,72 +28,817 @@ |
28 | 28 |
* -------- |
29 | 29 |
* 2003-03-19 replaced all the mallocs/frees w/ pkg_malloc/pkg_free (andrei) |
30 | 30 |
* 2003-03-29 cleaning pkg_mallocs introduced (jiri) |
31 |
+ * 2005-07-27 complete re-design/re-implementation (andrei) |
|
31 | 32 |
*/ |
32 | 33 |
|
33 | 34 |
|
34 | 35 |
#include "timer.h" |
36 |
+#include "timer_funcs.h" |
|
37 |
+#include "timer_ticks.h" |
|
35 | 38 |
#include "dprint.h" |
39 |
+#include <time.h> /* gettimeofday */ |
|
40 |
+#include <sys/time.h> /* setitimer, gettimeofday */ |
|
41 |
+#include <signal.h> /* SIGALRM */ |
|
42 |
+#include <errno.h> |
|
43 |
+#include <unistd.h> /* pause() */ |
|
44 |
+#include <stdlib.h> /* random, debugging only */ |
|
36 | 45 |
#include "error.h" |
46 |
+#include "signals.h" |
|
47 |
+/* |
|
37 | 48 |
#include "config.h" |
49 |
+*/ |
|
50 |
+#include "globals.h" |
|
38 | 51 |
#include "mem/mem.h" |
39 | 52 |
#ifdef SHM_MEM |
40 | 53 |
#include "mem/shm_mem.h" |
41 | 54 |
#endif |
55 |
+#include "locking.h" |
|
56 |
+ |
|
57 |
+ |
|
58 |
+ |
|
42 | 59 |
|
43 |
-#include <stdlib.h> |
|
60 |
+/* how often will the timer handler be called (in ticks) */ |
|
61 |
+#define TIMER_HANDLER_INTERVAL 1U |
|
62 |
+/* how often to try to re-adjust the ticks */ |
|
63 |
+#define TIMER_RESYNC_TICKS (TIMER_TICKS_HZ*5U) /* each 5 s */ |
|
64 |
+#define TIMER_MAX_DRIFT (TIMER_TICKS_HZ/10U) /* if drift > 0.1s adjust */ |
|
44 | 65 |
|
45 | 66 |
|
46 |
-struct sr_timer* timer_list=0; |
|
47 | 67 |
|
48 |
-static int* jiffies=0; |
|
68 |
+static ticks_t* ticks=0; |
|
69 |
+static ticks_t last_ticks; /* last time we adjusted the time */ |
|
70 |
+static ticks_t last_adj_check; /* last time we ran adjust_ticks */ |
|
71 |
+static ticks_t prev_ticks; /* last time we ran the timer, also used as |
|
72 |
+ "current" ticks when running the timer for |
|
73 |
+ "skipped" ticks */ |
|
74 |
+ |
|
75 |
+static struct timeval last_time; |
|
76 |
+static struct timeval start_time; /* for debugging */ |
|
77 |
+ |
|
78 |
+static volatile int run_timer=0; |
|
49 | 79 |
static int timer_id=0; |
50 | 80 |
|
81 |
+static gen_lock_t* timer_lock=0; |
|
82 |
+static struct timer_ln* volatile* running_timer=0;/* running timer handler */ |
|
83 |
+ |
|
84 |
+#define LOCK_TIMER_LIST() lock_get(timer_lock) |
|
85 |
+#define UNLOCK_TIMER_LIST() lock_release(timer_lock) |
|
86 |
+ |
|
87 |
+/* we can get away without atomic_set/atomic_cmp and write barriers because we |
|
88 |
+ * always call SET_RUNNING and IS_RUNNING while holding the timer lock |
|
89 |
+ * => it's implicitly atomic and the lock acts as write barrier */ |
|
90 |
+#define SET_RUNNING(t) (*running_timer=(t)) |
|
91 |
+#define IS_RUNNING(t) (*running_timer==(t)) |
|
92 |
+#define UNSET_RUNNING() (*running_timer=0) |
|
93 |
+ |
|
94 |
+#ifdef USE_SLOW_TIMER |
|
95 |
+ |
|
96 |
+#define SLOW_TIMER_SIG SIGUSR2 |
|
97 |
+/* timer flags checks */ |
|
98 |
+#define IS_FAST_TIMER(t) (t->flags&F_TIMER_FAST) |
|
99 |
+#define SET_SLOW_LIST(t) (t->flags|=F_TIMER_ON_SLOW_LIST) |
|
100 |
+#define RESET_SLOW_LIST(t) (t->flags&=~F_TIMER_ON_SLOW_LIST) |
|
101 |
+#define IS_ON_SLOW_LIST(t) (t->flags&F_TIMER_ON_SLOW_LIST) |
|
102 |
+ |
|
103 |
+#define SLOW_LISTS_NO 1024U /* slow lists number, 2^k recommended */ |
|
104 |
+ |
|
105 |
+ |
|
106 |
+static gen_lock_t* slow_timer_lock; /* slow timer lock */ |
|
107 |
+static struct timer_head* slow_timer_lists; |
|
108 |
+static volatile unsigned short* t_idx; /* "main" timer index in slow_lists[] */ |
|
109 |
+static volatile unsigned short* s_idx; /* "slow" timer index in slow_lists[] */ |
|
110 |
+static struct timer_ln* volatile* running_timer2=0; /* timer handler running |
|
111 |
+ in the "slow" timer */ |
|
112 |
+static sigset_t slow_timer_sset; |
|
113 |
+pid_t slow_timer_pid; |
|
114 |
+#define SET_RUNNING_SLOW(t) (*running_timer2=(t)) |
|
115 |
+#define IS_RUNNING_SLOW(t) (*running_timer2==(t)) |
|
116 |
+#define UNSET_RUNNING_SLOW() (*running_timer2=0) |
|
117 |
+ |
|
118 |
+#define LOCK_SLOW_TIMER_LIST() lock_get(slow_timer_lock) |
|
119 |
+#define UNLOCK_SLOW_TIMER_LIST() lock_release(slow_timer_lock) |
|
120 |
+ |
|
121 |
+ |
|
122 |
+#endif |
|
123 |
+ |
|
124 |
+ |
|
125 |
+struct timer_lists* timer_lst=0; |
|
126 |
+ |
|
127 |
+void sig_timer(int signo) |
|
128 |
+{ |
|
129 |
+ (*ticks)++; |
|
130 |
+ if (( *ticks % TIMER_HANDLER_INTERVAL)==0){ |
|
131 |
+ /* set a flag to run the handler */ |
|
132 |
+ run_timer=1; |
|
133 |
+ } |
|
134 |
+} |
|
135 |
+ |
|
136 |
+ |
|
137 |
+ |
|
138 |
+void destroy_timer() |
|
139 |
+{ |
|
140 |
+ struct itimerval it; |
|
141 |
+ |
|
142 |
+ /* disable timer */ |
|
143 |
+ memset(&it, 0, sizeof(it)); |
|
144 |
+ setitimer(ITIMER_REAL, &it, 0); |
|
145 |
+ set_sig_h(SIGALRM, SIG_IGN); |
|
146 |
+ if (timer_lock){ |
|
147 |
+ lock_destroy(timer_lock); |
|
148 |
+ lock_dealloc(timer_lock); |
|
149 |
+ timer_lock=0; |
|
150 |
+ } |
|
151 |
+ if (ticks){ |
|
152 |
+#ifdef SHM_MEM |
|
153 |
+ shm_free(ticks); |
|
154 |
+#else |
|
155 |
+ pkg_free(ticks); |
|
156 |
+#endif |
|
157 |
+ ticks=0; |
|
158 |
+ } |
|
159 |
+ if (timer_lst){ |
|
160 |
+#ifdef SHM_MEM |
|
161 |
+ shm_free(timer_lst); |
|
162 |
+#else |
|
163 |
+ pkg_free(timer_lst); |
|
164 |
+#endif |
|
165 |
+ timer_lst=0; |
|
166 |
+ } |
|
167 |
+ if (running_timer){ |
|
168 |
+ shm_free((void*)running_timer); |
|
169 |
+ running_timer=0; |
|
170 |
+ } |
|
171 |
+#ifdef USE_SLOW_TIMER |
|
172 |
+ if (slow_timer_lock){ |
|
173 |
+ lock_destroy(slow_timer_lock); |
|
174 |
+ lock_dealloc(slow_timer_lock); |
|
175 |
+ slow_timer_lock=0; |
|
176 |
+ } |
|
177 |
+ if (slow_timer_lists){ |
|
178 |
+ shm_free((void*)slow_timer_lists); |
|
179 |
+ slow_timer_lists=0; |
|
180 |
+ } |
|
181 |
+ if (t_idx){ |
|
182 |
+ shm_free((void*)t_idx); |
|
183 |
+ t_idx=0; |
|
184 |
+ } |
|
185 |
+ if (s_idx){ |
|
186 |
+ shm_free((void*)s_idx); |
|
187 |
+ s_idx=0; |
|
188 |
+ } |
|
189 |
+ if(running_timer2){ |
|
190 |
+ shm_free((void*)running_timer2); |
|
191 |
+ running_timer2=0; |
|
192 |
+ } |
|
193 |
+#endif |
|
194 |
+} |
|
195 |
+ |
|
51 | 196 |
|
52 | 197 |
|
53 | 198 |
/* ret 0 on success, <0 on error*/ |
54 | 199 |
int init_timer() |
55 | 200 |
{ |
201 |
+ int r; |
|
202 |
+ int ret; |
|
203 |
+ |
|
204 |
+ ret=-1; |
|
205 |
+ |
|
206 |
+ /* init the locks */ |
|
207 |
+ timer_lock=lock_alloc(); |
|
208 |
+ if (timer_lock==0){ |
|
209 |
+ ret=E_OUT_OF_MEM; |
|
210 |
+ goto error; |
|
211 |
+ } |
|
212 |
+ if (lock_init(timer_lock)==0){ |
|
213 |
+ lock_dealloc(timer_lock); |
|
214 |
+ timer_lock=0; |
|
215 |
+ ret=-1; |
|
216 |
+ goto error; |
|
217 |
+ } |
|
218 |
+ /* init the shared structs */ |
|
56 | 219 |
#ifdef SHM_MEM |
57 |
- jiffies=shm_malloc(sizeof(int)); |
|
220 |
+ ticks=shm_malloc(sizeof(ticks_t)); |
|
221 |
+ timer_lst=shm_malloc(sizeof(struct timer_lists)); |
|
58 | 222 |
#else |
59 | 223 |
/* in this case get_ticks won't work! */ |
60 | 224 |
LOG(L_INFO, "WARNING: no shared memory support compiled in" |
61 | 225 |
" get_ticks won't work\n"); |
62 |
- jiffies=pkg_malloc(sizeof(int)); |
|
226 |
+ ticks=pkg_malloc(sizeof(ticks_t)); |
|
227 |
+ timer_lst=pkg_malloc(sizeof(struct timer_lists)); |
|
63 | 228 |
#endif |
64 |
- if (jiffies==0){ |
|
65 |
- LOG(L_CRIT, "ERROR: init_timer: could not init jiffies\n"); |
|
66 |
- return E_OUT_OF_MEM; |
|
229 |
+ if (ticks==0){ |
|
230 |
+ LOG(L_CRIT, "ERROR: init_timer: out of shared memory (ticks)\n"); |
|
231 |
+ ret=E_OUT_OF_MEM; |
|
232 |
+ goto error; |
|
67 | 233 |
} |
68 |
- *jiffies=0; |
|
234 |
+ if (timer_lst==0){ |
|
235 |
+ LOG(L_CRIT, "ERROR: init_timer: out of shared memory (timer_lst)\n"); |
|
236 |
+ ret=E_OUT_OF_MEM; |
|
237 |
+ goto error; |
|
238 |
+ } |
|
239 |
+ running_timer=shm_malloc(sizeof(struct timer_ln*)); |
|
240 |
+ if (running_timer==0){ |
|
241 |
+ LOG(L_CRIT, "ERROR: init_timer: out of memory (running_timer)\n"); |
|
242 |
+ ret=E_OUT_OF_MEM; |
|
243 |
+ goto error; |
|
244 |
+ } |
|
245 |
+ |
|
246 |
+ /* initial values */ |
|
247 |
+ memset(timer_lst, 0, sizeof(struct timer_lists)); |
|
248 |
+ *ticks=random(); /* random value for start, for debugging */ |
|
249 |
+ prev_ticks=last_ticks=last_adj_check=*ticks; |
|
250 |
+ *running_timer=0; |
|
251 |
+ if (gettimeofday(&start_time, 0)<0){ |
|
252 |
+ LOG(L_ERR, "ERROR: init_timer: gettimeofday failed: %s [%d]\n", |
|
253 |
+ strerror(errno), errno); |
|
254 |
+ ret=-1; |
|
255 |
+ goto error; |
|
256 |
+ } |
|
257 |
+ last_time=start_time; |
|
258 |
+ DBG("init_timer: starting with *ticks=%u\n", (unsigned) *ticks); |
|
259 |
+ |
|
260 |
+ /* init timer structures */ |
|
261 |
+ for (r=0; r<H0_ENTRIES; r++) |
|
262 |
+ _timer_init_list(&timer_lst->h0[r]); |
|
263 |
+ for (r=0; r<H1_ENTRIES; r++) |
|
264 |
+ _timer_init_list(&timer_lst->h1[r]); |
|
265 |
+ for (r=0; r<H2_ENTRIES; r++) |
|
266 |
+ _timer_init_list(&timer_lst->h2[r]); |
|
267 |
+ _timer_init_list(&timer_lst->expired); |
|
268 |
+ |
|
269 |
+#ifdef USE_SLOW_TIMER |
|
270 |
+ |
|
271 |
+ /* init the locks */ |
|
272 |
+ slow_timer_lock=lock_alloc(); |
|
273 |
+ if (slow_timer_lock==0){ |
|
274 |
+ ret=E_OUT_OF_MEM; |
|
275 |
+ goto error; |
|
276 |
+ } |
|
277 |
+ if (lock_init(slow_timer_lock)==0){ |
|
278 |
+ lock_dealloc(slow_timer_lock); |
|
279 |
+ slow_timer_lock=0; |
|
280 |
+ ret=-1; |
|
281 |
+ goto error; |
|
282 |
+ } |
|
283 |
+ t_idx=shm_malloc(sizeof(*t_idx)); |
|
284 |
+ s_idx=shm_malloc(sizeof(*s_idx)); |
|
285 |
+ slow_timer_lists=shm_malloc(sizeof(struct timer_head)*SLOW_LISTS_NO); |
|
286 |
+ running_timer2=shm_malloc(sizeof(struct timer_ln*)); |
|
287 |
+ if ((t_idx==0)||(s_idx==0) || (slow_timer_lists==0) ||(running_timer2==0)){ |
|
288 |
+ LOG(L_ERR, "ERROR: init_timer: out of shared memory (slow)\n"); |
|
289 |
+ ret=E_OUT_OF_MEM; |
|
290 |
+ goto error; |
|
291 |
+ } |
|
292 |
+ *t_idx=*s_idx=0; |
|
293 |
+ *running_timer2=0; |
|
294 |
+ for (r=0; r<SLOW_LISTS_NO; r++) |
|
295 |
+ _timer_init_list(&slow_timer_lists[r]); |
|
296 |
+ |
|
297 |
+#endif |
|
298 |
+ |
|
299 |
+ DBG("init_timer: timer_list between %p and %p\n", |
|
300 |
+ &timer_lst->h0[0], &timer_lst->h2[H2_ENTRIES]); |
|
69 | 301 |
return 0; |
302 |
+error: |
|
303 |
+ destroy_timer(); |
|
304 |
+ return ret; |
|
70 | 305 |
} |
71 | 306 |
|
72 | 307 |
|
73 | 308 |
|
74 |
-void destroy_timer() |
|
309 |
+#ifdef USE_SLOW_TIMER |
|
310 |
+/* arm the "slow" timer ( start it) |
|
311 |
+ * returns -1 on error |
|
312 |
+ * WARNING: use it in the same process as the timer |
|
313 |
+ * (the one using pause(); timer_handler()) or |
|
314 |
+ * change run_timer to a pointer in shared mem */ |
|
315 |
+int arm_slow_timer() |
|
75 | 316 |
{ |
76 |
- struct sr_timer* t, *foo; |
|
317 |
+ sigemptyset(&slow_timer_sset); |
|
318 |
+ sigaddset(&slow_timer_sset, SLOW_TIMER_SIG); |
|
319 |
+again: |
|
320 |
+ if (sigprocmask(SIG_BLOCK, &slow_timer_sset, 0)==-1){ |
|
321 |
+ if (errno==EINTR) goto again; |
|
322 |
+ LOG(L_ERR, "ERROR: arm_slow_timer: sigprocmask failed: %s [%d]}n", |
|
323 |
+ strerror(errno), errno); |
|
324 |
+ goto error; |
|
325 |
+ } |
|
326 |
+ return 0; |
|
327 |
+error: |
|
328 |
+ return -1; |
|
329 |
+} |
|
330 |
+#endif |
|
77 | 331 |
|
78 |
- if (jiffies){ |
|
79 |
-#ifdef SHM_MEM |
|
80 |
- shm_free(jiffies); jiffies=0; |
|
332 |
+ |
|
333 |
+ |
|
334 |
+ |
|
335 |
+/* arm the timer ( start it) |
|
336 |
+ * returns -1 on error |
|
337 |
+ * WARNING: use it in the same process as the timer |
|
338 |
+ * (the one using pause(); timer_handler()) or |
|
339 |
+ * change run_timer to a pointer in shared mem */ |
|
340 |
+int arm_timer() |
|
341 |
+{ |
|
342 |
+ struct itimerval it; |
|
343 |
+ /* init signal generation */ |
|
344 |
+ it.it_interval.tv_sec=0; |
|
345 |
+ it.it_interval.tv_usec=1000000/TIMER_TICKS_HZ; |
|
346 |
+ it.it_value=it.it_interval; |
|
347 |
+ /* install the signal handler */ |
|
348 |
+ if (set_sig_h(SIGALRM, sig_timer) == SIG_ERR ){ |
|
349 |
+ LOG(L_CRIT, "ERROR: init_timer: the SIGALRM signal handler cannot" |
|
350 |
+ " be installed: %s [%d]\n", strerror(errno), errno); |
|
351 |
+ return -1; |
|
352 |
+ } |
|
353 |
+ if (setitimer(ITIMER_REAL, &it, 0) == -1){ |
|
354 |
+ LOG(L_CRIT, "ERROR: init_timer: setitimer failed: %s [%d]\n", |
|
355 |
+ strerror(errno), errno); |
|
356 |
+ return -1; |
|
357 |
+ } |
|
358 |
+ if (gettimeofday(&last_time, 0)<0){ |
|
359 |
+ LOG(L_ERR, "ERROR: arm_timer: gettimeofday failed: %s [%d]\n", |
|
360 |
+ strerror(errno), errno); |
|
361 |
+ return -1; |
|
362 |
+ } |
|
363 |
+ return 0; |
|
364 |
+} |
|
365 |
+ |
|
366 |
+ |
|
367 |
+ |
|
368 |
+/* adjust the timer using the "real" time, each TIMER_RESYNC_TICKS, but only |
|
369 |
+ * if timer drift > TIMER_MAX_DRIFT |
|
370 |
+ * NOTES: - it will adjust time within TIMER_MAX_DRIFT from the "real" |
|
371 |
+ * elapsed time |
|
372 |
+ * - it will never decrease the *ticks, only increase it (monotonic) |
|
373 |
+ * - it works ok as long as the adjustment interval < MAX_TICKS_T |
|
374 |
+ * -- andrei |
|
375 |
+ */ |
|
376 |
+inline static void adjust_ticks() |
|
377 |
+{ |
|
378 |
+ struct timeval crt_time; |
|
379 |
+ long long diff_time; |
|
380 |
+ ticks_t diff_time_ticks; |
|
381 |
+ ticks_t diff_ticks_raw; |
|
382 |
+ s_ticks_t delta; |
|
383 |
+ |
|
384 |
+ /* fix ticks if necessary */ |
|
385 |
+ if ((*ticks-last_adj_check)>=(ticks_t)TIMER_RESYNC_TICKS){ |
|
386 |
+ last_adj_check=*ticks; |
|
387 |
+ if (gettimeofday(&crt_time, 0)<0){ |
|
388 |
+ LOG(L_ERR, "ERROR: adjust_ticks: gettimeofday failed: %s [%d]\n", |
|
389 |
+ strerror(errno), errno); |
|
390 |
+ return; /* ignore */ |
|
391 |
+ } |
|
392 |
+ diff_time=(long long)crt_time.tv_sec*1000000+crt_time.tv_usec- |
|
393 |
+ ((long long) last_time.tv_sec*1000000+last_time.tv_usec); |
|
394 |
+ if (diff_time<0){ |
|
395 |
+ LOG(L_WARN, "WARNING: time changed backwards %ld ms ignoring...\n", |
|
396 |
+ (long)(diff_time/1000)); |
|
397 |
+ last_time=crt_time; |
|
398 |
+ last_ticks=*ticks; |
|
399 |
+ }else{ |
|
400 |
+ diff_ticks_raw=*ticks-last_ticks; |
|
401 |
+ diff_time_ticks=(ticks_t)((diff_time*TIMER_TICKS_HZ)/1000000LL); |
|
402 |
+ delta=(s_ticks_t)(diff_time_ticks-diff_ticks_raw); |
|
403 |
+ if (delta<-1){ |
|
404 |
+ LOG(L_WARN, "WARNING: our timer runs faster then real-time" |
|
405 |
+ " (%u ms / %u ticks our time .->" |
|
406 |
+ " %ld ms / %u ticks real time)\n", |
|
407 |
+ diff_ticks_raw*1000/TIMER_TICKS_HZ, diff_ticks_raw, |
|
408 |
+ (long)(diff_time/1000), diff_time_ticks); |
|
409 |
+ last_time=crt_time; |
|
410 |
+ last_ticks=*ticks; |
|
411 |
+ }else{ |
|
412 |
+ /* fix the ticks */ |
|
413 |
+ if (delta>(s_ticks_t)TIMER_MAX_DRIFT){ |
|
414 |
+#ifndef TIMER_DEBUG |
|
415 |
+ if (delta > 2*(s_ticks_t)TIMER_MAX_DRIFT) |
|
416 |
+#endif |
|
417 |
+ LOG(L_INFO, "adjusting timer ticks (%lu) with %ld ms" |
|
418 |
+ " (%ld ticks)\n", |
|
419 |
+ (unsigned long)*ticks, |
|
420 |
+ (long)(delta*1000)/TIMER_TICKS_HZ, (long)delta); |
|
421 |
+ *ticks+=(ticks_t)delta; |
|
422 |
+ }else{ |
|
423 |
+ /*DBG("incredible, but our timer is in sync with" |
|
424 |
+ " real time (%lu)\n", (unsigned long)*ticks); |
|
425 |
+ */ |
|
426 |
+ } |
|
427 |
+ } |
|
428 |
+ } |
|
429 |
+ } |
|
430 |
+} |
|
431 |
+ |
|
432 |
+ |
|
433 |
+ |
|
434 |
+ |
|
435 |
+struct timer_ln* timer_alloc() |
|
436 |
+{ |
|
437 |
+ return shm_malloc(sizeof(struct timer_ln)); |
|
438 |
+} |
|
439 |
+ |
|
440 |
+void timer_free(struct timer_ln* t) |
|
441 |
+{ |
|
442 |
+ shm_free(t); |
|
443 |
+} |
|
444 |
+ |
|
445 |
+ |
|
446 |
+/* unsafe (no lock ) timer add function |
|
447 |
+ * t = current ticks |
|
448 |
+ * tl must be filled (the intial_timeout and flags must be set) |
|
449 |
+ * returns -1 on error, 0 on success */ |
|
450 |
+static inline int _timer_add(ticks_t t, struct timer_ln* tl) |
|
451 |
+{ |
|
452 |
+ ticks_t delta; |
|
453 |
+ |
|
454 |
+#ifdef USE_SLOW_TIMER |
|
455 |
+ tl->flags&=~((unsigned short)F_TIMER_ON_SLOW_LIST); |
|
456 |
+ tl->slow_idx=0; |
|
457 |
+#endif |
|
458 |
+ delta=tl->initial_timeout; |
|
459 |
+ tl->expire=t+delta; |
|
460 |
+ return _timer_dist_tl(tl, delta); |
|
461 |
+} |
|
462 |
+ |
|
463 |
+ |
|
464 |
+ |
|
465 |
+/* "public", safe timer add functions |
|
466 |
+ * adds a timer at delta ticks from the current time |
|
467 |
+ * returns -1 on error, 0 on success |
|
468 |
+ * WARNING: to re-add a deleted or expired timer you must call |
|
469 |
+ * timer_reinit(tl) prior to timer_add |
|
470 |
+ * The default behaviour allows timer_add to add a timer only if it |
|
471 |
+ * has never been added before.*/ |
|
472 |
+#ifdef TIMER_DEBUG |
|
473 |
+int timer_add_safe(struct timer_ln* tl, ticks_t delta, |
|
474 |
+ const char* file, const char* func, unsigned line) |
|
81 | 475 |
#else |
82 |
- pkg_free(jiffies); jiffies=0; |
|
476 |
+int timer_add_safe(struct timer_ln* tl, ticks_t delta) |
|
83 | 477 |
#endif |
478 |
+{ |
|
479 |
+ int ret; |
|
480 |
+ |
|
481 |
+ LOCK_TIMER_LIST(); |
|
482 |
+ if (tl->flags & F_TIMER_ACTIVE){ |
|
483 |
+#ifdef TIMER_DEBUG |
|
484 |
+ LOG(timerlog, "timer_add called on an active timer %p (%p, %p)," |
|
485 |
+ " flags %x\n", tl, tl->next, tl->prev, tl->flags); |
|
486 |
+ LOG(timerlog, "WARN: -timer_add-; called from %s(%s):%d\n", |
|
487 |
+ func, file, line); |
|
488 |
+ LOG(timerlog, "WARN: -timer_add-: added %d times" |
|
489 |
+ ", last from: %s(%s):%d, deleted %d times" |
|
490 |
+ ", last from: %s(%s):%d, init %d times, expired %d \n", |
|
491 |
+ tl->add_calls, tl->add_func, tl->add_file, tl->add_line, |
|
492 |
+ tl->del_calls, tl->del_func, tl->del_file, tl->del_line, |
|
493 |
+ tl->init, tl->expires_no); |
|
494 |
+#else |
|
495 |
+ DBG("timer_add called on an active timer %p (%p, %p)," |
|
496 |
+ " flags %x\n", tl, tl->next, tl->prev, tl->flags); |
|
497 |
+#endif |
|
498 |
+ ret=-1; /* refusing to add active or non-reinit. timer */ |
|
499 |
+ goto error; |
|
84 | 500 |
} |
501 |
+ tl->initial_timeout=delta; |
|
502 |
+ if ((tl->next!=0) || (tl->prev!=0)){ |
|
503 |
+ LOG(L_CRIT, "BUG: timer_add: called with linked timer: %p (%p, %p)\n", |
|
504 |
+ tl, tl->next, tl->prev); |
|
505 |
+ ret=-1; |
|
506 |
+ goto error; |
|
507 |
+ } |
|
508 |
+ tl->flags|=F_TIMER_ACTIVE; |
|
509 |
+#ifdef TIMER_DEBUG |
|
510 |
+ tl->add_file=file; |
|
511 |
+ tl->add_func=func; |
|
512 |
+ tl->add_line=line; |
|
513 |
+ tl->add_calls++; |
|
514 |
+#endif |
|
515 |
+ ret=_timer_add(*ticks, tl); |
|
516 |
+error: |
|
517 |
+ UNLOCK_TIMER_LIST(); |
|
518 |
+ return ret; |
|
519 |
+} |
|
520 |
+ |
|
521 |
+ |
|
85 | 522 |
|
86 |
- t=timer_list; |
|
87 |
- while(t) { |
|
88 |
- foo=t->next; |
|
89 |
- pkg_free(t); |
|
90 |
- t=foo; |
|
523 |
+/* safe timer delete |
|
524 |
+ * deletes tl and inits the list pointer to 0 |
|
525 |
+ * WARNING: to be able to reuse a deleted timer you must call |
|
526 |
+ * timer_reinit(tl) on it |
|
527 |
+ * |
|
528 |
+ */ |
|
529 |
+#ifdef TIMER_DEBUG |
|
530 |
+void timer_del_safe(struct timer_ln* tl, |
|
531 |
+ const char* file, const char* func, unsigned line) |
|
532 |
+#else |
|
533 |
+void timer_del_safe(struct timer_ln* tl) |
|
534 |
+#endif |
|
535 |
+{ |
|
536 |
+ |
|
537 |
+again: |
|
538 |
+ /* quick exit if timer inactive */ |
|
539 |
+ if ( !(tl->flags & F_TIMER_ACTIVE)){ |
|
540 |
+#ifdef TIMER_DEBUG |
|
541 |
+ LOG(timerlog, "timer_del called on an inactive timer %p (%p, %p)," |
|
542 |
+ " flags %x\n", tl, tl->next, tl->prev, tl->flags); |
|
543 |
+ LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n", |
|
544 |
+ func, file, line); |
|
545 |
+ LOG(timerlog, "WARN: -timer_del-: added %d times" |
|
546 |
+ ", last from: %s(%s):%d, deleted %d times" |
|
547 |
+ ", last from: %s(%s):%d, init %d times, expired %d \n", |
|
548 |
+ tl->add_calls, tl->add_func, tl->add_file, tl->add_line, |
|
549 |
+ tl->del_calls, tl->del_func, tl->del_file, tl->del_line, |
|
550 |
+ tl->init, tl->expires_no); |
|
551 |
+#else |
|
552 |
+ DBG("timer_del called on an inactive timer %p (%p, %p)," |
|
553 |
+ " flags %x\n", tl, tl->next, tl->prev, tl->flags); |
|
554 |
+#endif |
|
555 |
+ return; |
|
556 |
+ } |
|
557 |
+#ifdef USE_SLOW_TIMER |
|
558 |
+ if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){ |
|
559 |
+ LOCK_SLOW_TIMER_LIST(); |
|
560 |
+ if (!IS_ON_SLOW_LIST(tl) || (tl->slow_idx==*t_idx)){ |
|
561 |
+ UNLOCK_SLOW_TIMER_LIST(); |
|
562 |
+ goto again; |
|
563 |
+ } |
|
564 |
+ if (IS_RUNNING_SLOW(tl)){ |
|
565 |
+ UNLOCK_SLOW_TIMER_LIST(); |
|
566 |
+ sched_yield(); /* wait for it to complete */ |
|
567 |
+ goto again; |
|
568 |
+ } |
|
569 |
+ if (tl->next!=0){ |
|
570 |
+ _timer_rm_list(tl); /* detach */ |
|
571 |
+ tl->next=tl->prev=0; |
|
572 |
+#ifdef TIMER_DEBUG |
|
573 |
+ tl->del_file=file; |
|
574 |
+ tl->del_func=func; |
|
575 |
+ tl->del_line=line; |
|
576 |
+ tl->flags|=F_TIMER_DELETED; |
|
577 |
+#endif |
|
578 |
+ }else{ |
|
579 |
+#ifdef TIMER_DEBUG |
|
580 |
+ LOG(timerlog, "timer_del: (s) timer %p (%p, %p) flags %x " |
|
581 |
+ "already detached\n", |
|
582 |
+ tl, tl->next, tl->prev, tl->flags); |
|
583 |
+ LOG(timerlog, "WARN: -timer_del-: @%d tl=%p " |
|
584 |
+ "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(), |
|
585 |
+ tl, tl->next, tl->prev, tl->expire, tl->initial_timeout, |
|
586 |
+ tl->data, tl->f, tl->flags); |
|
587 |
+ LOG(timerlog, "WARN: -timer_del-; called from %s(%s):%d\n", |
|
588 |
+ func, file, line); |
|
589 |
+ LOG(timerlog, "WARN: -timer_del-: added %d times" |
|
590 |
+ ", last from: %s(%s):%d, deleted %d times" |
|
591 |
+ ", last from: %s(%s):%d, init %d times, expired %d \n", |
|
592 |
+ tl->add_calls, |
|
593 |
+ tl->add_func, tl->add_file, tl->add_line, |
|
594 |
+ tl->del_calls, |
|
595 |
+ tl->del_func, tl->del_file, tl->del_line, |
|
596 |
+ tl->init, tl->expires_no); |
|
597 |
+#else |
|
598 |
+ DBG("timer_del: (s) timer %p (%p, %p) flags %x " |
|
599 |
+ "already detached\n", |
|
600 |
+ tl, tl->next, tl->prev, tl->flags); |
|
601 |
+#endif |
|
602 |
+ } |
|
603 |
+ UNLOCK_SLOW_TIMER_LIST(); |
|
604 |
+ }else{ |
|
605 |
+#endif |
|
606 |
+ LOCK_TIMER_LIST(); |
|
607 |
+#ifdef USE_SLOW_TIMER |
|
608 |
+ if (IS_ON_SLOW_LIST(tl) && (tl->slow_idx!=*t_idx)){ |
|
609 |
+ UNLOCK_TIMER_LIST(); |
|
610 |
+ goto again; |
|
611 |
+ } |
|
612 |
+#endif |
|
613 |
+ if (IS_RUNNING(tl)){ |
|
614 |
+ UNLOCK_TIMER_LIST(); |
|
615 |
+ sched_yield(); /* wait for it to complete */ |
|
616 |
+ goto again; |
|
617 |
+ } |
|
618 |
+ if ((tl->next!=0)&&(tl->prev!=0)){ |
|
619 |
+ _timer_rm_list(tl); /* detach */ |
|
620 |
+ tl->next=tl->prev=0; |
|
621 |
+#ifdef TIMER_DEBUG |
|
622 |
+ tl->del_file=file; |
|
623 |
+ tl->del_func=func; |
|
624 |
+ tl->del_line=line; |
|
625 |
+ tl->flags|=F_TIMER_DELETED; |
|
626 |
+#endif |
|
627 |
+ }else{ |
|
628 |
+#ifdef TIMER_DEBUG |
|
629 |
+ LOG(timerlog, "timer_del: (f) timer %p (%p, %p) flags %x " |
|
630 |
+ "already detached\n", |
|
631 |
+ tl, tl->next, tl->prev, tl->flags); |
|
632 |
+ LOG(timerlog, "WARN: -timer_del-: @%d tl=%p " |
|
633 |
+ "{ %p, %p, %d, %d, %p, %p, %04x, -}\n", get_ticks_raw(), |
|
634 |
+ tl, tl->next, tl->prev, tl->expire, tl->initial_timeout, |
|
635 |
+ tl->data, tl->f, tl->flags); |
|
636 |
+ LOG(timerlog, "WANT: -timer_del-; called from %s(%s):%d\n", |
|
637 |
+ func, file, line); |
|
638 |
+ LOG(timerlog, "WARN: -timer_del-: added %d times" |
|
639 |
+ ", last from: %s(%s):%d, deleted %d times" |
|
640 |
+ ", last from: %s(%s):%d, init %d times, expired %d \n", |
|
641 |
+ tl->add_calls, |
|
642 |
+ tl->add_func, tl->add_file, tl->add_line, |
|
643 |
+ tl->del_calls, |
|
644 |
+ tl->del_func, tl->del_file, tl->del_line, |
|
645 |
+ tl->init, tl->expires_no); |
|
646 |
+#else |
|
647 |
+ DBG("timer_del: (f) timer %p (%p, %p) flags %x " |
|
648 |
+ "already detached\n", |
|
649 |
+ tl, tl->next, tl->prev, tl->flags); |
|
650 |
+#endif |
|
651 |
+ } |
|
652 |
+ UNLOCK_TIMER_LIST(); |
|
653 |
+#ifdef USE_SLOW_TIMER |
|
654 |
+ } |
|
655 |
+#endif |
|
656 |
+} |
|
657 |
+ |
|
658 |
+ |
|
659 |
+ |
|
660 |
+/* called from timer_handle, must be called with the timer lock held */ |
|
661 |
+inline static void timer_list_expire(ticks_t t, struct timer_head* h |
|
662 |
+#ifdef USE_SLOW_TIMER |
|
663 |
+ , struct timer_head* slow_l, |
|
664 |
+ slow_idx_t slow_mark |
|
665 |
+#endif |
|
666 |
+ ) |
|
667 |
+{ |
|
668 |
+ struct timer_ln * tl; |
|
669 |
+ ticks_t ret; |
|
670 |
+#ifdef TIMER_DEBUG |
|
671 |
+ struct timer_ln* first; |
|
672 |
+ int i=0; |
|
673 |
+ |
|
674 |
+ first=h->next; |
|
675 |
+#endif |
|
676 |
+ |
|
677 |
+ /*DBG("timer_list_expire @ ticks = %lu, list =%p\n", |
|
678 |
+ (unsigned long) *ticks, h); |
|
679 |
+ */ |
|
680 |
+ while(h->next!=(struct timer_ln*)h){ |
|
681 |
+ tl=h->next; |
|
682 |
+#ifdef TIMER_DEBUG /* FIXME: replace w/ EXTRA_DEBUG */ |
|
683 |
+ if (tl==0){ |
|
684 |
+ LOG(L_CRIT, "BUG: timer_list_expire: tl=%p, h=%p {%p, %p}\n", |
|
685 |
+ tl, h, h->next, h->prev); |
|
686 |
+ abort(); |
|
687 |
+ }else if((tl->next==0) || (tl->prev==0)){ |
|
688 |
+ LOG(L_CRIT, "BUG: timer_list_expire: @%d tl=%p " |
|
689 |
+ "{ %p, %p, %d, %d, %p, %p, %04x, -}," |
|
690 |
+ " h=%p {%p, %p}\n", t, |
|
691 |
+ tl, tl->next, tl->prev, tl->expire, tl->initial_timeout, |
|
692 |
+ tl->data, tl->f, tl->flags, |
|
693 |
+ h, h->next, h->prev); |
|
694 |
+ LOG(L_CRIT, "BUG: -timer_list_expire-: cycle %d, first %p," |
|
695 |
+ "running %p\n", i, first, *running_timer); |
|
696 |
+ LOG(L_CRIT, "BUG: -timer_list_expire-: added %d times" |
|
697 |
+ ", last from: %s(%s):%d, deleted %d times" |
|
698 |
+ ", last from: %s(%s):%d, init %d times, expired %d \n", |
|
699 |
+ tl->add_calls, |
|
700 |
+ tl->add_func, tl->add_file, tl->add_line, |
|
701 |
+ tl->del_calls, |
|
702 |
+ tl->del_func, tl->del_file, tl->del_line, |
|
703 |
+ tl->init, tl->expires_no); |
|
704 |
+ abort(); |
|
705 |
+ } |
|
706 |
+ i++; |
|
707 |
+#endif |
|
708 |
+ _timer_rm_list(tl); /* detach */ |
|
709 |
+#ifdef USE_SLOW_TIMER |
|
710 |
+ if (IS_FAST_TIMER(tl)){ |
|
711 |
+#endif |
|
712 |
+ /* if fast timer */ |
|
713 |
+ SET_RUNNING(tl); |
|
714 |
+ tl->next=tl->prev=0; /* debugging */ |
|
715 |
+#ifdef TIMER_DEBUG |
|
716 |
+ tl->expires_no++; |
|
717 |
+#endif |
|
718 |
+ UNLOCK_TIMER_LIST(); /* acts also as write barrier */ |
|
719 |
+ ret=tl->f(t, tl, tl->data); |
|
720 |
+ if (ret==0){ |
|
721 |
+ UNSET_RUNNING(); |
|
722 |
+ LOCK_TIMER_LIST(); |
|
723 |
+ }else{ |
|
724 |
+ /* not one-shot, re-add it */ |
|
725 |
+ LOCK_TIMER_LIST(); |
|
726 |
+ if (ret!=(ticks_t)-1) /* ! periodic */ |
|
727 |
+ tl->initial_timeout=ret; |
|
728 |
+ _timer_add(t, tl); |
|
729 |
+ UNSET_RUNNING(); |
|
730 |
+ } |
|
731 |
+#ifdef USE_SLOW_TIMER |
|
732 |
+ }else{ |
|
733 |
+ /* slow timer */ |
|
734 |
+ SET_SLOW_LIST(tl); |
|
735 |
+ tl->slow_idx=slow_mark; /* current index */ |
|
736 |
+ /* overflow check in timer_handler*/ |
|
737 |
+ _timer_add_list(slow_l, tl); |
|
738 |
+ |
|
739 |
+ } |
|
740 |
+#endif |
|
91 | 741 |
} |
92 | 742 |
} |
93 | 743 |
|
94 | 744 |
|
95 | 745 |
|
96 |
-/*register a periodic timer; |
|
746 |
+/* "main" timer routine |
|
747 |
+ * WARNING: it should never be called twice for the same *ticks value |
|
748 |
+ * (it could cause too fast expires for long timers), *ticks must be also |
|
749 |
+ * always increasing */ |
|
750 |
+static void timer_handler() |
|
751 |
+{ |
|