samhendley-god 0.7.13

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.
Files changed (115) hide show
  1. data/History.txt +293 -0
  2. data/Manifest.txt +114 -0
  3. data/README.txt +60 -0
  4. data/Rakefile +35 -0
  5. data/bin/god +128 -0
  6. data/examples/events.god +84 -0
  7. data/examples/gravatar.god +54 -0
  8. data/examples/single.god +66 -0
  9. data/ext/god/extconf.rb +55 -0
  10. data/ext/god/kqueue_handler.c +123 -0
  11. data/ext/god/netlink_handler.c +167 -0
  12. data/init/god +42 -0
  13. data/lib/god.rb +667 -0
  14. data/lib/god/behavior.rb +52 -0
  15. data/lib/god/behaviors/clean_pid_file.rb +21 -0
  16. data/lib/god/behaviors/clean_unix_socket.rb +21 -0
  17. data/lib/god/behaviors/notify_when_flapping.rb +51 -0
  18. data/lib/god/cli/command.rb +229 -0
  19. data/lib/god/cli/run.rb +176 -0
  20. data/lib/god/cli/version.rb +23 -0
  21. data/lib/god/condition.rb +96 -0
  22. data/lib/god/conditions/always.rb +23 -0
  23. data/lib/god/conditions/complex.rb +86 -0
  24. data/lib/god/conditions/cpu_usage.rb +80 -0
  25. data/lib/god/conditions/degrading_lambda.rb +52 -0
  26. data/lib/god/conditions/disk_usage.rb +27 -0
  27. data/lib/god/conditions/file_mtime.rb +28 -0
  28. data/lib/god/conditions/flapping.rb +128 -0
  29. data/lib/god/conditions/http_response_code.rb +168 -0
  30. data/lib/god/conditions/lambda.rb +25 -0
  31. data/lib/god/conditions/memory_usage.rb +82 -0
  32. data/lib/god/conditions/process_exits.rb +72 -0
  33. data/lib/god/conditions/process_running.rb +74 -0
  34. data/lib/god/conditions/tries.rb +44 -0
  35. data/lib/god/configurable.rb +57 -0
  36. data/lib/god/contact.rb +106 -0
  37. data/lib/god/contacts/campfire.rb +82 -0
  38. data/lib/god/contacts/email.rb +95 -0
  39. data/lib/god/contacts/jabber.rb +65 -0
  40. data/lib/god/contacts/twitter.rb +39 -0
  41. data/lib/god/contacts/webhook.rb +47 -0
  42. data/lib/god/dependency_graph.rb +41 -0
  43. data/lib/god/diagnostics.rb +37 -0
  44. data/lib/god/driver.rb +206 -0
  45. data/lib/god/errors.rb +24 -0
  46. data/lib/god/event_handler.rb +111 -0
  47. data/lib/god/event_handlers/dummy_handler.rb +13 -0
  48. data/lib/god/event_handlers/kqueue_handler.rb +17 -0
  49. data/lib/god/event_handlers/netlink_handler.rb +13 -0
  50. data/lib/god/logger.rb +120 -0
  51. data/lib/god/metric.rb +59 -0
  52. data/lib/god/process.rb +342 -0
  53. data/lib/god/registry.rb +32 -0
  54. data/lib/god/simple_logger.rb +53 -0
  55. data/lib/god/socket.rb +96 -0
  56. data/lib/god/sugar.rb +47 -0
  57. data/lib/god/system/portable_poller.rb +42 -0
  58. data/lib/god/system/process.rb +42 -0
  59. data/lib/god/system/slash_proc_poller.rb +92 -0
  60. data/lib/god/task.rb +491 -0
  61. data/lib/god/timeline.rb +25 -0
  62. data/lib/god/trigger.rb +43 -0
  63. data/lib/god/watch.rb +184 -0
  64. data/test/configs/child_events/child_events.god +44 -0
  65. data/test/configs/child_events/simple_server.rb +3 -0
  66. data/test/configs/child_polls/child_polls.god +37 -0
  67. data/test/configs/child_polls/simple_server.rb +12 -0
  68. data/test/configs/complex/complex.god +59 -0
  69. data/test/configs/complex/simple_server.rb +3 -0
  70. data/test/configs/contact/contact.god +84 -0
  71. data/test/configs/contact/simple_server.rb +3 -0
  72. data/test/configs/daemon_events/daemon_events.god +37 -0
  73. data/test/configs/daemon_events/simple_server.rb +8 -0
  74. data/test/configs/daemon_events/simple_server_stop.rb +11 -0
  75. data/test/configs/daemon_polls/daemon_polls.god +17 -0
  76. data/test/configs/daemon_polls/simple_server.rb +6 -0
  77. data/test/configs/degrading_lambda/degrading_lambda.god +31 -0
  78. data/test/configs/degrading_lambda/tcp_server.rb +15 -0
  79. data/test/configs/matias/matias.god +50 -0
  80. data/test/configs/real.rb +59 -0
  81. data/test/configs/running_load/running_load.god +16 -0
  82. data/test/configs/stress/simple_server.rb +3 -0
  83. data/test/configs/stress/stress.god +15 -0
  84. data/test/configs/task/logs/.placeholder +0 -0
  85. data/test/configs/task/task.god +26 -0
  86. data/test/configs/test.rb +61 -0
  87. data/test/helper.rb +151 -0
  88. data/test/suite.rb +6 -0
  89. data/test/test_behavior.rb +21 -0
  90. data/test/test_campfire.rb +41 -0
  91. data/test/test_condition.rb +50 -0
  92. data/test/test_conditions_disk_usage.rb +56 -0
  93. data/test/test_conditions_http_response_code.rb +109 -0
  94. data/test/test_conditions_process_running.rb +44 -0
  95. data/test/test_conditions_tries.rb +67 -0
  96. data/test/test_contact.rb +109 -0
  97. data/test/test_dependency_graph.rb +62 -0
  98. data/test/test_driver.rb +11 -0
  99. data/test/test_email.rb +45 -0
  100. data/test/test_event_handler.rb +80 -0
  101. data/test/test_god.rb +598 -0
  102. data/test/test_handlers_kqueue_handler.rb +16 -0
  103. data/test/test_logger.rb +63 -0
  104. data/test/test_metric.rb +72 -0
  105. data/test/test_process.rb +246 -0
  106. data/test/test_registry.rb +15 -0
  107. data/test/test_socket.rb +42 -0
  108. data/test/test_sugar.rb +42 -0
  109. data/test/test_system_portable_poller.rb +17 -0
  110. data/test/test_system_process.rb +30 -0
  111. data/test/test_task.rb +262 -0
  112. data/test/test_timeline.rb +37 -0
  113. data/test/test_trigger.rb +59 -0
  114. data/test/test_watch.rb +279 -0
  115. metadata +193 -0
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+
4
+ Hoe.new('god', '0.7.13') do |p|
5
+ p.rubyforge_name = 'god'
6
+ p.author = 'Tom Preston-Werner'
7
+ p.email = 'tom@rubyisawesome.com'
8
+ p.url = 'http://god.rubyforge.org/'
9
+ p.summary = 'Like monit, only awesome'
10
+ p.description = "God is an easy to configure, easy to extend monitoring framework written in Ruby."
11
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
12
+ p.spec_extras = {:extensions => ['ext/god/extconf.rb']}
13
+ end
14
+
15
+ desc "Open an irb session preloaded with this library"
16
+ task :console do
17
+ sh "irb -rubygems -r ./lib/god.rb"
18
+ end
19
+
20
+ desc "Upload site to Rubyforge"
21
+ task :site do
22
+ sh "scp -r site/* mojombo@god.rubyforge.org:/var/www/gforge-projects/god"
23
+ end
24
+
25
+ desc "Upload site to Rubyforge"
26
+ task :site_edge do
27
+ sh "scp -r site/* mojombo@god.rubyforge.org:/var/www/gforge-projects/god/edge"
28
+ end
29
+
30
+ desc "Run rcov"
31
+ task :coverage do
32
+ `rm -fr coverage`
33
+ `rcov test/test_*.rb`
34
+ `open coverage/index.html`
35
+ end
data/bin/god ADDED
@@ -0,0 +1,128 @@
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
+ signal <task or group name> <sig> signal all matching tasks
37
+ quit stop god
38
+ terminate stop god and all tasks
39
+ check run self diagnostic
40
+
41
+ Options:
42
+ EOF
43
+
44
+ opts.on("-cCONFIG", "--config-file CONFIG", "Configuration file") do |x|
45
+ options[:config] = x
46
+ end
47
+
48
+ opts.on("-pPORT", "--port PORT", "Communications port (default 17165)") do |x|
49
+ options[:port] = x
50
+ end
51
+
52
+ opts.on("-b", "--auto-bind", "Auto-bind to an unused port number") do
53
+ options[:port] = "0"
54
+ end
55
+
56
+ opts.on("-PFILE", "--pid FILE", "Where to write the PID file") do |x|
57
+ options[:pid] = x
58
+ end
59
+
60
+ opts.on("-lFILE", "--log FILE", "Where to write the log file") do |x|
61
+ options[:log] = x
62
+ end
63
+
64
+ opts.on("-D", "--no-daemonize", "Don't daemonize") do
65
+ options[:daemonize] = false
66
+ end
67
+
68
+ opts.on("-v", "--version", "Print the version number and exit") do
69
+ options[:version] = true
70
+ end
71
+
72
+ opts.on("-V", "Print extended version and build information") do
73
+ options[:info] = true
74
+ end
75
+
76
+ opts.on("--log-level LEVEL", "Log level [debug|info|warn|error|fatal]") do |x|
77
+ options[:log_level] = x.to_sym
78
+ end
79
+
80
+ opts.on("--no-syslog", "Disable output to syslog") do
81
+ options[:syslog] = false
82
+ end
83
+
84
+ opts.on("--attach PID", "Quit god when the attached process dies") do |x|
85
+ options[:attach] = x
86
+ end
87
+
88
+ opts.on("--no-events", "Disable the event system") do
89
+ options[:events] = false
90
+ end
91
+
92
+ opts.on("--bleakhouse", "Enable bleakhouse profiling") do
93
+ options[:bleakhouse] = true
94
+ end
95
+ end
96
+
97
+ opts.parse!
98
+
99
+ # validate
100
+ if options[:log_level] && ![:debug, :info, :warn, :error, :fatal].include?(options[:log_level])
101
+ abort("Invalid log level '#{options[:log_level]}'")
102
+ end
103
+
104
+ # dispatch
105
+ if !options[:config] && options[:version]
106
+ require 'god'
107
+ God::CLI::Version.version
108
+ elsif !options[:config] && options[:info]
109
+ require 'god'
110
+ God::EventHandler.load
111
+ God::CLI::Version.version_extended
112
+ elsif !options[:config] && command = ARGV[0]
113
+ require 'god'
114
+ God::EventHandler.load
115
+ God::CLI::Command.new(command, options, ARGV)
116
+ else
117
+ require 'god/cli/run'
118
+ God::CLI::Run.new(options)
119
+ end
120
+ rescue Exception => e
121
+ if e.instance_of?(SystemExit)
122
+ raise
123
+ else
124
+ puts 'Uncaught exception'
125
+ puts e.message
126
+ puts e.backtrace.join("\n")
127
+ end
128
+ end
@@ -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
@@ -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
@@ -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