eventmachine 0.12.10 → 1.0.0.beta.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.
Files changed (69) hide show
  1. data/.gitignore +2 -0
  2. data/Gemfile +1 -0
  3. data/README +1 -2
  4. data/Rakefile +4 -76
  5. data/docs/DEFERRABLES +183 -70
  6. data/docs/KEYBOARD +15 -11
  7. data/docs/LIGHTWEIGHT_CONCURRENCY +84 -24
  8. data/docs/SMTP +3 -1
  9. data/docs/SPAWNED_PROCESSES +84 -25
  10. data/eventmachine.gemspec +19 -26
  11. data/examples/ex_tick_loop_array.rb +15 -0
  12. data/examples/ex_tick_loop_counter.rb +32 -0
  13. data/ext/binder.cpp +0 -1
  14. data/ext/cmain.cpp +36 -11
  15. data/ext/cplusplus.cpp +1 -1
  16. data/ext/ed.cpp +104 -113
  17. data/ext/ed.h +24 -30
  18. data/ext/em.cpp +347 -248
  19. data/ext/em.h +23 -16
  20. data/ext/eventmachine.h +5 -3
  21. data/ext/extconf.rb +5 -3
  22. data/ext/fastfilereader/extconf.rb +5 -3
  23. data/ext/fastfilereader/mapper.cpp +1 -1
  24. data/ext/kb.cpp +1 -3
  25. data/ext/pipe.cpp +9 -11
  26. data/ext/project.h +12 -4
  27. data/ext/rubymain.cpp +138 -89
  28. data/java/src/com/rubyeventmachine/EmReactor.java +1 -0
  29. data/lib/em/channel.rb +1 -1
  30. data/lib/em/connection.rb +6 -1
  31. data/lib/em/deferrable.rb +16 -2
  32. data/lib/em/iterator.rb +270 -0
  33. data/lib/em/protocols.rb +1 -1
  34. data/lib/em/protocols/httpclient.rb +5 -0
  35. data/lib/em/protocols/line_protocol.rb +28 -0
  36. data/lib/em/protocols/smtpserver.rb +101 -8
  37. data/lib/em/protocols/stomp.rb +1 -1
  38. data/lib/{pr_eventmachine.rb → em/pure_ruby.rb} +1 -11
  39. data/lib/em/queue.rb +1 -0
  40. data/lib/em/streamer.rb +1 -1
  41. data/lib/em/tick_loop.rb +85 -0
  42. data/lib/em/timers.rb +2 -1
  43. data/lib/em/version.rb +1 -1
  44. data/lib/eventmachine.rb +38 -84
  45. data/lib/jeventmachine.rb +1 -0
  46. data/tests/test_attach.rb +13 -3
  47. data/tests/test_basic.rb +60 -95
  48. data/tests/test_channel.rb +3 -2
  49. data/tests/test_defer.rb +14 -12
  50. data/tests/test_deferrable.rb +35 -0
  51. data/tests/test_file_watch.rb +1 -1
  52. data/tests/test_futures.rb +1 -1
  53. data/tests/test_hc.rb +40 -68
  54. data/tests/test_httpclient.rb +15 -6
  55. data/tests/test_httpclient2.rb +3 -2
  56. data/tests/test_inactivity_timeout.rb +3 -3
  57. data/tests/test_ltp.rb +13 -5
  58. data/tests/test_next_tick.rb +1 -1
  59. data/tests/test_pending_connect_timeout.rb +2 -2
  60. data/tests/test_process_watch.rb +36 -34
  61. data/tests/test_proxy_connection.rb +52 -0
  62. data/tests/test_pure.rb +10 -1
  63. data/tests/test_sasl.rb +1 -1
  64. data/tests/test_send_file.rb +16 -7
  65. data/tests/test_servers.rb +1 -1
  66. data/tests/test_tick_loop.rb +59 -0
  67. data/tests/test_timers.rb +13 -15
  68. metadata +45 -17
  69. data/web/whatis +0 -7
data/ext/em.h CHANGED
@@ -57,16 +57,6 @@ See the file COPYING for complete licensing information.
57
57
  #define EmSelect select
58
58
  #endif
59
59
 
60
-
61
- #ifdef OS_UNIX
62
- typedef long long Int64;
63
- #endif
64
- #ifdef OS_WIN32
65
- typedef __int64 Int64;
66
- #endif
67
-
68
- extern Int64 gCurrentLoopTime;
69
-
70
60
  class EventableDescriptor;
71
61
  class InotifyDescriptor;
72
62
 
@@ -82,7 +72,7 @@ class EventMachine_t
82
72
  static void SetMaxTimerCount (int);
83
73
 
84
74
  public:
85
- EventMachine_t (void(*event_callback)(const unsigned long, int, const char*, const unsigned long));
75
+ EventMachine_t (EMCallback);
86
76
  virtual ~EventMachine_t();
87
77
 
88
78
  void Run();
@@ -137,6 +127,8 @@ class EventMachine_t
137
127
  void _HandleKqueuePidEvent (struct kevent*);
138
128
  #endif
139
129
 
130
+ uint64_t GetCurrentLoopTime() { return MyCurrentLoopTime; }
131
+
140
132
  // Temporary:
141
133
  void _UseEpoll();
142
134
  void _UseKqueue();
@@ -144,6 +136,11 @@ class EventMachine_t
144
136
  bool UsingKqueue() { return bKqueue; }
145
137
  bool UsingEpoll() { return bEpoll; }
146
138
 
139
+ void QueueHeartbeat(EventableDescriptor*);
140
+ void ClearHeartbeat(uint64_t);
141
+
142
+ uint64_t GetRealTime();
143
+
147
144
  private:
148
145
  bool _RunOnce();
149
146
  bool _RunTimers();
@@ -151,12 +148,16 @@ class EventMachine_t
151
148
  void _AddNewDescriptors();
152
149
  void _ModifyDescriptors();
153
150
  void _InitializeLoopBreaker();
151
+ void _CleanupSockets();
154
152
 
155
153
  bool _RunSelectOnce();
156
154
  bool _RunEpollOnce();
157
155
  bool _RunKqueueOnce();
158
156
 
159
157
  void _ModifyEpollEvent (EventableDescriptor*);
158
+ void _DispatchHeartbeats();
159
+ timeval _TimeTilNextEvent();
160
+ void _CleanBadDescriptors();
160
161
 
161
162
  public:
162
163
  void _ReadLoopBreaker();
@@ -168,19 +169,20 @@ class EventMachine_t
168
169
  MaxEvents = 4096
169
170
  };
170
171
  int HeartbeatInterval;
171
- void (*EventCallback)(const unsigned long, int, const char*, const unsigned long);
172
+ EMCallback EventCallback;
172
173
 
173
174
  class Timer_t: public Bindable_t {
174
175
  };
175
176
 
176
- multimap<Int64, Timer_t> Timers;
177
+ multimap<uint64_t, Timer_t> Timers;
178
+ multimap<uint64_t, EventableDescriptor*> Heartbeats;
177
179
  map<int, Bindable_t*> Files;
178
180
  map<int, Bindable_t*> Pids;
179
181
  vector<EventableDescriptor*> Descriptors;
180
182
  vector<EventableDescriptor*> NewDescriptors;
181
183
  set<EventableDescriptor*> ModifiedDescriptors;
182
184
 
183
- Int64 NextHeartbeatTime;
185
+ uint64_t NextHeartbeatTime;
184
186
 
185
187
  int LoopBreakerReader;
186
188
  int LoopBreakerWriter;
@@ -190,6 +192,13 @@ class EventMachine_t
190
192
 
191
193
  timeval Quantum;
192
194
 
195
+ uint64_t MyCurrentLoopTime;
196
+
197
+ #ifdef OS_WIN32
198
+ unsigned TickCountTickover;
199
+ unsigned LastTickCount;
200
+ #endif
201
+
193
202
  private:
194
203
  bool bEpoll;
195
204
  int epfd; // Epoll file-descriptor
@@ -225,8 +234,6 @@ struct SelectData_t
225
234
  int nSockets;
226
235
  };
227
236
 
228
-
229
-
230
237
  #endif // __EventMachine__H_
231
238
 
232
239
  //#endif // OS_UNIX
@@ -35,11 +35,12 @@ extern "C" {
35
35
  EM_CONNECTION_NOTIFY_WRITABLE = 107,
36
36
  EM_SSL_HANDSHAKE_COMPLETED = 108,
37
37
  EM_SSL_VERIFY = 109,
38
- EM_PROXY_TARGET_UNBOUND = 110
38
+ EM_PROXY_TARGET_UNBOUND = 110,
39
+ EM_PROXY_COMPLETED = 111
39
40
 
40
41
  };
41
42
 
42
- void evma_initialize_library (void(*)(const unsigned long, int, const char*, const unsigned long));
43
+ void evma_initialize_library (EMCallback);
43
44
  void evma_run_machine();
44
45
  void evma_release_library();
45
46
  const unsigned long evma_install_oneshot_timer (int seconds);
@@ -105,7 +106,7 @@ extern "C" {
105
106
  const unsigned long evma_watch_pid (int);
106
107
  void evma_unwatch_pid (const unsigned long);
107
108
 
108
- void evma_start_proxy(const unsigned long, const unsigned long, const unsigned long);
109
+ void evma_start_proxy(const unsigned long, const unsigned long, const unsigned long, const unsigned long);
109
110
  void evma_stop_proxy(const unsigned long);
110
111
 
111
112
  int evma_set_rlimit_nofile (int n_files);
@@ -113,6 +114,7 @@ extern "C" {
113
114
  void evma_set_epoll (int use);
114
115
  void evma_set_kqueue (int use);
115
116
 
117
+ uint64_t evma_get_current_loop_time();
116
118
  #if __cplusplus
117
119
  }
118
120
  #endif
@@ -53,11 +53,13 @@ when /solaris/
53
53
  add_define 'OS_SOLARIS8'
54
54
  check_libs(%w[nsl socket], true)
55
55
 
56
- # Patch by Tim Pease, fixes SUNWspro compile problems.
57
- if CONFIG['CC'] == 'cc'
56
+ if CONFIG['CC'] == 'cc' and `cc -flags 2>&1` =~ /Sun/ # detect SUNWspro compiler
58
57
  # SUN CHAIN
59
- $CFLAGS = CONFIG['CFLAGS'] = "-KPIC -G"
58
+ add_define 'CC_SUNWspro'
59
+ $preload = ["\nCXX = CC"] # hack a CXX= line into the makefile
60
+ $CFLAGS = CONFIG['CFLAGS'] = "-KPIC"
60
61
  CONFIG['CCDLFLAGS'] = "-KPIC"
62
+ CONFIG['LDSHARED'] = "$(CXX) -G -KPIC -lCstd"
61
63
  else
62
64
  # GNU CHAIN
63
65
  # on Unix we need a g++ link, not gcc.
@@ -44,11 +44,13 @@ when /solaris/
44
44
  add_define 'OS_SOLARIS8'
45
45
  check_libs(%w[nsl socket], true)
46
46
 
47
- # Patch by Tim Pease, fixes SUNWspro compile problems.
48
- if CONFIG['CC'] == 'cc'
47
+ if CONFIG['CC'] == 'cc' and `cc -flags 2>&1` =~ /Sun/ # detect SUNWspro compiler
49
48
  # SUN CHAIN
50
- $CFLAGS = CONFIG['CFLAGS'] = "-KPIC -G"
49
+ add_define 'CC_SUNWspro'
50
+ $preload = ["\nCXX = CC"] # hack a CXX= line into the makefile
51
+ $CFLAGS = CONFIG['CFLAGS'] = "-KPIC"
51
52
  CONFIG['CCDLFLAGS'] = "-KPIC"
53
+ CONFIG['LDSHARED'] = "$(CXX) -G -KPIC -lCstd"
52
54
  else
53
55
  # GNU CHAIN
54
56
  # on Unix we need a g++ link, not gcc.
@@ -88,7 +88,7 @@ void Mapper_t::Close()
88
88
  // Can be called multiple times.
89
89
  // Calls to GetChunk are invalid after a call to Close.
90
90
  if (MapPoint) {
91
- #ifdef OS_SOLARIS8
91
+ #ifdef CC_SUNWspro
92
92
  munmap ((char*)MapPoint, FileSize);
93
93
  #else
94
94
  munmap ((void*)MapPoint, FileSize);
data/ext/kb.cpp CHANGED
@@ -26,9 +26,7 @@ KeyboardDescriptor::KeyboardDescriptor
26
26
 
27
27
  KeyboardDescriptor::KeyboardDescriptor (EventMachine_t *parent_em):
28
28
  EventableDescriptor (0, parent_em),
29
- bReadAttemptedAfterClose (false),
30
- LastIo (gCurrentLoopTime),
31
- InactivityTimeout (0)
29
+ bReadAttemptedAfterClose (false)
32
30
  {
33
31
  #ifdef HAVE_EPOLL
34
32
  EpollEvent.events = EPOLLIN;
@@ -30,8 +30,6 @@ PipeDescriptor::PipeDescriptor
30
30
  PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em):
31
31
  EventableDescriptor (fd, parent_em),
32
32
  bReadAttemptedAfterClose (false),
33
- LastIo (gCurrentLoopTime),
34
- InactivityTimeout (0),
35
33
  OutboundDataSize (0),
36
34
  SubprocessPid (subpid)
37
35
  {
@@ -104,22 +102,22 @@ PipeDescriptor::~PipeDescriptor()
104
102
  struct timespec req = {0, 50000000}; // 0.05s
105
103
  int n;
106
104
 
107
- // wait 0.25s for the process to die
108
- for (n=0; n<5; n++) {
105
+ // wait 0.5s for the process to die
106
+ for (n=0; n<10; n++) {
109
107
  if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
110
108
  nanosleep (&req, NULL);
111
109
  }
112
110
 
113
- // send SIGTERM and wait another 0.5s
111
+ // send SIGTERM and wait another 1s
114
112
  kill (SubprocessPid, SIGTERM);
115
- for (n=0; n<10; n++) {
113
+ for (n=0; n<20; n++) {
116
114
  nanosleep (&req, NULL);
117
115
  if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
118
116
  }
119
117
 
120
- // send SIGKILL and wait another 1s
118
+ // send SIGKILL and wait another 5s
121
119
  kill (SubprocessPid, SIGKILL);
122
- for (n=0; n<20; n++) {
120
+ for (n=0; n<100; n++) {
123
121
  nanosleep (&req, NULL);
124
122
  if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
125
123
  }
@@ -143,7 +141,7 @@ void PipeDescriptor::Read()
143
141
  return;
144
142
  }
145
143
 
146
- LastIo = gCurrentLoopTime;
144
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
147
145
 
148
146
  int total_bytes_read = 0;
149
147
  char readbuffer [16 * 1024];
@@ -203,7 +201,7 @@ void PipeDescriptor::Write()
203
201
  int sd = GetSocket();
204
202
  assert (sd != INVALID_SOCKET);
205
203
 
206
- LastIo = gCurrentLoopTime;
204
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
207
205
  char output_buffer [16 * 1024];
208
206
  size_t nbytes = 0;
209
207
 
@@ -268,7 +266,7 @@ PipeDescriptor::Heartbeat
268
266
  void PipeDescriptor::Heartbeat()
269
267
  {
270
268
  // If an inactivity timeout is defined, then check for it.
271
- if (InactivityTimeout && ((gCurrentLoopTime - LastIo) >= InactivityTimeout))
269
+ if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout))
272
270
  ScheduleClose (false);
273
271
  //bCloseNow = true;
274
272
  }
@@ -55,8 +55,8 @@ See the file COPYING for complete licensing information.
55
55
  #include <netinet/tcp.h>
56
56
  #include <arpa/inet.h>
57
57
  #include <pwd.h>
58
+ #include <string.h>
58
59
  typedef int SOCKET;
59
- #define closesocket close
60
60
  #define INVALID_SOCKET -1
61
61
  #define SOCKET_ERROR -1
62
62
  #ifdef OS_SOLARIS8
@@ -96,6 +96,9 @@ typedef int socklen_t;
96
96
  typedef int pid_t;
97
97
  #endif
98
98
 
99
+ #if !defined(_MSC_VER) || _MSC_VER > 1400
100
+ #include <stdint.h>
101
+ #endif
99
102
 
100
103
  using namespace std;
101
104
 
@@ -134,6 +137,14 @@ static inline int inotify_rm_watch (int fd, __u32 wd) { return syscall (__NR_ino
134
137
  #include <sys/uio.h>
135
138
  #endif
136
139
 
140
+ #if __cplusplus
141
+ extern "C" {
142
+ #endif
143
+ typedef void (*EMCallback)(const unsigned long, int, const char*, const unsigned long);
144
+ #if __cplusplus
145
+ }
146
+ #endif
147
+
137
148
  #include "binder.h"
138
149
  #include "em.h"
139
150
  #include "epoll.h"
@@ -145,7 +156,4 @@ static inline int inotify_rm_watch (int fd, __u32 wd) { return syscall (__NR_ino
145
156
  #include "eventmachine.h"
146
157
  #include "eventmachine_cpp.h"
147
158
 
148
-
149
-
150
-
151
159
  #endif // __Project__H_
@@ -31,6 +31,8 @@ Statics
31
31
 
32
32
  static VALUE EmModule;
33
33
  static VALUE EmConnection;
34
+ static VALUE EmConnsHash;
35
+ static VALUE EmTimersHash;
34
36
 
35
37
  static VALUE EM_eConnectionError;
36
38
  static VALUE EM_eUnknownTimerFired;
@@ -51,89 +53,117 @@ static VALUE Intern_ssl_verify_peer;
51
53
  static VALUE Intern_notify_readable;
52
54
  static VALUE Intern_notify_writable;
53
55
  static VALUE Intern_proxy_target_unbound;
56
+ static VALUE Intern_proxy_completed;
57
+ static VALUE Intern_connection_completed;
54
58
 
55
59
  static VALUE rb_cProcStatus;
56
60
 
57
61
  struct em_event {
58
- unsigned long a1;
59
- int a2;
60
- const char *a3;
61
- unsigned long a4;
62
+ unsigned long signature;
63
+ int event;
64
+ const char *data_str;
65
+ unsigned long data_num;
62
66
  };
63
67
 
68
+ static inline VALUE ensure_conn(const unsigned long signature)
69
+ {
70
+ VALUE conn = rb_hash_aref (EmConnsHash, ULONG2NUM (signature));
71
+ if (conn == Qnil)
72
+ rb_raise (EM_eConnectionNotBound, "unknown connection: %lu", signature);
73
+ return conn;
74
+ }
75
+
76
+
64
77
  /****************
65
78
  t_event_callback
66
79
  ****************/
67
80
 
68
- static void event_callback (struct em_event* e)
69
- {
70
- const unsigned long a1 = e->a1;
71
- int a2 = e->a2;
72
- const char *a3 = e->a3;
73
- const unsigned long a4 = e->a4;
74
-
75
- if (a2 == EM_CONNECTION_READ) {
76
- VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
77
- VALUE q = rb_hash_aref (t, ULONG2NUM (a1));
78
- if (q == Qnil)
79
- rb_raise (EM_eConnectionNotBound, "received %lu bytes of data for unknown signature: %lu", a4, a1);
80
- rb_funcall (q, Intern_receive_data, 1, rb_str_new (a3, a4));
81
- }
82
- else if (a2 == EM_CONNECTION_NOTIFY_READABLE) {
83
- VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
84
- VALUE q = rb_hash_aref (t, ULONG2NUM (a1));
85
- if (q == Qnil)
86
- rb_raise (EM_eConnectionNotBound, "unknown connection: %lu", a1);
87
- rb_funcall (q, Intern_notify_readable, 0);
88
- }
89
- else if (a2 == EM_CONNECTION_NOTIFY_WRITABLE) {
90
- VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
91
- VALUE q = rb_hash_aref (t, ULONG2NUM (a1));
92
- if (q == Qnil)
93
- rb_raise (EM_eConnectionNotBound, "unknown connection: %lu", a1);
94
- rb_funcall (q, Intern_notify_writable, 0);
95
- }
96
- else if (a2 == EM_LOOPBREAK_SIGNAL) {
97
- rb_funcall (EmModule, Intern_run_deferred_callbacks, 0);
98
- }
99
- else if (a2 == EM_TIMER_FIRED) {
100
- VALUE t = rb_ivar_get (EmModule, Intern_at_timers);
101
- VALUE q = rb_funcall (t, Intern_delete, 1, ULONG2NUM (a4));
102
- if (q == Qnil) {
103
- rb_raise (EM_eUnknownTimerFired, "no such timer: %lu", a4);
104
- } else if (q == Qfalse) {
105
- /* Timer Canceled */
106
- } else {
107
- rb_funcall (q, Intern_call, 0);
81
+ static inline void event_callback (struct em_event* e)
82
+ {
83
+ const unsigned long signature = e->signature;
84
+ int event = e->event;
85
+ const char *data_str = e->data_str;
86
+ const unsigned long data_num = e->data_num;
87
+
88
+ switch (event) {
89
+ case EM_CONNECTION_READ:
90
+ {
91
+ VALUE conn = rb_hash_aref (EmConnsHash, ULONG2NUM (signature));
92
+ if (conn == Qnil)
93
+ rb_raise (EM_eConnectionNotBound, "received %lu bytes of data for unknown signature: %lu", data_num, signature);
94
+ rb_funcall (conn, Intern_receive_data, 1, rb_str_new (data_str, data_num));
95
+ return;
96
+ }
97
+ case EM_CONNECTION_ACCEPTED:
98
+ case EM_CONNECTION_UNBOUND:
99
+ {
100
+ rb_funcall (EmModule, Intern_event_callback, 3, ULONG2NUM(signature), INT2FIX(event), data_str ? rb_str_new(data_str,data_num) : ULONG2NUM(data_num));
101
+ return;
102
+ }
103
+ case EM_CONNECTION_COMPLETED:
104
+ {
105
+ VALUE conn = ensure_conn(signature);
106
+ rb_funcall (conn, Intern_connection_completed, 0);
107
+ return;
108
+ }
109
+ case EM_CONNECTION_NOTIFY_READABLE:
110
+ {
111
+ VALUE conn = ensure_conn(signature);
112
+ rb_funcall (conn, Intern_notify_readable, 0);
113
+ return;
114
+ }
115
+ case EM_CONNECTION_NOTIFY_WRITABLE:
116
+ {
117
+ VALUE conn = ensure_conn(signature);
118
+ rb_funcall (conn, Intern_notify_writable, 0);
119
+ return;
120
+ }
121
+ case EM_LOOPBREAK_SIGNAL:
122
+ {
123
+ rb_funcall (EmModule, Intern_run_deferred_callbacks, 0);
124
+ return;
125
+ }
126
+ case EM_TIMER_FIRED:
127
+ {
128
+ VALUE timer = rb_funcall (EmTimersHash, Intern_delete, 1, ULONG2NUM (data_num));
129
+ if (timer == Qnil) {
130
+ rb_raise (EM_eUnknownTimerFired, "no such timer: %lu", data_num);
131
+ } else if (timer == Qfalse) {
132
+ /* Timer Canceled */
133
+ } else {
134
+ rb_funcall (timer, Intern_call, 0);
135
+ }
136
+ return;
137
+ }
138
+ #ifdef WITH_SSL
139
+ case EM_SSL_HANDSHAKE_COMPLETED:
140
+ {
141
+ VALUE conn = ensure_conn(signature);
142
+ rb_funcall (conn, Intern_ssl_handshake_completed, 0);
143
+ return;
144
+ }
145
+ case EM_SSL_VERIFY:
146
+ {
147
+ VALUE conn = ensure_conn(signature);
148
+ VALUE should_accept = rb_funcall (conn, Intern_ssl_verify_peer, 1, rb_str_new(data_str, data_num));
149
+ if (RTEST(should_accept))
150
+ evma_accept_ssl_peer (signature);
151
+ return;
152
+ }
153
+ #endif
154
+ case EM_PROXY_TARGET_UNBOUND:
155
+ {
156
+ VALUE conn = ensure_conn(signature);
157
+ rb_funcall (conn, Intern_proxy_target_unbound, 0);
158
+ return;
159
+ }
160
+ case EM_PROXY_COMPLETED:
161
+ {
162
+ VALUE conn = ensure_conn(signature);
163
+ rb_funcall (conn, Intern_proxy_completed, 0);
164
+ return;
108
165
  }
109
166
  }
110
- #ifdef WITH_SSL
111
- else if (a2 == EM_SSL_HANDSHAKE_COMPLETED) {
112
- VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
113
- VALUE q = rb_hash_aref (t, ULONG2NUM (a1));
114
- if (q == Qnil)
115
- rb_raise (EM_eConnectionNotBound, "unknown connection: %lu", a1);
116
- rb_funcall (q, Intern_ssl_handshake_completed, 0);
117
- }
118
- else if (a2 == EM_SSL_VERIFY) {
119
- VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
120
- VALUE q = rb_hash_aref (t, ULONG2NUM (a1));
121
- if (q == Qnil)
122
- rb_raise (EM_eConnectionNotBound, "unknown connection: %lu", a1);
123
- VALUE r = rb_funcall (q, Intern_ssl_verify_peer, 1, rb_str_new(a3, a4));
124
- if (RTEST(r))
125
- evma_accept_ssl_peer (a1);
126
- }
127
- #endif
128
- else if (a2 == EM_PROXY_TARGET_UNBOUND) {
129
- VALUE t = rb_ivar_get (EmModule, Intern_at_conns);
130
- VALUE q = rb_hash_aref (t, ULONG2NUM (a1));
131
- if (q == Qnil)
132
- rb_raise (EM_eConnectionNotBound, "unknown connection: %lu", a1);
133
- rb_funcall (q, Intern_proxy_target_unbound, 0);
134
- }
135
- else
136
- rb_funcall (EmModule, Intern_event_callback, 3, ULONG2NUM(a1), INT2FIX(a2), a3 ? rb_str_new(a3,a4) : ULONG2NUM(a4));
137
167
  }
138
168
 
139
169
  /*******************
@@ -150,13 +180,13 @@ static void event_error_handler(VALUE unused, VALUE err)
150
180
  event_callback_wrapper
151
181
  **********************/
152
182
 
153
- static void event_callback_wrapper (const unsigned long a1, int a2, const char *a3, const unsigned long a4)
183
+ static void event_callback_wrapper (const unsigned long signature, int event, const char *data_str, const unsigned long data_num)
154
184
  {
155
185
  struct em_event e;
156
- e.a1 = a1;
157
- e.a2 = a2;
158
- e.a3 = a3;
159
- e.a4 = a4;
186
+ e.signature = signature;
187
+ e.event = event;
188
+ e.data_str = data_str;
189
+ e.data_num = data_num;
160
190
 
161
191
  if (!rb_ivar_defined(EmModule, Intern_at_error_handler))
162
192
  event_callback(&e);
@@ -170,7 +200,11 @@ t_initialize_event_machine
170
200
 
171
201
  static VALUE t_initialize_event_machine (VALUE self)
172
202
  {
173
- evma_initialize_library (event_callback_wrapper);
203
+ EmConnsHash = rb_ivar_get (EmModule, Intern_at_conns);
204
+ EmTimersHash = rb_ivar_get (EmModule, Intern_at_timers);
205
+ assert(EmConnsHash != Qnil);
206
+ assert(EmTimersHash != Qnil);
207
+ evma_initialize_library ((EMCallback)event_callback_wrapper);
174
208
  return Qnil;
175
209
  }
176
210
 
@@ -208,7 +242,7 @@ static VALUE t_start_server (VALUE self, VALUE server, VALUE port)
208
242
  {
209
243
  const unsigned long f = evma_create_tcp_server (StringValuePtr(server), FIX2INT(port));
210
244
  if (!f)
211
- rb_raise (rb_eRuntimeError, "no acceptor");
245
+ rb_raise (rb_eRuntimeError, "no acceptor (port is in use or requires root privileges)");
212
246
  return ULONG2NUM (f);
213
247
  }
214
248
 
@@ -467,6 +501,7 @@ static VALUE t_connect_server (VALUE self, VALUE server, VALUE port)
467
501
  } catch (std::runtime_error e) {
468
502
  rb_raise (EM_eConnectionError, e.what());
469
503
  }
504
+ return Qnil;
470
505
  }
471
506
 
472
507
  /*********************
@@ -487,6 +522,7 @@ static VALUE t_bind_connect_server (VALUE self, VALUE bind_addr, VALUE bind_port
487
522
  } catch (std::runtime_error e) {
488
523
  rb_raise (EM_eConnectionError, e.what());
489
524
  }
525
+ return Qnil;
490
526
  }
491
527
 
492
528
  /*********************
@@ -725,9 +761,9 @@ static VALUE t_invoke_popen (VALUE self, VALUE cmd)
725
761
  #else
726
762
  int len = RARRAY (cmd)->len;
727
763
  #endif
728
- if (len > 98)
764
+ if (len >= 2048)
729
765
  rb_raise (rb_eRuntimeError, "too many arguments to popen");
730
- char *strings [100];
766
+ char *strings [2048];
731
767
  for (int i=0; i < len; i++) {
732
768
  VALUE ix = INT2FIX (i);
733
769
  VALUE s = rb_ary_aref (1, &ix, cmd);
@@ -769,8 +805,9 @@ static VALUE t_watch_filename (VALUE self, VALUE fname)
769
805
  try {
770
806
  return ULONG2NUM(evma_watch_filename(StringValuePtr(fname)));
771
807
  } catch (std::runtime_error e) {
772
- rb_sys_fail(e.what());
808
+ rb_raise (EM_eUnsupported, e.what());
773
809
  }
810
+ return Qnil;
774
811
  }
775
812
 
776
813
 
@@ -794,8 +831,9 @@ static VALUE t_watch_pid (VALUE self, VALUE pid)
794
831
  try {
795
832
  return ULONG2NUM(evma_watch_pid(NUM2INT(pid)));
796
833
  } catch (std::runtime_error e) {
797
- rb_sys_fail(e.what());
834
+ rb_raise (EM_eUnsupported, e.what());
798
835
  }
836
+ return Qnil;
799
837
  }
800
838
 
801
839
 
@@ -972,11 +1010,12 @@ static VALUE t_get_loop_time (VALUE self)
972
1010
  static ID at = rb_intern("at");
973
1011
  #endif
974
1012
 
975
- if (gCurrentLoopTime != 0) {
1013
+ uint64_t current_time = evma_get_current_loop_time();
1014
+ if (current_time != 0) {
976
1015
  #ifndef HAVE_RB_TIME_NEW
977
- return rb_funcall(cTime, at, 2, INT2NUM(gCurrentLoopTime / 1000000), INT2NUM(gCurrentLoopTime % 1000000));
1016
+ return rb_funcall(cTime, at, 2, INT2NUM(current_time / 1000000), INT2NUM(current_time % 1000000));
978
1017
  #else
979
- return rb_time_new(gCurrentLoopTime / 1000000, gCurrentLoopTime % 1000000);
1018
+ return rb_time_new(current_time / 1000000, current_time % 1000000);
980
1019
  #endif
981
1020
  }
982
1021
  return Qnil;
@@ -987,9 +1026,13 @@ static VALUE t_get_loop_time (VALUE self)
987
1026
  t_start_proxy
988
1027
  **************/
989
1028
 
990
- static VALUE t_start_proxy (VALUE self, VALUE from, VALUE to, VALUE bufsize)
1029
+ static VALUE t_start_proxy (VALUE self, VALUE from, VALUE to, VALUE bufsize, VALUE length)
991
1030
  {
992
- evma_start_proxy(NUM2ULONG (from), NUM2ULONG (to), NUM2ULONG(bufsize));
1031
+ try {
1032
+ evma_start_proxy(NUM2ULONG (from), NUM2ULONG (to), NUM2ULONG(bufsize), NUM2ULONG(length));
1033
+ } catch (std::runtime_error e) {
1034
+ rb_raise (EM_eConnectionError, e.what());
1035
+ }
993
1036
  return Qnil;
994
1037
  }
995
1038
 
@@ -1000,7 +1043,11 @@ t_stop_proxy
1000
1043
 
1001
1044
  static VALUE t_stop_proxy (VALUE self, VALUE from)
1002
1045
  {
1003
- evma_stop_proxy(NUM2ULONG (from));
1046
+ try{
1047
+ evma_stop_proxy(NUM2ULONG (from));
1048
+ } catch (std::runtime_error e) {
1049
+ rb_raise (EM_eConnectionError, e.what());
1050
+ }
1004
1051
  return Qnil;
1005
1052
  }
1006
1053
 
@@ -1054,6 +1101,8 @@ extern "C" void Init_rubyeventmachine()
1054
1101
  Intern_notify_readable = rb_intern ("notify_readable");
1055
1102
  Intern_notify_writable = rb_intern ("notify_writable");
1056
1103
  Intern_proxy_target_unbound = rb_intern ("proxy_target_unbound");
1104
+ Intern_proxy_completed = rb_intern ("proxy_completed");
1105
+ Intern_connection_completed = rb_intern ("connection_completed");
1057
1106
 
1058
1107
  // INCOMPLETE, we need to define class Connections inside module EventMachine
1059
1108
  // run_machine and run_machine_without_threads are now identical.
@@ -1097,7 +1146,7 @@ extern "C" void Init_rubyeventmachine()
1097
1146
  rb_define_module_function (EmModule, "resume_connection", (VALUE (*)(...))t_resume, 1);
1098
1147
  rb_define_module_function (EmModule, "connection_paused?", (VALUE (*)(...))t_paused_p, 1);
1099
1148
 
1100
- rb_define_module_function (EmModule, "start_proxy", (VALUE (*)(...))t_start_proxy, 3);
1149
+ rb_define_module_function (EmModule, "start_proxy", (VALUE (*)(...))t_start_proxy, 4);
1101
1150
  rb_define_module_function (EmModule, "stop_proxy", (VALUE (*)(...))t_stop_proxy, 1);
1102
1151
 
1103
1152
  rb_define_module_function (EmModule, "watch_filename", (VALUE (*)(...))t_watch_filename, 1);