SystemTimer 1.0 → 1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +13 -0
- data/README +7 -0
- data/ext/system_timer/extconf.rb +0 -0
- data/ext/system_timer/system_timer_native.c +204 -127
- data/lib/system_timer.rb +65 -30
- data/lib/system_timer/concurrent_timer_pool.rb +83 -0
- data/lib/system_timer/thread_timer.rb +21 -0
- data/lib/system_timer_stub.rb +5 -0
- data/test/all_tests.rb +3 -1
- data/test/system_timer/concurrent_timer_pool_unit_test.rb +274 -0
- data/test/system_timer/thread_timer_test.rb +20 -0
- data/test/system_timer_functional_test.rb +260 -0
- data/test/system_timer_unit_test.rb +96 -0
- data/test/test_helper.rb +10 -0
- metadata +10 -4
- data/test/system_timer_test.rb +0 -121
data/ChangeLog
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
=== 1.1.0 / 2008-11-05
|
2
|
+
|
3
|
+
* New implementation supporting concurrent timers, i.e. :
|
4
|
+
|
5
|
+
(1..10).each do
|
6
|
+
Thread.new do
|
7
|
+
SystemTimer.timeout_after(5) do
|
8
|
+
sleep 60
|
9
|
+
puts "hi there!"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
1
14
|
=== 1.0.0 / 2008-02-27
|
2
15
|
|
3
16
|
* Initial Release
|
data/README
CHANGED
@@ -5,6 +5,11 @@ solution to Ruby processes which hang beyond the time limit when accessing
|
|
5
5
|
external resources. This is useful when timeout.rb, which relies on green
|
6
6
|
threads, does not work consistently.
|
7
7
|
|
8
|
+
More background on:
|
9
|
+
|
10
|
+
* http://ph7spot.com/articles/system_timer
|
11
|
+
* http://davidvollbracht.com/2008/6/2/30-days-of-teach-day-1-systemtimer
|
12
|
+
|
8
13
|
== Usage
|
9
14
|
|
10
15
|
require 'systemtimer'
|
@@ -58,6 +63,8 @@ in particular MySQL.
|
|
58
63
|
This implementation is not intended to be drop-in replacement to
|
59
64
|
timeout.rb, just a way to wrap sensitive call to system resources.
|
60
65
|
|
66
|
+
You can find more details on SystemTimer and how to use it
|
67
|
+
at http://ph7spot.com/articles/system_timer
|
61
68
|
|
62
69
|
== License
|
63
70
|
|
data/ext/system_timer/extconf.rb
CHANGED
File without changes
|
@@ -1,7 +1,14 @@
|
|
1
|
+
/*
|
2
|
+
* SystemTimer native implementation relying on ITIMER_REAL
|
3
|
+
*
|
4
|
+
* Copyright 2008 David Vollbracht & Philippe Hanrigou
|
5
|
+
*/
|
6
|
+
|
1
7
|
#include "ruby.h"
|
2
8
|
#include "rubysig.h"
|
3
9
|
#include <signal.h>
|
4
10
|
#include <errno.h>
|
11
|
+
#include <stdarg.h>
|
5
12
|
|
6
13
|
#define DISPLAY_ERRNO 1
|
7
14
|
#define DO_NOT_DISPLAY_ERRNO 0
|
@@ -11,103 +18,151 @@ sigset_t original_mask;
|
|
11
18
|
sigset_t sigalarm_mask;
|
12
19
|
struct sigaction original_signal_handler;
|
13
20
|
struct itimerval original_timer_interval;
|
21
|
+
static int debug_enabled = 0;
|
14
22
|
|
15
23
|
static void clear_pending_sigalrm_for_ruby_threads();
|
16
|
-
static void log_debug(char*);
|
17
|
-
static void log_error(char*, int);
|
18
24
|
static void install_ruby_sigalrm_handler(VALUE);
|
19
25
|
static void restore_original_ruby_sigalrm_handler(VALUE);
|
20
26
|
static void restore_original_sigalrm_mask_when_blocked();
|
21
27
|
static void restore_original_timer_interval();
|
28
|
+
static void set_itimerval_with_minimum_1s_interval(struct itimerval *, int);
|
22
29
|
static void set_itimerval(struct itimerval *, int);
|
30
|
+
static void restore_sigalrm_mask(sigset_t *previous_mask);
|
31
|
+
static void log_debug(char*, ...);
|
32
|
+
static void log_error(char*, int);
|
23
33
|
|
24
|
-
static int debug_enabled = 0;
|
25
34
|
|
26
|
-
static VALUE
|
35
|
+
static VALUE install_first_timer_and_save_original_configuration(VALUE self, VALUE seconds)
|
27
36
|
{
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
37
|
+
struct itimerval timer_interval;
|
38
|
+
|
39
|
+
if (debug_enabled) {
|
40
|
+
log_debug("[install_first_timer] %d s\n", NUM2INT(seconds));
|
41
|
+
}
|
42
|
+
|
43
|
+
/*
|
44
|
+
* Block SIG_ALRM for safe processing of SIG_ALRM configuration and save mask.
|
45
|
+
*/
|
46
|
+
if (0 != sigprocmask(SIG_BLOCK, &sigalarm_mask, &original_mask)) {
|
47
|
+
log_error("[install_first_timer] Could not block SIG_ALRM\n", DISPLAY_ERRNO);
|
48
|
+
return Qnil;
|
49
|
+
}
|
50
|
+
clear_pending_sigalrm_for_ruby_threads();
|
51
|
+
log_debug("[install_first_timer] Successfully blocked SIG_ALRM at O.S. level\n");
|
39
52
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
53
|
+
/*
|
54
|
+
* Save previous signal handler.
|
55
|
+
*/
|
56
|
+
log_debug("[install_first_timer] Saving original system handler\n");
|
57
|
+
original_signal_handler.sa_handler = NULL;
|
58
|
+
if (0 != sigaction(SIGALRM, NULL, &original_signal_handler)) {
|
59
|
+
log_error("[install_first_timer] Could not save existing handler for SIG_ALRM\n", DISPLAY_ERRNO);
|
60
|
+
restore_original_sigalrm_mask_when_blocked();
|
61
|
+
return Qnil;
|
62
|
+
}
|
63
|
+
log_debug("[install_first_timer] Successfully saved existing SIG_ALRM handler\n");
|
64
|
+
|
65
|
+
/*
|
66
|
+
* Install Ruby Level SIG_ALRM handler
|
67
|
+
*/
|
68
|
+
install_ruby_sigalrm_handler(self);
|
69
|
+
|
70
|
+
/*
|
71
|
+
* Save original real time interval timer and aet new real time interval timer.
|
72
|
+
*/
|
73
|
+
set_itimerval(&original_timer_interval, 0);
|
74
|
+
set_itimerval_with_minimum_1s_interval(&timer_interval, seconds);
|
75
|
+
if (0 != setitimer(ITIMER_REAL, &timer_interval, &original_timer_interval)) {
|
76
|
+
log_error("[install_first_timer] Could not install our own timer, timeout will not work", DISPLAY_ERRNO);
|
77
|
+
restore_original_ruby_sigalrm_handler(self);
|
78
|
+
restore_original_sigalrm_mask_when_blocked();
|
79
|
+
return Qnil;
|
80
|
+
}
|
81
|
+
log_debug("[install_first_timer] Successfully installed timer (%ds)\n", timer_interval.it_value.tv_sec);
|
82
|
+
|
83
|
+
/*
|
84
|
+
* Unblock SIG_ALRM
|
85
|
+
*/
|
86
|
+
if (0 != sigprocmask(SIG_UNBLOCK, &sigalarm_mask, NULL)) {
|
87
|
+
log_error("[install_first_timer] Could not unblock SIG_ALRM, timeout will not work", DISPLAY_ERRNO);
|
88
|
+
restore_original_timer_interval();
|
89
|
+
restore_original_ruby_sigalrm_handler(self);
|
90
|
+
restore_original_sigalrm_mask_when_blocked();
|
91
|
+
}
|
92
|
+
log_debug("[install_first_timer] Successfully unblocked SIG_ALRM.\n");
|
93
|
+
|
94
|
+
return Qnil;
|
95
|
+
}
|
96
|
+
|
97
|
+
static VALUE install_next_timer(VALUE self, VALUE seconds)
|
84
98
|
{
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
99
|
+
struct itimerval timer_interval;
|
100
|
+
sigset_t previous_sigalarm_mask;
|
101
|
+
|
102
|
+
if (debug_enabled) {
|
103
|
+
log_debug("[install_next_timer] %ds\n", NUM2INT(seconds));
|
104
|
+
}
|
105
|
+
|
106
|
+
/*
|
107
|
+
* Block SIG_ALRM for safe processing of SIG_ALRM configuration and save mask.
|
108
|
+
*/
|
109
|
+
if (0 != sigprocmask(SIG_BLOCK, &sigalarm_mask, &previous_sigalarm_mask)) {
|
110
|
+
log_error("[install_next_timer] Could not block SIG_ALRM\n", DISPLAY_ERRNO);
|
111
|
+
return Qnil;
|
112
|
+
}
|
113
|
+
clear_pending_sigalrm_for_ruby_threads();
|
114
|
+
log_debug("[install_next_timer] Successfully blocked SIG_ALRM at O.S. level\n");
|
98
115
|
|
116
|
+
/*
|
117
|
+
* Set new real time interval timer.
|
118
|
+
*/
|
119
|
+
set_itimerval_with_minimum_1s_interval(&timer_interval, seconds);
|
120
|
+
if (0 != setitimer(ITIMER_REAL, &timer_interval, NULL)) {
|
121
|
+
log_error("[install_next_timer] Could not install our own timer, timeout will not work", DISPLAY_ERRNO);
|
122
|
+
restore_sigalrm_mask(&previous_sigalarm_mask);
|
123
|
+
return Qnil;
|
124
|
+
}
|
125
|
+
log_debug("[install_next_timer] Successfully installed timer (%ds)\n", timer_interval.it_value.tv_sec);
|
126
|
+
|
127
|
+
/*
|
128
|
+
* Unblock SIG_ALRM
|
129
|
+
*/
|
130
|
+
if (0 != sigprocmask(SIG_UNBLOCK, &sigalarm_mask, NULL)) {
|
131
|
+
log_error("[install_next_timer] Could not unblock SIG_ALRM, timeout will not work", DISPLAY_ERRNO);
|
132
|
+
restore_sigalrm_mask(&previous_sigalarm_mask);
|
133
|
+
}
|
134
|
+
log_debug("[install_next_timer] Successfully unblocked SIG_ALRM.\n");
|
135
|
+
|
136
|
+
return Qnil;
|
137
|
+
}
|
138
|
+
|
139
|
+
static VALUE restore_original_configuration(VALUE self)
|
140
|
+
{
|
141
|
+
/*
|
142
|
+
* Block SIG_ALRM for safe processing of SIG_ALRM configuration.
|
143
|
+
*/
|
144
|
+
if (0 != sigprocmask(SIG_BLOCK, &sigalarm_mask, NULL)) {
|
145
|
+
log_error("restore_original_configuration: Could not block SIG_ALRM", errno);
|
146
|
+
}
|
147
|
+
clear_pending_sigalrm_for_ruby_threads();
|
148
|
+
log_debug("[restore_original_configuration] Blocked SIG_ALRM\n");
|
149
|
+
|
150
|
+
/*
|
151
|
+
* Install Ruby Level SIG_ALRM handler
|
152
|
+
*/
|
153
|
+
restore_original_ruby_sigalrm_handler(self);
|
99
154
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
155
|
+
if (original_signal_handler.sa_handler == NULL) {
|
156
|
+
log_error("[restore_original_configuration] Previous SIG_ALRM handler not initialized!", DO_NOT_DISPLAY_ERRNO);
|
157
|
+
} else if (0 == sigaction(SIGALRM, &original_signal_handler, NULL)) {
|
158
|
+
log_debug("[restore_original_configuration] Successfully restored previous handler for SIG_ALRM\n");
|
159
|
+
} else {
|
160
|
+
log_error("[restore_original_configuration] Could not restore previous handler for SIG_ALRM", DISPLAY_ERRNO);
|
161
|
+
}
|
162
|
+
original_signal_handler.sa_handler = NULL;
|
108
163
|
|
109
|
-
|
110
|
-
|
164
|
+
restore_original_timer_interval();
|
165
|
+
restore_original_sigalrm_mask_when_blocked();
|
111
166
|
}
|
112
167
|
|
113
168
|
/*
|
@@ -119,61 +174,70 @@ static VALUE cleanup_timer(VALUE self, VALUE seconds)
|
|
119
174
|
*
|
120
175
|
*/
|
121
176
|
static void restore_original_timer_interval() {
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
177
|
+
if (0 != setitimer(ITIMER_REAL, &original_timer_interval, NULL)) {
|
178
|
+
log_error("[restore_original_configuration] Could not restore original timer", DISPLAY_ERRNO);
|
179
|
+
}
|
180
|
+
log_debug("[restore_original_configuration] Successfully restored original timer\n");
|
181
|
+
}
|
182
|
+
|
183
|
+
static void restore_sigalrm_mask(sigset_t *previous_mask)
|
184
|
+
{
|
185
|
+
if (!sigismember(previous_mask, SIGALRM)) {
|
186
|
+
sigprocmask(SIG_UNBLOCK, &sigalarm_mask, NULL);
|
187
|
+
log_debug("[restore_sigalrm_mask] Unblocked SIG_ALRM\n");
|
188
|
+
} else {
|
189
|
+
log_debug("[restore_sigalrm_mask] No Need to unblock SIG_ALRM\n");
|
190
|
+
}
|
126
191
|
}
|
127
192
|
|
128
193
|
static void restore_original_sigalrm_mask_when_blocked()
|
129
194
|
{
|
130
|
-
|
131
|
-
sigprocmask(SIG_UNBLOCK, &sigalarm_mask, NULL);
|
132
|
-
log_debug("cleanup_timer: Unblocked SIG_ALRM");
|
133
|
-
} else {
|
134
|
-
log_debug("cleanup_timer: No Need to unblock SIG_ALRM");
|
135
|
-
}
|
195
|
+
restore_sigalrm_mask(&original_mask);
|
136
196
|
}
|
137
197
|
|
138
198
|
static void install_ruby_sigalrm_handler(VALUE self) {
|
139
|
-
|
140
|
-
|
141
|
-
|
199
|
+
rb_thread_critical = 1;
|
200
|
+
rb_funcall(self, rb_intern("install_ruby_sigalrm_handler"), 0);
|
201
|
+
rb_thread_critical = 0;
|
142
202
|
}
|
143
203
|
|
144
204
|
static void restore_original_ruby_sigalrm_handler(VALUE self) {
|
145
|
-
|
146
|
-
|
147
|
-
|
205
|
+
rb_thread_critical = 1;
|
206
|
+
rb_funcall(self, rb_intern("restore_original_ruby_sigalrm_handler"), 0);
|
207
|
+
rb_thread_critical = 0;
|
148
208
|
}
|
149
209
|
|
150
210
|
|
151
211
|
static VALUE debug_enabled_p(VALUE self) {
|
152
|
-
|
212
|
+
return debug_enabled ? Qtrue : Qfalse;
|
153
213
|
}
|
154
214
|
|
155
215
|
static VALUE enable_debug(VALUE self) {
|
156
|
-
|
157
|
-
|
216
|
+
debug_enabled = 1;
|
217
|
+
return Qnil;
|
158
218
|
}
|
159
219
|
|
160
220
|
static VALUE disable_debug(VALUE self) {
|
161
|
-
|
162
|
-
|
221
|
+
debug_enabled = 0;
|
222
|
+
return Qnil;
|
163
223
|
}
|
164
224
|
|
165
|
-
static void log_debug(char* message)
|
225
|
+
static void log_debug(char* message, ...)
|
166
226
|
{
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
227
|
+
va_list argp;
|
228
|
+
|
229
|
+
if (0 != debug_enabled) {
|
230
|
+
va_start(argp, message);
|
231
|
+
vfprintf(stdout, message, argp);
|
232
|
+
va_end(argp);
|
233
|
+
}
|
234
|
+
return;
|
171
235
|
}
|
172
236
|
|
173
237
|
static void log_error(char* message, int display_errno)
|
174
238
|
{
|
175
|
-
|
176
|
-
|
239
|
+
fprintf(stderr, "%s: %s\n", message, display_errno ? strerror(errno) : "");
|
240
|
+
return;
|
177
241
|
}
|
178
242
|
|
179
243
|
/*
|
@@ -186,32 +250,45 @@ static void log_error(char* message, int display_errno)
|
|
186
250
|
*/
|
187
251
|
static void clear_pending_sigalrm_for_ruby_threads()
|
188
252
|
{
|
189
|
-
|
190
|
-
|
253
|
+
CHECK_INTS;
|
254
|
+
log_debug("[native] Successfully triggered all pending signals at Green Thread level\n");
|
191
255
|
}
|
192
256
|
|
193
257
|
static void init_sigalarm_mask()
|
194
258
|
{
|
195
|
-
|
196
|
-
|
197
|
-
|
259
|
+
sigemptyset(&sigalarm_mask);
|
260
|
+
sigaddset(&sigalarm_mask, SIGALRM);
|
261
|
+
return;
|
262
|
+
}
|
263
|
+
|
264
|
+
static void set_itimerval_with_minimum_1s_interval(struct itimerval *value,
|
265
|
+
int seconds) {
|
266
|
+
|
267
|
+
int sanitized_second_interval;
|
268
|
+
|
269
|
+
sanitized_second_interval = NUM2INT(seconds);
|
270
|
+
if (sanitized_second_interval <= 0 ) {
|
271
|
+
sanitized_second_interval = 1;
|
272
|
+
}
|
273
|
+
set_itimerval(value, sanitized_second_interval);
|
198
274
|
}
|
199
275
|
|
200
276
|
static void set_itimerval(struct itimerval *value, int seconds) {
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
277
|
+
value->it_interval.tv_usec = 0;
|
278
|
+
value->it_interval.tv_sec = 0;
|
279
|
+
value->it_value.tv_usec = 0;
|
280
|
+
value->it_value.tv_sec = seconds; // (long int)
|
281
|
+
return;
|
206
282
|
}
|
207
283
|
|
208
284
|
void Init_system_timer_native()
|
209
285
|
{
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
286
|
+
init_sigalarm_mask();
|
287
|
+
rb_cSystemTimer = rb_define_module("SystemTimer");
|
288
|
+
rb_define_singleton_method(rb_cSystemTimer, "install_first_timer_and_save_original_configuration", install_first_timer_and_save_original_configuration, 1);
|
289
|
+
rb_define_singleton_method(rb_cSystemTimer, "install_next_timer", install_next_timer, 1);
|
290
|
+
rb_define_singleton_method(rb_cSystemTimer, "restore_original_configuration", restore_original_configuration, 0);
|
291
|
+
rb_define_singleton_method(rb_cSystemTimer, "debug_enabled?", debug_enabled_p, 0);
|
292
|
+
rb_define_singleton_method(rb_cSystemTimer, "enable_debug", enable_debug, 0);
|
293
|
+
rb_define_singleton_method(rb_cSystemTimer, "disable_debug", disable_debug, 0);
|
217
294
|
}
|
data/lib/system_timer.rb
CHANGED
@@ -1,11 +1,21 @@
|
|
1
|
+
# Copyright 2008 David Vollbracht & Philippe Hanrigou
|
2
|
+
|
1
3
|
require 'rubygems'
|
2
4
|
require 'timeout'
|
5
|
+
require 'forwardable'
|
6
|
+
require File.dirname(__FILE__) + '/system_timer/thread_timer'
|
7
|
+
require File.dirname(__FILE__) + '/system_timer/concurrent_timer_pool'
|
3
8
|
|
4
|
-
# Timer based on underlying
|
9
|
+
# Timer based on underlying +ITIMER_REAL+ system timer. It is a
|
5
10
|
# solution to Ruby processes which hang beyond the time limit when accessing
|
6
11
|
# external resources. This is useful when timeout.rb, which relies on green
|
7
12
|
# threads, does not work consistently.
|
8
13
|
#
|
14
|
+
# For more information and background check out:
|
15
|
+
#
|
16
|
+
# * http://ph7spot.com/articles/system_timer
|
17
|
+
# * http://davidvollbracht.com/2008/6/2/30-days-of-teach-day-1-systemtimer
|
18
|
+
#
|
9
19
|
# == Usage
|
10
20
|
#
|
11
21
|
# require 'systemtimer'
|
@@ -17,54 +27,79 @@ require 'timeout'
|
|
17
27
|
#
|
18
28
|
# end
|
19
29
|
#
|
20
|
-
module SystemTimer
|
21
|
-
class << self
|
22
|
-
|
23
|
-
# Executes the method's block. If the block execution terminates before
|
24
|
-
# +seconds+ seconds has passed, it returns true. If not, it terminates
|
25
|
-
# the execution and raises a +Timeout::Error+.
|
26
|
-
def timeout_after(seconds)
|
27
|
-
install_timer(seconds)
|
28
|
-
return yield
|
29
|
-
ensure
|
30
|
-
cleanup_timer
|
31
|
-
end
|
30
|
+
module SystemTimer
|
32
31
|
|
33
|
-
|
34
|
-
|
32
|
+
Thread.exclusive do # Avoid race conditions for mutex and pool creation
|
33
|
+
@timer_pool = ConcurrentTimerPool.new
|
34
|
+
@mutex = Mutex.new
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
attr_reader :timer_pool
|
39
|
+
|
40
|
+
# Executes the method's block. If the block execution terminates before
|
41
|
+
# +seconds+ seconds has passed, it returns true. If not, it terminates
|
42
|
+
# the execution and raises a +Timeout::Error+.
|
43
|
+
def timeout_after(seconds)
|
44
|
+
new_timer = nil # just for scope
|
45
|
+
@mutex.synchronize do
|
46
|
+
new_timer = timer_pool.add_timer seconds
|
47
|
+
timer_interval = timer_pool.next_trigger_interval_in_seconds
|
48
|
+
debug "==== Install Timer ==== at #{Time.now.to_i}, next interval: #{timer_interval}"
|
49
|
+
if timer_pool.first_timer?
|
50
|
+
install_first_timer_and_save_original_configuration timer_interval
|
51
|
+
else
|
52
|
+
install_next_timer timer_interval
|
53
|
+
end
|
54
|
+
end
|
55
|
+
return yield
|
56
|
+
ensure
|
57
|
+
@mutex.synchronize do
|
58
|
+
debug "==== Cleanup Timer ==== at #{Time.now.to_i}, #{new_timer} "
|
59
|
+
timer_pool.cancel new_timer
|
60
|
+
timer_pool.log_registered_timers if debug_enabled?
|
61
|
+
next_interval = timer_pool.next_trigger_interval_in_seconds
|
62
|
+
debug "Cleanup Timer : next interval #{next_interval.inspect} "
|
63
|
+
if next_interval
|
64
|
+
install_next_timer next_interval
|
65
|
+
else
|
66
|
+
restore_original_configuration
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Backward compatibility with timeout.rb
|
72
|
+
alias timeout timeout_after
|
35
73
|
|
36
74
|
protected
|
37
75
|
|
38
|
-
def install_ruby_sigalrm_handler
|
39
|
-
timed_thread = Thread.current # Ruby signals are always delivered to main thread by default.
|
76
|
+
def install_ruby_sigalrm_handler #:nodoc:
|
40
77
|
@original_ruby_sigalrm_handler = trap('SIGALRM') do
|
41
|
-
|
42
|
-
|
43
|
-
|
78
|
+
@mutex.synchronize do
|
79
|
+
# Triggers timers one at a time to ensure more deterministic results
|
80
|
+
timer_pool.trigger_next_expired_timer
|
81
|
+
end
|
82
|
+
end
|
44
83
|
end
|
45
84
|
|
46
|
-
def restore_original_ruby_sigalrm_handler
|
85
|
+
def restore_original_ruby_sigalrm_handler #:nodoc:
|
47
86
|
trap('SIGALRM', original_ruby_sigalrm_handler || 'DEFAULT')
|
48
87
|
ensure
|
49
88
|
reset_original_ruby_sigalrm_handler
|
50
89
|
end
|
51
90
|
|
52
|
-
def original_ruby_sigalrm_handler
|
91
|
+
def original_ruby_sigalrm_handler #:nodoc:
|
53
92
|
@original_ruby_sigalrm_handler
|
54
93
|
end
|
55
94
|
|
56
|
-
def reset_original_ruby_sigalrm_handler
|
95
|
+
def reset_original_ruby_sigalrm_handler #:nodoc:
|
57
96
|
@original_ruby_sigalrm_handler = nil
|
58
97
|
end
|
59
98
|
|
60
|
-
def
|
61
|
-
puts
|
62
|
-
install_ruby_sigalrm_handler: Got Timeout in #{Thread.current}
|
63
|
-
Main thread : #{Thread.main}
|
64
|
-
Timed_thread : #{timed_thread}
|
65
|
-
All Threads : #{Thread.list.inspect}
|
66
|
-
EOS
|
99
|
+
def debug(message) #:nodoc
|
100
|
+
puts message if debug_enabled?
|
67
101
|
end
|
102
|
+
|
68
103
|
end
|
69
104
|
|
70
105
|
end
|