evdispatch 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. data/History.txt +3 -0
  2. data/License.txt +20 -0
  3. data/Manifest.txt +96 -0
  4. data/README.txt +73 -0
  5. data/Rakefile +4 -0
  6. data/config/hoe.rb +70 -0
  7. data/config/requirements.rb +15 -0
  8. data/ext/revdispatch/extconf.rb +31 -0
  9. data/ext/revdispatch/libevdispatch/Changelog +0 -0
  10. data/ext/revdispatch/libevdispatch/LICENSE +0 -0
  11. data/ext/revdispatch/libevdispatch/Makefile.am +10 -0
  12. data/ext/revdispatch/libevdispatch/Makefile.in +637 -0
  13. data/ext/revdispatch/libevdispatch/README +3 -0
  14. data/ext/revdispatch/libevdispatch/TODO +5 -0
  15. data/ext/revdispatch/libevdispatch/aclocal.m4 +7459 -0
  16. data/ext/revdispatch/libevdispatch/autogen.sh +11 -0
  17. data/ext/revdispatch/libevdispatch/confdefs.h +32 -0
  18. data/ext/revdispatch/libevdispatch/config.guess +1516 -0
  19. data/ext/revdispatch/libevdispatch/config.h.in +112 -0
  20. data/ext/revdispatch/libevdispatch/config.sub +1626 -0
  21. data/ext/revdispatch/libevdispatch/configure +21949 -0
  22. data/ext/revdispatch/libevdispatch/configure.ac +40 -0
  23. data/ext/revdispatch/libevdispatch/depcomp +584 -0
  24. data/ext/revdispatch/libevdispatch/install-sh +507 -0
  25. data/ext/revdispatch/libevdispatch/libev/Changes +54 -0
  26. data/ext/revdispatch/libevdispatch/libev/LICENSE +25 -0
  27. data/ext/revdispatch/libevdispatch/libev/Makefile.am +18 -0
  28. data/ext/revdispatch/libevdispatch/libev/Makefile.in +677 -0
  29. data/ext/revdispatch/libevdispatch/libev/README +130 -0
  30. data/ext/revdispatch/libevdispatch/libev/aclocal.m4 +7430 -0
  31. data/ext/revdispatch/libevdispatch/libev/autogen.sh +7 -0
  32. data/ext/revdispatch/libevdispatch/libev/config.guess +1516 -0
  33. data/ext/revdispatch/libevdispatch/libev/config.h.in +106 -0
  34. data/ext/revdispatch/libevdispatch/libev/config.sub +1626 -0
  35. data/ext/revdispatch/libevdispatch/libev/configure +21636 -0
  36. data/ext/revdispatch/libevdispatch/libev/configure.ac +18 -0
  37. data/ext/revdispatch/libevdispatch/libev/ev++.h +779 -0
  38. data/ext/revdispatch/libevdispatch/libev/ev.3 +3276 -0
  39. data/ext/revdispatch/libevdispatch/libev/ev.c +2547 -0
  40. data/ext/revdispatch/libevdispatch/libev/ev.h +608 -0
  41. data/ext/revdispatch/libevdispatch/libev/ev.pod +3192 -0
  42. data/ext/revdispatch/libevdispatch/libev/ev_epoll.c +182 -0
  43. data/ext/revdispatch/libevdispatch/libev/ev_kqueue.c +194 -0
  44. data/ext/revdispatch/libevdispatch/libev/ev_poll.c +135 -0
  45. data/ext/revdispatch/libevdispatch/libev/ev_port.c +163 -0
  46. data/ext/revdispatch/libevdispatch/libev/ev_select.c +244 -0
  47. data/ext/revdispatch/libevdispatch/libev/ev_vars.h +157 -0
  48. data/ext/revdispatch/libevdispatch/libev/ev_win32.c +125 -0
  49. data/ext/revdispatch/libevdispatch/libev/ev_wrap.h +144 -0
  50. data/ext/revdispatch/libevdispatch/libev/event.c +404 -0
  51. data/ext/revdispatch/libevdispatch/libev/event.h +152 -0
  52. data/ext/revdispatch/libevdispatch/libev/install-sh +294 -0
  53. data/ext/revdispatch/libevdispatch/libev/libev.m4 +28 -0
  54. data/ext/revdispatch/libevdispatch/libev/ltmain.sh +6930 -0
  55. data/ext/revdispatch/libevdispatch/libev/missing +336 -0
  56. data/ext/revdispatch/libevdispatch/libev/mkinstalldirs +111 -0
  57. data/ext/revdispatch/libevdispatch/ltmain.sh +6930 -0
  58. data/ext/revdispatch/libevdispatch/missing +367 -0
  59. data/ext/revdispatch/libevdispatch/src/Makefile.am +11 -0
  60. data/ext/revdispatch/libevdispatch/src/Makefile.in +486 -0
  61. data/ext/revdispatch/libevdispatch/src/ev_dispatch.cc +264 -0
  62. data/ext/revdispatch/libevdispatch/src/ev_dispatch.h +300 -0
  63. data/ext/revdispatch/libevdispatch/src/ev_http.cc +238 -0
  64. data/ext/revdispatch/libevdispatch/src/ev_http.h +65 -0
  65. data/ext/revdispatch/libevdispatch/test/Makefile.am +16 -0
  66. data/ext/revdispatch/libevdispatch/test/Makefile.in +513 -0
  67. data/ext/revdispatch/libevdispatch/test/helper.rb +94 -0
  68. data/ext/revdispatch/libevdispatch/test/key_test.cc +52 -0
  69. data/ext/revdispatch/libevdispatch/test/next_test.cc +86 -0
  70. data/ext/revdispatch/libevdispatch/test/next_test.rb +8 -0
  71. data/ext/revdispatch/libevdispatch/test/server.rb +9 -0
  72. data/ext/revdispatch/revdispatch.cc +151 -0
  73. data/ext/revdispatch/server.rb +60 -0
  74. data/ext/revdispatch/test.rb +100 -0
  75. data/lib/evdispatch/loop.rb +16 -0
  76. data/lib/evdispatch/version.rb +9 -0
  77. data/lib/evdispatch.rb +8 -0
  78. data/log/debug.log +0 -0
  79. data/script/console +10 -0
  80. data/script/destroy +14 -0
  81. data/script/generate +14 -0
  82. data/script/txt2html +74 -0
  83. data/setup.rb +1585 -0
  84. data/tasks/deployment.rake +34 -0
  85. data/tasks/environment.rake +7 -0
  86. data/tasks/extconf/revdispatch.rake +43 -0
  87. data/tasks/extconf.rake +13 -0
  88. data/tasks/website.rake +17 -0
  89. data/test/test_evdispatch.rb +11 -0
  90. data/test/test_helper.rb +3 -0
  91. data/test/test_revdispatch_extn.rb +14 -0
  92. data/website/index.html +128 -0
  93. data/website/index.txt +55 -0
  94. data/website/javascripts/rounded_corners_lite.inc.js +285 -0
  95. data/website/stylesheets/screen.css +138 -0
  96. data/website/template.html.erb +49 -0
  97. metadata +157 -0
@@ -0,0 +1,264 @@
1
+ #include "config.h"
2
+ #include <stdio.h>
3
+ #include "ev_dispatch.h"
4
+ #include "ev_http.h"
5
+
6
+ #define DEBUG
7
+
8
+ #ifdef DEBUG
9
+ #include <assert.h>
10
+ #define ASSERT_IS_D_THRAD\
11
+ pthread_t tid = pthread_self();\
12
+ assert( tid == this->m_tid );
13
+ #else
14
+ #define ASSERT_IS_D_THRAD
15
+ #endif
16
+
17
+ // ---
18
+ // TODO:
19
+ // libcurl: is used to handle the http requests
20
+ // sphinxclient: library for the search engine requests
21
+ // memcached: client library for the memcached requests
22
+ //
23
+
24
+ namespace EVD {
25
+
26
+ Dispatch::Dispatch() : m_loop(NULL), m_counter(0), m_loop_started(false), m_http_client(NULL), m_pending(0)
27
+ {
28
+ // zero everything out
29
+ memset(&m_clock,0,sizeof(ev_timer));
30
+ memset(&m_request_watcher,0,sizeof(ev_async));
31
+ memset(&m_tid,0,sizeof(pthread_t));
32
+ m_pid = getpid();
33
+ }
34
+
35
+ Dispatch::~Dispatch()
36
+ {
37
+ if( m_http_client ) {
38
+ delete m_http_client;
39
+ }
40
+ }
41
+
42
+ // start up the background event listener
43
+ bool Dispatch::start()
44
+ {
45
+ int rc;
46
+ if( m_loop_started ){ return false; }
47
+
48
+ rc = pthread_create( &m_tid, NULL, Dispatch::event_loop_start, this );
49
+ if( rc ){ return false; }
50
+ pthread_detach( m_tid );
51
+
52
+ m_http_client = new HttpClient(this);
53
+
54
+ // block until we get notified that the event thead is up and running
55
+ Guard lock(m_lock);
56
+ int count = 0;
57
+
58
+ // wait until the event loop is started
59
+ while( !m_loop_started && count < 100 ) { // never wait more then 100 iterations
60
+ m_cond.timed_wait( m_lock, Timer(1,0) );
61
+ //printf( "waiting another second\n" );
62
+ ++count;
63
+ }
64
+
65
+ return (count < 100);
66
+ }
67
+
68
+ // tell the background event listener to terminate
69
+ void Dispatch::stop()
70
+ {
71
+ if( !m_loop_started ){ return ; }
72
+
73
+ //printf( "EVD::Dispatch stopping...\n" );
74
+ m_loop_started = false;
75
+
76
+ m_cond.broadcast();
77
+ m_requests.signal();
78
+ m_responses.signal();
79
+ ev_unloop( m_loop, EVUNLOOP_ALL );
80
+ if( m_http_client ) {
81
+ delete m_http_client;
82
+ m_http_client = NULL;
83
+ }
84
+ }
85
+
86
+ // all event loop activity happens on this thread
87
+ void* Dispatch::event_loop_start( void *ptr )
88
+ {
89
+ Dispatch *dis = (Dispatch*)ptr;
90
+ dis->event_loop_main();
91
+ //printf( "EVD::Dispatch event loop stopped\n" );
92
+ return NULL;
93
+ }
94
+
95
+ static void
96
+ sigint_cb( struct ev_loop *loop, struct ev_signal *w, int revents )
97
+ {
98
+ Dispatch *ptr = ((Dispatch*)w->data);
99
+ ptr->stop();
100
+ }
101
+
102
+ // called when a new request was signaled from the main thread
103
+ void Dispatch::request_cb_start( struct ev_loop *loop, struct ev_async *w, int revents )
104
+ {
105
+ Dispatch *ptr = (Dispatch*)w->data;
106
+ ptr->request_cb( loop, w, revents );
107
+ }
108
+ void Dispatch::request_cb( struct ev_loop *loop, struct ev_async *w, int revents )
109
+ {
110
+ ASSERT_IS_D_THRAD
111
+
112
+ // create a new queue to store incoming requests
113
+ std::queue<Request*> new_requests;
114
+ // lock down the request queue
115
+ m_requests.m_lock.lock();
116
+ // lock and read as much as we can out of the queue
117
+ new_requests = m_requests.m_queue;
118
+ m_requests.m_queue = std::queue<Request*>(); // empty out the request queue
119
+ m_requests.m_lock.unlock(); // unlock the queue
120
+
121
+ // process the new requests
122
+ while( !new_requests.empty() ) {
123
+ Request *req = new_requests.front();
124
+ new_requests.pop();
125
+ //printf( "Request: %s, time since requested: %.2f\n", req->url.c_str(), difftime(time(NULL),req->start_time) );
126
+
127
+ // inc before we enable the request, since the time to enable and push to responses queue may
128
+ // be long enough for a context switch to allow someone to check request, response and pending count all be zero.
129
+ ++m_pending;
130
+ if( !req->enable() ) { // XXX: if using DNS in requests expect this method to block while dns resolves
131
+ --m_pending;
132
+ printf("EVD::Dispatch request error\n");
133
+ // for some reason we couldn't enable the request cleanup the request and continue
134
+ delete req;
135
+ }
136
+ }
137
+
138
+ }
139
+
140
+ // the main event loop
141
+ void Dispatch::event_loop_main()
142
+ {
143
+ // struct ev_signal signal_exit_watcher;
144
+ m_loop = ev_loop_new(0); //ev_default_loop(0);
145
+
146
+ // m_clock.data = this;
147
+
148
+ // every 100s of a second we'll check the queue for requests
149
+ // ev_timer_init( &m_clock, timeout_cb_start, 0.5, 0.5 );
150
+ // ev_timer_again( m_loop, &m_clock ); // start timer
151
+
152
+ // trap sigint to ensure we clean up the event loop before exit
153
+ // signal_exit_watcher.data = this;
154
+ // ev_signal_init( &signal_exit_watcher, sigint_cb, SIGINT );
155
+ // ev_signal_start( m_loop, &signal_exit_watcher );
156
+
157
+ m_request_watcher.data = this;
158
+ ev_async_init( &m_request_watcher, request_cb_start );
159
+ ev_async_start( m_loop, &m_request_watcher );
160
+
161
+ // start the main event loop
162
+
163
+ m_lock.lock();
164
+ m_loop_started = true;
165
+ m_cond.signal(); // let the world know we're ready for them
166
+ m_lock.unlock();
167
+
168
+ ev_loop( m_loop, 0 );
169
+ ev_loop_destroy( m_loop );
170
+ pthread_exit(NULL);
171
+ }
172
+ void Dispatch::timeout_cb_start(struct ev_loop *loop, struct ev_timer *w, int revents)
173
+ {
174
+ Dispatch *ptr = ((Dispatch*)w->data);
175
+ ptr->timeout_cb( loop, w, revents );
176
+ }
177
+
178
+ // called on the event loop thread
179
+ void Dispatch::timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents)
180
+ {
181
+ ASSERT_IS_D_THRAD
182
+ //printf("timeout cb\n");
183
+ }
184
+
185
+ // called on the main thread, not the event loop thread
186
+ request_t Dispatch::request( Request::Type type, const std::string &url )
187
+ {
188
+ request_t key = m_counter++;
189
+ Request *req = NULL;
190
+ // check the request type and
191
+ switch( type ) {
192
+ case Request::HTTP:
193
+ req = new HttpRequest( m_http_client, key, url );
194
+ break;
195
+ case Request::SPHINX:
196
+ //req = new SphinxRequest( key, url );
197
+ break;
198
+ case Request::MEMCACHED:
199
+ break;
200
+ default:
201
+ // TODO: log an error
202
+ break;
203
+ }
204
+ m_requests.push( req );
205
+ ev_async_send( m_loop, &m_request_watcher );
206
+ return key;
207
+ }
208
+
209
+ Response *Dispatch::response_for( request_t id )
210
+ {
211
+ RespondedTable::iterator loc = m_responded.find(id);
212
+ if( loc == m_responded.end() ){ return NULL; }
213
+ Response *res = loc->second;
214
+ m_responded.erase(loc);
215
+ return res;
216
+ }
217
+
218
+ Queue<Response>::POP_STATE Dispatch::wait_for_response_by_id( request_t id, Timer timeout )
219
+ {
220
+ // first check if the response is loaded
221
+ Response *rep = NULL;
222
+ Queue<Response>::POP_STATE rstate;
223
+ RespondedTable::iterator loc = m_responded.find(id);
224
+
225
+ if( loc != m_responded.end() ){ return Queue<Response>::POPPED; }
226
+
227
+ while( (rep = m_responses.pop_or_wait( &rstate, m_loop_started, timeout )) ) {
228
+ //printf( "rep: %s, id: %d\n", rep->name.c_str(), rep->id );
229
+ m_responded[rep->id] = rep;
230
+ if( rep->id == id ){ return rstate; }
231
+ }
232
+
233
+ return rstate;
234
+ }
235
+
236
+ Response *Dispatch::get_next_response( Timer timer )
237
+ {
238
+ Response *rep = NULL;
239
+ Queue<Response>::POP_STATE rstate;
240
+
241
+ do {
242
+ rep = m_responses.pop_or_wait( &rstate, m_loop_started, timer );
243
+ if( rstate == Queue<Response>::EXITING ){ rep = NULL; break; }
244
+ if( !rep && rstate == Queue<Response>::EXPIRED ) {
245
+ int pending_count = m_pending;
246
+ if( pending_count == 0 ) { // if pending is zero then acquire locks on the request and response queue
247
+ int request_count = m_requests.size();
248
+ int response_count = m_responses.size();
249
+ //printf( "pending: %d, request: %d, response: %d\n", pending_count, request_count, response_count );
250
+ if( pending_count == 0 && request_count == 0 && response_count == 0 ) {
251
+ return NULL;
252
+ }
253
+ }
254
+ }
255
+ else if( rep ) {
256
+ --m_pending;
257
+ }
258
+
259
+ } while( !rep && rstate == Queue<Response>::EXPIRED );
260
+
261
+ return rep;
262
+ }
263
+
264
+ }// end namespace EVD
@@ -0,0 +1,300 @@
1
+ #ifndef EV_DISPATCH_H
2
+ #define EV_DISPATCH_H
3
+
4
+ #include "config.h"
5
+ #include <time.h>
6
+ #include <sys/time.h>
7
+ #include <ev.h>
8
+ #include <pthread.h>
9
+ #include <string>
10
+ #include <list>
11
+ #include <queue>
12
+ #include <map>
13
+
14
+ namespace EVD {
15
+
16
+ // unique id to represent a request
17
+ typedef unsigned long request_t;
18
+
19
+ struct Request {
20
+ enum Type{
21
+ HTTP,
22
+ SPHINX,
23
+ MEMCACHED
24
+ };
25
+ Request( request_t k, const std::string &u ) : key(k), url(u){ time( &start_time); }
26
+ virtual ~Request (){ }
27
+
28
+ // attach to the event loop
29
+ virtual bool enable() = 0;
30
+
31
+ // TODO: add a method to access the response
32
+
33
+ request_t key;
34
+ std::string url;
35
+ time_t start_time;
36
+ };
37
+
38
+ // TODO:
39
+ //struct MemcachedRequesst : public Request {
40
+ //};
41
+
42
+ // TODO:
43
+ //struct SphinxRequest : public Request {
44
+ //};
45
+
46
+ struct Response {
47
+ virtual ~Response(){}
48
+ std::string name;
49
+ std::string body;
50
+ request_t id;
51
+ double response_time; // computed as difftime(start_time,end_time);
52
+ };
53
+
54
+ struct Mutex {
55
+ Mutex() {
56
+ pthread_mutex_init( &m_lock, NULL );
57
+ }
58
+ ~Mutex() {
59
+ pthread_mutex_destroy( &m_lock );
60
+ }
61
+ void lock() {
62
+ pthread_mutex_lock( &m_lock );
63
+ }
64
+ void unlock() {
65
+ pthread_mutex_unlock( &m_lock );
66
+ }
67
+
68
+ pthread_mutex_t m_lock;
69
+ };
70
+
71
+ struct Timer {
72
+ Timer( long int seconds, long int nanoseconds ){
73
+ struct timeval now;
74
+ gettimeofday(&now, NULL);
75
+ m_time.tv_sec = now.tv_sec + seconds;
76
+ m_time.tv_nsec = (now.tv_usec * 1000) + nanoseconds;
77
+ }
78
+ struct timespec m_time;
79
+ };
80
+
81
+ struct Cond {
82
+ Cond() {
83
+ pthread_cond_init( &m_cond, NULL );
84
+ }
85
+ ~Cond() {
86
+ pthread_cond_destroy( &m_cond );
87
+ }
88
+
89
+ void wait( Mutex &m ) {
90
+ pthread_cond_wait( &m_cond, &(m.m_lock) );
91
+ }
92
+
93
+ // wait 500 ms
94
+ // timed_wait( m, Timer(0,500) );
95
+ void timed_wait( Mutex &m, const Timer &t ) {
96
+ pthread_cond_timedwait( &m_cond, &(m.m_lock), &(t.m_time) );
97
+ }
98
+
99
+ void signal() {
100
+ pthread_cond_signal( &m_cond );
101
+ }
102
+
103
+ void broadcast() {
104
+ pthread_cond_broadcast( &m_cond );
105
+ }
106
+
107
+ pthread_cond_t m_cond;
108
+ };
109
+
110
+ struct Guard {
111
+ Guard( Mutex &mutex ): m_mutex(mutex){ m_mutex.lock(); }
112
+ ~Guard(){ m_mutex.unlock(); }
113
+ Mutex &m_mutex;
114
+ };
115
+
116
+ // thread safe queue
117
+ template <typename T>
118
+ struct Queue {
119
+ Queue() {}
120
+ ~Queue() {}
121
+
122
+ // the reason the pop returned, time expired, event loop is exiting, or an object was popped
123
+ enum POP_STATE {
124
+ POPPED = 0,
125
+ EXPIRED = 1,
126
+ EXITING = 2
127
+ };
128
+
129
+ // heap allocated T object
130
+ void push( T *req ) {
131
+ m_lock.lock();
132
+ m_queue.push( req );
133
+ m_lock.unlock();
134
+ m_cond.signal();
135
+ }
136
+
137
+ // returns a value from the queue
138
+ // rstate: the status of the return, see POP_STATE above.
139
+ // cond: an external reason to abort and not pop e.g. exiting event loop
140
+ T *pop_or_wait( POP_STATE *rstate, volatile bool &cond = true, Timer timer = Timer(1,0) ) {
141
+
142
+ Guard lock(m_lock);
143
+ T *req = NULL;
144
+ size_t size = m_queue.size();
145
+ if( size > 0 ){
146
+ req = m_queue.front();
147
+ }
148
+ while( !req ) {
149
+ m_cond.timed_wait( m_lock, timer );
150
+ if( !cond ){ *rstate = EXITING; break; }
151
+ size = m_queue.size();
152
+ if( size > 0 ){
153
+ req = m_queue.front();
154
+ }
155
+ else {
156
+ *rstate = EXPIRED;
157
+ req = NULL;
158
+ break;
159
+ }
160
+ }
161
+ if( req ){
162
+ *rstate = POPPED;
163
+ m_queue.pop();
164
+ }
165
+ return req;
166
+ }
167
+ size_t size(){
168
+ Guard lock(m_lock);
169
+ return m_queue.size();
170
+ }
171
+
172
+ T *pop() {
173
+ Guard lock(m_lock);
174
+ T *req = NULL;
175
+ req = m_queue.front();
176
+ if( req ){
177
+ m_queue.pop();
178
+ }
179
+ return req;
180
+ }
181
+
182
+ void signal(){ m_cond.signal(); }
183
+
184
+ std::queue<T*> m_queue;
185
+ Mutex m_lock;
186
+ Cond m_cond;
187
+ };
188
+
189
+ // used to keep track of pending requests vs completed responses
190
+ struct AtomicCounter {
191
+ // initialization is not threadsafe
192
+ AtomicCounter( int init ) : m_count(init){}
193
+ inline operator int(){ Guard g(m_lock); return m_count; }
194
+ inline int operator++(){ Guard g(m_lock); return ++m_count; }
195
+ inline int operator--(){ Guard g(m_lock); return --m_count; }
196
+
197
+ Mutex m_lock;
198
+ int m_count;
199
+ };
200
+
201
+ //
202
+ // Dispatch requests to a thread running an event loop
203
+ // all methods here should be used within the same thread
204
+ //
205
+ // create a Dispatcher
206
+ // call start
207
+ //
208
+ // send the dispatcher some requests
209
+ //
210
+ // do some work
211
+ //
212
+ // request the dispatcher results
213
+ //
214
+ // TODO: optionally you can tell the dispatcher to store the results on the file system via a pipe
215
+ //
216
+ struct Dispatch {
217
+ typedef std::map<request_t,Response*> RespondedTable;
218
+
219
+ Dispatch();
220
+ ~Dispatch();
221
+
222
+ // start up the background event listener
223
+ bool start();
224
+ // tell the background event listener to terminate
225
+ void stop();
226
+
227
+ request_t request( Request::Type type, const std::string &url );
228
+
229
+ // from the main thread, get the next available response
230
+ // just keep pop'ing off the response queue until we get something
231
+ // if you get a non NULL response from this method it's your responsiblity to delete it
232
+ //
233
+ // Use this method if you want to get all pending requests
234
+ Response *get_next_response( Timer timer = Timer(1,0) );
235
+
236
+ // get a specific respone by id
237
+ // if you get a non NULL response from this method it's your responsiblity to delete it
238
+ //
239
+ // Use this method if you want to get a specific request
240
+ Response *response_for( request_t id );
241
+
242
+ // call this method to block and wait for a specific request
243
+ // then call response_for to retrieve the response, in the background this will collect
244
+ // other pending requests into an internal lookup table
245
+ Queue<Response>::POP_STATE wait_for_response_by_id( request_t id, Timer timeout );
246
+
247
+ // from the backend called on the event loop thread
248
+ inline void send_response( Response *response ) {
249
+ m_responses.push( response );
250
+ }
251
+
252
+ inline struct ev_loop *get_loop(){ return m_loop; }
253
+
254
+ inline pthread_t get_thread_id()const{ return m_tid; }
255
+
256
+ protected:
257
+
258
+ // all event loop activity happens on this thread
259
+ static void* event_loop_start( void *ptr );
260
+ void event_loop_main();
261
+
262
+ static void timeout_cb_start(struct ev_loop *loop, struct ev_timer *w, int revents);
263
+ void timeout_cb(struct ev_loop *loop, struct ev_timer *w, int revents);
264
+
265
+ static void request_cb_start( struct ev_loop *loop, struct ev_async *w, int revents );
266
+ void request_cb( struct ev_loop *loop, struct ev_async *w, int revents );
267
+
268
+ bool store_response_for( request_t id );
269
+
270
+ protected:
271
+
272
+ struct ev_loop *m_loop;
273
+
274
+ // this triggers a callback once every N milliseconds
275
+ struct ev_timer m_clock;
276
+
277
+ struct ev_async m_request_watcher;
278
+
279
+ pid_t m_pid;
280
+ pthread_t m_tid;
281
+ request_t m_counter; // used to create ids for each requests
282
+
283
+ // sync startup to main thread
284
+ Mutex m_lock;
285
+ Cond m_cond;
286
+ bool m_loop_started;
287
+
288
+ Queue <Request> m_requests;
289
+ Queue <Response> m_responses;
290
+
291
+ // stores all responded messages stored when calling wait_for_request_by_id( request_t id )
292
+ RespondedTable m_responded;
293
+
294
+ struct HttpClient *m_http_client;
295
+ AtomicCounter m_pending;
296
+ };
297
+
298
+ }
299
+
300
+ #endif