eventmachine 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,10 +3,8 @@ language: ruby
3
3
  rvm:
4
4
  - 1.8.7
5
5
  - 1.9.3
6
- - rbx-18mode
7
- - rbx-19mode
6
+ - 2.0.0
7
+ - 2.1
8
+ - 2.2
9
+ - rbx
8
10
  - jruby
9
- matrix:
10
- allow_failures:
11
- - rvm: rbx-18mode
12
- - rvm: rbx-19mode
@@ -1,6 +1,25 @@
1
1
  # Changelog
2
2
 
3
- ## 1.0.x
3
+ ## 1.0.4 (December 19, 2014)
4
+ * add starttls_options to smtp server [#552]
5
+ * fix closesocket on windows [#497]
6
+ * fix build on ruby 2.2 [#503]
7
+ * fix build error on ruby 1.9 [#508]
8
+ * fix timer leak during dns resolution [#489]
9
+ * add concurrency validation to EM::Iterator [#468]
10
+ * add get_file_descriptor to get fd for a signature [#467]
11
+ * add EM.attach_server and EM.attach_socket_server [#465, #466]
12
+ * calling pause from receive_data takes effect immediately [#464]
13
+ * reactor_running? returns false after fork [#455]
14
+ * fix infinite loop on double close [edc4d0e6, #441, #445]
15
+ * fix compilation issue on llvm [#433]
16
+ * fix socket error codes on win32 [ff811a81]
17
+ * fix EM.stop latency when timers exist [8b613d05, #426]
18
+ * fix infinite loop when system time changes [1427a2c80, #428]
19
+ * fix crash when callin attach/detach in the same tick [#427]
20
+ * fix compilation issue on solaris [#416]
21
+
22
+ ## 1.0.3 (March 8, 2013)
4
23
  * EM.system was broken in 1.0.2 release [#413]
5
24
 
6
25
  ## 1.0.2 (March 8, 2013)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # About EventMachine #
1
+ # About EventMachine [![Code Climate](https://codeclimate.com/github/eventmachine/eventmachine.png)](https://codeclimate.com/github/eventmachine/eventmachine)
2
2
 
3
3
 
4
4
  ## What is EventMachine ##
@@ -75,7 +75,7 @@ Here's a fully-functional echo server written with EventMachine:
75
75
 
76
76
  def unbind
77
77
  puts "-- someone disconnected from the echo server!"
78
- end
78
+ end
79
79
  end
80
80
 
81
81
  # Note that this will block current thread.
@@ -86,7 +86,7 @@ Here's a fully-functional echo server written with EventMachine:
86
86
 
87
87
  ## EventMachine documentation ##
88
88
 
89
- Currently we only have [reference documentation](http://eventmachine.rubyforge.org) and a [wiki](https://github.com/eventmachine/eventmachine/wiki).
89
+ Currently we only have [reference documentation](http://rdoc.info/github/eventmachine/eventmachine/frames) and a [wiki](https://github.com/eventmachine/eventmachine/wiki).
90
90
 
91
91
 
92
92
  ## Community and where to get help ##
@@ -8,6 +8,7 @@ Gem::Specification.new do |s|
8
8
  s.version = EventMachine::VERSION
9
9
  s.homepage = 'http://rubyeventmachine.com'
10
10
  s.rubyforge_project = 'eventmachine'
11
+ s.licenses = ["Ruby", "GPL"]
11
12
 
12
13
  s.authors = ["Francis Cianfrocca", "Aman Gupta"]
13
14
  s.email = ["garbagecat10@gmail.com", "aman@tmm1.net"]
@@ -32,7 +32,7 @@ STATIC Bindable_t::CreateBinding
32
32
  unsigned long Bindable_t::CreateBinding()
33
33
  {
34
34
  static unsigned long num = 0;
35
- while(BindingBag[++num]);
35
+ while(BindingBag[++num]) {}
36
36
  return num;
37
37
  }
38
38
 
@@ -259,6 +259,7 @@ evma_num_close_scheduled
259
259
 
260
260
  extern "C" int evma_num_close_scheduled ()
261
261
  {
262
+ ensure_eventmachine("evma_num_close_scheduled");
262
263
  return EventMachine->NumCloseScheduled;
263
264
  }
264
265
 
@@ -282,6 +283,16 @@ extern "C" const unsigned long evma_create_unix_domain_server (const char *filen
282
283
  return EventMachine->CreateUnixDomainServer (filename);
283
284
  }
284
285
 
286
+ /***********************
287
+ evma_attach_sd
288
+ ************************/
289
+
290
+ extern "C" const unsigned long evma_attach_sd (int sd)
291
+ {
292
+ ensure_eventmachine("evma_attach_sd");
293
+ return EventMachine->AttachSD (sd);
294
+ }
295
+
285
296
  /*************************
286
297
  evma_open_datagram_socket
287
298
  *************************/
data/ext/ed.cpp CHANGED
@@ -217,6 +217,8 @@ EventableDescriptor::ScheduleClose
217
217
 
218
218
  void EventableDescriptor::ScheduleClose (bool after_writing)
219
219
  {
220
+ if (IsCloseScheduled())
221
+ return;
220
222
  MyEventMachine->NumCloseScheduled++;
221
223
  // KEEP THIS SYNCHRONIZED WITH ::IsCloseScheduled.
222
224
  if (after_writing)
@@ -765,7 +767,11 @@ void ConnectionDescriptor::Read()
765
767
 
766
768
 
767
769
  int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
770
+ #ifdef OS_WIN32
771
+ int e = WSAGetLastError();
772
+ #else
768
773
  int e = errno;
774
+ #endif
769
775
  //cerr << "<R:" << r << ">";
770
776
 
771
777
  if (r > 0) {
@@ -779,6 +785,8 @@ void ConnectionDescriptor::Read()
779
785
  // a security guard against buffer overflows.
780
786
  readbuffer [r] = 0;
781
787
  _DispatchInboundData (readbuffer, r);
788
+ if (bPaused)
789
+ break;
782
790
  }
783
791
  else if (r == 0) {
784
792
  break;
@@ -981,11 +989,7 @@ void ConnectionDescriptor::_WriteOutboundData()
981
989
  // Max of 16 outbound pages at a time
982
990
  if (iovcnt > 16) iovcnt = 16;
983
991
 
984
- #ifdef CC_SUNWspro
985
- struct iovec iov[16];
986
- #else
987
- struct iovec iov[ iovcnt ];
988
- #endif
992
+ iovec iov[16];
989
993
 
990
994
  for(int i = 0; i < iovcnt; i++){
991
995
  OutboundPage *op = &(OutboundPages[i]);
@@ -1032,7 +1036,11 @@ void ConnectionDescriptor::_WriteOutboundData()
1032
1036
  #endif
1033
1037
 
1034
1038
  bool err = false;
1039
+ #ifdef OS_WIN32
1040
+ int e = WSAGetLastError();
1041
+ #else
1035
1042
  int e = errno;
1043
+ #endif
1036
1044
  if (bytes_written < 0) {
1037
1045
  err = true;
1038
1046
  bytes_written = 0;
@@ -1663,7 +1671,11 @@ void DatagramDescriptor::Write()
1663
1671
 
1664
1672
  // The nasty cast to (char*) is needed because Windows is brain-dead.
1665
1673
  int s = sendto (sd, (char*)op->Buffer, op->Length, 0, (struct sockaddr*)&(op->From), sizeof(op->From));
1674
+ #ifdef OS_WIN32
1675
+ int e = WSAGetLastError();
1676
+ #else
1666
1677
  int e = errno;
1678
+ #endif
1667
1679
 
1668
1680
  OutboundDataSize -= op->Length;
1669
1681
  op->Free();
data/ext/ed.h CHANGED
@@ -69,14 +69,14 @@ class EventableDescriptor: public Bindable_t
69
69
  virtual bool GetSubprocessPid (pid_t*) {return false;}
70
70
 
71
71
  virtual void StartTls() {}
72
- virtual void SetTlsParms (const char *privkey_filename, const char *certchain_filename, bool verify_peer) {}
72
+ virtual void SetTlsParms (const char *, const char *, bool) {}
73
73
 
74
74
  #ifdef WITH_SSL
75
75
  virtual X509 *GetPeerCert() {return NULL;}
76
76
  #endif
77
77
 
78
78
  virtual uint64_t GetCommInactivityTimeout() {return 0;}
79
- virtual int SetCommInactivityTimeout (uint64_t value) {return 0;}
79
+ virtual int SetCommInactivityTimeout (uint64_t) {return 0;}
80
80
  uint64_t GetPendingConnectTimeout();
81
81
  int SetPendingConnectTimeout (uint64_t value);
82
82
  uint64_t GetLastActivity() { return LastActivity; }
@@ -215,7 +215,7 @@ class ConnectionDescriptor: public EventableDescriptor
215
215
  protected:
216
216
  struct OutboundPage {
217
217
  OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
218
- void Free() {if (Buffer) free ((char*)Buffer); }
218
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
219
219
  const char *Buffer;
220
220
  int Length;
221
221
  int Offset;
@@ -292,7 +292,7 @@ class DatagramDescriptor: public EventableDescriptor
292
292
  protected:
293
293
  struct OutboundPage {
294
294
  OutboundPage (const char *b, int l, struct sockaddr_in f, int o=0): Buffer(b), Length(l), Offset(o), From(f) {}
295
- void Free() {if (Buffer) free ((char*)Buffer); }
295
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
296
296
  const char *Buffer;
297
297
  int Length;
298
298
  int Offset;
@@ -354,7 +354,7 @@ class PipeDescriptor: public EventableDescriptor
354
354
  protected:
355
355
  struct OutboundPage {
356
356
  OutboundPage (const char *b, int l, int o=0): Buffer(b), Length(l), Offset(o) {}
357
- void Free() {if (Buffer) free ((char*)Buffer); }
357
+ void Free() {if (Buffer) free (const_cast<char*>(Buffer)); }
358
358
  const char *Buffer;
359
359
  int Length;
360
360
  int Offset;
data/ext/em.cpp CHANGED
@@ -382,15 +382,27 @@ EventMachine_t::_DispatchHeartbeats
382
382
 
383
383
  void EventMachine_t::_DispatchHeartbeats()
384
384
  {
385
+ // Store the first processed heartbeat descriptor and bail out if
386
+ // we see it again. This fixes an infinite loop in case the system time
387
+ // is changed out from underneath MyCurrentLoopTime.
388
+ const EventableDescriptor *head = NULL;
389
+
385
390
  while (true) {
386
391
  multimap<uint64_t,EventableDescriptor*>::iterator i = Heartbeats.begin();
387
392
  if (i == Heartbeats.end())
388
393
  break;
389
394
  if (i->first > MyCurrentLoopTime)
390
395
  break;
396
+
391
397
  EventableDescriptor *ed = i->second;
398
+ if (ed == head)
399
+ break;
400
+
392
401
  ed->Heartbeat();
393
402
  QueueHeartbeat(ed);
403
+
404
+ if (head == NULL)
405
+ head = ed;
394
406
  }
395
407
  }
396
408
 
@@ -675,7 +687,7 @@ EventMachine_t::_TimeTilNextEvent
675
687
 
676
688
  timeval EventMachine_t::_TimeTilNextEvent()
677
689
  {
678
- // 29jul11: Changed calculation base from MyCurrentLoopTime to the
690
+ // 29jul11: Changed calculation base from MyCurrentLoopTime to the
679
691
  // real time. As MyCurrentLoopTime is set at the beginning of an
680
692
  // iteration and this calculation is done at the end, evenmachine
681
693
  // will potentially oversleep by the amount of time the iteration
@@ -697,10 +709,12 @@ timeval EventMachine_t::_TimeTilNextEvent()
697
709
  if (!NewDescriptors.empty() || !ModifiedDescriptors.empty()) {
698
710
  next_event = current_time;
699
711
  }
700
-
712
+
701
713
  timeval tv;
702
714
 
703
- if (next_event == 0 || NumCloseScheduled > 0) {
715
+ if (NumCloseScheduled > 0 || bTerminateSignalReceived) {
716
+ tv.tv_sec = tv.tv_usec = 0;
717
+ } else if (next_event == 0) {
704
718
  tv = Quantum;
705
719
  } else {
706
720
  if (next_event > current_time) {
@@ -803,7 +817,7 @@ SelectData_t::SelectData_t()
803
817
  _SelectDataSelect
804
818
  *****************/
805
819
 
806
- #ifdef HAVE_TBR
820
+ #if defined(HAVE_TBR) || defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
807
821
  static VALUE _SelectDataSelect (void *v)
808
822
  {
809
823
  SelectData_t *sd = (SelectData_t*)v;
@@ -818,12 +832,13 @@ SelectData_t::_Select
818
832
 
819
833
  int SelectData_t::_Select()
820
834
  {
821
- #ifdef HAVE_TBR
835
+ #if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
836
+ rb_thread_call_without_gvl ((void *(*)(void *))_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
837
+ return nSockets;
838
+ #elif defined(HAVE_TBR)
822
839
  rb_thread_blocking_region (_SelectDataSelect, (void*)this, RUBY_UBF_IO, 0);
823
840
  return nSockets;
824
- #endif
825
-
826
- #ifndef HAVE_TBR
841
+ #else
827
842
  return EmSelect (maxsocket+1, &fdreads, &fdwrites, &fderrors, &tv);
828
843
  #endif
829
844
  }
@@ -1399,6 +1414,14 @@ int EventMachine_t::DetachFD (EventableDescriptor *ed)
1399
1414
  // Prevent the descriptor from being modified, in case DetachFD was called from a timer or next_tick
1400
1415
  ModifiedDescriptors.erase (ed);
1401
1416
 
1417
+ // Prevent the descriptor from being added, in case DetachFD was called in the same tick as AttachFD
1418
+ for (size_t i = 0; i < NewDescriptors.size(); i++) {
1419
+ if (ed == NewDescriptors[i]) {
1420
+ NewDescriptors.erase(NewDescriptors.begin() + i);
1421
+ break;
1422
+ }
1423
+ }
1424
+
1402
1425
  // Set MySocket = INVALID_SOCKET so ShouldDelete() is true (and the descriptor gets deleted and removed),
1403
1426
  // and also to prevent anyone from calling close() on the detached fd
1404
1427
  ed->SetSocketInvalid();
@@ -1491,8 +1514,6 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1491
1514
  if (!bind_here)
1492
1515
  return 0;
1493
1516
 
1494
- unsigned long output_binding = 0;
1495
-
1496
1517
  //struct sockaddr_in sin;
1497
1518
 
1498
1519
  int sd_accept = socket (family, SOCK_STREAM, 0);
@@ -1529,25 +1550,7 @@ const unsigned long EventMachine_t::CreateTcpServer (const char *server, int por
1529
1550
  goto fail;
1530
1551
  }
1531
1552
 
1532
- {
1533
- // Set the acceptor non-blocking.
1534
- // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
1535
- if (!SetSocketNonblocking (sd_accept)) {
1536
- //int val = fcntl (sd_accept, F_GETFL, 0);
1537
- //if (fcntl (sd_accept, F_SETFL, val | O_NONBLOCK) == -1) {
1538
- goto fail;
1539
- }
1540
- }
1541
-
1542
- { // Looking good.
1543
- AcceptorDescriptor *ad = new AcceptorDescriptor (sd_accept, this);
1544
- if (!ad)
1545
- throw std::runtime_error ("unable to allocate acceptor");
1546
- Add (ad);
1547
- output_binding = ad->GetBinding();
1548
- }
1549
-
1550
- return output_binding;
1553
+ return AttachSD(sd_accept);
1551
1554
 
1552
1555
  fail:
1553
1556
  if (sd_accept != INVALID_SOCKET)
@@ -1838,7 +1841,6 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1838
1841
 
1839
1842
  // The whole rest of this function is only compiled on Unix systems.
1840
1843
  #ifdef OS_UNIX
1841
- unsigned long output_binding = 0;
1842
1844
 
1843
1845
  struct sockaddr_un s_sun;
1844
1846
 
@@ -1876,6 +1878,24 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1876
1878
  goto fail;
1877
1879
  }
1878
1880
 
1881
+ return AttachSD(sd_accept);
1882
+
1883
+ fail:
1884
+ if (sd_accept != INVALID_SOCKET)
1885
+ close (sd_accept);
1886
+ return 0;
1887
+ #endif // OS_UNIX
1888
+ }
1889
+
1890
+
1891
+ /**************************************
1892
+ EventMachine_t::AttachSD
1893
+ **************************************/
1894
+
1895
+ const unsigned long EventMachine_t::AttachSD (int sd_accept)
1896
+ {
1897
+ unsigned long output_binding = 0;
1898
+
1879
1899
  {
1880
1900
  // Set the acceptor non-blocking.
1881
1901
  // THIS IS CRUCIALLY IMPORTANT because we read it in a select loop.
@@ -1900,7 +1920,6 @@ const unsigned long EventMachine_t::CreateUnixDomainServer (const char *filename
1900
1920
  if (sd_accept != INVALID_SOCKET)
1901
1921
  close (sd_accept);
1902
1922
  return 0;
1903
- #endif // OS_UNIX
1904
1923
  }
1905
1924
 
1906
1925
 
data/ext/em.h CHANGED
@@ -22,7 +22,16 @@ See the file COPYING for complete licensing information.
22
22
 
23
23
  #ifdef BUILD_FOR_RUBY
24
24
  #include <ruby.h>
25
- #define EmSelect rb_thread_select
25
+
26
+ #ifdef HAVE_RB_THREAD_FD_SELECT
27
+ #define EmSelect rb_thread_fd_select
28
+ #else
29
+ #define EmSelect rb_thread_select
30
+ #endif
31
+
32
+ #ifdef HAVE_RB_THREAD_CALL_WITHOUT_GVL
33
+ #include <ruby/thread.h>
34
+ #endif
26
35
 
27
36
  #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
28
37
  #include <ruby/io.h>
@@ -88,6 +97,7 @@ class EventMachine_t
88
97
  const unsigned long CreateTcpServer (const char *, int);
89
98
  const unsigned long OpenDatagramSocket (const char *, int);
90
99
  const unsigned long CreateUnixDomainServer (const char*);
100
+ const unsigned long AttachSD (int);
91
101
  const unsigned long OpenKeyboard();
92
102
  //const char *Popen (const char*, const char*);
93
103
  const unsigned long Socketpair (char* const*);
@@ -64,6 +64,7 @@ extern "C" {
64
64
  void evma_stop_tcp_server (const unsigned long signature);
65
65
  const unsigned long evma_create_tcp_server (const char *address, int port);
66
66
  const unsigned long evma_create_unix_domain_server (const char *filename);
67
+ const unsigned long evma_attach_sd (int sd);
67
68
  const unsigned long evma_open_datagram_socket (const char *server, int port);
68
69
  const unsigned long evma_open_keyboard();
69
70
  void evma_set_tls_parms (const unsigned long binding, const char *privatekey_filename, const char *certchain_filenane, int verify_peer);
@@ -40,7 +40,7 @@ def manual_ssl_config
40
40
  end
41
41
 
42
42
  if ENV['CROSS_COMPILING']
43
- openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.0j")
43
+ openssl_version = ENV.fetch("OPENSSL_VERSION", "1.0.1i")
44
44
  openssl_dir = File.expand_path("~/.rake-compiler/builds/openssl-#{openssl_version}/")
45
45
  if File.exists?(openssl_dir)
46
46
  FileUtils.mkdir_p Dir.pwd+"/openssl/"
@@ -67,9 +67,11 @@ end
67
67
  add_define 'BUILD_FOR_RUBY'
68
68
  add_define 'HAVE_RBTRAP' if have_var('rb_trap_immediate', ['ruby.h', 'rubysig.h'])
69
69
  add_define "HAVE_TBR" if have_func('rb_thread_blocking_region')# and have_macro('RUBY_UBF_IO', 'ruby.h')
70
+ add_define "HAVE_RB_THREAD_CALL_WITHOUT_GVL" if have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
70
71
  add_define "HAVE_INOTIFY" if inotify = have_func('inotify_init', 'sys/inotify.h')
71
72
  add_define "HAVE_OLD_INOTIFY" if !inotify && have_macro('__NR_inotify_init', 'sys/syscall.h')
72
73
  add_define 'HAVE_WRITEV' if have_func('writev', 'sys/uio.h')
74
+ add_define 'HAVE_RB_THREAD_FD_SELECT' if have_func('rb_thread_fd_select')
73
75
 
74
76
  have_func('rb_wait_for_single_fd')
75
77
  have_func('rb_enable_interrupt')
@@ -106,7 +108,7 @@ when /mswin32/, /mingw32/, /bccwin32/
106
108
  check_libs(%w[kernel32 rpcrt4 gdi32], true)
107
109
 
108
110
  if GNU_CHAIN
109
- CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
111
+ CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
110
112
  else
111
113
  $defs.push "-EHs"
112
114
  $defs.push "-GR"
@@ -170,7 +172,7 @@ TRY_LINK.sub!('$(CC)', '$(CXX)')
170
172
  add_define 'HAVE_MAKE_PAIR' if try_link(<<SRC, '-lstdc++')
171
173
  #include <utility>
172
174
  using namespace std;
173
- int main(){ pair<int,int> tuple = make_pair(1,2); }
175
+ int main(){ pair<const int,int> tuple = make_pair(1,2); }
174
176
  SRC
175
177
  TRY_LINK.sub!('$(CXX)', '$(CC)')
176
178
 
@@ -43,7 +43,7 @@ when /mswin32/, /mingw32/, /bccwin32/
43
43
  check_libs(%w[kernel32 rpcrt4 gdi32], true)
44
44
 
45
45
  if GNU_CHAIN
46
- CONFIG['LDSHARED'] = "$(CXX) -shared -lstdc++"
46
+ CONFIG['LDSHAREDXX'] = "$(CXX) -shared -static-libgcc -static-libstdc++"
47
47
  else
48
48
  $defs.push "-EHs"
49
49
  $defs.push "-GR"
@@ -93,9 +93,14 @@ typedef int SOCKET;
93
93
  #include <fcntl.h>
94
94
  #include <assert.h>
95
95
 
96
+ #define close closesocket
97
+
96
98
  typedef int socklen_t;
99
+ #ifndef _PID_T_
100
+ #define _PID_T_
97
101
  typedef int pid_t;
98
- #endif
102
+ #endif /* _PID_T_ */
103
+ #endif /* OS_WIN32 */
99
104
 
100
105
  #if !defined(_MSC_VER) || _MSC_VER > 1500
101
106
  #include <stdint.h>
@@ -273,6 +273,17 @@ static VALUE t_start_unix_server (VALUE self, VALUE filename)
273
273
  return ULONG2NUM (f);
274
274
  }
275
275
 
276
+ /********************
277
+ t_attach_sd
278
+ ********************/
279
+
280
+ static VALUE t_attach_sd(VALUE self, VALUE sd)
281
+ {
282
+ const unsigned long f = evma_attach_sd(FIX2INT(sd));
283
+ if (!f)
284
+ rb_raise (rb_eRuntimeError, "%s", "no socket descriptor acceptor");
285
+ return ULONG2NUM (f);
286
+ }
276
287
 
277
288
 
278
289
  /***********
@@ -566,6 +577,14 @@ static VALUE t_detach_fd (VALUE self, VALUE signature)
566
577
  return INT2NUM(evma_detach_fd (NUM2ULONG (signature)));
567
578
  }
568
579
 
580
+ /*********************
581
+ t_get_file_descriptor
582
+ *********************/
583
+ static VALUE t_get_file_descriptor (VALUE self, VALUE signature)
584
+ {
585
+ return INT2NUM(evma_get_file_descriptor (NUM2ULONG (signature)));
586
+ }
587
+
569
588
  /**************
570
589
  t_get_sock_opt
571
590
  **************/
@@ -1204,6 +1223,7 @@ extern "C" void Init_rubyeventmachine()
1204
1223
  rb_define_module_function (EmModule, "start_tcp_server", (VALUE(*)(...))t_start_server, 2);
1205
1224
  rb_define_module_function (EmModule, "stop_tcp_server", (VALUE(*)(...))t_stop_server, 1);
1206
1225
  rb_define_module_function (EmModule, "start_unix_server", (VALUE(*)(...))t_start_unix_server, 1);
1226
+ rb_define_module_function (EmModule, "attach_sd", (VALUE(*)(...))t_attach_sd, 1);
1207
1227
  rb_define_module_function (EmModule, "set_tls_parms", (VALUE(*)(...))t_set_tls_parms, 4);
1208
1228
  rb_define_module_function (EmModule, "start_tls", (VALUE(*)(...))t_start_tls, 1);
1209
1229
  rb_define_module_function (EmModule, "get_peer_cert", (VALUE(*)(...))t_get_peer_cert, 1);
@@ -1217,6 +1237,7 @@ extern "C" void Init_rubyeventmachine()
1217
1237
 
1218
1238
  rb_define_module_function (EmModule, "attach_fd", (VALUE (*)(...))t_attach_fd, 2);
1219
1239
  rb_define_module_function (EmModule, "detach_fd", (VALUE (*)(...))t_detach_fd, 1);
1240
+ rb_define_module_function (EmModule, "get_file_descriptor", (VALUE (*)(...))t_get_file_descriptor, 1);
1220
1241
  rb_define_module_function (EmModule, "get_sock_opt", (VALUE (*)(...))t_get_sock_opt, 3);
1221
1242
  rb_define_module_function (EmModule, "set_sock_opt", (VALUE (*)(...))t_set_sock_opt, 4);
1222
1243
  rb_define_module_function (EmModule, "set_notify_readable", (VALUE (*)(...))t_set_notify_readable, 2);
@@ -50,6 +50,7 @@ module EventMachine
50
50
  #
51
51
  def initialize(list, concurrency = 1)
52
52
  raise ArgumentError, 'argument must be an array' unless list.respond_to?(:to_a)
53
+ raise ArgumentError, 'concurrency must be bigger than zero' unless (concurrency > 0)
53
54
  @list = list.to_a.dup
54
55
  @concurrency = concurrency
55
56
 
@@ -224,47 +225,7 @@ module EventMachine
224
225
  end
225
226
  end
226
227
 
227
- if __FILE__ == $0
228
- $:.unshift File.join(File.dirname(__FILE__), '..')
229
- require 'eventmachine'
230
-
231
- # TODO: real tests
232
- # TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
233
- # TODO: support iter.pause/resume/stop/break/continue?
234
- # TODO: create some exceptions instead of using RuntimeError
235
- # TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
236
-
237
- EM.run{
238
- EM::Iterator.new(1..50).each{ |num,iter| p num; iter.next }
239
- EM::Iterator.new([1,2,3], 10).each{ |num,iter| p num; iter.next }
240
-
241
- i = EM::Iterator.new(1..100, 5)
242
- i.each(proc{|num,iter|
243
- p num.to_s
244
- iter.next
245
- }, proc{
246
- p :done
247
- })
248
- EM.add_timer(0.03){
249
- i.concurrency = 1
250
- }
251
- EM.add_timer(0.04){
252
- i.concurrency = 3
253
- }
254
-
255
- EM::Iterator.new(100..150).map(proc{ |num,iter|
256
- EM.add_timer(0.01){ iter.return(num) }
257
- }, proc{ |results|
258
- p results
259
- })
260
-
261
- EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
262
- EM.system(cmd){ |output,status|
263
- hash[cmd] = status.exitstatus == 0 ? output.strip : nil
264
- iter.return(hash)
265
- }
266
- }, proc{ |results|
267
- p results
268
- })
269
- }
270
- end
228
+ # TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
229
+ # TODO: support iter.pause/resume/stop/break/continue?
230
+ # TODO: create some exceptions instead of using RuntimeError
231
+ # TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
@@ -409,8 +409,12 @@ module EventMachine
409
409
  #--
410
410
  # STARTTLS may not be issued before EHLO, or unless the user has chosen
411
411
  # to support it.
412
- # TODO, must support user-supplied certificates.
413
412
  #
413
+ # If :starttls_options is present and :starttls is set in the parms
414
+ # pass the options in :starttls_options to start_tls. Do this if you want to use
415
+ # your own certificate
416
+ # e.g. {:cert_chain_file => "/etc/ssl/cert.pem", :private_key_file => "/etc/ssl/private/cert.key"}
417
+
414
418
  def process_starttls
415
419
  if @@parms[:starttls]
416
420
  if @state.include?(:starttls)
@@ -419,7 +423,7 @@ module EventMachine
419
423
  send_data "503 EHLO required before STARTTLS\r\n"
420
424
  else
421
425
  send_data "220 Start TLS negotiation\r\n"
422
- start_tls
426
+ start_tls(@@parms[:starttls_options] || {})
423
427
  @state << :starttls
424
428
  end
425
429
  else
@@ -66,7 +66,15 @@ module EventMachine
66
66
 
67
67
  def post_init
68
68
  @requests = {}
69
- EM.add_periodic_timer(0.1, &method(:tick))
69
+ end
70
+
71
+ def start_timer
72
+ @timer ||= EM.add_periodic_timer(0.1, &method(:tick))
73
+ end
74
+
75
+ def stop_timer
76
+ EM.cancel_timer(@timer)
77
+ @timer = nil
70
78
  end
71
79
 
72
80
  def unbind
@@ -84,6 +92,13 @@ module EventMachine
84
92
  else
85
93
  @requests[id] = req
86
94
  end
95
+
96
+ start_timer
97
+ end
98
+
99
+ def deregister_request(id, req)
100
+ @requests.delete(id)
101
+ stop_timer if @requests.length == 0
87
102
  end
88
103
 
89
104
  def send_packet(pkt)
@@ -109,6 +124,7 @@ module EventMachine
109
124
  req = @requests[msg.id]
110
125
  if req
111
126
  @requests.delete(msg.id)
127
+ stop_timer if @requests.length == 0
112
128
  req.receive_answer(msg)
113
129
  end
114
130
  end
@@ -140,6 +156,7 @@ module EventMachine
140
156
  if @tries < @max_tries
141
157
  send
142
158
  else
159
+ @socket.deregister_request(@id, self)
143
160
  fail 'retries exceeded'
144
161
  end
145
162
  end
@@ -7,25 +7,25 @@ module EventMachine
7
7
  # A TickLoop is useful when one needs to distribute amounts of work
8
8
  # throughout ticks in order to maintain response times. It is also useful for
9
9
  # simple repeated checks and metrics.
10
- #
11
- # # Here we run through an array one item per tick until it is empty,
12
- # # printing each element.
13
- # # When the array is empty, we return :stop from the callback, and the
14
- # # loop will terminate.
15
- # # When the loop terminates, the on_stop callbacks will be called.
16
- # EM.run do
17
- # array = (1..100).to_a
18
- #
19
- # tickloop = EM.tick_loop do
20
- # if array.empty?
21
- # :stop
22
- # else
23
- # puts array.shift
24
- # end
25
- # end
26
- #
27
- # tickloop.on_stop { EM.stop }
28
- # end
10
+ # @example
11
+ # # Here we run through an array one item per tick until it is empty,
12
+ # # printing each element.
13
+ # # When the array is empty, we return :stop from the callback, and the
14
+ # # loop will terminate.
15
+ # # When the loop terminates, the on_stop callbacks will be called.
16
+ # EM.run do
17
+ # array = (1..100).to_a
18
+ #
19
+ # tickloop = EM.tick_loop do
20
+ # if array.empty?
21
+ # :stop
22
+ # else
23
+ # puts array.shift
24
+ # end
25
+ # end
26
+ #
27
+ # tickloop.on_stop { EM.stop }
28
+ # end
29
29
  #
30
30
  class TickLoop
31
31
 
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "1.0.3"
2
+ VERSION = "1.0.4"
3
3
  end
@@ -156,7 +156,7 @@ module EventMachine
156
156
  # will start without release_machine being called and will immediately throw
157
157
 
158
158
  #
159
- if reactor_running? and @reactor_pid != Process.pid
159
+ if @reactor_running and @reactor_pid != Process.pid
160
160
  # Reactor was started in a different parent, meaning we have forked.
161
161
  # Clean up reactor state so a new reactor boots up in this child.
162
162
  stop_event_loop
@@ -531,6 +531,15 @@ module EventMachine
531
531
  s
532
532
  end
533
533
 
534
+ # Attach to an existing socket's file descriptor. The socket may have been
535
+ # started with {EventMachine.start_server}.
536
+ def self.attach_server sock, handler=nil, *args, &block
537
+ klass = klass_from_handler(Connection, handler, *args)
538
+ sd = sock.respond_to?(:fileno) ? sock.fileno : sock
539
+ s = attach_sd(sd)
540
+ @acceptors[s] = [klass,args,block,sock]
541
+ s
542
+ end
534
543
 
535
544
  # Stop a TCP server socket that was started with {EventMachine.start_server}.
536
545
  # @see EventMachine.start_server
@@ -1181,7 +1190,7 @@ module EventMachine
1181
1190
  #
1182
1191
  # @return [Boolean] true if the EventMachine reactor loop is currently running
1183
1192
  def self.reactor_running?
1184
- (@reactor_running || false)
1193
+ @reactor_running && Process.pid == @reactor_pid
1185
1194
  end
1186
1195
 
1187
1196
 
@@ -31,8 +31,13 @@ else
31
31
  def hack_cross_compilation(ext)
32
32
  # inject 1.8/1.9 pure-ruby entry point
33
33
  # HACK: add these dependencies to the task instead of using cross_compiling
34
- ext.cross_platform.each do |platform|
35
- Rake::Task["native:#{GEMSPEC.name}:#{platform}"].prerequisites.unshift "lib/#{ext.name}.rb"
34
+ if ext.cross_platform.is_a?(Array)
35
+ ext.cross_platform.each do |platform|
36
+ task = "native:#{GEMSPEC.name}:#{platform}"
37
+ if Rake::Task.task_defined?(task)
38
+ Rake::Task[task].prerequisites.unshift "lib/#{ext.name}.rb"
39
+ end
40
+ end
36
41
  end
37
42
  end
38
43
 
@@ -4,6 +4,7 @@ require 'socket'
4
4
  class TestAttach < Test::Unit::TestCase
5
5
  class EchoServer < EM::Connection
6
6
  def receive_data data
7
+ $received_data << data
7
8
  send_data data
8
9
  end
9
10
  end
@@ -31,12 +32,14 @@ class TestAttach < Test::Unit::TestCase
31
32
  def setup
32
33
  @port = next_port
33
34
  $read, $r, $w, $fd = nil
35
+ $received_data = ""
34
36
  end
35
37
 
36
38
  def teardown
37
39
  [$r, $w].each do |io|
38
40
  io.close rescue nil
39
41
  end
42
+ $received_data = nil
40
43
  end
41
44
 
42
45
  def test_attach
@@ -63,6 +66,27 @@ class TestAttach < Test::Unit::TestCase
63
66
  end
64
67
  end
65
68
 
69
+ def test_attach_server
70
+ $before = TCPServer.new("127.0.0.1", @port)
71
+ sig = nil
72
+ EM.run {
73
+ sig = EM.attach_server $before, EchoServer
74
+
75
+ handler = Class.new(EM::Connection) do
76
+ def initialize
77
+ send_data "hello world"
78
+ close_connection_after_writing
79
+ EM.add_timer(0.1) { EM.stop }
80
+ end
81
+ end
82
+ EM.connect("127.0.0.1", @port, handler)
83
+ }
84
+
85
+ assert_equal false, $before.closed?
86
+ assert_equal "hello world", $received_data
87
+ assert sig.is_a?(Integer)
88
+ end
89
+
66
90
  def test_attach_pipe
67
91
  EM.run{
68
92
  $r, $w = IO.pipe
@@ -30,4 +30,24 @@ class TestConnectionCount < Test::Unit::TestCase
30
30
  assert_equal(1, $server_conns)
31
31
  assert_equal(4, $client_conns + $server_conns)
32
32
  end
33
- end
33
+
34
+ module DoubleCloseClient
35
+ def unbind
36
+ close_connection
37
+ $num_close_scheduled_1 = EM.num_close_scheduled
38
+ EM.next_tick do
39
+ $num_close_scheduled_2 = EM.num_close_scheduled
40
+ EM.stop
41
+ end
42
+ end
43
+ end
44
+
45
+ def test_num_close_scheduled
46
+ EM.run {
47
+ assert_equal(0, EM.num_close_scheduled)
48
+ EM.connect("127.0.0.1", 9999, DoubleCloseClient) # nothing listening on 9999
49
+ }
50
+ assert_equal(1, $num_close_scheduled_1)
51
+ assert_equal(0, $num_close_scheduled_2)
52
+ end
53
+ end
@@ -126,5 +126,20 @@ class TestEpoll < Test::Unit::TestCase
126
126
  File.unlink(fn) if File.exist?(fn)
127
127
  end
128
128
 
129
+ def test_attach_detach
130
+ EM.epoll
131
+ EM.run {
132
+ EM.add_timer(0.01) { EM.stop }
133
+
134
+ r, w = IO.pipe
135
+
136
+ # This tests a regression where detach in the same tick as attach crashes EM
137
+ EM.watch(r) do |connection|
138
+ connection.detach
139
+ end
140
+ }
141
+
142
+ assert true
143
+ end
129
144
  end
130
145
 
@@ -9,15 +9,17 @@ class TestIdleConnection < Test::Unit::TestCase
9
9
  $idle_time = conn.get_idle_time
10
10
  conn.send_data "GET / HTTP/1.0\r\n\r\n"
11
11
  EM.next_tick{
12
- $idle_time_after_send = conn.get_idle_time
13
- conn.close_connection
14
- EM.stop
12
+ EM.next_tick{
13
+ $idle_time_after_send = conn.get_idle_time
14
+ conn.close_connection
15
+ EM.stop
16
+ }
15
17
  }
16
18
  }
17
19
  }
18
20
 
19
21
  assert_in_delta 3, $idle_time, 0.2
20
- assert_equal 0, $idle_time_after_send
22
+ assert_in_delta 0, $idle_time_after_send, 0.1
21
23
  end
22
24
  end
23
25
  end
@@ -0,0 +1,97 @@
1
+ require 'em_test_helper'
2
+
3
+ class TestIterator < Test::Unit::TestCase
4
+
5
+ def get_time
6
+ EM.current_time.strftime('%H:%M:%S')
7
+ end
8
+
9
+ def test_default_concurrency
10
+ items = {}
11
+ list = 1..10
12
+ EM.run {
13
+ EM::Iterator.new(list).each( proc {|num,iter|
14
+ time = get_time
15
+ items[time] ||= []
16
+ items[time] << num
17
+ EM::Timer.new(1) {iter.next}
18
+ }, proc {EM.stop})
19
+ }
20
+ assert_equal(10, items.keys.size)
21
+ assert_equal((list).to_a, items.values.flatten)
22
+ end
23
+
24
+ def test_concurrency_bigger_than_list_size
25
+ items = {}
26
+ list = [1,2,3]
27
+ EM.run {
28
+ EM::Iterator.new(list,10).each(proc {|num,iter|
29
+ time = get_time
30
+ items[time] ||= []
31
+ items[time] << num
32
+ EM::Timer.new(1) {iter.next}
33
+ }, proc {EM.stop})
34
+ }
35
+ assert_equal(1, items.keys.size)
36
+ assert_equal((list).to_a, items.values.flatten)
37
+ end
38
+
39
+
40
+ def test_changing_concurrency_affects_active_iteration
41
+ items = {}
42
+ list = 1..25
43
+ EM.run {
44
+ i = EM::Iterator.new(list,5)
45
+ i.each(proc {|num,iter|
46
+ time = get_time
47
+ items[time] ||= []
48
+ items[time] << num
49
+ EM::Timer.new(1) {iter.next}
50
+ }, proc {EM.stop})
51
+ EM.add_timer(1){
52
+ i.concurrency = 1
53
+ }
54
+ EM.add_timer(3){
55
+ i.concurrency = 3
56
+ }
57
+ }
58
+ assert_equal(9, items.keys.size)
59
+ assert_equal((list).to_a, items.values.flatten)
60
+ end
61
+
62
+ def test_map
63
+ list = 100..150
64
+ EM.run {
65
+ EM::Iterator.new(list).map(proc{ |num,iter|
66
+ EM.add_timer(0.01){ iter.return(num) }
67
+ }, proc{ |results|
68
+ assert_equal((list).to_a.size, results.size)
69
+ EM.stop
70
+ })
71
+ }
72
+ end
73
+
74
+ def test_inject
75
+ list = %w[ pwd uptime uname date ]
76
+ EM.run {
77
+ EM::Iterator.new(list, 2).inject({}, proc{ |hash,cmd,iter|
78
+ EM.system(cmd){ |output,status|
79
+ hash[cmd] = status.exitstatus == 0 ? output.strip : nil
80
+ iter.return(hash)
81
+ }
82
+ }, proc{ |results|
83
+ assert_equal(results.keys, list)
84
+ EM.stop
85
+ })
86
+ }
87
+ end
88
+
89
+ def test_concurrency_is_0
90
+ EM.run {
91
+ assert_raise ArgumentError do
92
+ EM::Iterator.new(1..5,0)
93
+ end
94
+ EM.stop
95
+ }
96
+ end
97
+ end
@@ -67,6 +67,30 @@ class TestPause < Test::Unit::TestCase
67
67
  end
68
68
  end
69
69
  end
70
+
71
+ def test_pause_in_receive_data
72
+ incoming = []
73
+
74
+ test_server = Module.new do
75
+ define_method(:receive_data) do |data|
76
+ incoming << data
77
+ pause
78
+ EM.add_timer(0.5){ close_connection }
79
+ end
80
+ define_method(:unbind) do
81
+ EM.stop
82
+ end
83
+ end
84
+
85
+ EM.run do
86
+ EM.start_server "127.0.0.1", @port, test_server
87
+ cli = EM.connect "127.0.0.1", @port
88
+ cli.send_data 'a'*(17*1024)
89
+ end
90
+
91
+ assert_equal 1, incoming.size
92
+ assert_equal 16*1024, incoming[0].bytesize
93
+ end
70
94
  else
71
95
  warn "EM.pause_connection not implemented, skipping tests in #{__FILE__}"
72
96
 
metadata CHANGED
@@ -1,90 +1,93 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: eventmachine
3
- version: !ruby/object:Gem::Version
4
- hash: 17
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.4
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- - 3
10
- version: 1.0.3
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Francis Cianfrocca
14
9
  - Aman Gupta
15
10
  autorequire:
16
11
  bindir: bin
17
12
  cert_chain: []
18
-
19
- date: 2013-03-08 00:00:00 Z
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
13
+ date: 2014-12-19 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
22
16
  name: rake-compiler
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
25
18
  none: false
26
- requirements:
19
+ requirements:
27
20
  - - ~>
28
- - !ruby/object:Gem::Version
29
- hash: 57
30
- segments:
31
- - 0
32
- - 8
33
- - 3
21
+ - !ruby/object:Gem::Version
34
22
  version: 0.8.3
35
23
  type: :development
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: yard
39
24
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ version: 0.8.3
31
+ - !ruby/object:Gem::Dependency
32
+ name: yard
33
+ requirement: !ruby/object:Gem::Requirement
41
34
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 31
46
- segments:
47
- - 0
48
- - 8
49
- - 5
50
- - 2
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
51
38
  version: 0.8.5.2
52
39
  type: :development
53
- version_requirements: *id002
54
- - !ruby/object:Gem::Dependency
55
- name: bluecloth
56
40
  prerelease: false
57
- requirement: &id003 !ruby/object:Gem::Requirement
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 0.8.5.2
47
+ - !ruby/object:Gem::Dependency
48
+ name: bluecloth
49
+ requirement: !ruby/object:Gem::Requirement
58
50
  none: false
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- hash: 3
63
- segments:
64
- - 0
65
- version: "0"
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
66
55
  type: :development
67
- version_requirements: *id003
68
- description: |-
69
- EventMachine implements a fast, single-threaded engine for arbitrary network
70
- communications. It's extremely easy to use in Ruby. EventMachine wraps all
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ description: ! 'EventMachine implements a fast, single-threaded engine for arbitrary
64
+ network
65
+
66
+ communications. It''s extremely easy to use in Ruby. EventMachine wraps all
67
+
71
68
  interactions with IP sockets, allowing programs to concentrate on the
69
+
72
70
  implementation of network protocols. It can be used to create both network
71
+
73
72
  servers and clients. To create a server or client, a Ruby program only needs
73
+
74
74
  to specify the IP address and port, and provide a Module that implements the
75
+
75
76
  communications protocol. Implementations of several standard network protocols
77
+
76
78
  are provided with the package, primarily to serve as examples. The real goal
79
+
77
80
  of EventMachine is to enable programs to easily interface with other programs
78
- using TCP/IP, especially if custom protocols are required.
79
- email:
81
+
82
+ using TCP/IP, especially if custom protocols are required.'
83
+ email:
80
84
  - garbagecat10@gmail.com
81
85
  - aman@tmm1.net
82
86
  executables: []
83
-
84
- extensions:
87
+ extensions:
85
88
  - ext/extconf.rb
86
89
  - ext/fastfilereader/extconf.rb
87
- extra_rdoc_files:
90
+ extra_rdoc_files:
88
91
  - README.md
89
92
  - docs/DocumentationGuidesIndex.md
90
93
  - docs/GettingStarted.md
@@ -100,7 +103,7 @@ extra_rdoc_files:
100
103
  - docs/old/SMTP
101
104
  - docs/old/SPAWNED_PROCESSES
102
105
  - docs/old/TODO
103
- files:
106
+ files:
104
107
  - .gitignore
105
108
  - .travis.yml
106
109
  - .yardopts
@@ -232,6 +235,7 @@ files:
232
235
  - tests/test_httpclient2.rb
233
236
  - tests/test_idle_connection.rb
234
237
  - tests/test_inactivity_timeout.rb
238
+ - tests/test_iterator.rb
235
239
  - tests/test_kb.rb
236
240
  - tests/test_line_protocol.rb
237
241
  - tests/test_ltp.rb
@@ -267,10 +271,11 @@ files:
267
271
  - tests/test_ud.rb
268
272
  - tests/test_unbind_reason.rb
269
273
  homepage: http://rubyeventmachine.com
270
- licenses: []
271
-
274
+ licenses:
275
+ - Ruby
276
+ - GPL
272
277
  post_install_message:
273
- rdoc_options:
278
+ rdoc_options:
274
279
  - --title
275
280
  - EventMachine
276
281
  - --main
@@ -279,32 +284,25 @@ rdoc_options:
279
284
  - lib/em/version
280
285
  - -x
281
286
  - lib/jeventmachine
282
- require_paths:
287
+ require_paths:
283
288
  - lib
284
- required_ruby_version: !ruby/object:Gem::Requirement
289
+ required_ruby_version: !ruby/object:Gem::Requirement
285
290
  none: false
286
- requirements:
287
- - - ">="
288
- - !ruby/object:Gem::Version
289
- hash: 3
290
- segments:
291
- - 0
292
- version: "0"
293
- required_rubygems_version: !ruby/object:Gem::Requirement
291
+ requirements:
292
+ - - ! '>='
293
+ - !ruby/object:Gem::Version
294
+ version: '0'
295
+ required_rubygems_version: !ruby/object:Gem::Requirement
294
296
  none: false
295
- requirements:
296
- - - ">="
297
- - !ruby/object:Gem::Version
298
- hash: 3
299
- segments:
300
- - 0
301
- version: "0"
297
+ requirements:
298
+ - - ! '>='
299
+ - !ruby/object:Gem::Version
300
+ version: '0'
302
301
  requirements: []
303
-
304
302
  rubyforge_project: eventmachine
305
- rubygems_version: 1.8.24
303
+ rubygems_version: 1.8.23
306
304
  signing_key:
307
305
  specification_version: 3
308
306
  summary: Ruby/EventMachine library
309
307
  test_files: []
310
-
308
+ has_rdoc: