Skip to content

Instantly share code, notes, and snippets.

@tmm1
Created February 19, 2009 23:13
Show Gist options
  • Select an option

  • Save tmm1/67184 to your computer and use it in GitHub Desktop.

Select an option

Save tmm1/67184 to your computer and use it in GitHub Desktop.
diff --git a/ext/rubymain.cpp b/ext/rubymain.cpp
index 1e0dd6f..4eb7738 100644
--- a/ext/rubymain.cpp
+++ b/ext/rubymain.cpp
@@ -33,24 +33,36 @@ static VALUE EmConnection;
static VALUE Intern_at_signature;
static VALUE Intern_at_timers;
static VALUE Intern_at_conns;
+static VALUE Intern_at_error_handler;
static VALUE Intern_event_callback;
static VALUE Intern_run_deferred_callbacks;
static VALUE Intern_delete;
static VALUE Intern_call;
static VALUE Intern_receive_data;
static VALUE Intern_ssl_handshake_completed;
-
static VALUE Intern_notify_readable;
static VALUE Intern_notify_writable;
static VALUE rb_cProcStatus;
+struct em_event {
+ const char *a1;
+ int a2;
+ const char *a3;
+ int a4;
+};
+
/****************
t_event_callback
****************/
-static void event_callback (const char *a1, int a2, const char *a3, int a4)
+static void event_callback (struct em_event* e)
{
+ const char *a1 = e->a1;
+ int a2 = e->a2;
+ const char *a3 = e->a3;
+ int a4 = e->a4;
+
if (a2 == EM_CONNECTION_READ) {
VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
VALUE q = rb_hash_aref (t, rb_str_new2(a1));
@@ -93,7 +105,33 @@ static void event_callback (const char *a1, int a2, const char *a3, int a4)
rb_funcall (EmModule, Intern_event_callback, 3, rb_str_new2(a1), (a2 << 1) | 1, rb_str_new(a3,a4));
}
+/*******************
+event_error_handler
+*******************/
+
+static void event_error_handler(void *, VALUE err)
+{
+ VALUE error_handler = rb_ivar_get(EmModule, Intern_at_error_handler);
+ rb_funcall (error_handler, Intern_call, 1, err);
+}
+
+/**********************
+event_callback_wrapper
+**********************/
+static void event_callback_wrapper (const char *a1, int a2, const char *a3, int a4)
+{
+ struct em_event e;
+ e.a1 = a1;
+ e.a2 = a2;
+ e.a3 = a3;
+ e.a4 = a4;
+
+ if (!rb_ivar_defined(EmModule, Intern_at_error_handler))
+ event_callback(&e);
+ else
+ rb_rescue((VALUE (*)(ANYARGS))event_callback, (VALUE)&e, (VALUE (*)(ANYARGS))event_error_handler, NULL);
+}
/**************************
t_initialize_event_machine
@@ -101,7 +139,7 @@ t_initialize_event_machine
static VALUE t_initialize_event_machine (VALUE self)
{
- evma_initialize_library (event_callback);
+ evma_initialize_library (event_callback_wrapper);
return Qnil;
}
@@ -703,6 +741,7 @@ extern "C" void Init_rubyeventmachine()
Intern_at_signature = rb_intern ("@signature");
Intern_at_timers = rb_intern ("@timers");
Intern_at_conns = rb_intern ("@conns");
+ Intern_at_error_handler = rb_intern("@error_handler");
Intern_event_callback = rb_intern ("event_callback");
Intern_run_deferred_callbacks = rb_intern ("run_deferred_callbacks");
@@ -710,7 +749,6 @@ extern "C" void Init_rubyeventmachine()
Intern_call = rb_intern ("call");
Intern_receive_data = rb_intern ("receive_data");
Intern_ssl_handshake_completed = rb_intern ("ssl_handshake_completed");
-
Intern_notify_readable = rb_intern ("notify_readable");
Intern_notify_writable = rb_intern ("notify_writable");
diff --git a/lib/eventmachine.rb b/lib/eventmachine.rb
index d355e1b..f9b415d 100644
--- a/lib/eventmachine.rb
+++ b/lib/eventmachine.rb
@@ -1165,7 +1165,19 @@ module EventMachine
c
end
-
+ # Catch-all for errors raised during event loop callbacks.
+ #
+ # EM.error_handler{ |e|
+ # puts "Error raised during event loop: #{e.message}"
+ # }
+ #
+ def EventMachine::error_handler cb = nil, &blk
+ if cb or blk
+ @error_handler = cb || blk
+ elsif instance_variable_defined? :@error_handler
+ remove_instance_variable :@error_handler
+ end
+ end
private
def EventMachine::event_callback conn_binding, opcode, data
diff --git a/tasks/tests.rake b/tasks/tests.rake
index 81f3dea..af575b6 100644
--- a/tasks/tests.rake
+++ b/tasks/tests.rake
@@ -37,6 +37,7 @@ namespace :test do
"test_basic.rb",
"test_epoll.rb",
"test_errors.rb",
+ "test_error_handler.rb",
"test_eventables.rb",
"test_exc.rb",
"test_futures.rb",
diff --git a/tests/test_error_handler.rb b/tests/test_error_handler.rb
new file mode 100644
index 0000000..0bc9432
--- /dev/null
+++ b/tests/test_error_handler.rb
@@ -0,0 +1,32 @@
+$:.unshift "../lib"
+require 'eventmachine'
+require 'test/unit'
+
+class TestErrorHandler < Test::Unit::TestCase
+ def test_error_handler
+ error = nil
+ EM.error_handler{ |e|
+ error = e
+ EM.error_handler(nil)
+ EM.stop
+ }
+
+ EM.run{
+ EM.add_timer(0){
+ raise 'test'
+ }
+ }
+
+ assert_equal error.message, 'test'
+ end
+
+ def test_without_error_handler
+ assert_raise RuntimeError do
+ EM.run{
+ EM.add_timer(0){
+ raise 'test'
+ }
+ }
+ end
+ end
+end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment