ebb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -53,7 +53,7 @@ hacking at the moment! :)
53
53
 
54
54
  ## Speed
55
55
 
56
- Because Ebb-Ruby handles most of the processing in C, it is able to do work
56
+ Because Ebb handles most of the processing in C, it is able to do work
57
57
  often times more efficiently than other Ruby language web servers.
58
58
 
59
59
  ![Benchmark](http://s3.amazonaws.com/four.livejournal/20080311/ebb.png)
@@ -70,17 +70,14 @@ Contributions (patches, criticism, advice) are very welcome!
70
70
  Please send all to to
71
71
  [the mailing list](http://groups.google.com/group/ebbebb).
72
72
 
73
- The source code
74
- is hosted [github](http://github.com/ry/ebb/tree/master). It can be retrieved
75
- by executing
73
+ The source code is hosted [github](http://github.com/ry/ebb/tree/master). It
74
+ can be retrieved by executing
76
75
 
77
76
  git clone git://github.com/ry/ebb.git
78
77
 
79
78
  Here are some features that I would like to add:
80
79
  * HTTP 1.1 Expect/Continue (RFC 2616, sections 8.2.3 and 10.1.1)
81
- * A parser for multipart/form-data
82
- * Optimize and clean up upload handling
83
- * Option to listen on unix sockets instead of TCP
80
+ * A parser for multipart/form-data (only for optimization - this functionality is currently handled at the framework level)
84
81
  * Python binding
85
82
 
86
83
  ## (The MIT) License
@@ -20,8 +20,13 @@ class SimpleApp
20
20
  @count = 0
21
21
  end
22
22
 
23
+ def deferred?(env)
24
+ false
25
+ end
26
+
23
27
  def call(env)
24
- commands = env['PATH_INFO'].split('/')
28
+ path = env['PATH_INFO'] || env['REQUEST_URI']
29
+ commands = path.split('/')
25
30
 
26
31
  @count += 1
27
32
  if commands.include?('periodical_activity') and @count % 10 != 1
@@ -52,12 +57,12 @@ class SimpleApp
52
57
  while chunk = env['rack.input'].read(512)
53
58
  input_body << chunk
54
59
  end
55
- if env['HTTP_CONTENT_LENGTH'].to_i == input_body.length
60
+ if env['CONTENT_LENGTH'].to_i == input_body.length
56
61
  body = "Content-Length matches input length"
57
62
  status = 200
58
63
  else
59
64
  body = "Content-Length doesn't matches input length!
60
- content_length = #{env['HTTP_CONTENT_LENGTH'].to_i}
65
+ content_length = #{env['CONTENT_LENGTH'].to_i}
61
66
  input_body.length = #{input_body.length}"
62
67
  status = 500
63
68
  end
@@ -67,12 +72,15 @@ class SimpleApp
67
72
  body = "Undefined url"
68
73
  end
69
74
 
70
- [status, {'Content-Type' => 'text/plain'}, body + "\r\n\r\n"]
75
+ body += "\r\n"
76
+ headers = {'Content-Type' => 'text/plain', 'Content-Length' => body.length.to_s }
77
+ [status, headers, body]
71
78
  end
72
79
  end
73
80
 
74
81
 
75
82
  if $0 == __FILE__
76
83
  require DIR + '/../ruby_lib/ebb'
84
+ #server = Ebb::start_server(SimpleApp.new, :unix_socket => '/tmp/ebb.sock')
77
85
  server = Ebb::start_server(SimpleApp.new, :port => 4001)
78
86
  end
@@ -115,10 +115,8 @@ class ServerTest
115
115
  case name
116
116
  when 'emongrel'
117
117
  @pid = fork { start_emongrel }
118
- when 'ebb_threaded'
119
- @pid = fork { start_ebb_threaded }
120
- when 'ebb_sequential'
121
- @pid = fork { start_ebb_sequential }
118
+ when 'ebb'
119
+ @pid = fork { start_ebb }
122
120
  when 'mongrel'
123
121
  @pid = fork { start_mongrel }
124
122
  when 'thin'
@@ -139,15 +137,11 @@ class ServerTest
139
137
  Rack::Handler::Mongrel.run(app, :Host => '0.0.0.0', :Port => @port.to_i)
140
138
  end
141
139
 
142
- def start_ebb_threaded
140
+ def start_ebb
143
141
  require File.dirname(__FILE__) + '/../ruby_lib/ebb'
144
- server = Ebb::start_server(app, :port => @port, :threaded_processing => true)
142
+ server = Ebb::start_server(app, :port => @port)
145
143
  end
146
144
 
147
- def start_ebb_sequential
148
- require File.dirname(__FILE__) + '/../ruby_lib/ebb'
149
- server = Ebb::start_server(app, :port => @port, :threaded_processing => false)
150
- end
151
145
 
152
146
  def start_mongrel
153
147
  require 'mongrel'
@@ -173,6 +167,9 @@ class ServerTest
173
167
 
174
168
  return nil unless r =~ /Requests per second:\s*(\d+\.\d\d)/
175
169
  rps = $1.to_f
170
+ if r =~ /Time taken for tests:\s*(\d+\.\d+) seconds/
171
+ time_taken = $1.to_f
172
+ end
176
173
  if r =~ /Complete requests:\s*(\d+)/
177
174
  requests_completed = $1.to_i
178
175
  end
@@ -181,11 +178,13 @@ class ServerTest
181
178
  else
182
179
  raise "didn't get how many failed requests from ab"
183
180
  end
184
- puts " #{rps} req/sec (#{requests_completed} completed, #{failed_requests} failed)"
181
+ successful_requests = requests_completed - failed_requests
182
+ puts " #{rps} req/sec (#{requests_completed} total, #{failed_requests} failed in #{"%.2f" % time_taken} seconds)"
185
183
 
186
184
  {
187
185
  :server => @name,
188
186
  :rps => rps,
187
+ :time_taken => time_taken,
189
188
  :requests_completed => requests_completed,
190
189
  :requests_failed => failed_requests,
191
190
  :ab_cmd => cmd
data/bin/ebb_rails CHANGED
File without changes
data/libev/ev.c CHANGED
@@ -1,32 +1,40 @@
1
1
  /*
2
2
  * libev event processing core, watcher management
3
3
  *
4
- * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
4
+ * Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
- * Redistribution and use in source and binary forms, with or without
8
- * modification, are permitted provided that the following conditions are
9
- * met:
7
+ * Redistribution and use in source and binary forms, with or without modifica-
8
+ * tion, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
10
27
  *
11
- * * Redistributions of source code must retain the above copyright
12
- * notice, this list of conditions and the following disclaimer.
13
- *
14
- * * Redistributions in binary form must reproduce the above
15
- * copyright notice, this list of conditions and the following
16
- * disclaimer in the documentation and/or other materials provided
17
- * with the distribution.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ * Alternatively, the contents of this file may be used under the terms of
29
+ * the GNU General Public License ("GPL") version 2 or any later version,
30
+ * in which case the provisions of the GPL are applicable instead of
31
+ * the above. If you wish to allow the use of your version of this file
32
+ * only under the terms of the GPL and not to allow others to use your
33
+ * version of this file under the BSD license, indicate your decision
34
+ * by deleting the provisions above and replace them with the notice
35
+ * and other provisions required by the GPL. If you do not delete the
36
+ * provisions above, a recipient may use your version of this file under
37
+ * either the BSD or the GPL.
30
38
  */
31
39
 
32
40
  #ifdef __cplusplus
@@ -282,9 +290,11 @@ typedef ev_watcher *W;
282
290
  typedef ev_watcher_list *WL;
283
291
  typedef ev_watcher_time *WT;
284
292
 
293
+ #if EV_USE_MONOTONIC
285
294
  /* sig_atomic_t is used to avoid per-thread variables or locking but still */
286
295
  /* giving it a reasonably high chance of working on typical architetcures */
287
- static sig_atomic_t have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */
296
+ static EV_ATOMIC_T have_monotonic; /* did clock_gettime (CLOCK_MONOTONIC) work? */
297
+ #endif
288
298
 
289
299
  #ifdef _WIN32
290
300
  # include "ev_win32.c"
@@ -443,7 +453,7 @@ ev_sleep (ev_tstamp delay)
443
453
 
444
454
  nanosleep (&ts, 0);
445
455
  #elif defined(_WIN32)
446
- Sleep (delay * 1e3);
456
+ Sleep ((unsigned long)(delay * 1e3));
447
457
  #else
448
458
  struct timeval tv;
449
459
 
@@ -592,7 +602,11 @@ fd_reify (EV_P)
592
602
  if (events)
593
603
  {
594
604
  unsigned long argp;
595
- anfd->handle = _get_osfhandle (fd);
605
+ #ifdef EV_FD_TO_WIN32_HANDLE
606
+ anfd->handle = EV_FD_TO_WIN32_HANDLE (fd);
607
+ #else
608
+ anfd->handle = _get_osfhandle (fd);
609
+ #endif
596
610
  assert (("libev only supports socket fds in this configuration", ioctlsocket (anfd->handle, FIONREAD, &argp) == 0));
597
611
  }
598
612
  #endif
@@ -751,15 +765,13 @@ adjustheap (WT *heap, int N, int k)
751
765
  typedef struct
752
766
  {
753
767
  WL head;
754
- sig_atomic_t volatile gotsig;
768
+ EV_ATOMIC_T gotsig;
755
769
  } ANSIG;
756
770
 
757
771
  static ANSIG *signals;
758
772
  static int signalmax;
759
773
 
760
- static int sigpipe [2];
761
- static sig_atomic_t volatile gotsig;
762
- static ev_io sigev;
774
+ static EV_ATOMIC_T gotsig;
763
775
 
764
776
  void inline_size
765
777
  signals_init (ANSIG *base, int count)
@@ -773,24 +785,102 @@ signals_init (ANSIG *base, int count)
773
785
  }
774
786
  }
775
787
 
776
- static void
777
- sighandler (int signum)
788
+ /*****************************************************************************/
789
+
790
+ void inline_speed
791
+ fd_intern (int fd)
778
792
  {
779
- #if _WIN32
780
- signal (signum, sighandler);
793
+ #ifdef _WIN32
794
+ int arg = 1;
795
+ ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg);
796
+ #else
797
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
798
+ fcntl (fd, F_SETFL, O_NONBLOCK);
781
799
  #endif
800
+ }
782
801
 
783
- signals [signum - 1].gotsig = 1;
802
+ static void noinline
803
+ evpipe_init (EV_P)
804
+ {
805
+ if (!ev_is_active (&pipeev))
806
+ {
807
+ while (pipe (evpipe))
808
+ syserr ("(libev) error creating signal/async pipe");
784
809
 
785
- if (!gotsig)
810
+ fd_intern (evpipe [0]);
811
+ fd_intern (evpipe [1]);
812
+
813
+ ev_io_set (&pipeev, evpipe [0], EV_READ);
814
+ ev_io_start (EV_A_ &pipeev);
815
+ ev_unref (EV_A); /* watcher should not keep loop alive */
816
+ }
817
+ }
818
+
819
+ void inline_size
820
+ evpipe_write (EV_P_ EV_ATOMIC_T *flag)
821
+ {
822
+ if (!*flag)
786
823
  {
787
- int old_errno = errno;
788
- gotsig = 1;
789
- write (sigpipe [1], &signum, 1);
824
+ int old_errno = errno; /* save errno because write might clobber it */
825
+
826
+ *flag = 1;
827
+ write (evpipe [1], &old_errno, 1);
828
+
790
829
  errno = old_errno;
791
830
  }
792
831
  }
793
832
 
833
+ static void
834
+ pipecb (EV_P_ ev_io *iow, int revents)
835
+ {
836
+ {
837
+ int dummy;
838
+ read (evpipe [0], &dummy, 1);
839
+ }
840
+
841
+ if (gotsig && ev_is_default_loop (EV_A))
842
+ {
843
+ int signum;
844
+ gotsig = 0;
845
+
846
+ for (signum = signalmax; signum--; )
847
+ if (signals [signum].gotsig)
848
+ ev_feed_signal_event (EV_A_ signum + 1);
849
+ }
850
+
851
+ #if EV_ASYNC_ENABLE
852
+ if (gotasync)
853
+ {
854
+ int i;
855
+ gotasync = 0;
856
+
857
+ for (i = asynccnt; i--; )
858
+ if (asyncs [i]->sent)
859
+ {
860
+ asyncs [i]->sent = 0;
861
+ ev_feed_event (EV_A_ asyncs [i], EV_ASYNC);
862
+ }
863
+ }
864
+ #endif
865
+ }
866
+
867
+ /*****************************************************************************/
868
+
869
+ static void
870
+ ev_sighandler (int signum)
871
+ {
872
+ #if EV_MULTIPLICITY
873
+ struct ev_loop *loop = &default_loop_struct;
874
+ #endif
875
+
876
+ #if _WIN32
877
+ signal (signum, ev_sighandler);
878
+ #endif
879
+
880
+ signals [signum - 1].gotsig = 1;
881
+ evpipe_write (EV_A_ &gotsig);
882
+ }
883
+
794
884
  void noinline
795
885
  ev_feed_signal_event (EV_P_ int signum)
796
886
  {
@@ -811,42 +901,6 @@ ev_feed_signal_event (EV_P_ int signum)
811
901
  ev_feed_event (EV_A_ (W)w, EV_SIGNAL);
812
902
  }
813
903
 
814
- static void
815
- sigcb (EV_P_ ev_io *iow, int revents)
816
- {
817
- int signum;
818
-
819
- read (sigpipe [0], &revents, 1);
820
- gotsig = 0;
821
-
822
- for (signum = signalmax; signum--; )
823
- if (signals [signum].gotsig)
824
- ev_feed_signal_event (EV_A_ signum + 1);
825
- }
826
-
827
- void inline_speed
828
- fd_intern (int fd)
829
- {
830
- #ifdef _WIN32
831
- int arg = 1;
832
- ioctlsocket (_get_osfhandle (fd), FIONBIO, &arg);
833
- #else
834
- fcntl (fd, F_SETFD, FD_CLOEXEC);
835
- fcntl (fd, F_SETFL, O_NONBLOCK);
836
- #endif
837
- }
838
-
839
- static void noinline
840
- siginit (EV_P)
841
- {
842
- fd_intern (sigpipe [0]);
843
- fd_intern (sigpipe [1]);
844
-
845
- ev_io_set (&sigev, sigpipe [0], EV_READ);
846
- ev_io_start (EV_A_ &sigev);
847
- ev_unref (EV_A); /* child watcher should not keep loop alive */
848
- }
849
-
850
904
  /*****************************************************************************/
851
905
 
852
906
  static WL childs [EV_PID_HASHSIZE];
@@ -855,19 +909,27 @@ static WL childs [EV_PID_HASHSIZE];
855
909
 
856
910
  static ev_signal childev;
857
911
 
912
+ #ifndef WIFCONTINUED
913
+ # define WIFCONTINUED(status) 0
914
+ #endif
915
+
858
916
  void inline_speed
859
- child_reap (EV_P_ ev_signal *sw, int chain, int pid, int status)
917
+ child_reap (EV_P_ int chain, int pid, int status)
860
918
  {
861
919
  ev_child *w;
920
+ int traced = WIFSTOPPED (status) || WIFCONTINUED (status);
862
921
 
863
922
  for (w = (ev_child *)childs [chain & (EV_PID_HASHSIZE - 1)]; w; w = (ev_child *)((WL)w)->next)
864
- if (w->pid == pid || !w->pid)
865
- {
866
- ev_set_priority (w, ev_priority (sw)); /* need to do it *now* */
867
- w->rpid = pid;
868
- w->rstatus = status;
869
- ev_feed_event (EV_A_ (W)w, EV_CHILD);
870
- }
923
+ {
924
+ if ((w->pid == pid || !w->pid)
925
+ && (!traced || (w->flags & 1)))
926
+ {
927
+ ev_set_priority (w, EV_MAXPRI); /* need to do it *now*, this *must* be the same prio as the signal watcher itself */
928
+ w->rpid = pid;
929
+ w->rstatus = status;
930
+ ev_feed_event (EV_A_ (W)w, EV_CHILD);
931
+ }
932
+ }
871
933
  }
872
934
 
873
935
  #ifndef WCONTINUED
@@ -886,13 +948,13 @@ childcb (EV_P_ ev_signal *sw, int revents)
886
948
  || 0 >= (pid = waitpid (-1, &status, WNOHANG | WUNTRACED)))
887
949
  return;
888
950
 
889
- /* make sure we are called again until all childs have been reaped */
951
+ /* make sure we are called again until all children have been reaped */
890
952
  /* we need to do it this way so that the callback gets called before we continue */
891
953
  ev_feed_event (EV_A_ (W)sw, EV_SIGNAL);
892
954
 
893
- child_reap (EV_A_ sw, pid, pid, status);
955
+ child_reap (EV_A_ pid, pid, status);
894
956
  if (EV_PID_HASHSIZE > 1)
895
- child_reap (EV_A_ sw, 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */
957
+ child_reap (EV_A_ 0, pid, status); /* this might trigger a watcher twice, but feed_event catches that */
896
958
  }
897
959
 
898
960
  #endif
@@ -1020,13 +1082,19 @@ loop_init (EV_P_ unsigned int flags)
1020
1082
  }
1021
1083
  #endif
1022
1084
 
1023
- ev_rt_now = ev_time ();
1024
- mn_now = get_clock ();
1025
- now_floor = mn_now;
1026
- rtmn_diff = ev_rt_now - mn_now;
1085
+ ev_rt_now = ev_time ();
1086
+ mn_now = get_clock ();
1087
+ now_floor = mn_now;
1088
+ rtmn_diff = ev_rt_now - mn_now;
1027
1089
 
1028
1090
  io_blocktime = 0.;
1029
1091
  timeout_blocktime = 0.;
1092
+ backend = 0;
1093
+ backend_fd = -1;
1094
+ gotasync = 0;
1095
+ #if EV_USE_INOTIFY
1096
+ fs_fd = -2;
1097
+ #endif
1030
1098
 
1031
1099
  /* pid check not overridable via env */
1032
1100
  #ifndef _WIN32
@@ -1042,12 +1110,6 @@ loop_init (EV_P_ unsigned int flags)
1042
1110
  if (!(flags & 0x0000ffffUL))
1043
1111
  flags |= ev_recommended_backends ();
1044
1112
 
1045
- backend = 0;
1046
- backend_fd = -1;
1047
- #if EV_USE_INOTIFY
1048
- fs_fd = -2;
1049
- #endif
1050
-
1051
1113
  #if EV_USE_PORT
1052
1114
  if (!backend && (flags & EVBACKEND_PORT )) backend = port_init (EV_A_ flags);
1053
1115
  #endif
@@ -1064,8 +1126,8 @@ loop_init (EV_P_ unsigned int flags)
1064
1126
  if (!backend && (flags & EVBACKEND_SELECT)) backend = select_init (EV_A_ flags);
1065
1127
  #endif
1066
1128
 
1067
- ev_init (&sigev, sigcb);
1068
- ev_set_priority (&sigev, EV_MAXPRI);
1129
+ ev_init (&pipeev, pipecb);
1130
+ ev_set_priority (&pipeev, EV_MAXPRI);
1069
1131
  }
1070
1132
  }
1071
1133
 
@@ -1074,6 +1136,15 @@ loop_destroy (EV_P)
1074
1136
  {
1075
1137
  int i;
1076
1138
 
1139
+ if (ev_is_active (&pipeev))
1140
+ {
1141
+ ev_ref (EV_A); /* signal watcher */
1142
+ ev_io_stop (EV_A_ &pipeev);
1143
+
1144
+ close (evpipe [0]); evpipe [0] = 0;
1145
+ close (evpipe [1]); evpipe [1] = 0;
1146
+ }
1147
+
1077
1148
  #if EV_USE_INOTIFY
1078
1149
  if (fs_fd >= 0)
1079
1150
  close (fs_fd);
@@ -1119,6 +1190,9 @@ loop_destroy (EV_P)
1119
1190
  #endif
1120
1191
  array_free (prepare, EMPTY);
1121
1192
  array_free (check, EMPTY);
1193
+ #if EV_ASYNC_ENABLE
1194
+ array_free (async, EMPTY);
1195
+ #endif
1122
1196
 
1123
1197
  backend = 0;
1124
1198
  }
@@ -1141,19 +1215,23 @@ loop_fork (EV_P)
1141
1215
  infy_fork (EV_A);
1142
1216
  #endif
1143
1217
 
1144
- if (ev_is_active (&sigev))
1218
+ if (ev_is_active (&pipeev))
1145
1219
  {
1146
- /* default loop */
1220
+ /* this "locks" the handlers against writing to the pipe */
1221
+ /* while we modify the fd vars */
1222
+ gotsig = 1;
1223
+ #if EV_ASYNC_ENABLE
1224
+ gotasync = 1;
1225
+ #endif
1147
1226
 
1148
1227
  ev_ref (EV_A);
1149
- ev_io_stop (EV_A_ &sigev);
1150
- close (sigpipe [0]);
1151
- close (sigpipe [1]);
1152
-
1153
- while (pipe (sigpipe))
1154
- syserr ("(libev) error creating pipe");
1228
+ ev_io_stop (EV_A_ &pipeev);
1229
+ close (evpipe [0]);
1230
+ close (evpipe [1]);
1155
1231
 
1156
- siginit (EV_A);
1232
+ evpipe_init (EV_A);
1233
+ /* now iterate over everything, in case we missed something */
1234
+ pipecb (EV_A_ &pipeev, EV_READ);
1157
1235
  }
1158
1236
 
1159
1237
  postfork = 0;
@@ -1185,7 +1263,7 @@ ev_loop_destroy (EV_P)
1185
1263
  void
1186
1264
  ev_loop_fork (EV_P)
1187
1265
  {
1188
- postfork = 1;
1266
+ postfork = 1; /* must be in line with ev_default_fork */
1189
1267
  }
1190
1268
 
1191
1269
  #endif
@@ -1198,10 +1276,6 @@ int
1198
1276
  ev_default_loop (unsigned int flags)
1199
1277
  #endif
1200
1278
  {
1201
- if (sigpipe [0] == sigpipe [1])
1202
- if (pipe (sigpipe))
1203
- return 0;
1204
-
1205
1279
  if (!ev_default_loop_ptr)
1206
1280
  {
1207
1281
  #if EV_MULTIPLICITY
@@ -1214,8 +1288,6 @@ ev_default_loop (unsigned int flags)
1214
1288
 
1215
1289
  if (ev_backend (EV_A))
1216
1290
  {
1217
- siginit (EV_A);
1218
-
1219
1291
  #ifndef _WIN32
1220
1292
  ev_signal_init (&childev, childcb, SIGCHLD);
1221
1293
  ev_set_priority (&childev, EV_MAXPRI);
@@ -1242,12 +1314,6 @@ ev_default_destroy (void)
1242
1314
  ev_signal_stop (EV_A_ &childev);
1243
1315
  #endif
1244
1316
 
1245
- ev_ref (EV_A); /* signal watcher */
1246
- ev_io_stop (EV_A_ &sigev);
1247
-
1248
- close (sigpipe [0]); sigpipe [0] = 0;
1249
- close (sigpipe [1]); sigpipe [1] = 0;
1250
-
1251
1317
  loop_destroy (EV_A);
1252
1318
  }
1253
1319
 
@@ -1259,7 +1325,7 @@ ev_default_fork (void)
1259
1325
  #endif
1260
1326
 
1261
1327
  if (backend)
1262
- postfork = 1;
1328
+ postfork = 1; /* must be in line with ev_loop_fork */
1263
1329
  }
1264
1330
 
1265
1331
  /*****************************************************************************/
@@ -1478,9 +1544,7 @@ static int loop_done;
1478
1544
  void
1479
1545
  ev_loop (EV_P_ int flags)
1480
1546
  {
1481
- loop_done = flags & (EVLOOP_ONESHOT | EVLOOP_NONBLOCK)
1482
- ? EVUNLOOP_ONE
1483
- : EVUNLOOP_CANCEL;
1547
+ loop_done = EVUNLOOP_CANCEL;
1484
1548
 
1485
1549
  call_pending (EV_A); /* in case we recurse, ensure ordering stays nice and clean */
1486
1550
 
@@ -1586,9 +1650,12 @@ ev_loop (EV_P_ int flags)
1586
1650
  queue_events (EV_A_ (W *)checks, checkcnt, EV_CHECK);
1587
1651
 
1588
1652
  call_pending (EV_A);
1589
-
1590
1653
  }
1591
- while (expect_true (activecnt && !loop_done));
1654
+ while (expect_true (
1655
+ activecnt
1656
+ && !loop_done
1657
+ && !(flags & (EVLOOP_ONESHOT | EVLOOP_NONBLOCK))
1658
+ ));
1592
1659
 
1593
1660
  if (loop_done == EVUNLOOP_ONE)
1594
1661
  loop_done = EVUNLOOP_CANCEL;
@@ -1844,6 +1911,8 @@ ev_signal_start (EV_P_ ev_signal *w)
1844
1911
 
1845
1912
  assert (("ev_signal_start called with illegal signal number", w->signum > 0));
1846
1913
 
1914
+ evpipe_init (EV_A);
1915
+
1847
1916
  {
1848
1917
  #ifndef _WIN32
1849
1918
  sigset_t full, prev;
@@ -1864,10 +1933,10 @@ ev_signal_start (EV_P_ ev_signal *w)
1864
1933
  if (!((WL)w)->next)
1865
1934
  {
1866
1935
  #if _WIN32
1867
- signal (w->signum, sighandler);
1936
+ signal (w->signum, ev_sighandler);
1868
1937
  #else
1869
1938
  struct sigaction sa;
1870
- sa.sa_handler = sighandler;
1939
+ sa.sa_handler = ev_sighandler;
1871
1940
  sigfillset (&sa.sa_mask);
1872
1941
  sa.sa_flags = SA_RESTART; /* if restarting works we save one iteration */
1873
1942
  sigaction (w->signum, &sa, 0);
@@ -2366,6 +2435,44 @@ ev_fork_stop (EV_P_ ev_fork *w)
2366
2435
  }
2367
2436
  #endif
2368
2437
 
2438
+ #if EV_ASYNC_ENABLE
2439
+ void
2440
+ ev_async_start (EV_P_ ev_async *w)
2441
+ {
2442
+ if (expect_false (ev_is_active (w)))
2443
+ return;
2444
+
2445
+ evpipe_init (EV_A);
2446
+
2447
+ ev_start (EV_A_ (W)w, ++asynccnt);
2448
+ array_needsize (ev_async *, asyncs, asyncmax, asynccnt, EMPTY2);
2449
+ asyncs [asynccnt - 1] = w;
2450
+ }
2451
+
2452
+ void
2453
+ ev_async_stop (EV_P_ ev_async *w)
2454
+ {
2455
+ clear_pending (EV_A_ (W)w);
2456
+ if (expect_false (!ev_is_active (w)))
2457
+ return;
2458
+
2459
+ {
2460
+ int active = ((W)w)->active;
2461
+ asyncs [active - 1] = asyncs [--asynccnt];
2462
+ ((W)asyncs [active - 1])->active = active;
2463
+ }
2464
+
2465
+ ev_stop (EV_A_ (W)w);
2466
+ }
2467
+
2468
+ void
2469
+ ev_async_send (EV_P_ ev_async *w)
2470
+ {
2471
+ w->sent = 1;
2472
+ evpipe_write (EV_A_ &gotasync);
2473
+ }
2474
+ #endif
2475
+
2369
2476
  /*****************************************************************************/
2370
2477
 
2371
2478
  struct ev_once