@@ -32,6 +32,7 @@ namespace cppcms { | |||
class url_dispatcher; | |||
class url_mapper; | |||
class applications_pool; | |||
class application_specific_pool; | |||
class application; | |||
class base_content; | |||
class cache_interface; | |||
@@ -391,8 +392,8 @@ namespace cppcms { | |||
void recycle(); | |||
void parent(application *parent); | |||
void pool_id(int id); | |||
int pool_id(); | |||
booster::weak_ptr<application_specific_pool> get_pool(); | |||
void set_pool(booster::weak_ptr<application_specific_pool> pool); | |||
struct _data; // future use | |||
@@ -403,6 +404,7 @@ namespace cppcms { | |||
booster::atomic_counter refs_; | |||
friend class applications_pool; | |||
friend class application_specific_pool; | |||
friend void booster::intrusive_ptr_add_ref(application *p); | |||
friend void booster::intrusive_ptr_release(application *p); | |||
}; | |||
@@ -12,16 +12,89 @@ | |||
#include <booster/noncopyable.h> | |||
#include <booster/hold_ptr.h> | |||
#include <booster/intrusive_ptr.h> | |||
#include <booster/shared_ptr.h> | |||
#include <booster/weak_ptr.h> | |||
#include <booster/enable_shared_from_this.h> | |||
#include <memory> | |||
#include <string> | |||
namespace cppcms { | |||
class application; | |||
} | |||
namespace booster { | |||
void CPPCMS_API intrusive_ptr_add_ref(cppcms::application *p); | |||
void CPPCMS_API intrusive_ptr_release(cppcms::application *p); | |||
} | |||
namespace cppcms { | |||
class service; | |||
class mount_point; | |||
class application_specific_pool; | |||
class applications_pool; | |||
namespace http { | |||
class context; | |||
} | |||
/// | |||
/// Flags for application pool management | |||
/// | |||
namespace app { | |||
static const int synchronous = 0x0000; ///< Synchronous application | |||
static const int asynchronous = 0x0001; ///< Asynchronous application that operates in asynchronous mode | |||
// TBD | |||
//static const int content_filter = 0x0002; ///< Asynchronous application that validates incoming content during upload | |||
static const int op_mode_mask = 0x000F; /// mask to select sync vs async flags | |||
static const int thread_specific= 0x0010; ///< Make synchronous application thread specific | |||
/// \cond INTERNAL | |||
static const int legacy = 0x8000; ///< Use legacy handling of application life time when the application is created in the event loop and than dispatched as a job to a thread pool | |||
/// \endcond | |||
} | |||
/// | |||
/// \brief an interface for creating user applications | |||
/// | |||
class CPPCMS_API application_specific_pool : | |||
public booster::noncopyable, | |||
public booster::enable_shared_from_this<application_specific_pool> | |||
{ | |||
public: | |||
application_specific_pool(); | |||
virtual ~application_specific_pool(); | |||
int flags(); | |||
void flags(int f); | |||
protected: | |||
/// | |||
/// Returns newly created instance of an application, its ownership | |||
/// is transferred | |||
/// | |||
virtual application *new_application(service &srv) = 0; | |||
private: | |||
friend class applications_pool; | |||
friend class http::context; | |||
friend void booster::intrusive_ptr_release(cppcms::application *app); | |||
application *get_new(service &srv); | |||
void size(size_t n); | |||
booster::intrusive_ptr<application> get(service &); | |||
void put(application *app); | |||
struct _data; | |||
class _policy; | |||
class _tls_policy; | |||
class _pool_policy; | |||
class _async_policy; | |||
class _async_legacy_policy; | |||
booster::hold_ptr<_data> d; | |||
}; | |||
/// | |||
/// \brief Application pool is the central class that holds user created applications | |||
/// | |||
@@ -42,7 +115,10 @@ namespace cppcms { | |||
public: | |||
/// | |||
/// \brief a base class for user application factories | |||
/// \brief a base class for user application factories - to be deprecated, use | |||
/// application_specific_pool instead | |||
/// | |||
/// \deprecated Use application_specific_pool | |||
/// | |||
struct factory : public booster::noncopyable { | |||
/// | |||
@@ -58,6 +134,8 @@ namespace cppcms { | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
/// \deprecated Use mount(booster::shared_ptr<application_specific_pool> gen,int application_options) instead | |||
/// | |||
void mount(std::auto_ptr<factory> aps); | |||
/// | |||
@@ -66,7 +144,8 @@ namespace cppcms { | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
/// \deprecated Use mount(booster::shared_ptr<application_specific_pool> gen,mount_point const &point,int application_options) instead | |||
/// | |||
void mount(std::auto_ptr<factory> aps,mount_point const &point); | |||
/// | |||
@@ -75,6 +154,8 @@ namespace cppcms { | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
/// \deprecated Use mount(booster::shared_ptr<application_specific_pool> gen,int application_options) with application_options=app::asynchronous instead | |||
/// | |||
void mount(booster::intrusive_ptr<application> app); | |||
/// | |||
/// Mount an asynchronous application \a app by mount_point \a point application matching and | |||
@@ -82,14 +163,45 @@ namespace cppcms { | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
/// \deprecated Use mount(booster::shared_ptr<application_specific_pool> gen,mount_point const &point,int application_options) with application_options=app::asynchronous instead | |||
/// | |||
void mount(booster::intrusive_ptr<application> app,mount_point const &point); | |||
/// | |||
/// Mount a application_specific_pool for an application that processes all requests, path provided to application's main is PATH_INFO | |||
/// | |||
/// \a application_options allow to specify mode of operation - synchronous, asynchronous, see namespace | |||
/// cppcms::app | |||
/// | |||
/// Note: applications_pool owns gen now and is responsible for destroying it | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(booster::shared_ptr<application_specific_pool> gen,int application_options = 0); | |||
/// | |||
/// Mount a application_specific_pool to a specific mount point | |||
/// | |||
/// \a application_options allow to specify mode of operation - synchronous, asynchronous, see namespace | |||
/// cppcms::app | |||
/// | |||
/// Note: applications_pool owns gen now and is responsible for destroying it | |||
/// | |||
/// This member function is thread safe. | |||
/// | |||
void mount(booster::shared_ptr<application_specific_pool> gen,mount_point const &point,int application_options = 0); | |||
/// \cond INTERNAL | |||
/// get is not in use any more | |||
booster::intrusive_ptr<application> | |||
get(char const *h,char const *s,char const *path_info,std::string &match); | |||
booster::shared_ptr<application_specific_pool> | |||
get_application_specific_pool(char const *h,char const *s,char const *path_info,std::string &match); | |||
// put is not in use any more | |||
void put(application *app); | |||
applications_pool(service &srv,int pool_size_limit); | |||
~applications_pool(); | |||
@@ -97,9 +209,6 @@ namespace cppcms { | |||
/// \endcond | |||
private: | |||
struct basic_app_data; | |||
struct app_data; | |||
struct long_running_app_data; | |||
struct _data; | |||
service *srv_; | |||
booster::hold_ptr<_data> d; | |||
@@ -147,6 +256,8 @@ namespace cppcms { | |||
/// Create application factory for application of type T, such as T has a constructor | |||
/// T::T(cppcms::service &s); | |||
/// | |||
/// \deprecated Use applications_genrator | |||
/// | |||
template<typename T> | |||
std::auto_ptr<applications_pool::factory> applications_factory() | |||
{ | |||
@@ -158,6 +269,8 @@ namespace cppcms { | |||
/// Create application factory for application of type T, such as T has a constructor | |||
/// T::T(cppcms::service &s,P1); | |||
/// | |||
/// \deprecated Use applications_genrator | |||
/// | |||
template<typename T,typename P1> | |||
std::auto_ptr<applications_pool::factory> applications_factory(P1 p1) | |||
{ | |||
@@ -169,6 +282,8 @@ namespace cppcms { | |||
/// Create application factory for application of type T, such as T has a constructor | |||
/// T::T(cppcms::service &s,P1,P2); | |||
/// | |||
/// \deprecated Use applications_genrator | |||
/// | |||
template<typename T,typename P1,typename P2> | |||
std::auto_ptr<applications_pool::factory> applications_factory(P1 p1,P2 p2) | |||
{ | |||
@@ -176,6 +291,79 @@ namespace cppcms { | |||
return f; | |||
} | |||
/// \cond INTERNAL | |||
namespace details { | |||
template<typename T> | |||
struct simple_application_specific_pool0 : public application_specific_pool | |||
{ | |||
T *new_application(service &s) | |||
{ | |||
return new T(s); | |||
} | |||
}; | |||
template<typename T,typename P1> | |||
struct simple_application_specific_pool1 : public application_specific_pool | |||
{ | |||
simple_application_specific_pool1(P1 p1) : p1_(p1) {} | |||
P1 p1_; | |||
T *new_application(service &s) | |||
{ | |||
return new T(s,p1_); | |||
} | |||
}; | |||
template<typename T,typename P1,typename P2> | |||
struct simple_application_specific_pool2 : public application_specific_pool | |||
{ | |||
simple_application_specific_pool2(P1 p1,P2 p2) : p1_(p1),p2_(p2) {} | |||
P1 p1_; | |||
P2 p2_; | |||
T *new_application(service &s) | |||
{ | |||
return new T(s,p1_,p2_); | |||
} | |||
}; | |||
} // details | |||
/// \endcond | |||
/// | |||
/// Create application application_specific_pool for application of type T, such as T has a constructor | |||
/// T::T(cppcms::service &s); | |||
/// | |||
/// \deprecated Use applications_genrator | |||
/// | |||
template<typename T> | |||
booster::shared_ptr<application_specific_pool> create_pool() | |||
{ | |||
booster::shared_ptr<application_specific_pool> f(new details::simple_application_specific_pool0<T>); | |||
return f; | |||
} | |||
/// | |||
/// Create application application_specific_pool for application of type T, such as T has a constructor | |||
/// T::T(cppcms::service &s,P1); | |||
/// | |||
/// \deprecated Use applications_genrator | |||
/// | |||
template<typename T,typename P1> | |||
booster::shared_ptr<application_specific_pool> create_pool(P1 p1) | |||
{ | |||
booster::shared_ptr<application_specific_pool> f(new details::simple_application_specific_pool1<T,P1>(p1)); | |||
return f; | |||
} | |||
/// | |||
/// Create application application_specific_pool for application of type T, such as T has a constructor | |||
/// T::T(cppcms::service &s,P1,P2); | |||
/// | |||
/// \deprecated Use applications_genrator | |||
/// | |||
template<typename T,typename P1,typename P2> | |||
booster::shared_ptr<application_specific_pool> create_pool(P1 p1,P2 p2) | |||
{ | |||
booster::shared_ptr<application_specific_pool> f(new details::simple_application_specific_pool2<T,P1,P2>(p1,p2)); | |||
return f; | |||
} | |||
} // cppcms | |||
@@ -21,6 +21,7 @@ namespace cppcms { | |||
class service; | |||
class application; | |||
class application_specific_pool; | |||
class cache_interface; | |||
class session_interface; | |||
namespace json { class value; } | |||
@@ -165,7 +166,8 @@ namespace cppcms { | |||
void async_on_peer_reset(booster::callback<void()> const &h); | |||
private: | |||
void on_request_ready(bool error); | |||
static void dispatch(booster::intrusive_ptr<application> app,std::string url,bool syncronous); | |||
static void dispatch(booster::shared_ptr<application_specific_pool> const &pool,booster::shared_ptr<context> const &self,std::string const &url); | |||
static void dispatch(booster::intrusive_ptr<application> const &app,std::string const &url,bool syncronous); | |||
void try_restart(bool e); | |||
booster::shared_ptr<context> self(); | |||
@@ -31,16 +31,15 @@ namespace cppcms { | |||
struct application::_data { | |||
_data(cppcms::service *s): | |||
service(s), | |||
pool_id(-1) | |||
service(s) | |||
{ | |||
} | |||
cppcms::service *service; | |||
booster::shared_ptr<http::context> conn; | |||
int pool_id; | |||
url_dispatcher url; | |||
booster::hold_ptr<url_mapper> url_map; | |||
std::vector<application *> managed_children; | |||
booster::weak_ptr<application_specific_pool> my_pool; | |||
}; | |||
application::application(cppcms::service &srv) : | |||
@@ -110,7 +109,10 @@ booster::shared_ptr<http::context> application::release_context() | |||
bool application::is_asynchronous() | |||
{ | |||
return pool_id() < 0; | |||
booster::shared_ptr<application_specific_pool> p=d->my_pool.lock(); | |||
if(p && (p->flags() & app::op_mode_mask) != 0) | |||
return true; | |||
return false; | |||
} | |||
void application::assign_context(booster::shared_ptr<http::context> conn) | |||
@@ -118,14 +120,14 @@ void application::assign_context(booster::shared_ptr<http::context> conn) | |||
root()->d->conn=conn; | |||
} | |||
void application::pool_id(int id) | |||
void application::set_pool(booster::weak_ptr<application_specific_pool> p) | |||
{ | |||
d->pool_id=id; | |||
d->my_pool = p; | |||
} | |||
int application::pool_id() | |||
booster::weak_ptr<application_specific_pool> application::get_pool() | |||
{ | |||
return d->pool_id; | |||
return d->my_pool; | |||
} | |||
application *application::parent() | |||
@@ -362,33 +364,27 @@ namespace booster { | |||
// REMEMBER THIS IS CALLED FROM DESTRUCTOR!!! | |||
void intrusive_ptr_release(cppcms::application *app) | |||
{ | |||
// it is called in destructors... So be very careful | |||
if(!app) | |||
return; | |||
try { | |||
app = app->root(); | |||
long refs=--(app->refs_); | |||
if(refs > 0) | |||
return; | |||
cppcms::service &service=app->service(); | |||
try { | |||
app->recycle(); | |||
} | |||
catch(...) { | |||
if(app->pool_id() < 0) { | |||
service.applications_pool().put(app); | |||
} | |||
else | |||
delete app; | |||
throw; | |||
app->recycle(); | |||
booster::shared_ptr<cppcms::application_specific_pool> p = app->get_pool().lock(); | |||
if(p) { | |||
cppcms::application *tmp = app; | |||
app = 0; | |||
p->put(tmp); | |||
} | |||
service.applications_pool().put(app); | |||
// return the application to pool... or delete it if "pooled" | |||
else | |||
delete app; | |||
} | |||
catch(...) | |||
{ | |||
// FIXME LOG IT? | |||
if(app) | |||
delete app; | |||
} | |||
} | |||
} // booster |
@@ -12,146 +12,362 @@ | |||
#include <cppcms/mount_point.h> | |||
#include <cppcms/cppcms_error.h> | |||
#include <cppcms/json.h> | |||
#include <set> | |||
#include <list> | |||
#include <vector> | |||
#include <cppcms/config.h> | |||
#include <booster/regex.h> | |||
#include <booster/shared_ptr.h> | |||
#include <booster/thread.h> | |||
#include <booster/log.h> | |||
namespace cppcms { | |||
struct applications_pool::basic_app_data : public booster::noncopyable { | |||
basic_app_data(mount_point const &p) : | |||
mount_point_(p) | |||
{ | |||
} | |||
mount_point mount_point_; | |||
}; | |||
struct applications_pool::app_data : public applications_pool::basic_app_data { | |||
app_data(mount_point const &p,std::auto_ptr<applications_pool::factory> f) : | |||
basic_app_data(p), | |||
factory(f), | |||
size(0) | |||
{ | |||
} | |||
std::auto_ptr<applications_pool::factory> factory; | |||
class application_specific_pool::_policy { | |||
public: | |||
_policy(application_specific_pool *self) : self_(self) {} | |||
virtual ~_policy() {} | |||
virtual booster::intrusive_ptr<application> get(cppcms::service &srv) = 0; | |||
virtual void put(application *app) = 0; | |||
application *get_new(cppcms::service &srv) { return self_->get_new(srv); } | |||
protected: | |||
application_specific_pool *self_; | |||
}; | |||
class application_specific_pool::_tls_policy : public application_specific_pool::_policy { | |||
public: | |||
_tls_policy(application_specific_pool *self) : application_specific_pool::_policy(self) {} | |||
virtual booster::intrusive_ptr<application> get(cppcms::service &srv) | |||
{ | |||
application *app = tss_.release(); | |||
if(!app) | |||
return get_new(srv); | |||
return app; | |||
} | |||
virtual void put(application *app) | |||
{ | |||
if(!app) | |||
return; | |||
tss_.reset(app); | |||
} | |||
private: | |||
booster::thread_specific_ptr<application> tss_; | |||
}; | |||
class application_specific_pool::_pool_policy : public application_specific_pool::_policy{ | |||
public: | |||
_pool_policy(application_specific_pool *self,size_t n) : | |||
_policy(self) | |||
{ | |||
apps_.resize(n,0); | |||
size_ = 0; | |||
} | |||
~_pool_policy() | |||
{ | |||
for(size_t i=0;i<size_;i++) | |||
delete apps_[i]; | |||
} | |||
virtual booster::intrusive_ptr<application> get(cppcms::service &srv) | |||
{ | |||
if(size_ == 0) | |||
return get_new(srv); | |||
size_ --; | |||
application *app = apps_[size_]; | |||
apps_[size_]=0; | |||
return app; | |||
} | |||
virtual void put(application *app) | |||
{ | |||
if(!app) | |||
return; | |||
if(size_ >= apps_.size()) | |||
delete app; | |||
apps_[size_++] = app; | |||
} | |||
private: | |||
std::vector<application *> apps_; | |||
size_t size_; | |||
}; | |||
class application_specific_pool::_async_policy : public application_specific_pool::_policy{ | |||
public: | |||
_async_policy(application_specific_pool *self) : _policy(self) {} | |||
virtual booster::intrusive_ptr<application> get(cppcms::service &srv) | |||
{ | |||
if(!app_) | |||
app_ = get_new(srv); | |||
return app_; | |||
} | |||
virtual void put(application *) | |||
{ | |||
// SHOULD NEVER BE CALLED as when pool is destroyed and app_ is destroyed weak_ptr would be invalid | |||
} | |||
private: | |||
booster::intrusive_ptr<application> app_; | |||
}; | |||
int size; | |||
std::set<application *> pool; | |||
class application_specific_pool::_async_legacy_policy : public application_specific_pool::_policy{ | |||
public: | |||
_async_legacy_policy(application_specific_pool *self) : | |||
_policy(self), | |||
app_(0) | |||
{ | |||
} | |||
virtual booster::intrusive_ptr<application> get(cppcms::service &srv) | |||
{ | |||
if(self_->flags()==-1) | |||
return 0; | |||
if(!app_) | |||
app_ = get_new(srv); | |||
return app_; | |||
} | |||
virtual void put(application *app) | |||
{ | |||
if(!app) | |||
return; | |||
delete app; | |||
app_ = 0; | |||
self_->flags(-1); | |||
} | |||
private: | |||
application *app_; | |||
}; | |||
struct application_specific_pool::_data { | |||
int flags; | |||
size_t size; | |||
booster::hold_ptr<application_specific_pool::_policy> policy; | |||
booster::recursive_mutex lock; | |||
}; | |||
application_specific_pool::~application_specific_pool() | |||
{ | |||
} | |||
application_specific_pool::application_specific_pool() : d(new application_specific_pool::_data()) | |||
{ | |||
d->flags = 0; | |||
d->size = 0; | |||
} | |||
int application_specific_pool::flags() | |||
{ | |||
return d->flags; | |||
} | |||
void application_specific_pool::flags(int flags) | |||
{ | |||
if(d->flags == -1 || d->policy.get()) | |||
return; | |||
d->flags = flags; | |||
if(flags == -1) | |||
return; | |||
~app_data() | |||
if(flags == (app::asynchronous | app::legacy)) { | |||
d->policy.reset(new _async_legacy_policy(this)); | |||
return; | |||
} | |||
if(flags == app::legacy) { | |||
d->policy.reset(new _pool_policy(this,d->size)); | |||
return; | |||
} | |||
if((flags & app::op_mode_mask) != app::synchronous) { | |||
d->policy.reset(new _async_policy(this)); | |||
return; | |||
} | |||
if(flags & app::thread_specific) { | |||
d->policy.reset(new _tls_policy(this)); | |||
} | |||
else { | |||
d->policy.reset(new _pool_policy(this,d->size)); | |||
} | |||
} | |||
void application_specific_pool::size(size_t n) | |||
{ | |||
d->size = n; | |||
} | |||
application *application_specific_pool::get_new(service &srv) | |||
{ | |||
application *a = new_application(srv); | |||
if(!a) | |||
return 0; | |||
a->set_pool(shared_from_this()); | |||
return a; | |||
} | |||
void application_specific_pool::put(application *a) | |||
{ | |||
booster::unique_lock<booster::recursive_mutex> g(d->lock); | |||
if(d->flags == -1) { | |||
delete a; | |||
return; | |||
} | |||
assert(d->policy.get()); | |||
d->policy->put(a); | |||
} | |||
booster::intrusive_ptr<application> application_specific_pool::get(cppcms::service &srv) | |||
{ | |||
booster::unique_lock<booster::recursive_mutex> g(d->lock); | |||
if(d->flags == -1) | |||
return 0; | |||
assert(d->policy.get()); | |||
booster::intrusive_ptr<application> app = d->policy->get(srv); | |||
return app; | |||
} | |||
namespace impl { | |||
class legacy_sync_pool : public application_specific_pool { | |||
public: | |||
legacy_sync_pool(std::auto_ptr<applications_pool::factory> f) | |||
{ | |||
std::set<application *>::iterator p; | |||
for(p=pool.begin();p!=pool.end();++p) { | |||
delete *p; | |||
} | |||
fact_ = f; | |||
} | |||
application *new_application(cppcms::service &srv) | |||
{ | |||
std::auto_ptr<application> a = (*fact_)(srv); | |||
return a.release(); | |||
} | |||
private: | |||
std::auto_ptr<applications_pool::factory> fact_; | |||
}; | |||
struct applications_pool::long_running_app_data : public applications_pool::basic_app_data | |||
class legacy_async_pool : public application_specific_pool | |||
{ | |||
long_running_app_data(mount_point const &p) : basic_app_data(p) | |||
public: | |||
legacy_async_pool(booster::intrusive_ptr<application> app) | |||
{ | |||
my_ = app.get(); | |||
} | |||
application *new_application(cppcms::service &) | |||
{ | |||
application *a = my_; | |||
my_ = 0; | |||
return a; | |||
} | |||
private: | |||
application *my_; | |||
}; | |||
} // impl | |||
struct applications_pool::_data { | |||
struct applications_pool::_data { | |||
std::vector<booster::shared_ptr<app_data> > apps; | |||
typedef std::map<application *,booster::shared_ptr<long_running_app_data> > long_running_aps_type; | |||
long_running_aps_type long_running_aps; | |||
int limit; | |||
booster::recursive_mutex mutex; | |||
struct attachment { | |||
mount_point mp; | |||
booster::shared_ptr<application_specific_pool> pool; | |||
attachment(booster::shared_ptr<application_specific_pool> p,mount_point const &m) : mp(m), pool(p) {} | |||
}; | |||
typedef booster::unique_lock<booster::recursive_mutex> lock_it; | |||
std::list<attachment> apps; | |||
std::list<attachment> legacy_async_apps; | |||
int legacy_limit; | |||
int thread_count; | |||
booster::recursive_mutex lock; | |||
}; | |||
applications_pool::applications_pool(service &srv,int limit) : | |||
applications_pool::applications_pool(service &srv,int pool_size_limit) : | |||
srv_(&srv), | |||
d(new applications_pool::_data()) | |||
{ | |||
d->limit=limit; | |||
d->legacy_limit=pool_size_limit; | |||
d->thread_count = srv_->threads_no(); | |||
} | |||
applications_pool::~applications_pool() | |||
{ | |||
} | |||
void applications_pool::mount(std::auto_ptr<factory> aps) | |||
void applications_pool::mount(std::auto_ptr<factory> aps,mount_point const &mp) | |||
{ | |||
lock_it lock(d->mutex); | |||
d->apps.push_back(booster::shared_ptr<app_data>(new app_data(mount_point(),aps))); | |||
booster::shared_ptr<application_specific_pool> p(new impl::legacy_sync_pool(aps)); | |||
p->size(d->legacy_limit); | |||
p->flags(app::legacy); | |||
booster::unique_lock<booster::recursive_mutex> lock(d->lock); | |||
d->apps.push_back(_data::attachment(p,mp)); | |||
} | |||
void applications_pool::mount(std::auto_ptr<factory> aps,mount_point const &p) | |||
void applications_pool::mount(std::auto_ptr<factory> aps) | |||
{ | |||
lock_it lock(d->mutex); | |||
d->apps.push_back(booster::shared_ptr<app_data>(new app_data(p,aps))); | |||
mount(aps,mount_point()); | |||
} | |||
void applications_pool::mount(booster::intrusive_ptr<application> app) | |||
{ | |||
lock_it lock(d->mutex); | |||
d->long_running_aps[app.get()]= | |||
booster::shared_ptr<long_running_app_data>(new long_running_app_data(mount_point())); | |||
mount(app,mount_point()); | |||
} | |||
void applications_pool::mount(booster::intrusive_ptr<application> app,mount_point const &p) | |||
void applications_pool::mount(booster::intrusive_ptr<application> app,mount_point const &mp) | |||
{ | |||
lock_it lock(d->mutex); | |||
d->long_running_aps[app.get()]= | |||
booster::shared_ptr<long_running_app_data>(new long_running_app_data(p)); | |||
booster::shared_ptr<application_specific_pool> p(new impl::legacy_async_pool(app)); | |||
p->flags(app::legacy | app::asynchronous); | |||
booster::unique_lock<booster::recursive_mutex> lock(d->lock); | |||
d->legacy_async_apps.push_back(_data::attachment(p,mp)); | |||
} | |||
booster::intrusive_ptr<application> applications_pool::get( char const *host, | |||
char const *script_name, | |||
char const *path_info, | |||
std::string &m) | |||
void applications_pool::mount(booster::shared_ptr<application_specific_pool> gen,mount_point const &point,int flags) | |||
{ | |||
lock_it lock(d->mutex); | |||
for(unsigned i=0;i<d->apps.size();i++) { | |||
std::pair<bool,std::string> match = d->apps[i]->mount_point_.match(host,script_name,path_info); | |||
if(match.first==false) | |||
continue; | |||
m=match.second; | |||
if(flags & app::legacy) { | |||
throw cppcms_error("Direct specification of cppcms::app::legacy flag is forbidden"); | |||
} | |||
gen->size(d->thread_count); | |||
gen->flags(flags); | |||
booster::unique_lock<booster::recursive_mutex> lock(d->lock); | |||
d->apps.push_back(_data::attachment(gen,point)); | |||
} | |||
if(d->apps[i]->pool.empty()) { | |||
booster::intrusive_ptr<application> app=(*d->apps[i]->factory)(*srv_).release(); | |||
app->pool_id(i); | |||
return app; | |||
} | |||
void applications_pool::mount(booster::shared_ptr<application_specific_pool> gen,int flags) | |||
{ | |||
mount(gen,mount_point(),flags); | |||
} | |||
d->apps[i]->size--; | |||
booster::intrusive_ptr<application> app(*(d->apps[i]->pool.begin())); | |||
d->apps[i]->pool.erase(app.get()); | |||
return app; | |||
} | |||
for(_data::long_running_aps_type::iterator p=d->long_running_aps.begin();p!=d->long_running_aps.end();++p){ | |||
std::pair<bool,std::string> match = p->second->mount_point_.match(host,script_name,path_info); | |||
if(match.first == false) | |||
booster::shared_ptr<application_specific_pool> | |||
applications_pool::get_application_specific_pool(char const *host,char const *script_name,char const *path_info,std::string &match) | |||
{ | |||
booster::unique_lock<booster::recursive_mutex> lock(d->lock); | |||
for(std::list<_data::attachment>::iterator it = d->apps.begin();it!=d->apps.end();++it) { | |||
std::pair<bool,std::string> m = it->mp.match(host,script_name,path_info); | |||
if(!m.first) | |||
continue; | |||
m=match.second; | |||
booster::intrusive_ptr<application> app=p->first; | |||
return app; | |||
match = m.second; | |||
return it->pool; | |||
} | |||
booster::shared_ptr<application_specific_pool> result; | |||
for(std::list<_data::attachment>::iterator itr = d->legacy_async_apps.begin();itr!=d->legacy_async_apps.end();) { | |||
std::list<_data::attachment>::iterator app_it = itr; | |||
++itr; | |||
if(app_it->pool->flags() == -1) { | |||
d->legacy_async_apps.erase(app_it); | |||
} | |||
else if (!result) { | |||
std::pair<bool,std::string> m = app_it->mp.match(host,script_name,path_info); | |||
if(!m.first) | |||
continue; | |||
match = m.second; | |||
result = app_it->pool; | |||
} | |||
} | |||
return 0; | |||
return result; | |||
} | |||
void applications_pool::put(application *app) | |||
booster::intrusive_ptr<application> applications_pool::get( char const *, | |||
char const *, | |||
char const *, | |||
std::string &) | |||
{ | |||
lock_it lock(d->mutex); | |||
if(!app) return; | |||
int id=app->pool_id(); | |||
if(id < 0) { | |||
d->long_running_aps.erase(app); | |||
delete app; | |||
return; | |||
} | |||
if(unsigned(id) >= d->apps.size() || d->apps[id]->size >= d->limit) { | |||
delete app; | |||
return; | |||
} | |||
d->apps[id]->pool.insert(app); | |||
d->apps[id]->size++; | |||
throw cppcms_error("THIS IS INTERNAL MEMBER FUNCTION METHOD MUST NOT BE USED"); | |||
} | |||
void applications_pool::put(application *) | |||
{ | |||
BOOSTER_WARNING("cppcms") << "CALL OF INTERNAL METHOD"; | |||
} | |||
@@ -89,12 +89,21 @@ void context::run() | |||
} | |||
namespace { | |||
struct dispatcher { | |||
void (*func)(booster::intrusive_ptr<application>,std::string,bool); | |||
struct dispatcher_legacy { | |||
void (*func)(booster::intrusive_ptr<application> const &,std::string const &,bool); | |||
booster::intrusive_ptr<application> app; | |||
std::string url; | |||
void operator()() { func(app,url,true); } | |||
}; | |||
struct dispatcher { | |||
void (*func)(booster::shared_ptr<application_specific_pool> const &,booster::shared_ptr<context> const &,std::string const &); | |||
booster::shared_ptr<application_specific_pool> pool; | |||
booster::shared_ptr<context> ctx; | |||
std::string url; | |||
void operator()() { | |||
func(pool,ctx,url); | |||
} | |||
}; | |||
} | |||
void context::on_request_ready(bool error) | |||
@@ -106,28 +115,56 @@ void context::on_request_ready(bool error) | |||
char const *script_name = conn_->cgetenv("SCRIPT_NAME"); | |||
std::string matched; | |||
booster::intrusive_ptr<application> app = service().applications_pool().get(host,script_name,path_info,matched); | |||
booster::shared_ptr<application_specific_pool> pool = | |||
service().applications_pool().get_application_specific_pool( | |||
host, | |||
script_name, | |||
path_info, | |||
matched | |||
); | |||
if(!app) { | |||
if(!pool) { | |||
response().io_mode(http::response::asynchronous); | |||
response().make_error_response(http::response::not_found); | |||
async_complete_response(); | |||
return; | |||
} | |||
app->assign_context(self()); | |||
if(app->is_asynchronous()) { | |||
response().io_mode(http::response::asynchronous); | |||
if(pool->flags() == (app::legacy | app::synchronous) || (pool->flags() & app::op_mode_mask)!=app::synchronous) { | |||
// synchronous legacy | |||
booster::intrusive_ptr<application> app = pool->get(service()); | |||
if(!app) { | |||
response().io_mode(http::response::asynchronous); | |||
response().make_error_response(http::response::internal_server_error); | |||
async_complete_response(); | |||
return; | |||
} | |||
app->assign_context(self()); | |||
if(pool->flags() == app::legacy) { | |||
dispatcher_legacy dt; | |||
dt.func = &context::dispatch; | |||
dt.app = app; | |||
dt.url.swap(matched); | |||
app->service().thread_pool().post(dt); | |||
return; | |||
} | |||
// Don't post, as context may be reassigned | |||
response().io_mode(http::response::asynchronous); | |||
dispatch(app,matched,false); | |||
return; | |||
} | |||
else { | |||
dispatcher dt; | |||
dt.func = &context::dispatch; | |||
dt.app = app; | |||
dt.pool = pool; | |||
dt.ctx = self(); | |||
dt.url.swap(matched); | |||
app->service().thread_pool().post(dt); | |||
service().thread_pool().post(dt); | |||
return; | |||
} | |||
} | |||
@@ -151,7 +188,19 @@ void context::complete_response() | |||
conn_.reset(); | |||
} | |||
// static | |||
void context::dispatch(booster::intrusive_ptr<application> app,std::string url,bool syncronous) | |||
void context::dispatch(booster::shared_ptr<application_specific_pool> const &pool,booster::shared_ptr<context> const &self,std::string const &url) | |||
{ | |||
booster::intrusive_ptr<application> app = pool->get(self->service()); | |||
if(!app) { | |||
self->response().make_error_response(http::response::internal_server_error); | |||
self->complete_response(); | |||
return; | |||
} | |||
app->assign_context(self); | |||
dispatch(app,url,true); | |||
} | |||
// static | |||
void context::dispatch(booster::intrusive_ptr<application> const &app,std::string const &url,bool syncronous) | |||
{ | |||
try { | |||
if(syncronous && !app->context().service().cached_settings().session.disable_automatic_load) | |||
@@ -189,14 +238,6 @@ void context::dispatch(booster::intrusive_ptr<application> app,std::string url,b | |||
} | |||
} | |||
namespace { | |||
void wrapper(context::handler const &h,bool r) | |||
{ | |||
h(r ? context::operation_aborted : context::operation_completed); | |||
} | |||
} | |||
void context::async_flush_output(context::handler const &h) | |||
{ | |||
if(response().io_mode() != http::response::asynchronous && response().io_mode()!=http::response::asynchronous_raw) { | |||
@@ -76,7 +76,7 @@ int main(int argc,char **argv) | |||
try { | |||
basic_test(); | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
} | |||
@@ -28,7 +28,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount(cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount(cppcms::create_pool<unit_test>()); | |||
srv.run(); | |||
} | |||
catch(std::exception const &e) { | |||
@@ -165,13 +165,17 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
booster::intrusive_ptr<cppcms::application> async = new async_unit_test(srv); | |||
booster::intrusive_ptr<cppcms::application> nb = new nonblocking_unit_test(srv); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<async_unit_test>(), | |||
cppcms::mount_point("/async"), | |||
cppcms::app::asynchronous); | |||
srv.applications_pool().mount( async, cppcms::mount_point("/async") ); | |||
srv.applications_pool().mount( nb, cppcms::mount_point("/nonblocking") ); | |||
srv.applications_pool().mount( | |||
cppcms::create_pool<nonblocking_unit_test>(), | |||
cppcms::mount_point("/nonblocking"), | |||
cppcms::app::asynchronous); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>(), cppcms::mount_point("/sync")); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>(), cppcms::mount_point("/sync")); | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
} | |||
@@ -273,7 +273,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
} | |||
@@ -116,7 +116,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
if(srv.settings().find("test.exec").type()==cppcms::json::is_string) | |||
srv.after_fork(submitter(srv)); | |||
@@ -63,7 +63,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
} | |||
@@ -141,9 +141,10 @@ int main(int argc,char **argv) | |||
try { | |||
cppcms::service srv(argc,argv); | |||
write_tests = srv.settings().get("test.write",false); | |||
booster::intrusive_ptr<cppcms::application> async = new async_test(srv); | |||
srv.applications_pool().mount( async, cppcms::mount_point("/async") ); | |||
srv.applications_pool().mount( cppcms::applications_factory<sync_test>(), cppcms::mount_point("/sync")); | |||
srv.applications_pool().mount( cppcms::create_pool<async_test>(), | |||
cppcms::mount_point("/async"), | |||
cppcms::app::asynchronous); | |||
srv.applications_pool().mount( cppcms::create_pool<sync_test>(), cppcms::mount_point("/sync")); | |||
srv.after_fork(submitter(srv)); | |||
cppcms::copy_filter flt(std::cerr); // record the log | |||
srv.run(); | |||
@@ -107,7 +107,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<json_service>()); | |||
srv.applications_pool().mount( cppcms::create_pool<json_service>()); | |||
if(srv.settings().type("test.exec")!=cppcms::json::is_undefined) | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
@@ -61,10 +61,9 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
booster::intrusive_ptr<cppcms::application> app; | |||
if(srv.settings().get("test.async","sync")=="sync") { | |||
std::cout << "Synchronous testing" << std::endl; | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
} | |||
else { | |||
if(srv.settings().get<std::string>("test.async")=="async") { | |||
@@ -80,8 +79,7 @@ int main(int argc,char **argv) | |||
std::cerr << "Invalid configuration value of test.async" << std::endl; | |||
return 1; | |||
} | |||
app=new unit_test(srv); | |||
srv.applications_pool().mount(app); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>(),cppcms::app::asynchronous); | |||
} | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
@@ -62,7 +62,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
} | |||
@@ -200,7 +200,7 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||
} | |||
@@ -108,15 +108,13 @@ int main(int argc,char **argv) | |||
{ | |||
try { | |||
cppcms::service srv(argc,argv); | |||
booster::intrusive_ptr<cppcms::application> app; | |||
if(srv.settings().get("test.async","sync")=="sync") { | |||
std::cerr << "Synchonous" << std::endl; | |||
srv.applications_pool().mount( cppcms::applications_factory<unit_test>()); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>()); | |||
} | |||
else { | |||
std::cerr << "Asynchonous" << std::endl; | |||
app=new unit_test(srv); | |||
srv.applications_pool().mount(app); | |||
srv.applications_pool().mount( cppcms::create_pool<unit_test>(),cppcms::app::asynchronous); | |||
} | |||
srv.after_fork(submitter(srv)); | |||
srv.run(); | |||