eventmachine 1.2.0.dev.2-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +105 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +108 -0
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +521 -0
  8. data/docs/old/ChangeLog +211 -0
  9. data/docs/old/DEFERRABLES +246 -0
  10. data/docs/old/EPOLL +141 -0
  11. data/docs/old/INSTALL +13 -0
  12. data/docs/old/KEYBOARD +42 -0
  13. data/docs/old/LEGAL +25 -0
  14. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  15. data/docs/old/PURE_RUBY +75 -0
  16. data/docs/old/RELEASE_NOTES +94 -0
  17. data/docs/old/SMTP +4 -0
  18. data/docs/old/SPAWNED_PROCESSES +148 -0
  19. data/docs/old/TODO +8 -0
  20. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  21. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  22. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  23. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  24. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  25. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  26. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  27. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  28. data/examples/old/ex_channel.rb +43 -0
  29. data/examples/old/ex_queue.rb +2 -0
  30. data/examples/old/ex_tick_loop_array.rb +15 -0
  31. data/examples/old/ex_tick_loop_counter.rb +32 -0
  32. data/examples/old/helper.rb +2 -0
  33. data/ext/binder.cpp +124 -0
  34. data/ext/binder.h +46 -0
  35. data/ext/cmain.cpp +988 -0
  36. data/ext/ed.cpp +2111 -0
  37. data/ext/ed.h +442 -0
  38. data/ext/em.cpp +2379 -0
  39. data/ext/em.h +308 -0
  40. data/ext/eventmachine.h +143 -0
  41. data/ext/extconf.rb +270 -0
  42. data/ext/fastfilereader/extconf.rb +110 -0
  43. data/ext/fastfilereader/mapper.cpp +216 -0
  44. data/ext/fastfilereader/mapper.h +59 -0
  45. data/ext/fastfilereader/rubymain.cpp +127 -0
  46. data/ext/kb.cpp +79 -0
  47. data/ext/page.cpp +107 -0
  48. data/ext/page.h +51 -0
  49. data/ext/pipe.cpp +354 -0
  50. data/ext/project.h +176 -0
  51. data/ext/rubymain.cpp +1504 -0
  52. data/ext/ssl.cpp +615 -0
  53. data/ext/ssl.h +103 -0
  54. data/java/.classpath +8 -0
  55. data/java/.project +17 -0
  56. data/java/src/com/rubyeventmachine/EmReactor.java +591 -0
  57. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  58. data/java/src/com/rubyeventmachine/EventableChannel.java +72 -0
  59. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +201 -0
  60. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +415 -0
  61. data/lib/2.0/fastfilereaderext.so +0 -0
  62. data/lib/2.0/rubyeventmachine.so +0 -0
  63. data/lib/2.1/fastfilereaderext.so +0 -0
  64. data/lib/2.1/rubyeventmachine.so +0 -0
  65. data/lib/2.2/fastfilereaderext.so +0 -0
  66. data/lib/2.2/rubyeventmachine.so +0 -0
  67. data/lib/2.3/fastfilereaderext.so +0 -0
  68. data/lib/2.3/rubyeventmachine.so +0 -0
  69. data/lib/em/buftok.rb +59 -0
  70. data/lib/em/callback.rb +58 -0
  71. data/lib/em/channel.rb +69 -0
  72. data/lib/em/completion.rb +304 -0
  73. data/lib/em/connection.rb +770 -0
  74. data/lib/em/deferrable.rb +210 -0
  75. data/lib/em/deferrable/pool.rb +2 -0
  76. data/lib/em/file_watch.rb +73 -0
  77. data/lib/em/future.rb +61 -0
  78. data/lib/em/iterator.rb +252 -0
  79. data/lib/em/messages.rb +66 -0
  80. data/lib/em/pool.rb +151 -0
  81. data/lib/em/process_watch.rb +45 -0
  82. data/lib/em/processes.rb +123 -0
  83. data/lib/em/protocols.rb +37 -0
  84. data/lib/em/protocols/header_and_content.rb +138 -0
  85. data/lib/em/protocols/httpclient.rb +299 -0
  86. data/lib/em/protocols/httpclient2.rb +600 -0
  87. data/lib/em/protocols/line_and_text.rb +125 -0
  88. data/lib/em/protocols/line_protocol.rb +29 -0
  89. data/lib/em/protocols/linetext2.rb +166 -0
  90. data/lib/em/protocols/memcache.rb +331 -0
  91. data/lib/em/protocols/object_protocol.rb +46 -0
  92. data/lib/em/protocols/postgres3.rb +246 -0
  93. data/lib/em/protocols/saslauth.rb +175 -0
  94. data/lib/em/protocols/smtpclient.rb +394 -0
  95. data/lib/em/protocols/smtpserver.rb +666 -0
  96. data/lib/em/protocols/socks4.rb +66 -0
  97. data/lib/em/protocols/stomp.rb +205 -0
  98. data/lib/em/protocols/tcptest.rb +54 -0
  99. data/lib/em/pure_ruby.rb +1022 -0
  100. data/lib/em/queue.rb +80 -0
  101. data/lib/em/resolver.rb +232 -0
  102. data/lib/em/spawnable.rb +84 -0
  103. data/lib/em/streamer.rb +118 -0
  104. data/lib/em/threaded_resource.rb +90 -0
  105. data/lib/em/tick_loop.rb +85 -0
  106. data/lib/em/timers.rb +61 -0
  107. data/lib/em/version.rb +3 -0
  108. data/lib/eventmachine.rb +1584 -0
  109. data/lib/fastfilereaderext.rb +2 -0
  110. data/lib/jeventmachine.rb +301 -0
  111. data/lib/rubyeventmachine.rb +2 -0
  112. data/rakelib/package.rake +120 -0
  113. data/rakelib/test.rake +8 -0
  114. data/tests/client.crt +31 -0
  115. data/tests/client.key +51 -0
  116. data/tests/dhparam.pem +13 -0
  117. data/tests/em_test_helper.rb +151 -0
  118. data/tests/test_attach.rb +151 -0
  119. data/tests/test_basic.rb +283 -0
  120. data/tests/test_channel.rb +75 -0
  121. data/tests/test_completion.rb +178 -0
  122. data/tests/test_connection_count.rb +54 -0
  123. data/tests/test_connection_write.rb +35 -0
  124. data/tests/test_defer.rb +35 -0
  125. data/tests/test_deferrable.rb +35 -0
  126. data/tests/test_epoll.rb +142 -0
  127. data/tests/test_error_handler.rb +38 -0
  128. data/tests/test_exc.rb +28 -0
  129. data/tests/test_file_watch.rb +66 -0
  130. data/tests/test_fork.rb +75 -0
  131. data/tests/test_futures.rb +170 -0
  132. data/tests/test_get_sock_opt.rb +37 -0
  133. data/tests/test_handler_check.rb +35 -0
  134. data/tests/test_hc.rb +155 -0
  135. data/tests/test_httpclient.rb +233 -0
  136. data/tests/test_httpclient2.rb +128 -0
  137. data/tests/test_idle_connection.rb +25 -0
  138. data/tests/test_inactivity_timeout.rb +54 -0
  139. data/tests/test_ipv4.rb +125 -0
  140. data/tests/test_ipv6.rb +131 -0
  141. data/tests/test_iterator.rb +115 -0
  142. data/tests/test_kb.rb +28 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +138 -0
  145. data/tests/test_ltp2.rb +308 -0
  146. data/tests/test_many_fds.rb +22 -0
  147. data/tests/test_next_tick.rb +104 -0
  148. data/tests/test_object_protocol.rb +36 -0
  149. data/tests/test_pause.rb +107 -0
  150. data/tests/test_pending_connect_timeout.rb +52 -0
  151. data/tests/test_pool.rb +196 -0
  152. data/tests/test_process_watch.rb +50 -0
  153. data/tests/test_processes.rb +128 -0
  154. data/tests/test_proxy_connection.rb +180 -0
  155. data/tests/test_pure.rb +88 -0
  156. data/tests/test_queue.rb +64 -0
  157. data/tests/test_resolver.rb +104 -0
  158. data/tests/test_running.rb +14 -0
  159. data/tests/test_sasl.rb +47 -0
  160. data/tests/test_send_file.rb +217 -0
  161. data/tests/test_servers.rb +33 -0
  162. data/tests/test_set_sock_opt.rb +39 -0
  163. data/tests/test_shutdown_hooks.rb +23 -0
  164. data/tests/test_smtpclient.rb +75 -0
  165. data/tests/test_smtpserver.rb +57 -0
  166. data/tests/test_spawn.rb +293 -0
  167. data/tests/test_ssl_args.rb +78 -0
  168. data/tests/test_ssl_dhparam.rb +83 -0
  169. data/tests/test_ssl_ecdh_curve.rb +79 -0
  170. data/tests/test_ssl_extensions.rb +49 -0
  171. data/tests/test_ssl_methods.rb +65 -0
  172. data/tests/test_ssl_protocols.rb +246 -0
  173. data/tests/test_ssl_verify.rb +126 -0
  174. data/tests/test_stomp.rb +37 -0
  175. data/tests/test_system.rb +46 -0
  176. data/tests/test_threaded_resource.rb +61 -0
  177. data/tests/test_tick_loop.rb +59 -0
  178. data/tests/test_timers.rb +123 -0
  179. data/tests/test_ud.rb +8 -0
  180. data/tests/test_unbind_reason.rb +52 -0
  181. metadata +381 -0
@@ -0,0 +1,59 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: mapper.h 4529 2007-07-04 11:32:22Z francis $
4
+
5
+ File: mapper.h
6
+ Date: 02Jul07
7
+
8
+ Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat10
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+
21
+ #ifndef __Mapper__H_
22
+ #define __Mapper__H_
23
+
24
+
25
+ /**************
26
+ class Mapper_t
27
+ **************/
28
+
29
+ class Mapper_t
30
+ {
31
+ public:
32
+ Mapper_t (const string&);
33
+ virtual ~Mapper_t();
34
+
35
+ const char *GetChunk (unsigned);
36
+ void Close();
37
+ size_t GetFileSize() {return FileSize;}
38
+
39
+ private:
40
+ size_t FileSize;
41
+
42
+ #ifdef OS_UNIX
43
+ private:
44
+ int Fd;
45
+ const char *MapPoint;
46
+ #endif // OS_UNIX
47
+
48
+ #ifdef OS_WIN32
49
+ private:
50
+ HANDLE hFile;
51
+ HANDLE hMapping;
52
+ char *MapPoint;
53
+ #endif // OS_WIN32
54
+
55
+ };
56
+
57
+
58
+ #endif // __Mapper__H_
59
+
@@ -0,0 +1,127 @@
1
+ /*****************************************************************************
2
+
3
+ $Id: rubymain.cpp 4529 2007-07-04 11:32:22Z francis $
4
+
5
+ File: rubymain.cpp
6
+ Date: 02Jul07
7
+
8
+ Copyright (C) 2007 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: garbagecat10
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+
21
+
22
+ #include <iostream>
23
+ #include <stdexcept>
24
+ using namespace std;
25
+
26
+ #include <ruby.h>
27
+ #include "mapper.h"
28
+
29
+ static VALUE EmModule;
30
+ static VALUE FastFileReader;
31
+ static VALUE Mapper;
32
+
33
+
34
+
35
+ /*********
36
+ mapper_dt
37
+ *********/
38
+
39
+ static void mapper_dt (void *ptr)
40
+ {
41
+ if (ptr)
42
+ delete (Mapper_t*) ptr;
43
+ }
44
+
45
+ /**********
46
+ mapper_new
47
+ **********/
48
+
49
+ static VALUE mapper_new (VALUE self, VALUE filename)
50
+ {
51
+ Mapper_t *m = new Mapper_t (StringValueCStr (filename));
52
+ if (!m)
53
+ rb_raise (rb_eStandardError, "No Mapper Object");
54
+ VALUE v = Data_Wrap_Struct (Mapper, 0, mapper_dt, (void*)m);
55
+ return v;
56
+ }
57
+
58
+
59
+ /****************
60
+ mapper_get_chunk
61
+ ****************/
62
+
63
+ static VALUE mapper_get_chunk (VALUE self, VALUE start, VALUE length)
64
+ {
65
+ Mapper_t *m = NULL;
66
+ Data_Get_Struct (self, Mapper_t, m);
67
+ if (!m)
68
+ rb_raise (rb_eStandardError, "No Mapper Object");
69
+
70
+ // TODO, what if some moron sends us a negative start value?
71
+ unsigned _start = NUM2INT (start);
72
+ unsigned _length = NUM2INT (length);
73
+ if ((_start + _length) > m->GetFileSize())
74
+ rb_raise (rb_eStandardError, "Mapper Range Error");
75
+
76
+ const char *chunk = m->GetChunk (_start);
77
+ if (!chunk)
78
+ rb_raise (rb_eStandardError, "No Mapper Chunk");
79
+ return rb_str_new (chunk, _length);
80
+ }
81
+
82
+ /************
83
+ mapper_close
84
+ ************/
85
+
86
+ static VALUE mapper_close (VALUE self)
87
+ {
88
+ Mapper_t *m = NULL;
89
+ Data_Get_Struct (self, Mapper_t, m);
90
+ if (!m)
91
+ rb_raise (rb_eStandardError, "No Mapper Object");
92
+ m->Close();
93
+ return Qnil;
94
+ }
95
+
96
+ /***********
97
+ mapper_size
98
+ ***********/
99
+
100
+ static VALUE mapper_size (VALUE self)
101
+ {
102
+ Mapper_t *m = NULL;
103
+ Data_Get_Struct (self, Mapper_t, m);
104
+ if (!m)
105
+ rb_raise (rb_eStandardError, "No Mapper Object");
106
+ return INT2NUM (m->GetFileSize());
107
+ }
108
+
109
+
110
+ /**********************
111
+ Init_fastfilereaderext
112
+ **********************/
113
+
114
+ extern "C" void Init_fastfilereaderext()
115
+ {
116
+ EmModule = rb_define_module ("EventMachine");
117
+ FastFileReader = rb_define_class_under (EmModule, "FastFileReader", rb_cObject);
118
+ Mapper = rb_define_class_under (FastFileReader, "Mapper", rb_cObject);
119
+
120
+ rb_define_module_function (Mapper, "new", (VALUE(*)(...))mapper_new, 1);
121
+ rb_define_method (Mapper, "size", (VALUE(*)(...))mapper_size, 0);
122
+ rb_define_method (Mapper, "close", (VALUE(*)(...))mapper_close, 0);
123
+ rb_define_method (Mapper, "get_chunk", (VALUE(*)(...))mapper_get_chunk, 2);
124
+ }
125
+
126
+
127
+
@@ -0,0 +1,79 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: kb.cpp
6
+ Date: 24Aug07
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ #include "project.h"
21
+
22
+
23
+ /**************************************
24
+ KeyboardDescriptor::KeyboardDescriptor
25
+ **************************************/
26
+
27
+ KeyboardDescriptor::KeyboardDescriptor (EventMachine_t *parent_em):
28
+ EventableDescriptor (0, parent_em),
29
+ bReadAttemptedAfterClose (false)
30
+ {
31
+ #ifdef HAVE_EPOLL
32
+ EpollEvent.events = EPOLLIN;
33
+ #endif
34
+ #ifdef HAVE_KQUEUE
35
+ MyEventMachine->ArmKqueueReader (this);
36
+ #endif
37
+ }
38
+
39
+
40
+ /***************************************
41
+ KeyboardDescriptor::~KeyboardDescriptor
42
+ ***************************************/
43
+
44
+ KeyboardDescriptor::~KeyboardDescriptor()
45
+ {
46
+ }
47
+
48
+
49
+ /*************************
50
+ KeyboardDescriptor::Write
51
+ *************************/
52
+
53
+ void KeyboardDescriptor::Write()
54
+ {
55
+ // Why are we here?
56
+ throw std::runtime_error ("bad code path in keyboard handler");
57
+ }
58
+
59
+
60
+ /*****************************
61
+ KeyboardDescriptor::Heartbeat
62
+ *****************************/
63
+
64
+ void KeyboardDescriptor::Heartbeat()
65
+ {
66
+ // no-op
67
+ }
68
+
69
+
70
+ /************************
71
+ KeyboardDescriptor::Read
72
+ ************************/
73
+
74
+ void KeyboardDescriptor::Read()
75
+ {
76
+ char c;
77
+ (void)read (GetSocket(), &c, 1);
78
+ _GenericInboundDispatch(&c, 1);
79
+ }
@@ -0,0 +1,107 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: page.cpp
6
+ Date: 30Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+
21
+ #include "project.h"
22
+
23
+
24
+ /******************
25
+ PageList::PageList
26
+ ******************/
27
+
28
+ PageList::PageList()
29
+ {
30
+ }
31
+
32
+
33
+ /*******************
34
+ PageList::~PageList
35
+ *******************/
36
+
37
+ PageList::~PageList()
38
+ {
39
+ while (HasPages())
40
+ PopFront();
41
+ }
42
+
43
+
44
+ /***************
45
+ PageList::Front
46
+ ***************/
47
+
48
+ void PageList::Front (const char **page, int *length)
49
+ {
50
+ assert (page && length);
51
+
52
+ if (HasPages()) {
53
+ Page p = Pages.front();
54
+ *page = p.Buffer;
55
+ *length = p.Size;
56
+ }
57
+ else {
58
+ *page = NULL;
59
+ *length = 0;
60
+ }
61
+ }
62
+
63
+
64
+ /******************
65
+ PageList::PopFront
66
+ ******************/
67
+
68
+ void PageList::PopFront()
69
+ {
70
+ if (HasPages()) {
71
+ Page p = Pages.front();
72
+ Pages.pop_front();
73
+ if (p.Buffer)
74
+ free ((void*)p.Buffer);
75
+ }
76
+ }
77
+
78
+
79
+ /******************
80
+ PageList::HasPages
81
+ ******************/
82
+
83
+ bool PageList::HasPages()
84
+ {
85
+ return (Pages.size() > 0) ? true : false;
86
+ }
87
+
88
+
89
+ /**************
90
+ PageList::Push
91
+ **************/
92
+
93
+ void PageList::Push (const char *buf, int size)
94
+ {
95
+ if (buf && (size > 0)) {
96
+ char *copy = (char*) malloc (size);
97
+ if (!copy)
98
+ throw runtime_error ("no memory in pagelist");
99
+ memcpy (copy, buf, size);
100
+ Pages.push_back (Page (copy, size));
101
+ }
102
+ }
103
+
104
+
105
+
106
+
107
+
@@ -0,0 +1,51 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: page.h
6
+ Date: 30Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+
21
+ #ifndef __PageManager__H_
22
+ #define __PageManager__H_
23
+
24
+
25
+ /**************
26
+ class PageList
27
+ **************/
28
+
29
+ class PageList
30
+ {
31
+ struct Page {
32
+ Page (const char *b, size_t s): Buffer(b), Size(s) {}
33
+ const char *Buffer;
34
+ size_t Size;
35
+ };
36
+
37
+ public:
38
+ PageList();
39
+ virtual ~PageList();
40
+
41
+ void Push (const char*, int);
42
+ bool HasPages();
43
+ void Front (const char**, int*);
44
+ void PopFront();
45
+
46
+ private:
47
+ deque<Page> Pages;
48
+ };
49
+
50
+
51
+ #endif // __PageManager__H_
@@ -0,0 +1,354 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: pipe.cpp
6
+ Date: 30May07
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ #include "project.h"
21
+
22
+
23
+ #ifdef OS_UNIX
24
+ // THIS ENTIRE FILE IS ONLY COMPILED ON UNIX-LIKE SYSTEMS.
25
+
26
+ /******************************
27
+ PipeDescriptor::PipeDescriptor
28
+ ******************************/
29
+
30
+ PipeDescriptor::PipeDescriptor (int fd, pid_t subpid, EventMachine_t *parent_em):
31
+ EventableDescriptor (fd, parent_em),
32
+ bReadAttemptedAfterClose (false),
33
+ OutboundDataSize (0),
34
+ SubprocessPid (subpid)
35
+ {
36
+ #ifdef HAVE_EPOLL
37
+ EpollEvent.events = EPOLLIN;
38
+ #endif
39
+ #ifdef HAVE_KQUEUE
40
+ MyEventMachine->ArmKqueueReader (this);
41
+ #endif
42
+ }
43
+
44
+
45
+ /*******************************
46
+ PipeDescriptor::~PipeDescriptor
47
+ *******************************/
48
+
49
+ PipeDescriptor::~PipeDescriptor()
50
+ {
51
+ // Run down any stranded outbound data.
52
+ for (size_t i=0; i < OutboundPages.size(); i++)
53
+ OutboundPages[i].Free();
54
+
55
+ /* As a virtual destructor, we come here before the base-class
56
+ * destructor that closes our file-descriptor.
57
+ * We have to make sure the subprocess goes down (if it's not
58
+ * already down) and we have to reap the zombie.
59
+ *
60
+ * This implementation is PROVISIONAL and will surely be improved.
61
+ * The intention here is that we never block, hence the highly
62
+ * undesirable sleeps. But if we can't reap the subprocess even
63
+ * after sending it SIGKILL, then something is wrong and we
64
+ * throw a fatal exception, which is also not something we should
65
+ * be doing.
66
+ *
67
+ * Eventually the right thing to do will be to have the reactor
68
+ * core respond to SIGCHLD by chaining a handler on top of the
69
+ * one Ruby may have installed, and dealing with a list of dead
70
+ * children that are pending cleanup.
71
+ *
72
+ * Since we want to have a signal processor integrated into the
73
+ * client-visible API, let's wait until that is done before cleaning
74
+ * this up.
75
+ *
76
+ * Added a very ugly hack to support passing the subprocess's exit
77
+ * status to the user. It only makes logical sense for user code to access
78
+ * the subprocess exit status in the unbind callback. But unbind is called
79
+ * back during the EventableDescriptor destructor. So by that time there's
80
+ * no way to call back this object through an object binding, because it's
81
+ * already been cleaned up. We might have added a parameter to the unbind
82
+ * callback, but that would probably break a huge amount of existing code.
83
+ * So the hack-solution is to define an instance variable in the EventMachine
84
+ * object and stick the exit status in there, where it can easily be accessed
85
+ * with an accessor visible to user code.
86
+ * User code should ONLY access the exit status from within the unbind callback.
87
+ * Otherwise there's no guarantee it'll be valid.
88
+ * This hack won't make it impossible to run multiple EventMachines in a single
89
+ * process, but it will make it impossible to reliably nest unbind calls
90
+ * within other unbind calls. (Not sure if that's even possible.)
91
+ */
92
+
93
+ assert (MyEventMachine);
94
+
95
+ /* Another hack to make the SubprocessPid available to get_subprocess_status */
96
+ MyEventMachine->SubprocessPid = SubprocessPid;
97
+
98
+ /* 01Mar09: Updated to use a small nanosleep in a loop. When nanosleep is interrupted by SIGCHLD,
99
+ * it resumes the system call after processing the signal (resulting in unnecessary latency).
100
+ * Calling nanosleep in a loop avoids this problem.
101
+ */
102
+ struct timespec req = {0, 50000000}; // 0.05s
103
+ int n;
104
+
105
+ // wait 0.5s for the process to die
106
+ for (n=0; n<10; n++) {
107
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
108
+ nanosleep (&req, NULL);
109
+ }
110
+
111
+ // send SIGTERM and wait another 1s
112
+ kill (SubprocessPid, SIGTERM);
113
+ for (n=0; n<20; n++) {
114
+ nanosleep (&req, NULL);
115
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
116
+ }
117
+
118
+ // send SIGKILL and wait another 5s
119
+ kill (SubprocessPid, SIGKILL);
120
+ for (n=0; n<100; n++) {
121
+ nanosleep (&req, NULL);
122
+ if (waitpid (SubprocessPid, &(MyEventMachine->SubprocessExitStatus), WNOHANG) != 0) return;
123
+ }
124
+
125
+ // still not dead, give up!
126
+ throw std::runtime_error ("unable to reap subprocess");
127
+ }
128
+
129
+
130
+
131
+ /********************
132
+ PipeDescriptor::Read
133
+ ********************/
134
+
135
+ void PipeDescriptor::Read()
136
+ {
137
+ int sd = GetSocket();
138
+ if (sd == INVALID_SOCKET) {
139
+ assert (!bReadAttemptedAfterClose);
140
+ bReadAttemptedAfterClose = true;
141
+ return;
142
+ }
143
+
144
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
145
+
146
+ int total_bytes_read = 0;
147
+ char readbuffer [16 * 1024];
148
+
149
+ for (int i=0; i < 10; i++) {
150
+ // Don't read just one buffer and then move on. This is faster
151
+ // if there is a lot of incoming.
152
+ // But don't read indefinitely. Give other sockets a chance to run.
153
+ // NOTICE, we're reading one less than the buffer size.
154
+ // That's so we can put a guard byte at the end of what we send
155
+ // to user code.
156
+ // Use read instead of recv, which on Linux gives a "socket operation
157
+ // on nonsocket" error.
158
+
159
+
160
+ int r = read (sd, readbuffer, sizeof(readbuffer) - 1);
161
+ //cerr << "<R:" << r << ">";
162
+
163
+ if (r > 0) {
164
+ total_bytes_read += r;
165
+
166
+ // Add a null-terminator at the the end of the buffer
167
+ // that we will send to the callback.
168
+ // DO NOT EVER CHANGE THIS. We want to explicitly allow users
169
+ // to be able to depend on this behavior, so they will have
170
+ // the option to do some things faster. Additionally it's
171
+ // a security guard against buffer overflows.
172
+ readbuffer [r] = 0;
173
+ _GenericInboundDispatch(readbuffer, r);
174
+ }
175
+ else if (r == 0) {
176
+ break;
177
+ }
178
+ else {
179
+ // Basically a would-block, meaning we've read everything there is to read.
180
+ break;
181
+ }
182
+
183
+ }
184
+
185
+
186
+ if (total_bytes_read == 0) {
187
+ // If we read no data on a socket that selected readable,
188
+ // it generally means the other end closed the connection gracefully.
189
+ ScheduleClose (false);
190
+ //bCloseNow = true;
191
+ }
192
+
193
+ }
194
+
195
+ /*********************
196
+ PipeDescriptor::Write
197
+ *********************/
198
+
199
+ void PipeDescriptor::Write()
200
+ {
201
+ int sd = GetSocket();
202
+ assert (sd != INVALID_SOCKET);
203
+
204
+ LastActivity = MyEventMachine->GetCurrentLoopTime();
205
+ char output_buffer [16 * 1024];
206
+ size_t nbytes = 0;
207
+
208
+ while ((OutboundPages.size() > 0) && (nbytes < sizeof(output_buffer))) {
209
+ OutboundPage *op = &(OutboundPages[0]);
210
+ if ((nbytes + op->Length - op->Offset) < sizeof (output_buffer)) {
211
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, op->Length - op->Offset);
212
+ nbytes += (op->Length - op->Offset);
213
+ op->Free();
214
+ OutboundPages.pop_front();
215
+ }
216
+ else {
217
+ int len = sizeof(output_buffer) - nbytes;
218
+ memcpy (output_buffer + nbytes, op->Buffer + op->Offset, len);
219
+ op->Offset += len;
220
+ nbytes += len;
221
+ }
222
+ }
223
+
224
+ // We should never have gotten here if there were no data to write,
225
+ // so assert that as a sanity check.
226
+ // Don't bother to make sure nbytes is less than output_buffer because
227
+ // if it were we probably would have crashed already.
228
+ assert (nbytes > 0);
229
+
230
+ assert (GetSocket() != INVALID_SOCKET);
231
+ int bytes_written = write (GetSocket(), output_buffer, nbytes);
232
+ #ifdef OS_WIN32
233
+ int e = WSAGetLastError();
234
+ #else
235
+ int e = errno;
236
+ #endif
237
+
238
+ if (bytes_written > 0) {
239
+ OutboundDataSize -= bytes_written;
240
+ if ((size_t)bytes_written < nbytes) {
241
+ int len = nbytes - bytes_written;
242
+ char *buffer = (char*) malloc (len + 1);
243
+ if (!buffer)
244
+ throw std::runtime_error ("bad alloc throwing back data");
245
+ memcpy (buffer, output_buffer + bytes_written, len);
246
+ buffer [len] = 0;
247
+ OutboundPages.push_front (OutboundPage (buffer, len));
248
+ }
249
+ #ifdef HAVE_EPOLL
250
+ EpollEvent.events = EPOLLIN;
251
+ if (SelectForWrite())
252
+ EpollEvent.events |= EPOLLOUT;
253
+ assert (MyEventMachine);
254
+ MyEventMachine->Modify (this);
255
+ #endif
256
+ }
257
+ else {
258
+ #ifdef OS_UNIX
259
+ if ((e != EINPROGRESS) && (e != EWOULDBLOCK) && (e != EINTR))
260
+ #endif
261
+ #ifdef OS_WIN32
262
+ if ((e != WSAEINPROGRESS) && (e != WSAEWOULDBLOCK))
263
+ #endif
264
+ Close();
265
+ }
266
+ }
267
+
268
+
269
+ /*************************
270
+ PipeDescriptor::Heartbeat
271
+ *************************/
272
+
273
+ void PipeDescriptor::Heartbeat()
274
+ {
275
+ // If an inactivity timeout is defined, then check for it.
276
+ if (InactivityTimeout && ((MyEventMachine->GetCurrentLoopTime() - LastActivity) >= InactivityTimeout))
277
+ ScheduleClose (false);
278
+ //bCloseNow = true;
279
+ }
280
+
281
+
282
+ /*****************************
283
+ PipeDescriptor::SelectForRead
284
+ *****************************/
285
+
286
+ bool PipeDescriptor::SelectForRead()
287
+ {
288
+ /* Pipe descriptors, being local by definition, don't have
289
+ * a pending state, so this is simpler than for the
290
+ * ConnectionDescriptor object.
291
+ */
292
+ return bPaused ? false : true;
293
+ }
294
+
295
+ /******************************
296
+ PipeDescriptor::SelectForWrite
297
+ ******************************/
298
+
299
+ bool PipeDescriptor::SelectForWrite()
300
+ {
301
+ /* Pipe descriptors, being local by definition, don't have
302
+ * a pending state, so this is simpler than for the
303
+ * ConnectionDescriptor object.
304
+ */
305
+ return (GetOutboundDataSize() > 0) && !bPaused ? true : false;
306
+ }
307
+
308
+
309
+
310
+
311
+ /********************************
312
+ PipeDescriptor::SendOutboundData
313
+ ********************************/
314
+
315
+ int PipeDescriptor::SendOutboundData (const char *data, unsigned long length)
316
+ {
317
+ //if (bCloseNow || bCloseAfterWriting)
318
+ if (IsCloseScheduled())
319
+ return 0;
320
+
321
+ if (!data && (length > 0))
322
+ throw std::runtime_error ("bad outbound data");
323
+ char *buffer = (char *) malloc (length + 1);
324
+ if (!buffer)
325
+ throw std::runtime_error ("no allocation for outbound data");
326
+ memcpy (buffer, data, length);
327
+ buffer [length] = 0;
328
+ OutboundPages.push_back (OutboundPage (buffer, length));
329
+ OutboundDataSize += length;
330
+ #ifdef HAVE_EPOLL
331
+ EpollEvent.events = (EPOLLIN | EPOLLOUT);
332
+ assert (MyEventMachine);
333
+ MyEventMachine->Modify (this);
334
+ #endif
335
+ return length;
336
+ }
337
+
338
+ /********************************
339
+ PipeDescriptor::GetSubprocessPid
340
+ ********************************/
341
+
342
+ bool PipeDescriptor::GetSubprocessPid (pid_t *pid)
343
+ {
344
+ bool ok = false;
345
+ if (pid && (SubprocessPid > 0)) {
346
+ *pid = SubprocessPid;
347
+ ok = true;
348
+ }
349
+ return ok;
350
+ }
351
+
352
+
353
+ #endif // OS_UNIX
354
+