@@ -197,6 +197,20 @@ namespace cppcms { | |||
void mount(booster::shared_ptr<application_specific_pool> gen,mount_point const &point,int application_options = 0); | |||
/// | |||
/// Unmount an application_specific_pool from the general pool. | |||
/// | |||
/// Notes: | |||
/// | |||
/// - Exiting request would continue to be executed | |||
/// - There is no guarantee when and in which thread application objects would be destroyed upon use of unmount | |||
/// - applications in the pool using thread_specific policy would be destroyed only on thread exit (i.e. when threads of thread pool are destroyed) | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void unmount(booster::weak_ptr<application_specific_pool> gen); | |||
/// \cond INTERNAL | |||
/// get is not in use any more | |||
@@ -420,6 +420,10 @@ void applications_pool::mount(booster::shared_ptr<application_specific_pool> gen | |||
if(flags & app::prepopulated) | |||
gen->prepopulate(*srv_); | |||
booster::unique_lock<booster::recursive_mutex> lock(d->lock); | |||
for(std::list<_data::attachment>::iterator it = d->apps.begin();it!=d->apps.end();++it) { | |||
if(it->pool == gen) | |||
throw cppcms_error("Attempt to mount application_specific_pool twice"); | |||
} | |||
d->apps.push_back(_data::attachment(gen,point)); | |||
} | |||
@@ -460,6 +464,21 @@ applications_pool::get_application_specific_pool(char const *host,char const *sc | |||
return result; | |||
} | |||
void applications_pool::unmount(booster::weak_ptr<application_specific_pool> wgen) | |||
{ | |||
booster::shared_ptr<application_specific_pool> gen = wgen.lock(); | |||
if(!gen) return; | |||
booster::unique_lock<booster::recursive_mutex> lock(d->lock); | |||
for(std::list<_data::attachment>::iterator it = d->apps.begin();it!=d->apps.end();++it) { | |||
if(it->pool == gen) { | |||
d->apps.erase(it); | |||
return; | |||
} | |||
} | |||
} | |||
booster::intrusive_ptr<application> applications_pool::get( char const *, | |||
char const *, | |||
char const *, | |||
@@ -151,6 +151,8 @@ private: | |||
int original_thread_id_; | |||
}; | |||
std::map<std::string,booster::weak_ptr<cppcms::application_specific_pool> > weak_pools; | |||
class tester : public cppcms::application { | |||
public: | |||
tester(cppcms::service &srv) : cppcms::application(srv) {} | |||
@@ -158,6 +160,15 @@ public: | |||
{ | |||
if(name=="/stats") | |||
counter::instance(request().get("id"))->print(response().out()); | |||
else if(name=="/unmount") { | |||
std::string id = request().get("id"); | |||
bool exists_before = weak_pools[id].lock(); | |||
service().applications_pool().unmount(weak_pools[id]); | |||
bool exists_after = weak_pools[id].lock(); | |||
response().out()<<"unmount=" << id << "\n" | |||
"before="<<exists_before <<"\n" | |||
"after="<<exists_after; | |||
} | |||
else if(name=="/install") { | |||
app_ = new unit_test(service(),counter::instance("/async/temporary")); | |||
service().applications_pool().mount(app_,cppcms::mount_point("/async","/temporary",0)); | |||
@@ -174,6 +185,16 @@ private: | |||
}; | |||
struct marker { | |||
marker(std::string const &name) : name_(name) {} | |||
booster::shared_ptr<cppcms::application_specific_pool> const &operator | (booster::shared_ptr<cppcms::application_specific_pool> const &in) | |||
{ | |||
weak_pools[name_] = in; | |||
return in; | |||
} | |||
std::string name_; | |||
}; | |||
int main(int argc,char **argv) | |||
{ | |||
try { | |||
@@ -184,7 +205,7 @@ int main(int argc,char **argv) | |||
set_thread_id(1); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<unit_test>(counter::instance("/sync")), | |||
marker("/sync") | cppcms::create_pool<unit_test>(counter::instance("/sync")), | |||
mount_point("/sync","",0), | |||
cppcms::app::synchronous); | |||
@@ -194,26 +215,26 @@ int main(int argc,char **argv) | |||
cppcms::app::synchronous); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<unit_test>(counter::instance("/sync/prepopulated")), | |||
marker("/sync/prepopulated") | cppcms::create_pool<unit_test>(counter::instance("/sync/prepopulated")), | |||
mount_point("/sync","/prepopulated",0), | |||
cppcms::app::synchronous | cppcms::app::prepopulated); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<unit_test>(counter::instance("/sync/tss")), | |||
marker("/sync/tss") | cppcms::create_pool<unit_test>(counter::instance("/sync/tss")), | |||
mount_point("/sync","/tss",0), | |||
cppcms::app::synchronous | cppcms::app::thread_specific); | |||
srv.applications_pool().mount( | |||
cppcms::applications_factory<unit_test>(counter::instance("/sync/legacy")), | |||
mount_point("/sync","/legacy",0)); | |||
mount_point("/sync","/legacy",0)); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<unit_test>(counter::instance("/async")), | |||
marker("/async") | cppcms::create_pool<unit_test>(counter::instance("/async")), | |||
mount_point("/async","",0), | |||
cppcms::app::asynchronous); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<unit_test>(counter::instance("/async/prepopulated")), | |||
marker("/async/prepopulated") | cppcms::create_pool<unit_test>(counter::instance("/async/prepopulated")), | |||
mount_point("/async","/prepopulated",0), | |||
cppcms::app::asynchronous | cppcms::app::prepopulated); | |||
@@ -228,6 +249,8 @@ int main(int argc,char **argv) | |||
srv.after_fork(thread_submitter(srv)); | |||
srv.run(); | |||
weak_pools.clear(); | |||
} | |||
std::cout << "Test all deleted" << std::endl; | |||
@@ -36,6 +36,7 @@ class Conn(): | |||
r2 = response.split('\r\n\r\n') | |||
headers=r2[0] | |||
body = r2[1] | |||
first_header = headers.split('\r\n')[0] | |||
if exp404: | |||
test(headers.find('HTTP/1.0 404')==0) | |||
return {'status' : 404 } | |||
@@ -49,7 +50,7 @@ class Conn(): | |||
r[ss[0]]=int(ss[1]) | |||
else: | |||
r[ss[0]]=ss[1] | |||
print now(), "Got",r | |||
print now(), "Got",first_header,r | |||
return r | |||
def pool_many(url,cb=None): | |||
@@ -63,7 +64,8 @@ def pool_many(url,cb=None): | |||
a[i]=None | |||
def test_sync(): | |||
print '/sync' | |||
n='/sync' | |||
print n | |||
st=Conn('/test/stats?id=/sync').get() | |||
test(st["total"]==0) | |||
@@ -88,6 +90,9 @@ def test_sync(): | |||
test(st["total"]==2) | |||
test(st["current"]==2) | |||
st=Conn('/test/unmount?id='+n).get() | |||
Conn(n).get(exp404 = True) | |||
test(Conn('/test/stats?id='+n).get()["current"]==0) | |||
def test_sync_prep(): | |||
@@ -112,9 +117,13 @@ def test_sync_prep(): | |||
test(st["total"]==2) | |||
test(st["current"]==2) | |||
Conn('/test/unmount?id='+n).get() | |||
Conn(n).get(exp404 = True) | |||
test(Conn('/test/stats?id='+n).get()["current"]==0) | |||
def test_sync_ts(): | |||
n='/sync/tss' | |||
print '/sync/tss' | |||
st=Conn('/test/stats?id=/sync/tss').get() | |||
test(st["total"]==0) | |||
@@ -143,6 +152,9 @@ def test_sync_ts(): | |||
test(st["total"]==2) | |||
test(st["current"]==2) | |||
st=Conn('/test/unmount?id='+n).get() | |||
Conn(n).get(exp404 = True) | |||
test(Conn('/test/stats?id='+n).get()["current"]==2) | |||
def test_sync_legacy(): | |||
@@ -187,6 +199,10 @@ def test_async(): | |||
st=Conn('/test/stats?id=' + n).get() | |||
test(st["total"]==1) | |||
test(st["current"]==1) | |||
st=Conn('/test/unmount?id='+n).get() | |||
Conn(n).get(exp404 = True) | |||
test(Conn('/test/stats?id='+n).get()["current"]==0) | |||
def test_async_prep(): | |||
n='/async/prepopulated' | |||
@@ -205,6 +221,10 @@ def test_async_prep(): | |||
test(st["total"]==1) | |||
test(st["current"]==1) | |||
st=Conn('/test/unmount?id='+n).get() | |||
Conn(n).get(exp404 = True) | |||
test(Conn('/test/stats?id='+n).get()["current"]==0) | |||
def test_async_legacy(): | |||
n='/async/legacy' | |||
print n | |||