mojombo-god 0.7.7
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/History.txt +255 -0
- data/Manifest.txt +107 -0
- data/README.txt +59 -0
- data/Rakefile +35 -0
- data/bin/god +127 -0
- data/examples/events.god +84 -0
- data/examples/gravatar.god +54 -0
- data/examples/single.god +66 -0
- data/ext/god/extconf.rb +55 -0
- data/ext/god/kqueue_handler.c +123 -0
- data/ext/god/netlink_handler.c +167 -0
- data/init/god +42 -0
- data/lib/god.rb +644 -0
- data/lib/god/behavior.rb +52 -0
- data/lib/god/behaviors/clean_pid_file.rb +21 -0
- data/lib/god/behaviors/clean_unix_socket.rb +21 -0
- data/lib/god/behaviors/notify_when_flapping.rb +51 -0
- data/lib/god/cli/command.rb +206 -0
- data/lib/god/cli/run.rb +177 -0
- data/lib/god/cli/version.rb +23 -0
- data/lib/god/condition.rb +96 -0
- data/lib/god/conditions/always.rb +23 -0
- data/lib/god/conditions/complex.rb +86 -0
- data/lib/god/conditions/cpu_usage.rb +80 -0
- data/lib/god/conditions/degrading_lambda.rb +52 -0
- data/lib/god/conditions/disk_usage.rb +27 -0
- data/lib/god/conditions/flapping.rb +128 -0
- data/lib/god/conditions/http_response_code.rb +168 -0
- data/lib/god/conditions/lambda.rb +25 -0
- data/lib/god/conditions/memory_usage.rb +82 -0
- data/lib/god/conditions/process_exits.rb +72 -0
- data/lib/god/conditions/process_running.rb +74 -0
- data/lib/god/conditions/tries.rb +44 -0
- data/lib/god/configurable.rb +57 -0
- data/lib/god/contact.rb +106 -0
- data/lib/god/contacts/email.rb +95 -0
- data/lib/god/dependency_graph.rb +41 -0
- data/lib/god/diagnostics.rb +37 -0
- data/lib/god/driver.rb +108 -0
- data/lib/god/errors.rb +24 -0
- data/lib/god/event_handler.rb +111 -0
- data/lib/god/event_handlers/dummy_handler.rb +13 -0
- data/lib/god/event_handlers/kqueue_handler.rb +17 -0
- data/lib/god/event_handlers/netlink_handler.rb +13 -0
- data/lib/god/logger.rb +120 -0
- data/lib/god/metric.rb +59 -0
- data/lib/god/process.rb +325 -0
- data/lib/god/registry.rb +32 -0
- data/lib/god/simple_logger.rb +53 -0
- data/lib/god/socket.rb +96 -0
- data/lib/god/sugar.rb +47 -0
- data/lib/god/system/portable_poller.rb +42 -0
- data/lib/god/system/process.rb +42 -0
- data/lib/god/system/slash_proc_poller.rb +82 -0
- data/lib/god/task.rb +487 -0
- data/lib/god/timeline.rb +25 -0
- data/lib/god/trigger.rb +43 -0
- data/lib/god/watch.rb +183 -0
- data/test/configs/child_events/child_events.god +44 -0
- data/test/configs/child_events/simple_server.rb +3 -0
- data/test/configs/child_polls/child_polls.god +37 -0
- data/test/configs/child_polls/simple_server.rb +12 -0
- data/test/configs/complex/complex.god +59 -0
- data/test/configs/complex/simple_server.rb +3 -0
- data/test/configs/contact/contact.god +74 -0
- data/test/configs/contact/simple_server.rb +3 -0
- data/test/configs/daemon_events/daemon_events.god +37 -0
- data/test/configs/daemon_events/simple_server.rb +8 -0
- data/test/configs/daemon_events/simple_server_stop.rb +11 -0
- data/test/configs/daemon_polls/daemon_polls.god +17 -0
- data/test/configs/daemon_polls/simple_server.rb +6 -0
- data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
- data/test/configs/degrading_lambda/tcp_server.rb +15 -0
- data/test/configs/matias/matias.god +50 -0
- data/test/configs/real.rb +59 -0
- data/test/configs/running_load/running_load.god +16 -0
- data/test/configs/stress/simple_server.rb +3 -0
- data/test/configs/stress/stress.god +15 -0
- data/test/configs/task/logs/.placeholder +0 -0
- data/test/configs/task/task.god +26 -0
- data/test/configs/test.rb +61 -0
- data/test/helper.rb +151 -0
- data/test/suite.rb +6 -0
- data/test/test_behavior.rb +21 -0
- data/test/test_condition.rb +50 -0
- data/test/test_conditions_disk_usage.rb +56 -0
- data/test/test_conditions_http_response_code.rb +109 -0
- data/test/test_conditions_process_running.rb +44 -0
- data/test/test_conditions_tries.rb +67 -0
- data/test/test_contact.rb +109 -0
- data/test/test_dependency_graph.rb +62 -0
- data/test/test_driver.rb +11 -0
- data/test/test_event_handler.rb +80 -0
- data/test/test_god.rb +598 -0
- data/test/test_handlers_kqueue_handler.rb +16 -0
- data/test/test_logger.rb +63 -0
- data/test/test_metric.rb +72 -0
- data/test/test_process.rb +246 -0
- data/test/test_registry.rb +15 -0
- data/test/test_socket.rb +42 -0
- data/test/test_sugar.rb +42 -0
- data/test/test_system_portable_poller.rb +17 -0
- data/test/test_system_process.rb +30 -0
- data/test/test_task.rb +262 -0
- data/test/test_timeline.rb +37 -0
- data/test/test_trigger.rb +59 -0
- data/test/test_watch.rb +279 -0
- metadata +186 -0
data/bin/god
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
STDOUT.sync = true
|
4
|
+
|
5
|
+
$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'optparse'
|
9
|
+
require 'drb'
|
10
|
+
|
11
|
+
begin
|
12
|
+
options = {:daemonize => true, :port => 17165, :syslog => true, :events => true}
|
13
|
+
|
14
|
+
opts = OptionParser.new do |opts|
|
15
|
+
opts.banner = <<-EOF
|
16
|
+
Usage:
|
17
|
+
Starting:
|
18
|
+
god [-c <config file>] [-p <port> | -b] [-P <file>] [-l <file>] [-D]
|
19
|
+
|
20
|
+
Querying:
|
21
|
+
god <command> <argument> [-p <port>]
|
22
|
+
god <command> [-p <port>]
|
23
|
+
god -v
|
24
|
+
god -V (must be run as root to be accurate on Linux)
|
25
|
+
|
26
|
+
Commands:
|
27
|
+
start <task or group name> start task or group
|
28
|
+
restart <task or group name> restart task or group
|
29
|
+
stop <task or group name> stop task or group
|
30
|
+
monitor <task or group name> monitor task or group
|
31
|
+
unmonitor <task or group name> unmonitor task or group
|
32
|
+
remove <task or group name> remove task or group from god
|
33
|
+
load <file> load a config into a running god
|
34
|
+
log <task name> show realtime log for given task
|
35
|
+
status show status of each task
|
36
|
+
quit stop god
|
37
|
+
terminate stop god and all tasks
|
38
|
+
check run self diagnostic
|
39
|
+
|
40
|
+
Options:
|
41
|
+
EOF
|
42
|
+
|
43
|
+
opts.on("-cCONFIG", "--config-file CONFIG", "Configuration file") do |x|
|
44
|
+
options[:config] = x
|
45
|
+
end
|
46
|
+
|
47
|
+
opts.on("-pPORT", "--port PORT", "Communications port (default 17165)") do |x|
|
48
|
+
options[:port] = x
|
49
|
+
end
|
50
|
+
|
51
|
+
opts.on("-b", "--auto-bind", "Auto-bind to an unused port number") do
|
52
|
+
options[:port] = "0"
|
53
|
+
end
|
54
|
+
|
55
|
+
opts.on("-PFILE", "--pid FILE", "Where to write the PID file") do |x|
|
56
|
+
options[:pid] = x
|
57
|
+
end
|
58
|
+
|
59
|
+
opts.on("-lFILE", "--log FILE", "Where to write the log file") do |x|
|
60
|
+
options[:log] = x
|
61
|
+
end
|
62
|
+
|
63
|
+
opts.on("-D", "--no-daemonize", "Don't daemonize") do
|
64
|
+
options[:daemonize] = false
|
65
|
+
end
|
66
|
+
|
67
|
+
opts.on("-v", "--version", "Print the version number and exit") do
|
68
|
+
options[:version] = true
|
69
|
+
end
|
70
|
+
|
71
|
+
opts.on("-V", "Print extended version and build information") do
|
72
|
+
options[:info] = true
|
73
|
+
end
|
74
|
+
|
75
|
+
opts.on("--log-level LEVEL", "Log level [debug|info|warn|error|fatal]") do |x|
|
76
|
+
options[:log_level] = x.to_sym
|
77
|
+
end
|
78
|
+
|
79
|
+
opts.on("--no-syslog", "Disable output to syslog") do
|
80
|
+
options[:syslog] = false
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on("--attach PID", "Quit god when the attached process dies") do |x|
|
84
|
+
options[:attach] = x
|
85
|
+
end
|
86
|
+
|
87
|
+
opts.on("--no-events", "Disable the event system") do
|
88
|
+
options[:events] = false
|
89
|
+
end
|
90
|
+
|
91
|
+
opts.on("--bleakhouse", "Enable bleakhouse profiling") do
|
92
|
+
options[:bleakhouse] = true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
opts.parse!
|
97
|
+
|
98
|
+
# validate
|
99
|
+
if options[:log_level] && ![:debug, :info, :warn, :error, :fatal].include?(options[:log_level])
|
100
|
+
abort("Invalid log level '#{options[:log_level]}'")
|
101
|
+
end
|
102
|
+
|
103
|
+
# dispatch
|
104
|
+
if !options[:config] && options[:version]
|
105
|
+
require 'god'
|
106
|
+
God::CLI::Version.version
|
107
|
+
elsif !options[:config] && options[:info]
|
108
|
+
require 'god'
|
109
|
+
God::EventHandler.load
|
110
|
+
God::CLI::Version.version_extended
|
111
|
+
elsif !options[:config] && command = ARGV[0]
|
112
|
+
require 'god'
|
113
|
+
God::EventHandler.load
|
114
|
+
God::CLI::Command.new(command, options, ARGV)
|
115
|
+
else
|
116
|
+
require 'god/cli/run'
|
117
|
+
God::CLI::Run.new(options)
|
118
|
+
end
|
119
|
+
rescue Exception => e
|
120
|
+
if e.instance_of?(SystemExit)
|
121
|
+
raise
|
122
|
+
else
|
123
|
+
puts 'Uncaught exception'
|
124
|
+
puts e.message
|
125
|
+
puts e.backtrace.join("\n")
|
126
|
+
end
|
127
|
+
end
|
data/examples/events.god
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# This example shows how you might keep a local development Rails server up
|
2
|
+
# and running on your Mac.
|
3
|
+
|
4
|
+
# Run with:
|
5
|
+
# god -c /path/to/events.god
|
6
|
+
|
7
|
+
RAILS_ROOT = ENV['GOD_TEST_RAILS_ROOT']
|
8
|
+
|
9
|
+
%w{3002}.each do |port|
|
10
|
+
God.watch do |w|
|
11
|
+
w.name = "local-#{port}"
|
12
|
+
w.interval = 5.seconds
|
13
|
+
w.start = "mongrel_rails start -p #{port} -P #{RAILS_ROOT}/log/mongrel.#{port}.pid -c #{RAILS_ROOT} -d"
|
14
|
+
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid -c #{RAILS_ROOT}"
|
15
|
+
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
|
16
|
+
w.log = File.join(RAILS_ROOT, "log/commands.#{port}.log")
|
17
|
+
|
18
|
+
# clean pid files before start if necessary
|
19
|
+
w.behavior(:clean_pid_file)
|
20
|
+
|
21
|
+
# determine the state on startup
|
22
|
+
w.transition(:init, { true => :up, false => :start }) do |on|
|
23
|
+
on.condition(:process_running) do |c|
|
24
|
+
c.running = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# determine when process has finished starting
|
29
|
+
w.transition([:start, :restart], :up) do |on|
|
30
|
+
on.condition(:process_running) do |c|
|
31
|
+
c.running = true
|
32
|
+
end
|
33
|
+
|
34
|
+
# failsafe
|
35
|
+
on.condition(:tries) do |c|
|
36
|
+
c.times = 8
|
37
|
+
c.within = 2.minutes
|
38
|
+
c.transition = :start
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# start if process is not running
|
43
|
+
w.transition(:up, :start) do |on|
|
44
|
+
on.condition(:process_exits)
|
45
|
+
end
|
46
|
+
|
47
|
+
# restart if memory or cpu is too high
|
48
|
+
w.transition(:up, :restart) do |on|
|
49
|
+
on.condition(:memory_usage) do |c|
|
50
|
+
c.interval = 20
|
51
|
+
c.above = 50.megabytes
|
52
|
+
c.times = [3, 5]
|
53
|
+
end
|
54
|
+
|
55
|
+
on.condition(:cpu_usage) do |c|
|
56
|
+
c.interval = 10
|
57
|
+
c.above = 10.percent
|
58
|
+
c.times = 5
|
59
|
+
end
|
60
|
+
|
61
|
+
on.condition(:http_response_code) do |c|
|
62
|
+
c.host = 'localhost'
|
63
|
+
c.port = port
|
64
|
+
c.path = '/'
|
65
|
+
c.code_is = 500
|
66
|
+
c.timeout = 10.seconds
|
67
|
+
c.times = [3, 5]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# lifecycle
|
72
|
+
w.lifecycle do |on|
|
73
|
+
on.condition(:flapping) do |c|
|
74
|
+
c.to_state = [:start, :restart]
|
75
|
+
c.times = 5
|
76
|
+
c.within = 1.minute
|
77
|
+
c.transition = :unmonitored
|
78
|
+
c.retry_in = 10.minutes
|
79
|
+
c.retry_times = 5
|
80
|
+
c.retry_within = 2.hours
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# run with: god -c /path/to/gravatar.god
|
2
|
+
#
|
3
|
+
# This is the actual config file used to keep the mongrels of
|
4
|
+
# gravatar.com running.
|
5
|
+
|
6
|
+
RAILS_ROOT = "/Users/tom/dev/gravatar2"
|
7
|
+
|
8
|
+
%w{8200 8201 8202}.each do |port|
|
9
|
+
God.watch do |w|
|
10
|
+
w.name = "gravatar2-mongrel-#{port}"
|
11
|
+
w.interval = 30.seconds # default
|
12
|
+
w.start = "mongrel_rails start -c #{RAILS_ROOT} -p #{port} \
|
13
|
+
-P #{RAILS_ROOT}/log/mongrel.#{port}.pid -d"
|
14
|
+
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.#{port}.pid"
|
15
|
+
w.restart = "mongrel_rails restart -P #{RAILS_ROOT}/log/mongrel.#{port}.pid"
|
16
|
+
w.start_grace = 10.seconds
|
17
|
+
w.restart_grace = 10.seconds
|
18
|
+
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.#{port}.pid")
|
19
|
+
|
20
|
+
w.behavior(:clean_pid_file)
|
21
|
+
|
22
|
+
w.start_if do |start|
|
23
|
+
start.condition(:process_running) do |c|
|
24
|
+
c.interval = 5.seconds
|
25
|
+
c.running = false
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
w.restart_if do |restart|
|
30
|
+
restart.condition(:memory_usage) do |c|
|
31
|
+
c.above = 150.megabytes
|
32
|
+
c.times = [3, 5] # 3 out of 5 intervals
|
33
|
+
end
|
34
|
+
|
35
|
+
restart.condition(:cpu_usage) do |c|
|
36
|
+
c.above = 50.percent
|
37
|
+
c.times = 5
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# lifecycle
|
42
|
+
w.lifecycle do |on|
|
43
|
+
on.condition(:flapping) do |c|
|
44
|
+
c.to_state = [:start, :restart]
|
45
|
+
c.times = 5
|
46
|
+
c.within = 5.minute
|
47
|
+
c.transition = :unmonitored
|
48
|
+
c.retry_in = 10.minutes
|
49
|
+
c.retry_times = 5
|
50
|
+
c.retry_within = 2.hours
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/examples/single.god
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
RAILS_ROOT = "/Users/tom/dev/gravatar2"
|
2
|
+
|
3
|
+
God.watch do |w|
|
4
|
+
w.name = "local-3000"
|
5
|
+
w.interval = 5.seconds # default
|
6
|
+
w.start = "mongrel_rails start -c #{RAILS_ROOT} -P #{RAILS_ROOT}/log/mongrel.pid -p 3000 -d"
|
7
|
+
w.stop = "mongrel_rails stop -P #{RAILS_ROOT}/log/mongrel.pid"
|
8
|
+
w.restart = "mongrel_rails restart -P #{RAILS_ROOT}/log/mongrel.pid"
|
9
|
+
w.pid_file = File.join(RAILS_ROOT, "log/mongrel.pid")
|
10
|
+
|
11
|
+
# clean pid files before start if necessary
|
12
|
+
w.behavior(:clean_pid_file)
|
13
|
+
|
14
|
+
# determine the state on startup
|
15
|
+
w.transition(:init, { true => :up, false => :start }) do |on|
|
16
|
+
on.condition(:process_running) do |c|
|
17
|
+
c.running = true
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# determine when process has finished starting
|
22
|
+
w.transition([:start, :restart], :up) do |on|
|
23
|
+
on.condition(:process_running) do |c|
|
24
|
+
c.running = true
|
25
|
+
end
|
26
|
+
|
27
|
+
# failsafe
|
28
|
+
on.condition(:tries) do |c|
|
29
|
+
c.times = 5
|
30
|
+
c.transition = :start
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# start if process is not running
|
35
|
+
w.transition(:up, :start) do |on|
|
36
|
+
on.condition(:process_exits)
|
37
|
+
end
|
38
|
+
|
39
|
+
# restart if memory or cpu is too high
|
40
|
+
w.transition(:up, :restart) do |on|
|
41
|
+
on.condition(:memory_usage) do |c|
|
42
|
+
c.interval = 20
|
43
|
+
c.above = 50.megabytes
|
44
|
+
c.times = [3, 5]
|
45
|
+
end
|
46
|
+
|
47
|
+
on.condition(:cpu_usage) do |c|
|
48
|
+
c.interval = 10
|
49
|
+
c.above = 10.percent
|
50
|
+
c.times = [3, 5]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# lifecycle
|
55
|
+
w.lifecycle do |on|
|
56
|
+
on.condition(:flapping) do |c|
|
57
|
+
c.to_state = [:start, :restart]
|
58
|
+
c.times = 5
|
59
|
+
c.within = 5.minute
|
60
|
+
c.transition = :unmonitored
|
61
|
+
c.retry_in = 10.minutes
|
62
|
+
c.retry_times = 5
|
63
|
+
c.retry_within = 2.hours
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/ext/god/extconf.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
fail = false
|
4
|
+
|
5
|
+
def create_dummy_makefile
|
6
|
+
File.open("Makefile", 'w') do |f|
|
7
|
+
f.puts "all:"
|
8
|
+
f.puts "install:"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
case RUBY_PLATFORM
|
13
|
+
when /bsd/i, /darwin/i
|
14
|
+
unless have_header('sys/event.h')
|
15
|
+
puts
|
16
|
+
puts "Missing 'sys/event.h' header"
|
17
|
+
fail = true
|
18
|
+
end
|
19
|
+
|
20
|
+
if fail
|
21
|
+
puts
|
22
|
+
puts "Events handler could not be compiled (see above error). Your god installation will not support event conditions."
|
23
|
+
create_dummy_makefile
|
24
|
+
else
|
25
|
+
create_makefile 'kqueue_handler_ext'
|
26
|
+
end
|
27
|
+
when /linux/i
|
28
|
+
unless have_header('linux/netlink.h')
|
29
|
+
puts
|
30
|
+
puts "Missing 'linux/netlink.h' header(s)"
|
31
|
+
puts "You may need to install a header package for your system"
|
32
|
+
fail = true
|
33
|
+
end
|
34
|
+
|
35
|
+
unless have_header('linux/connector.h') && have_header('linux/cn_proc.h')
|
36
|
+
puts
|
37
|
+
puts "Missing 'linux/connector.h', or 'linux/cn_proc.h' header(s)"
|
38
|
+
puts "These are only available in Linux kernel 2.6.15 and later (run `uname -a` to find yours)"
|
39
|
+
puts "You may need to install a header package for your system"
|
40
|
+
fail = true
|
41
|
+
end
|
42
|
+
|
43
|
+
if fail
|
44
|
+
puts
|
45
|
+
puts "Events handler could not be compiled (see above error). Your god installation will not support event conditions."
|
46
|
+
create_dummy_makefile
|
47
|
+
else
|
48
|
+
create_makefile 'netlink_handler_ext'
|
49
|
+
end
|
50
|
+
else
|
51
|
+
puts
|
52
|
+
puts "Unsupported platform '#{RUBY_PLATFORM}'. Supported platforms are BSD, DARWIN, and LINUX."
|
53
|
+
puts "Your god installation will not support event conditions."
|
54
|
+
create_dummy_makefile
|
55
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
#if defined(__FreeBSD__) || defined(__APPLE__)
|
2
|
+
|
3
|
+
#include <ruby.h>
|
4
|
+
#include <sys/event.h>
|
5
|
+
#include <sys/time.h>
|
6
|
+
#include <errno.h>
|
7
|
+
|
8
|
+
static VALUE mGod;
|
9
|
+
static VALUE cKQueueHandler;
|
10
|
+
static VALUE cEventHandler;
|
11
|
+
|
12
|
+
static ID proc_exit;
|
13
|
+
static ID proc_fork;
|
14
|
+
static ID m_call;
|
15
|
+
static ID m_size;
|
16
|
+
static ID m_deregister;
|
17
|
+
|
18
|
+
static int kq;
|
19
|
+
int num_events;
|
20
|
+
|
21
|
+
#define NUM_EVENTS FIX2INT(rb_funcall(rb_cv_get(cEventHandler, "@@actions"), m_size, 0))
|
22
|
+
|
23
|
+
VALUE
|
24
|
+
kqh_event_mask(VALUE klass, VALUE sym)
|
25
|
+
{
|
26
|
+
ID id = SYM2ID(sym);
|
27
|
+
if (proc_exit == id) {
|
28
|
+
return UINT2NUM(NOTE_EXIT);
|
29
|
+
} else if (proc_fork == id) {
|
30
|
+
return UINT2NUM(NOTE_FORK);
|
31
|
+
} else {
|
32
|
+
rb_raise(rb_eNotImpError, "Event `%s` not implemented", rb_id2name(id));
|
33
|
+
}
|
34
|
+
|
35
|
+
return Qnil;
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
VALUE
|
40
|
+
kqh_monitor_process(VALUE klass, VALUE pid, VALUE mask)
|
41
|
+
{
|
42
|
+
struct kevent new_event;
|
43
|
+
ID event;
|
44
|
+
|
45
|
+
u_int fflags = NUM2UINT(mask);
|
46
|
+
|
47
|
+
EV_SET(&new_event, FIX2UINT(pid), EVFILT_PROC,
|
48
|
+
EV_ADD | EV_ENABLE, fflags, 0, 0);
|
49
|
+
|
50
|
+
if (-1 == kevent(kq, &new_event, 1, NULL, 0, NULL)) {
|
51
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
52
|
+
}
|
53
|
+
|
54
|
+
num_events = NUM_EVENTS;
|
55
|
+
|
56
|
+
return Qnil;
|
57
|
+
}
|
58
|
+
|
59
|
+
VALUE
|
60
|
+
kqh_handle_events()
|
61
|
+
{
|
62
|
+
int nevents, i, num_to_fetch;
|
63
|
+
struct kevent *events;
|
64
|
+
fd_set read_set;
|
65
|
+
|
66
|
+
FD_ZERO(&read_set);
|
67
|
+
FD_SET(kq, &read_set);
|
68
|
+
|
69
|
+
// Don't actually run this method until we've got an event
|
70
|
+
rb_thread_select(kq + 1, &read_set, NULL, NULL, NULL);
|
71
|
+
|
72
|
+
// Grabbing num_events once for thread safety
|
73
|
+
num_to_fetch = num_events;
|
74
|
+
events = (struct kevent*)malloc(num_to_fetch * sizeof(struct kevent));
|
75
|
+
|
76
|
+
if (NULL == events) {
|
77
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
78
|
+
}
|
79
|
+
|
80
|
+
nevents = kevent(kq, NULL, 0, events, num_to_fetch, NULL);
|
81
|
+
|
82
|
+
if (-1 == nevents) {
|
83
|
+
free(events);
|
84
|
+
rb_raise(rb_eStandardError, strerror(errno));
|
85
|
+
} else {
|
86
|
+
for (i = 0; i < nevents; i++) {
|
87
|
+
if (events[i].fflags & NOTE_EXIT) {
|
88
|
+
rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_exit));
|
89
|
+
} else if (events[i].fflags & NOTE_FORK) {
|
90
|
+
rb_funcall(cEventHandler, m_call, 2, INT2NUM(events[i].ident), ID2SYM(proc_fork));
|
91
|
+
}
|
92
|
+
}
|
93
|
+
}
|
94
|
+
|
95
|
+
free(events);
|
96
|
+
|
97
|
+
return INT2FIX(nevents);
|
98
|
+
}
|
99
|
+
|
100
|
+
void
|
101
|
+
Init_kqueue_handler_ext()
|
102
|
+
{
|
103
|
+
kq = kqueue();
|
104
|
+
|
105
|
+
if (kq == -1) {
|
106
|
+
rb_raise(rb_eStandardError, "kqueue initilization failed");
|
107
|
+
}
|
108
|
+
|
109
|
+
proc_exit = rb_intern("proc_exit");
|
110
|
+
proc_fork = rb_intern("proc_fork");
|
111
|
+
m_call = rb_intern("call");
|
112
|
+
m_size = rb_intern("size");
|
113
|
+
m_deregister = rb_intern("deregister");
|
114
|
+
|
115
|
+
mGod = rb_const_get(rb_cObject, rb_intern("God"));
|
116
|
+
cEventHandler = rb_const_get(mGod, rb_intern("EventHandler"));
|
117
|
+
cKQueueHandler = rb_define_class_under(mGod, "KQueueHandler", rb_cObject);
|
118
|
+
rb_define_singleton_method(cKQueueHandler, "monitor_process", kqh_monitor_process, 2);
|
119
|
+
rb_define_singleton_method(cKQueueHandler, "handle_events", kqh_handle_events, 0);
|
120
|
+
rb_define_singleton_method(cKQueueHandler, "event_mask", kqh_event_mask, 1);
|
121
|
+
}
|
122
|
+
|
123
|
+
#endif
|