ry / ebb fork watch download tarball
public this repo is viewable by everyone
Description: web server
Homepage: http://ebb.rubyforge.org
Clone URL: git://github.com/ry/ebb.git
Back to rb_thread_schedule()

for some reason lots of speed is lost by waiting in rb_thread_select().
instead i've added a hack which allows us to go into select() only when
there are no connections open. Once the server starts processing
connections, though, it takes control of the operation.
Ryan Dahl (author)
2 months ago
commit  b128ee31d3751baae5229187a8f6ad865dba63d1
tree    188fbde21cd4b1b860eb691df212bf3d981f380f
parent  26e7c927f672e4a589e50387ec846c4d89a6b81e
...
19
20
21
22
 
23
24
25
...
19
20
21
 
22
23
24
25
0
@@ -19,7 +19,7 @@ module Ebb
0
     
0
     FFI::server_listen_on_port(port)
0
     @running = true
0
- #trap('INT') { stop_server }
0
+ trap('INT') { stop_server }
0
     
0
     puts "Ebb listening at http://0.0.0.0:#{port}/ (#{threaded_processing ? 'threaded' : 'sequential'} processing, PID #{Process.pid})"
0
     
...
28
29
30
31
32
33
34
...
43
44
45
46
47
48
49
...
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
70
71
72
73
74
75
 
 
 
 
 
 
76
 
 
 
 
 
 
 
77
78
79
 
 
 
80
81
82
83
84
 
 
 
 
 
 
 
 
85
86
87
...
91
92
93
 
 
 
 
94
95
96
...
28
29
30
 
31
32
33
...
42
43
44
 
45
46
47
...
51
52
53
 
 
 
 
 
 
54
55
 
 
 
 
 
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
 
 
 
 
 
 
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
 
87
88
89
90
 
 
 
 
91
92
93
94
95
96
97
98
99
100
101
...
105
106
107
108
109
110
111
112
113
114
0
@@ -28,7 +28,6 @@ static VALUE global_http_host;
0
  */
0
 static ebb_server *server;
0
 struct ev_loop *loop;
0
-static unsigned int client_count = 0;
0
 
0
 /* Variables with a leading underscore are C-level variables */
0
 
0
@@ -43,7 +42,6 @@ void request_cb(ebb_client *client, void *data)
0
   VALUE waiting_clients = (VALUE)data;
0
   VALUE rb_client = Data_Wrap_Struct(cClient, 0, 0, client);
0
   rb_ary_push(waiting_clients, rb_client);
0
- client_count++;
0
 }
0
 
0
 VALUE server_listen_on_port(VALUE _, VALUE port)
0
@@ -53,35 +51,51 @@ VALUE server_listen_on_port(VALUE _, VALUE port)
0
   return Qnil;
0
 }
0
 
0
-VALUE server_open(VALUE _)
0
-{
0
- return server->open ? Qtrue : Qfalse;
0
-}
0
-
0
-
0
 VALUE server_process_connections(VALUE _)
0
 {
0
- int fd_count = 0, max_fd = 0;
0
- struct timeval tv = { tv_sec: 0, tv_usec: 500000 };
0
- int i;
0
-
0
- fd_set fds; FD_ZERO(&fds);
0
+ /* This function is super hacky. The libev loop is called for one iteration
0
+ * this means that any pending events are handled. If no events exist then
0
+ * the function blocks. We want blocking so that the while loop in ruby
0
+ * doesn't race away - however there is a need to continue to process other
0
+ * ruby threads which are running. While this function is being called
0
+ * other ruby threads cannot execute.
0
+ * So we set this timeout event which breaks the block after 0.1 seconds.
0
+ * Additionally we make sure that other threads get enough processing time
0
+ * by calling rb_thread_schedule() many times.
0
+ *
0
+ * Instead we should probably use rb_thread_select on server->fd when no
0
+ * clients are in_use? Whatever happens here, one should make sure the
0
+ * 'wait' benchmark is running as quickly with Ebb as it does with mongrel.
0
+ */
0
   
0
- FD_SET(server->fd, &fds); fd_count++;
0
- for(i = 0; i < EBB_MAX_CLIENTS; i++) {
0
- ebb_client *client = &server->clients[i];
0
- if(client->open) {
0
- FD_SET(client->fd, &fds); fd_count++;
0
- if(client->fd > max_fd) max_fd = client->fd;
0
+ int i;
0
+ int running_clients = FALSE;
0
+ for(i = 0; i < EBB_MAX_CLIENTS; i++)
0
+ if(server->clients[i].open) {
0
+ running_clients = TRUE;
0
+ break;
0
     }
0
+ if(!running_clients) {
0
+ fd_set fds;
0
+ struct timeval tv = { tv_sec: 1, tv_usec: 0 };
0
+ FD_ZERO(&fds);
0
+ FD_SET(server->fd, &fds);
0
+ /* sit in ruby thread select for a second when there are no connections */
0
+ rb_thread_select(server->fd+1, &fds, &fds, &fds, &tv);
0
   }
0
   
0
- unsigned int last_client_count = client_count;
0
+ if(!server->open)
0
+ return Qnil;
0
+
0
   ev_loop(loop, EVLOOP_NONBLOCK);
0
- if(last_client_count == client_count) {
0
- rb_thread_select(max_fd+1, &fds, &fds, &fds, &tv);
0
- ev_loop(loop, EVLOOP_NONBLOCK);
0
- }
0
+
0
+ /* Call rb_thread_schedule() proportional to the number of rb threads running */
0
+ /* SO HACKY! Anyone have a better way to do this? */
0
+ for(i = 0; i < EBB_MAX_CLIENTS; i++)
0
+ if(server->clients[i].in_use)
0
+ rb_thread_schedule();
0
+
0
+ return Qnil;
0
 }
0
 
0
 
0
@@ -91,6 +105,10 @@ VALUE server_unlisten(VALUE _)
0
   return Qnil;
0
 }
0
 
0
+VALUE server_open(VALUE _)
0
+{
0
+ return server->open ? Qtrue : Qfalse;
0
+}
0
 
0
 VALUE env_field(struct ebb_env_item *item)
0
 {

Comments

    No one has commented yet.