eventmachine 0.12.10 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
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);