Skip to content

Commit 9522458

Browse files
committed
Added test for moving of context between applications and pools
1 parent 7eaa3f2 commit 9522458

5 files changed

Lines changed: 216 additions & 10 deletions

File tree

cppcms/applications_pool.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ namespace cppcms {
2626
namespace booster {
2727
void CPPCMS_API intrusive_ptr_add_ref(cppcms::application *p);
2828
void CPPCMS_API intrusive_ptr_release(cppcms::application *p);
29+
namespace aio {
30+
class io_service;
31+
}
2932
}
3033

3134
namespace cppcms {
@@ -66,6 +69,28 @@ namespace cppcms {
6669
application_specific_pool();
6770
virtual ~application_specific_pool();
6871

72+
///
73+
/// Returns asynchronous application that runs at given booster::aio::io_service constext, it the application
74+
/// does not exist yet, it is created
75+
///
76+
/// Notes:
77+
///
78+
/// - if the application is created upon function call it would be created in the calling thread regardless if it is event loop thread or not
79+
/// - If the pool isn't mounted as asynchronous pool then cppcms_error is thrown
80+
/// - if the io_srv isn't main cppcms io_service cppcms_error is thrown
81+
///
82+
booster::intrusive_ptr<application> asynchronous_application_by_io_service(booster::aio::io_service &io_srv,cppcms::service &srv);
83+
///
84+
/// Returns asynchronous application that runs at given booster::aio::io_service constext, it the application
85+
/// does not exist yet NULL pointer is returned
86+
///
87+
/// Notes:
88+
///
89+
/// - If the pool isn't mounted as asynchronous pool then cppcms_error is thrown
90+
/// - if the io_srv isn't main cppcms io_service cppcms_error is thrown
91+
///
92+
booster::intrusive_ptr<application> asynchronous_application_by_io_service(booster::aio::io_service &io_srv);
93+
6994
protected:
7095
///
7196
/// Returns newly created instance of an application, its ownership

src/applications_pool.cpp

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@ class application_specific_pool::_policy {
2929
virtual void prepopulate(cppcms::service &srv) = 0;
3030
virtual void application_requested(cppcms::service &) {}
3131
virtual ~_policy() {}
32+
virtual booster::intrusive_ptr<application> get_async(booster::aio::io_service &,cppcms::service *srv=0);
3233
virtual booster::intrusive_ptr<application> get(cppcms::service &srv) = 0;
3334
virtual void put(application *app) = 0;
3435
application *get_new(cppcms::service &srv) { return self_->get_new(srv); }
3536
protected:
3637
application_specific_pool *self_;
3738
};
39+
booster::intrusive_ptr<application> application_specific_pool::_policy::get_async(booster::aio::io_service &,cppcms::service *)
40+
{
41+
throw cppcms_error("Is not implemented for synchronous application");
42+
}
3843

3944
class application_specific_pool::_tls_policy : public application_specific_pool::_policy {
4045
public:
@@ -170,28 +175,49 @@ class application_specific_pool::_legacy_pool_policy : public application_specif
170175
class application_specific_pool::_async_policy : public application_specific_pool::_policy{
171176
public:
172177
_async_policy(application_specific_pool *self) :
173-
_policy(self)
178+
_policy(self),
179+
io_srv_(0)
174180
{
175181
}
176182
virtual void prepopulate(cppcms::service &srv)
177183
{
178184
if((self_->flags() & app::prepopulated) && !(self_->flags() & app::legacy)) {
179-
if(!app_)
185+
if(!app_) {
180186
app_ = get_new(srv);
187+
io_srv_ = &srv.get_io_service();
188+
}
181189
}
182190
}
183191
virtual booster::intrusive_ptr<application> get(cppcms::service &srv)
184192
{
185-
if(!app_)
193+
if(!app_) {
186194
app_ = get_new(srv);
195+
if(app_) {
196+
io_srv_ = &srv.get_io_service();
197+
}
198+
}
187199
return app_;
188200
}
189201
virtual void put(application *)
190202
{
191203
// SHOULD NEVER BE CALLED as when pool is destroyed and app_ is destroyed weak_ptr would be invalid
192204
}
205+
virtual booster::intrusive_ptr<application> get_async(booster::aio::io_service &io_srv,cppcms::service *srv = 0)
206+
{
207+
208+
if(app_) {
209+
if(&io_srv == io_srv_)
210+
return app_;
211+
else
212+
throw cppcms_error("given booster::aio::io_service isn't main event loop io_service");
213+
}
214+
if(!srv)
215+
return 0;
216+
return get(*srv);
217+
}
193218
private:
194219
booster::intrusive_ptr<application> app_;
220+
booster::aio::io_service *io_srv_;
195221
};
196222

197223
class application_specific_pool::_async_legacy_policy : public application_specific_pool::_policy{
@@ -286,6 +312,16 @@ void application_specific_pool::flags(int flags)
286312
}
287313
}
288314

315+
booster::intrusive_ptr<application> application_specific_pool::asynchronous_application_by_io_service(booster::aio::io_service &ios,cppcms::service &srv)
316+
{
317+
return d->policy->get_async(ios,&srv);
318+
}
319+
320+
booster::intrusive_ptr<application> application_specific_pool::asynchronous_application_by_io_service(booster::aio::io_service &ios)
321+
{
322+
return d->policy->get_async(ios);
323+
}
324+
289325
application *application_specific_pool::get_new(service &srv)
290326
{
291327
application *a = new_application(srv);

src/http_context.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,12 +125,14 @@ void context::submit_to_pool(booster::shared_ptr<application_specific_pool> pool
125125
namespace {
126126
struct dispatch_binder {
127127
void (*dispatch)(booster::intrusive_ptr<application> const &,std::string const &,bool);
128+
booster::shared_ptr<context> ctx;
128129
booster::intrusive_ptr<application> app;
129130
std::string matched;
130131
bool flag;
131132

132133
void operator()()
133134
{
135+
app->assign_context(ctx);
134136
dispatch(app,matched,flag);
135137
}
136138

@@ -154,11 +156,10 @@ namespace {
154156
}
155157

156158

159+
157160
void context::submit_to_asynchronous_application(booster::intrusive_ptr<application> app,std::string const &matched)
158161
{
159-
app->assign_context(self());
160-
response().io_mode(http::response::asynchronous);
161-
dispatch_binder bd = { &context::dispatch, app,matched,false };
162+
dispatch_binder bd = { &context::dispatch, self(), app,matched,false };
162163
conn_->get_io_service().post(bd);
163164
}
164165

tests/pool_test.cpp

Lines changed: 99 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
#include <booster/log.h>
2424
#include "test.h"
2525

26+
int g_fail;
27+
#define TESTNT(x) do { if(x) break; std::cerr << "FAIL: " #x " in line: " << __LINE__ << std::endl; g_fail = 1; return; } while(0)
28+
2629
booster::thread_specific_ptr<int> g_thread_id;
2730
booster::mutex g_id_lock;
2831
int g_thread_id_counter=1000;
@@ -195,6 +198,76 @@ struct marker {
195198
std::string name_;
196199
};
197200

201+
struct pools {
202+
booster::weak_ptr<cppcms::application_specific_pool> sync,async;
203+
bool async_requested;
204+
pools() : async_requested(false) {}
205+
};
206+
207+
class sender : public cppcms::application {
208+
public:
209+
210+
struct src_prop {
211+
bool src_async;
212+
bool src_created;
213+
bool src_to_app;
214+
};
215+
sender(cppcms::service &srv,pools *p) :
216+
cppcms::application(srv),
217+
pools_(p),
218+
first_time_(true)
219+
{
220+
}
221+
222+
void main(std::string url)
223+
{
224+
if(url!="/sender") {
225+
src_prop *p = context().get_specific<src_prop>();
226+
TESTNT(p);
227+
response().out() << "async=" << is_asynchronous() << "\n"
228+
"src_async=" << p->src_async <<"\n"
229+
"src_created="<< p->src_created <<"\n"
230+
"src_to_app=" << p->src_to_app <<"\n"
231+
"path=" << url<<"\n"
232+
;
233+
return;
234+
}
235+
236+
src_prop *p=new src_prop();
237+
context().reset_specific<src_prop>(p);
238+
239+
bool to_app = request().get("to_app")=="1";
240+
p->src_to_app = to_app;
241+
p->src_async = is_asynchronous();
242+
p->src_created = false;
243+
booster::shared_ptr<cppcms::application_specific_pool> tgt;
244+
if(request().get("to")=="sync")
245+
tgt = pools_->sync.lock();
246+
else
247+
tgt = pools_->async.lock();
248+
249+
booster::shared_ptr<cppcms::http::context> ctx = release_context();
250+
TESTNT(tgt);
251+
252+
if(!to_app) {
253+
ctx->submit_to_pool(tgt,"/pool");
254+
return;
255+
}
256+
257+
booster::intrusive_ptr<cppcms::application> app;
258+
app =tgt->asynchronous_application_by_io_service(service().get_io_service());
259+
if(!app) {
260+
app = tgt->asynchronous_application_by_io_service(service().get_io_service(),service());
261+
p->src_created=true;
262+
}
263+
TESTNT(app);
264+
ctx->submit_to_asynchronous_application(app,"/app");
265+
}
266+
private:
267+
pools *pools_;
268+
bool first_time_;
269+
};
270+
198271
int main(int argc,char **argv)
199272
{
200273
try {
@@ -247,6 +320,25 @@ int main(int argc,char **argv)
247320

248321
srv.applications_pool().mount(cppcms::create_pool<tester>(),mount_point("/test"),cppcms::app::asynchronous);
249322

323+
pools p;
324+
{
325+
booster::shared_ptr<cppcms::application_specific_pool> tmp;
326+
srv.applications_pool().mount(
327+
(tmp=cppcms::create_pool<sender>(&p)),
328+
mount_point("/async","/sender",0),
329+
cppcms::app::asynchronous);
330+
p.async = tmp;
331+
}
332+
333+
{
334+
booster::shared_ptr<cppcms::application_specific_pool> tmp;
335+
srv.applications_pool().mount(
336+
(tmp=cppcms::create_pool<sender>(&p)),
337+
mount_point("/sync","/sender",0),
338+
cppcms::app::synchronous);
339+
p.sync = tmp;
340+
}
341+
250342
srv.after_fork(thread_submitter(srv));
251343
srv.run();
252344

@@ -267,9 +359,12 @@ int main(int argc,char **argv)
267359
std::cerr << e.what() << std::endl;
268360
return EXIT_FAILURE;
269361
}
270-
if(run_ok)
271-
std::cout << "Ok" << std::endl;
272-
else
362+
if(run_ok && !g_fail) {
363+
std::cout << "Full Test: Ok" << std::endl;
364+
return EXIT_SUCCESS;
365+
}
366+
else {
273367
std::cout << "FAILED" << std::endl;
274-
return run_ok ? EXIT_SUCCESS : EXIT_FAILURE;
368+
return EXIT_FAILURE;
369+
}
275370
}

tests/pool_test.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,54 @@ def test_async_temporary():
281281

282282
Conn(n).get(exp404 = True)
283283

284+
def test_send():
285+
286+
print "/sync/sender"
287+
288+
r=Conn('/sync/sender?to=async&to_app=1').get()
289+
test(r["path"]=="/app")
290+
test(r["async"]==1)
291+
test(r["src_async"]==0)
292+
test(r["src_created"]==1)
293+
test(r["src_to_app"]==1)
294+
295+
r=Conn('/sync/sender?to=async&to_app=1').get()
296+
test(r["path"]=="/app")
297+
test(r["async"]==1)
298+
test(r["src_async"]==0)
299+
test(r["src_created"]==0)
300+
test(r["src_to_app"]==1)
301+
302+
r=Conn('/sync/sender?to=async').get()
303+
test(r["path"]=="/pool")
304+
test(r["async"]==1)
305+
test(r["src_async"]==0)
306+
test(r["src_created"]==0)
307+
test(r["src_to_app"]==0)
308+
309+
r=Conn('/sync/sender?to=sync').get()
310+
test(r["path"]=="/pool")
311+
test(r["async"]==0)
312+
test(r["src_async"]==0)
313+
314+
print "/async/sender"
315+
316+
r=Conn('/async/sender?to=async&to_app=1').get()
317+
test(r["path"]=="/app")
318+
test(r["async"]==1)
319+
test(r["src_async"]==1)
320+
test(r["src_to_app"]==1)
321+
322+
r=Conn('/async/sender?to=async').get()
323+
test(r["path"]=="/pool")
324+
test(r["async"]==1)
325+
test(r["src_async"]==1)
326+
327+
r=Conn('/async/sender?to=sync').get()
328+
test(r["path"]=="/pool")
329+
test(r["async"]==0)
330+
test(r["src_async"]==1)
331+
284332

285333
test_sync()
286334
test_sync_prep()
@@ -290,4 +338,5 @@ def test_async_temporary():
290338
test_async_prep()
291339
test_async_legacy()
292340
test_async_temporary()
341+
test_send()
293342
print "OK"

0 commit comments

Comments
 (0)