woolen_common 0.0.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.
- checksums.yaml +15 -0
- data/README.md +31 -0
- data/ext/woolen_common/extconf.rb +26 -0
- data/ext/woolen_common/linux.h +3 -0
- data/ext/woolen_common/win.c +18 -0
- data/ext/woolen_common/win.h +4 -0
- data/ext/woolen_common/win/puts_color.c +139 -0
- data/ext/woolen_common/win/puts_color.h +5 -0
- data/ext/woolen_common/woolen_common.c +20 -0
- data/ext/woolen_common/woolen_common.h +7 -0
- data/lib/woolen_common.rb +39 -0
- data/lib/woolen_common/abstract_middleware/builder.rb +138 -0
- data/lib/woolen_common/abstract_middleware/map_cfg_manager.rb +52 -0
- data/lib/woolen_common/abstract_middleware/runner.rb +72 -0
- data/lib/woolen_common/action_pool_proxy.rb +28 -0
- data/lib/woolen_common/actionpool.rb +10 -0
- data/lib/woolen_common/actionpool/pool.rb +295 -0
- data/lib/woolen_common/actionpool/queue.rb +41 -0
- data/lib/woolen_common/actionpool/thread.rb +181 -0
- data/lib/woolen_common/addr_helper.rb +93 -0
- data/lib/woolen_common/cache.rb +305 -0
- data/lib/woolen_common/common_helper.rb +42 -0
- data/lib/woolen_common/config_manager.rb +36 -0
- data/lib/woolen_common/drb_helper.rb +125 -0
- data/lib/woolen_common/ffi/win32_kernel32.rb +86 -0
- data/lib/woolen_common/logger.rb +419 -0
- data/lib/woolen_common/pcap/mu/fixnum_ext.rb +8 -0
- data/lib/woolen_common/pcap/mu/pcap/ethernet.rb +164 -0
- data/lib/woolen_common/pcap/mu/pcap/header.rb +76 -0
- data/lib/woolen_common/pcap/mu/pcap/io_pair.rb +68 -0
- data/lib/woolen_common/pcap/mu/pcap/io_wrapper.rb +77 -0
- data/lib/woolen_common/pcap/mu/pcap/ip.rb +62 -0
- data/lib/woolen_common/pcap/mu/pcap/ipv4.rb +274 -0
- data/lib/woolen_common/pcap/mu/pcap/ipv6.rb +149 -0
- data/lib/woolen_common/pcap/mu/pcap/packet.rb +106 -0
- data/lib/woolen_common/pcap/mu/pcap/pkthdr.rb +162 -0
- data/lib/woolen_common/pcap/mu/pcap/reader.rb +62 -0
- data/lib/woolen_common/pcap/mu/pcap/reader/http_family.rb +175 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp.rb +369 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp/chunk.rb +124 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/data.rb +135 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/init.rb +101 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp/chunk/init_ack.rb +69 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp/parameter.rb +111 -0
- data/lib/woolen_common/pcap/mu/pcap/sctp/parameter/ip_address.rb +49 -0
- data/lib/woolen_common/pcap/mu/pcap/stream_packetizer.rb +74 -0
- data/lib/woolen_common/pcap/mu/pcap/tcp.rb +522 -0
- data/lib/woolen_common/pcap/mu/pcap/udp.rb +81 -0
- data/lib/woolen_common/pcap/mu/scenario/pcap.rb +175 -0
- data/lib/woolen_common/pcap/mu/scenario/pcap/fields.rb +51 -0
- data/lib/woolen_common/pcap/mu/scenario/pcap/rtp.rb +72 -0
- data/lib/woolen_common/pcap/pcap.rb +115 -0
- data/lib/woolen_common/pcap/readme.md +72 -0
- data/lib/woolen_common/ruby_ext/blank.rb +126 -0
- data/lib/woolen_common/ruby_ext/drb_ext.rb +7 -0
- data/lib/woolen_common/ruby_ext/string.rb +116 -0
- data/lib/woolen_common/ruby_ext/win32_ole.rb +4 -0
- data/lib/woolen_common/ruby_proxy.rb +5 -0
- data/lib/woolen_common/ruby_proxy/client.rb +305 -0
- data/lib/woolen_common/ruby_proxy/config.rb +44 -0
- data/lib/woolen_common/ruby_proxy/exceptions.rb +17 -0
- data/lib/woolen_common/ruby_proxy/proxy.rb +157 -0
- data/lib/woolen_common/ruby_proxy/proxy_global_set.rb +44 -0
- data/lib/woolen_common/ruby_proxy/proxy_load.rb +34 -0
- data/lib/woolen_common/ruby_proxy/server.rb +53 -0
- data/lib/woolen_common/splib.rb +36 -0
- data/lib/woolen_common/splib/Array.rb +33 -0
- data/lib/woolen_common/splib/CodeReloader.rb +59 -0
- data/lib/woolen_common/splib/Constants.rb +44 -0
- data/lib/woolen_common/splib/Conversions.rb +47 -0
- data/lib/woolen_common/splib/Exec.rb +132 -0
- data/lib/woolen_common/splib/Float.rb +13 -0
- data/lib/woolen_common/splib/HumanIdealRandomIterator.rb +40 -0
- data/lib/woolen_common/splib/Monitor.rb +214 -0
- data/lib/woolen_common/splib/PriorityQueue.rb +110 -0
- data/lib/woolen_common/splib/Sleep.rb +10 -0
- data/lib/woolen_common/splib/UrlShorteners.rb +48 -0
- data/lib/woolen_common/ssh_proxy.rb +146 -0
- data/lib/woolen_common/system_helper.rb +123 -0
- data/lib/woolen_common/system_monitor.rb +23 -0
- data/lib/woolen_common/system_monitor/linux_monitor.rb +250 -0
- data/lib/woolen_common/system_monitor/windows_monitor.rb +145 -0
- data/lib/woolen_common/type_helper.rb +42 -0
- data/lib/woolen_common/ver_ctrl_middle_ware.rb +92 -0
- data/lib/woolen_common/version.rb +3 -0
- metadata +210 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
module Splib
|
2
|
+
# c:: constant name (String)
|
3
|
+
# things:: Array of Object/Module constants to look in
|
4
|
+
# Finds a constant if it exists
|
5
|
+
# Example:: Foo::Bar
|
6
|
+
# Returns nil if nothing found
|
7
|
+
def self.find_const(c, things=[])
|
8
|
+
raise ArgumentError.new('Exepcting an array') unless things.is_a?(Array)
|
9
|
+
const = nil
|
10
|
+
(things + [Object]).each do |base|
|
11
|
+
begin
|
12
|
+
c.split('::').each do |part|
|
13
|
+
const = const.nil? ? base.const_get(part) : const.const_get(part)
|
14
|
+
end
|
15
|
+
rescue NameError
|
16
|
+
const = nil
|
17
|
+
end
|
18
|
+
break unless const.nil?
|
19
|
+
end
|
20
|
+
const
|
21
|
+
end
|
22
|
+
|
23
|
+
# a:: an object
|
24
|
+
# b:: constant or string
|
25
|
+
# Returns true of a is a type of b. b can be given as a String
|
26
|
+
# to allow for matching of types contained within a module or
|
27
|
+
# for types that may not be loaded
|
28
|
+
def self.type_of?(a, b)
|
29
|
+
case b
|
30
|
+
when String
|
31
|
+
if(a.class.to_s.slice(0).chr == '#')
|
32
|
+
name = a.class.to_s
|
33
|
+
return name.slice(name.index('::')+2, name.length) == b
|
34
|
+
else
|
35
|
+
const = self.find_const(b)
|
36
|
+
return const.nil? ? false : a.is_a?(const)
|
37
|
+
end
|
38
|
+
when Class
|
39
|
+
return a.is_a?(b)
|
40
|
+
else
|
41
|
+
raise ArgumentError.new('Comparision type must be a string or constant')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Splib
|
2
|
+
# secs:: number of seconds
|
3
|
+
# Converts seconds into a human readable string (This is an estimate
|
4
|
+
# and does not account for leaps)
|
5
|
+
def self.format_seconds(secs)
|
6
|
+
arg = [{:year => 31536000},
|
7
|
+
{:month => 2678400},
|
8
|
+
{:week => 604800},
|
9
|
+
{:day => 86400},
|
10
|
+
{:hour => 3600},
|
11
|
+
{:minute => 60},
|
12
|
+
{:second => 1}]
|
13
|
+
res = ''
|
14
|
+
arg.each do |val|
|
15
|
+
val.each_pair do |k,v|
|
16
|
+
z = (secs / v).to_i
|
17
|
+
next unless z > 0
|
18
|
+
res += " #{z} #{k}#{z == 1 ? '':'s'}"
|
19
|
+
secs = secs % v
|
20
|
+
end
|
21
|
+
end
|
22
|
+
res = '0 seconds' if res.empty?
|
23
|
+
return res.strip
|
24
|
+
end
|
25
|
+
|
26
|
+
# bytes:: number of bytes
|
27
|
+
# Converts bytes into easy human readable form
|
28
|
+
# O(1) version by Ryan "pizza_milkshake" Flynn
|
29
|
+
Suff = [
|
30
|
+
"", # 1024^0
|
31
|
+
"Kilo", # 1024^1
|
32
|
+
"Mega", # 1024^2
|
33
|
+
"Giga", # 1024^3
|
34
|
+
"Tera", # 1024^4
|
35
|
+
"Peta", # 1024^5
|
36
|
+
"Exa", # 1024^6
|
37
|
+
"Zetta", # 1024^7
|
38
|
+
"Yotta" # 1024^8
|
39
|
+
]
|
40
|
+
def self.format_size(bytes)
|
41
|
+
return "0 bytes" if bytes == 0
|
42
|
+
mag = (Math.log(bytes) / Math.log(1024)).floor
|
43
|
+
mag = [ Suff.length - 1, mag ].min
|
44
|
+
val = bytes.to_f / (1024 ** mag)
|
45
|
+
("%.2f %sbyte%s" % [ val, Suff[mag], val == 1 ? "" : "s" ]).strip
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
|
3
|
+
module Splib
|
4
|
+
|
5
|
+
@@processes = []
|
6
|
+
@@owner ||= Thread.current
|
7
|
+
Kernel.at_exit do
|
8
|
+
if(Thread.current == @@owner)
|
9
|
+
@@processes.each{|pro| Process.kill('KILL', pro.pid) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns current array of running Processes
|
14
|
+
def self.running_procs
|
15
|
+
@@processes
|
16
|
+
end
|
17
|
+
# command:: command string to execute
|
18
|
+
# timeout:: length of time to execute
|
19
|
+
# maxbytes:: maximum number return bytes allowed
|
20
|
+
# Execute system command. This is a wrapper method
|
21
|
+
# that will redirect to the proper command
|
22
|
+
def self.exec(*args)
|
23
|
+
if(RUBY_PLATFORM == 'java')
|
24
|
+
thread_exec(*args)
|
25
|
+
else
|
26
|
+
standard_exec(*args)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# command:: command to execute
|
31
|
+
# timeout:: maximum number of seconds to run
|
32
|
+
# maxbytes:: maximum number of result bytes to accept
|
33
|
+
# priority:: set priority of the process
|
34
|
+
# Execute a system command (use with care)
|
35
|
+
# This is the normal exec command that is used
|
36
|
+
def self.standard_exec(command, timeout=10, maxbytes=500, priority=nil)
|
37
|
+
timeout = timeout.to_i
|
38
|
+
maxbytes = maxbytes.to_i
|
39
|
+
priority = priority.to_i
|
40
|
+
output = []
|
41
|
+
pro = nil
|
42
|
+
begin
|
43
|
+
if(timeout > 0)
|
44
|
+
Timeout::timeout(timeout) do
|
45
|
+
pro = IO.popen(command)
|
46
|
+
@@processes << pro
|
47
|
+
if(priority > 0)
|
48
|
+
Process.setpriority(Process::PRIO_PROCESS, pro.pid, priority)
|
49
|
+
end
|
50
|
+
until(pro.closed? || pro.eof?)
|
51
|
+
output << pro.getc.chr
|
52
|
+
if(maxbytes > 0 && output.size > maxbytes)
|
53
|
+
raise IOError.new("Maximum allowed output bytes exceeded. (#{maxbytes} bytes)")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
else
|
58
|
+
pro = IO.popen(command)
|
59
|
+
@@processes << pro
|
60
|
+
until(pro.closed? || pro.eof?)
|
61
|
+
output << pro.getc.chr
|
62
|
+
if(maxbytes > 0 && output.size > maxbytes)
|
63
|
+
raise IOError.new("Maximum allowed output bytes exceeded. (#{maxbytes} bytes)")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
output = output.join('')
|
68
|
+
ensure
|
69
|
+
Process.kill('KILL', pro.pid) if Process.waitpid2(pro.pid, Process::WNOHANG).nil? # make sure the process is dead
|
70
|
+
@@processes.delete(pro)
|
71
|
+
end
|
72
|
+
return output
|
73
|
+
end
|
74
|
+
# Used for the thread_exec method to notify of completion
|
75
|
+
class Complete < StandardError
|
76
|
+
end
|
77
|
+
|
78
|
+
# command:: command to execute
|
79
|
+
# timeout:: maximum number of seconds to run
|
80
|
+
# maxbytes:: maximum number of result bytes to accept
|
81
|
+
# priority:: set priority of the process
|
82
|
+
# Execute a system command (use with care)
|
83
|
+
# This is the threaded exec command that is generally used
|
84
|
+
# with JRuby. The regular timeout does not work when executing
|
85
|
+
# a process, so we do it in a separate thread and sleep the main
|
86
|
+
# thread until the timeout is reached.
|
87
|
+
def self.thread_exec(command, timeout=10, maxbytes=500)
|
88
|
+
timeout = timeout.to_i
|
89
|
+
maxbytes = maxbytes.to_i
|
90
|
+
priority = priority.to_i
|
91
|
+
current = Thread.current
|
92
|
+
output = []
|
93
|
+
pro = nil
|
94
|
+
thread = Thread.new do
|
95
|
+
boom = Complete.new
|
96
|
+
begin
|
97
|
+
pro = IO.popen(command)
|
98
|
+
@@processes << pro
|
99
|
+
if(priority > 0)
|
100
|
+
Process.setpriority(Process::PRIO_PROCESS, pro.pid, priority)
|
101
|
+
end
|
102
|
+
until(pro.closed? || pro.eof?)
|
103
|
+
output << pro.getc.chr
|
104
|
+
if(maxbytes > 0 && output.size > maxbytes)
|
105
|
+
raise IOError.new("Maximum allowed output bytes exceeded. (#{maxbytes} bytes)")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
rescue Exception => boom
|
109
|
+
# just want it set
|
110
|
+
end
|
111
|
+
current.raise boom unless boom.is_a?(Timeout::Error)
|
112
|
+
end
|
113
|
+
begin
|
114
|
+
begin
|
115
|
+
if(timeout > 0)
|
116
|
+
thread.join(timeout)
|
117
|
+
thread.raise Timeout::Error.new
|
118
|
+
raise Timeout::Error.new
|
119
|
+
else
|
120
|
+
thread.join
|
121
|
+
end
|
122
|
+
output.join('')
|
123
|
+
rescue Complete
|
124
|
+
# ignore this exception
|
125
|
+
end
|
126
|
+
ensure
|
127
|
+
Process.kill('KILL', pro.pid) unless pro.nil?
|
128
|
+
@@processes.delete(pro)
|
129
|
+
end
|
130
|
+
output.join('')
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Splib
|
2
|
+
# While not a big fan of monkeypatching, I want to be
|
3
|
+
# lazy getting to this
|
4
|
+
class ::Float
|
5
|
+
def within_delta?(args={})
|
6
|
+
raise ArgumentError.new('Missing required argument: :expected') unless args[:expected]
|
7
|
+
raise ArgumentError.new('Missing required argument: :delta') unless args[:delta]
|
8
|
+
e = args[:expected].to_f
|
9
|
+
d = args[:delta].to_f
|
10
|
+
self.between?(e-d, e+d)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Splib
|
2
|
+
# IdealHumanRandomIterator - select "random" members of a population, favoring
|
3
|
+
# those least-recently selected, to appease silly humans who hate repeats
|
4
|
+
#
|
5
|
+
# Abstract:
|
6
|
+
# given a decently-sized set of items (say, 100 famous quotes), an
|
7
|
+
# average persons's idea of N "random" entries is not actually random.
|
8
|
+
# people don't want items to appear twice in a row, or too frequently
|
9
|
+
# (even though true randomness means this is just as likely as any other order).
|
10
|
+
#
|
11
|
+
# instead, design a scheme whereby LRU items are weighted more heavily,
|
12
|
+
# to "encourage" subsequent selections to not repeat.
|
13
|
+
#
|
14
|
+
# Author: Ryan "pizza_" Flynn
|
15
|
+
# - pulled from the algodict project
|
16
|
+
# - - http://github.com/pizza/algodict
|
17
|
+
class IdealHumanRandomIterator
|
18
|
+
|
19
|
+
def initialize(list)
|
20
|
+
raise ArgumentError.new("Array type required") unless list.is_a?(Array)
|
21
|
+
@items = list
|
22
|
+
end
|
23
|
+
|
24
|
+
# Given length L, generate a random number in the range [0,len-1), heavily
|
25
|
+
# weighted towards the low end.
|
26
|
+
def self.nexti(len)
|
27
|
+
len += 1 if len % 2 == 1
|
28
|
+
index = len > 2 ? rand(len/2) : 0
|
29
|
+
return index
|
30
|
+
end
|
31
|
+
|
32
|
+
# return a psuedo-random member of items. subsequent calls should never
|
33
|
+
# return the same item.
|
34
|
+
def next()
|
35
|
+
index = IdealHumanRandomIterator.nexti(@items.length)
|
36
|
+
@items.push @items.delete_at(index)
|
37
|
+
return @items.last
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Splib
|
4
|
+
Splib.load :Sleep
|
5
|
+
# Basic exception to wakeup a monitor timer
|
6
|
+
class Wakeup < Exception
|
7
|
+
end
|
8
|
+
class Monitor
|
9
|
+
# Create a new Monitor
|
10
|
+
def initialize
|
11
|
+
@threads = []
|
12
|
+
@locks = []
|
13
|
+
@lock_owner = nil
|
14
|
+
@timers = {}
|
15
|
+
@timer = start_timer
|
16
|
+
@stop = false
|
17
|
+
Kernel.at_exit do
|
18
|
+
if(@timer)
|
19
|
+
@stop = true
|
20
|
+
@timer.raise Wakeup.new
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# timeout:: Wait for given amount of time
|
26
|
+
# Park a thread here
|
27
|
+
def wait(timeout=nil)
|
28
|
+
raise 'This thread is already a registered sleeper' if @threads.include?(Thread.current)
|
29
|
+
Thread.exclusive{ @threads << Thread.current }
|
30
|
+
if(timeout)
|
31
|
+
timeout = timeout.to_f
|
32
|
+
Thread.exclusive{ @timers[Thread.current] = timeout }
|
33
|
+
@timer.raise Wakeup.new
|
34
|
+
end
|
35
|
+
Thread.stop
|
36
|
+
Thread.exclusive{ @threads.delete(Thread.current) }
|
37
|
+
if(timeout && @timers.has_key?(Thread.current))
|
38
|
+
Thread.exclusive{ @timers.delete(Thread.current) }
|
39
|
+
@timer.raise Wakeup.new
|
40
|
+
end
|
41
|
+
true
|
42
|
+
end
|
43
|
+
# Park thread while block is true
|
44
|
+
def wait_while
|
45
|
+
while yield
|
46
|
+
wait
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# Park thread until block is true
|
50
|
+
def wait_until
|
51
|
+
until yield
|
52
|
+
wait
|
53
|
+
end
|
54
|
+
end
|
55
|
+
# Wake up earliest thread
|
56
|
+
def signal
|
57
|
+
synchronize do
|
58
|
+
while(t = @threads.shift)
|
59
|
+
if(t && t.alive? && t.stop?)
|
60
|
+
t.wakeup
|
61
|
+
break
|
62
|
+
else
|
63
|
+
next
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
# Wake up all threads
|
69
|
+
def broadcast
|
70
|
+
synchronize do
|
71
|
+
@threads.dup.each do |t|
|
72
|
+
t.wakeup if t.alive? && t.stop?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
# Number of threads waiting
|
77
|
+
def waiters
|
78
|
+
@threads.size
|
79
|
+
end
|
80
|
+
# Lock the monitor
|
81
|
+
def lock
|
82
|
+
Thread.exclusive{ do_lock }
|
83
|
+
until(owner?(Thread.current)) do
|
84
|
+
Thread.stop
|
85
|
+
end
|
86
|
+
end
|
87
|
+
# Unlock the monitor
|
88
|
+
def unlock
|
89
|
+
do_unlock
|
90
|
+
end
|
91
|
+
# Attempt to lock. Returns true if lock is aquired and false if not.
|
92
|
+
def try_lock
|
93
|
+
locked = false
|
94
|
+
Thread.exclusive do
|
95
|
+
clean
|
96
|
+
unless(locked?(false))
|
97
|
+
do_lock
|
98
|
+
locked = true
|
99
|
+
else
|
100
|
+
locked = owner?(Thread.current)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
locked
|
104
|
+
end
|
105
|
+
# cln:: Clean dead threads
|
106
|
+
# Is monitor locked
|
107
|
+
def locked?(cln=true)
|
108
|
+
Thread.exclusive{clean} if cln
|
109
|
+
@locks.size > 0 || @lock_owner
|
110
|
+
end
|
111
|
+
# Lock the monitor, execute block and unlock the monitor
|
112
|
+
def synchronize
|
113
|
+
result = nil
|
114
|
+
lock
|
115
|
+
result = yield
|
116
|
+
do_unlock
|
117
|
+
result
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
|
123
|
+
# This is a simple helper method to help keep threads from ending
|
124
|
+
# up stuck waiting for a lock when a thread locks the monitor and
|
125
|
+
# then decides to die without unlocking. It is only called when
|
126
|
+
# new locks are attempted or a check is made if the monitor is
|
127
|
+
# currently locked.
|
128
|
+
def clean
|
129
|
+
@locks.delete_if{|t|!t.alive?}
|
130
|
+
if(@lock_owner && !@lock_owner.alive?)
|
131
|
+
@lock_owner = @locks.empty? ? nil : @locks.shift
|
132
|
+
@lock_owner.wakeup if @lock_owner && !owner?(Thread.current)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Check if the givin thread is the current owner
|
137
|
+
def owner?(t)
|
138
|
+
@lock_owner == t
|
139
|
+
end
|
140
|
+
|
141
|
+
# Aquire monitor lock or be queued for lock
|
142
|
+
# NOTE: To make this method more generic and useful, it does
|
143
|
+
# not perform a Thread.exclusive, and as such this method should
|
144
|
+
# only be called from within a Thread.exclusive{}
|
145
|
+
def do_lock
|
146
|
+
clean
|
147
|
+
if(@lock_owner)
|
148
|
+
if(owner?(Thread.current))
|
149
|
+
@locks.unshift(Thread.current)
|
150
|
+
else
|
151
|
+
@locks << Thread.current
|
152
|
+
end
|
153
|
+
else
|
154
|
+
@lock_owner = Thread.current
|
155
|
+
end
|
156
|
+
true
|
157
|
+
end
|
158
|
+
|
159
|
+
# Unlock the monitor
|
160
|
+
def do_unlock
|
161
|
+
unless(owner?(Thread.current))
|
162
|
+
raise ThreadError.new("Thread #{Thread.current} is not the current owner: #{@lock_owner}")
|
163
|
+
end
|
164
|
+
Thread.exclusive do
|
165
|
+
@locks.delete_if{|t|!t.alive?}
|
166
|
+
unless(@locks.empty?)
|
167
|
+
old_owner = @lock_owner
|
168
|
+
@lock_owner = @locks.shift
|
169
|
+
@lock_owner.wakeup unless old_owner == @lock_owner
|
170
|
+
else
|
171
|
+
@lock_owner = nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# Starts the timer for waiting threads with a timeout
|
177
|
+
def start_timer
|
178
|
+
@timer = Thread.new do
|
179
|
+
begin
|
180
|
+
until(@stop) do
|
181
|
+
cur = []
|
182
|
+
t = 0
|
183
|
+
Thread.exclusive do
|
184
|
+
t = @timers.values.min
|
185
|
+
cur = @timers.dup
|
186
|
+
end
|
187
|
+
t = 0 if !t.nil? && t < 0
|
188
|
+
a = 0
|
189
|
+
begin
|
190
|
+
a = Splib.sleep(t)
|
191
|
+
rescue Wakeup
|
192
|
+
# do nothing of importance
|
193
|
+
ensure
|
194
|
+
next if t.nil?
|
195
|
+
Thread.exclusive do
|
196
|
+
cur.each_pair do |thread, value|
|
197
|
+
value -= a
|
198
|
+
if(value <= 0)
|
199
|
+
thread.wakeup
|
200
|
+
@timers.delete(thread)
|
201
|
+
else
|
202
|
+
@timers[thread] = value
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
rescue
|
209
|
+
retry
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|