summaryrefslogtreecommitdiffabout
path: root/lib/component_so.cc
Side-by-side diff
Diffstat (limited to 'lib/component_so.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--lib/component_so.cc112
1 files changed, 112 insertions, 0 deletions
diff --git a/lib/component_so.cc b/lib/component_so.cc
new file mode 100644
index 0000000..57cce01
--- a/dev/null
+++ b/lib/component_so.cc
@@ -0,0 +1,112 @@
+#ifdef USE_PCH
+ #include "pch.h"
+#else
+ #include <unistd.h>
+ #include <dlfcn.h>
+ #include <iostream>
+ #include <cassert>
+ #include <stdexcept>
+ using namespace std;
+ #include "sitecing/component_so.h"
+ #include "sitecing/sitecing_util.h"
+#endif
+
+namespace sitecing {
+
+ /*
+ * component_so
+ */
+
+ component_so::component_so(const string& soname)
+ : dl(NULL), sofile(soname) {
+ if(stat(sofile.c_str(),&stso))
+ throw konforka::exception(CODEPOINT,"failed to stat() shared object");
+ file_lock lock(sofile+".lock");
+ dl = dlopen(sofile.c_str(),RTLD_LAZY);
+ lock.unlock();
+ if(!dl)
+ throw konforka::exception(CODEPOINT,"failed to dlopen: "+string(dlerror()));
+ egg = (egg_t)dlsym(dl,"_egg");
+ if(!egg)
+ throw konforka::exception(CODEPOINT,"failed to dlsym: "+string(dlerror()));
+ }
+ component_so::~component_so() {
+ for(free_chickens_t::iterator i=chickens_free.begin();i!=chickens_free.end();i++)
+ delete *i;
+ chickens_free.clear();
+ if(!chickens_used.empty())
+ throw konforka::exception(CODEPOINT,"attempt to destroy the component in use");
+ dlclose(dl);
+ }
+
+ bool component_so::is_uptodate() const {
+ struct stat st;
+ if(stat(sofile.c_str(),&st))
+ throw konforka::exception(CODEPOINT,"failed to stat() shared object");
+ return stso.st_mtime==st.st_mtime;
+ }
+
+ acomponent* component_so::allocate_chicken() {
+ acomponent *rv;
+ if(!chickens_free.empty()) {
+ rv = chickens_free.front();
+ chickens_free.pop_front();
+ }else{
+ rv = (*egg)();
+ }
+ assert(chickens_used.find(rv)==chickens_used.end());
+ chickens_used[rv]=1;
+ return rv;
+ }
+
+ void component_so::allocate_chicken(acomponent* ac) {
+ used_chickens_t::iterator i = chickens_used.find(ac);
+ if(i!=chickens_used.end()) {
+ i->second++;
+ }else{
+ free_chickens_t::iterator i;
+ for(i=chickens_free.begin();*i!=ac && i!=chickens_free.end();i++);
+ if(i==chickens_free.end())
+ throw konforka::exception(CODEPOINT,"hens rarely adopt chickens");
+ chickens_free.erase(i);
+ chickens_used[ac]=1;
+ }
+ }
+
+ void component_so::deallocate_chicken(acomponent* ac) {
+ used_chickens_t::iterator i = chickens_used.find(ac);
+ if(i==chickens_used.end())
+ throw konforka::exception(CODEPOINT,"you can't deallocate what is not allocated");
+ i->second--;
+ if(i->second>0)
+ return;
+ chickens_used.erase(i);
+ chickens_free.push_front(ac);
+ }
+
+ /*
+ * so_component
+ */
+
+ so_component::so_component(component_so *h,sitecing_interface *scif)
+ : hen(h), ac(NULL) {
+ if(!hen)
+ throw konforka::exception(CODEPOINT,"can't get an egg from the null-hen");
+ ac = hen->allocate_chicken();
+ ac->__set_interface(scif);
+ }
+
+ void so_component::attach(component_so *h,acomponent *a) {
+ detach(); hen = h; ac = a;
+ if(!ac)
+ throw konforka::exception(CODEPOINT,"trying to clone null-chicken");
+ if(!hen)
+ throw konforka::exception(CODEPOINT,"trying to clone orphan chicken");
+ hen->allocate_chicken(ac);
+ }
+ void so_component::detach() {
+ if(hen && ac)
+ hen->deallocate_chicken(ac);
+ }
+
+}