| Module | Timeout |
| In: |
lib/active_ldap/timeout_stub.rb
lib/active_ldap/timeout.rb |
STUB
# File lib/active_ldap/timeout_stub.rb, line 5 5: def Timeout.alarm(sec, exception=Timeout::Error, &block) 6: timeout(sec, exception, &block) 7: end
A forking timeout implementation that relies on signals to interrupt blocking I/O instead of passing that code to run in a separate process.
A process is fork()ed, sleeps for sec, then sends a ALRM signal to the Process.ppid process. ALRM is used to avoid conflicts with sleep()
This overwrites any signal
# File lib/active_ldap/timeout.rb, line 14
14: def Timeout.alarm(sec, exception=Timeout::Error, &block)
15: return block.call if sec == nil or sec.zero?
16:
17:
18: # Trap an alarm in case it comes before we're ready
19: orig_alrm = trap(:ALRM, 'IGNORE')
20:
21: # Setup a fallback in case of a race condition of an
22: # alarm before we set the other trap
23: trap(:ALRM) do
24: # Don't leave zombies
25: Process.wait2()
26: # Restore the original handler
27: trap('ALRM', orig_alrm)
28: # Now raise an exception!
29: raise exception, 'execution expired'
30: end
31:
32: # Spawn the sleeper
33: pid = Process.fork {
34: begin
35: # Sleep x seconds then send SIGALRM
36: sleep(sec)
37: # Send alarm!
38: Process.kill(:ALRM, Process.ppid)
39: end
40: exit! 0
41: }
42:
43: # Setup the real handler
44: trap(:ALRM) do
45: # Make sure we clean up any zombies
46: Process.waitpid(pid)
47: # Restore the original handler
48: trap(:ALRM, orig_alrm)
49: # Now raise an exception!
50: raise exception, 'execution expired'
51: end
52:
53: begin
54: # Run the code!
55: return block.call
56: ensure
57: # Restore old alarm handler since we're done
58: trap(:ALRM, orig_alrm)
59: # Make sure the process is dead
60: # This may be run twice (trap occurs during execution) so ignore ESRCH
61: Process.kill(:TERM, pid) rescue Errno::ESRCH
62: # Don't leave zombies
63: Process.waitpid(pid) rescue Errno::ECHILD
64: end
65: end