summaryrefslogtreecommitdiffabout
path: root/lib/component_so.cc
blob: 57cce016519ee4327fea17345dae0be6a2fa51d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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);
    }

}