ceph提供了一个ClassHandler来管理动态链接库
使用ClassHandler 之前必要要先注册
ClassHandler::ClassData *ClassHandler::register_class(const char *cname)
{
assert(mutex.is_locked());
#根据name得到要使用的class
ClassData *cls = _get_class(cname, false);
ldout(cct, 10) << "register_class " << cname << " status " << cls->status << dendl;
#如果class的status不是CLASS_INITIALIZING,说明这里动态链接库并没有被加载进来,这里直接返回NULL
if (cls->status != ClassData::CLASS_INITIALIZING) {
ldout(cct, 0) << "class " << cname << " isn't loaded; is the class registering under the wrong name?" << dendl;
return NULL;
}
return cls;
}
继续看_get_class
ClassHandler::ClassData *ClassHandler::_get_class(const string& cname,
bool check_allowed)
{
ClassData *cls;
#通过map的find函数根据这个class的name找到对应clasdata
map<string, ClassData>::iterator iter = classes.find(cname);
#如果不等于classes.end说明找到这个class了,这里通过iter->second就可以得到ClassData,随意不能重复注册
if (iter != classes.end()) {
cls = &iter->second;
} else {
if (check_allowed && !in_class_list(cname, cct->_conf->osd_class_load_list)) {
ldout(cct, 0) << "_get_class not permitted to load " << cname << dendl;
return NULL;
}
#正常情况下应该走下面这段code 会新建一个ClassData.
cls = &classes[cname];
ldout(cct, 10) << "_get_class adding new class name " << cname << " " << cls << dendl;
cls->name = cname;
cls->handler = this;
cls->whitelisted = in_class_list(cname, cct->_conf->osd_class_default_list);
}
return cls;
}
注册类后要为这个类注册方法
ClassHandler::ClassMethod *ClassHandler::ClassData::register_method(const char *mname,
int flags,
cls_method_call_t func)
{
/* no need for locking, called under the class_init mutex */
if (!flags) {
lderr(handler->cct) << "register_method " << name << "." << mname
<< " flags " << flags << " " << (void*)func
<< " FAILED -- flags must be non-zero" << dendl;
return NULL;
}
ldout(handler->cct, 10) << "register_method " << name << "." << mname << " flags " << flags << " " << (void*)func << dendl;
ClassMethod& method = methods_map[mname];
method.func = func;
method.name = mname;
method.flags = flags;
method.cls = this;
return &method;
}
可以看到基本是为method赋值
当使用的时候要调用open_class来dlopen动态链接库
int ClassHandler::open_class(const string& cname, ClassData **pcls)
{
Mutex::Locker lock(mutex);
#通过调用_get_class来根据name得到class,不过在这次正确情况下可以找到class
ClassData *cls = _get_class(cname, true);
if (!cls)
return -EPERM;
#如果这个类没有open的话,则调用_load_class来dlopen
if (cls->status != ClassData::CLASS_OPEN) {
int r = _load_class(cls);
if (r)
return r;
}
*pcls = cls;
return 0;
}
int ClassHandler::_load_class(ClassData *cls)
{
// already open
#不能重复打开
if (cls->status == ClassData::CLASS_OPEN)
return 0;
if (cls->status == ClassData::CLASS_UNKNOWN ||
cls->status == ClassData::CLASS_MISSING) {
char fname[PATH_MAX];
snprintf(fname, sizeof(fname), "%s/" CLS_PREFIX "%s" CLS_SUFFIX,
cct->_conf->osd_class_dir.c_str(),
cls->name.c_str());
ldout(cct, 10) << "_load_class " << cls->name << " from " << fname << dendl;
#这里很清楚的看到是调用dlopen来打开这个class
cls->handle = dlopen(fname, RTLD_NOW);
if (!cls->handle) {
struct stat st;
int r = ::stat(fname, &st);
if (r < 0) {
r = -errno;
ldout(cct, 0) << __func__ << " could not stat class " << fname
<< ": " << cpp_strerror(r) << dendl;
} else {
ldout(cct, 0) << "_load_class could not open class " << fname
<< " (dlopen failed): " << dlerror() << dendl;
r = -EIO;
}
cls->status = ClassData::CLASS_MISSING;
return r;
}
#如果这个class 依赖其他class,则统计这些依赖类
cls_deps_t *(*cls_deps)();
cls_deps = (cls_deps_t *(*)())dlsym(cls->handle, "class_deps");
if (cls_deps) {
cls_deps_t *deps = cls_deps();
while (deps) {
if (!deps->name)
break;
#将这里依赖类保存到dependencies 中
ClassData *cls_dep = _get_class(deps->name, false);
cls->dependencies.insert(cls_dep);
if (cls_dep->status != ClassData::CLASS_OPEN)
cls->missing_dependencies.insert(cls_dep);
deps++;
}
}
}
// resolve dependencies
#统一load这些依赖类
set<ClassData*>::iterator p = cls->missing_dependencies.begin();
while (p != cls->missing_dependencies.end()) {
ClassData *dc = *p;
int r = _load_class(dc);
if (r < 0) {
cls->status = ClassData::CLASS_MISSING_DEPS;
return r;
}
ldout(cct, 10) << "_load_class " << cls->name << " satisfied dependency " << dc->name << dendl;
cls->missing_dependencies.erase(p++);
}
打开这个类后就可以调用exec 来执行这个类的方法
int ClassHandler::ClassMethod::exec(cls_method_context_t ctx, bufferlist& indata, bufferlist& outdata)
{
int ret;
if (cxx_func) {
// C++ call version
ret = cxx_func(ctx, &indata, &outdata);
} else {
// C version
char *out = NULL;
int olen = 0;
#这里的func 在register_method中赋值
ret = func(ctx, indata.c_str(), indata.length(), &out, &olen);
if (out) {
// assume *out was allocated via cls_alloc (which calls malloc!)
buffer::ptr bp = buffer::claim_malloc(olen, out);
outdata.push_back(bp);
}
}
return ret;
}
下来看一个编写helloworld的例子
static int say_hello(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
{
// see if the input data from the client matches what this method
// expects to receive. your class can fill this buffer with what it
// wants.
if (in->length() > 100)
return -EINVAL;
// we generate our reply
out->append("Hello, ");
if (in->length() == 0)
out->append("world");
else
out->append(*in);
out->append("!");
// this return value will be returned back to the librados caller
return 0;
}
/**
* initialize class
*
* We do two things here: we register the new class, and then register
* all of the class's methods.
*/
CLS_INIT(hello)
{
// this log message, at level 0, will always appear in the ceph-osd
// log file.
CLS_LOG(0, "loading cls_hello");
cls_handle_t h_class;
cls_method_handle_t h_say_hello;
#注册类
cls_register("hello", &h_class);
#为这个类注册方法
cls_register_cxx_method(h_class, "say_hello",
CLS_METHOD_RD,
say_hello, &h_say_hello);
}
ceph为了方便大家提供了一个套更简答的api,例如本例中的cls_register
int cls_register(const char *name, cls_handle_t *handle)
{
#可见还是调用上面讲到的register_class来进行
ClassHandler::ClassData *cls = ch->register_class(name);
*handle = (cls_handle_t)cls;
return (cls != NULL);
}
ceph 对动态加载类的管理
最新推荐文章于 2024-06-03 09:13:07 发布