现在我们开始阅读direct_modules_explore_directory()【lib\direct\Modules. C】.
Int direct_modules_explore_directory ( DirectModuleDir *directory )
{
#ifdef DYNAMIC_LINKING
#一般情况下,driver都是以动态链接库的形式存在的
int dir_len;
DIR *dir;
struct dirent *entry = NULL;
struct dirent tmp;
int count = 0;
D_ASSERT( directory != NULL );
D_ASSERT( directory->path != NULL );
D_DEBUG_AT( Direct_Modules, "%s( '%s' )\n", __FUNCTION__, directory->path );
dir_len = strlen( directory->path );
#打开目录,path 就是上面宏定义中设定的
dir = opendir( directory->path );
if (!dir) {
D_DEBUG_AT( Direct_Modules, " -> ERROR opening directory: %s!\n", strerror(errno) );
return 0;
}
while (readdir_r( dir, &tmp, &entry ) == 0 && entry)
{
#读取目录下的每一个文件
#opendir, readdir_r等都是c语言中操作目录的函数
void *handle;
DirectModuleEntry *module;
int entry_len = strlen(entry->d_name);
#只处理后缀是so的文件, 即动态连接库
if (entry_len < 4 ||
entry->d_name[entry_len-1] != 'o' ||
entry->d_name[entry_len-2] != 's')
continue;
#查看一下这个文件是否已经在链表中了,即这个driver是否已经遍历过了,如果是,则跳过
if (lookup_by_file( directory, entry->d_name ))
continue;
#为新的module分配一个DirectModuleEntry 的数据结构, 这个结构将来要加入的到链表中
module = D_CALLOC( 1, sizeof(DirectModuleEntry) );
if (!module)
continue;
module->directory = directory;
module->dynamic = true;
module->file = D_STRDUP( entry->d_name );
directory->loading = module;
#打开这个动态链接库, 实际调用的是dlopen。
#需要注意的是这时候这module并没有加入到list中,只是通过directory->loading暂时记录起来。
if ((handle = open_module( module )) != NULL) {
#如果一切顺利,这个module应该已经注册成功并加入到directory的链表中,而module->loaded 也设为了true,你可能纳闷,因为open_module 中并没有这些代码呀,别急,我们后面会讲
if (!module->loaded)
{
int len;
void (*func)();
#如果进入了这里就意味的module自己注册没有成功,这是需要手动注册。
D_ERROR( "Direct/Modules: Module '%s' did not register itself after loading! "
"Trying default module constructor...\n", entry->d_name );
len = strlen( entry->d_name );
#去掉后缀“.so”
entry->d_name[len-3] = 0;
#掉前缀”lib”,例如“libdirectfb_fbdev.so”就变成了”directfb_fbdev”,
func = dlsym( handle, entry->d_name + 3 );
#在动态库中搜索函数directfb_fbdev
#可是所有的Fbdev源码中好像并没有directfb_fbdev这个函数的定义,这是怎么回事呢?
#原来在libdirectfb_fbdev.so 的源码Fbdev.c 中有个宏定义DFB_CORE_SYSTEM(fbdev),展开这个 宏定义,一切都明白了。而directfb_fbdev实际调用的是direct_modules_register,它的工作就是自动注册的过程,我们在此我详述,稍后会讲
if (func)
{
#执行这个函数,
func();
#上述函数执行完毕后,loaded应为true, 否则就意味着注册失败
if (!module->loaded)
{
D_ERROR( "Direct/Modules: ... even did not register after "
"explicitly calling the module constructor!\n" );
}
}
else
{
#func为NULL, 即不存在构造函数,则什么也不做
D_ERROR( "Direct/Modules: ... default contructor not found!\n" );
}
if (!module->loaded)
{
#如果手工注册也失败则仍然将该动态链接库加入到链表中,
#只不过disabled设为true, 表示不可用
module->disabled = true;
D_MAGIC_SET( module, DirectModuleEntry );
direct_list_prepend( &directory->entries,
&module->link );
}
}
if (module->disabled)
{
#对于状态是disable的module,也就是自动注册和手动注册都没有成功的,则将其关闭
dlclose( handle );
module->loaded = false;
}
else
{
#对于注册成功的module, 记录动态库的handle
#以后就可以根据这个handle调用库中的函数了,
#注意的是这些动态库是处于打开状态,
module->handle = handle;
count++;
}
}#endif(handle=open_module(…))
else
{
#如果module打开失败,则仍然将其加入链表中,disabled设为true,表示不可用
module->disabled = true;
D_MAGIC_SET( module, DirectModuleEntry );
direct_list_prepend( &directory->entries, &module->link );
}
directory->loading = NULL;#当前没有试图加载的module,为加载下一个module做准备
}//endof while(readdir_r)
closedir( dir );
return count;
#else
return 0;
#endif
}
现在我们解决上一节中那个悬而未决的问题:dlopen()中能够到底做了些什么?
dlopen()是一个标准的C函数,在dlopen()函数说明中有这样一段话:
“Instead, libraries should export routines using the __attribute__((constructor)) and __attribute__((destructor)) function attributes. See the gcc info pages for information on these. Constructor routines are executed before dlopen() returns, and destructor routines are executed before dlclose() returns.”
也就是在dlopen()返回前,它将执行动态链接库中被__attribute__((constructor)) 修饰的函数。
现在再回头看一下src\core\Core_system.h的定义,确实有一个被__attribute__((constructor))修饰的函数:
#define DFB_CORE_SYSTEM(shortname) \
__attribute__((constructor)) void directfb_##shortname( void ); \
\
void \
directfb_##shortname( void ) \
{ \
direct_modules_register( &dfb_core_systems, \
DFB_CORE_SYSTEM_ABI_VERSION, \
#shortname, &system_funcs ); \
}
不论具体的system是什么(也就是shortname是什么,每个system的实现中都会调用DFB_CORE_SYSTEM这个宏),其最终都会调用direct_modules_register()。
direct_modules_register()【lib\direct\Modules.c】才真正完成将当前module加入各个链表的工作,例如我们当前遍历的system链表,它就将每一个system实现挂在dfb_core_systems这个链表中,同时设置 ‘entry->loaded = true'表示该module已经加载成功。
至此dfb_system_lookup()中direct_modules_explore_directory( &dfb_core_systems )全部完成。这时候实际上所有的system 实现都是打开的同时挂在dfb_core_systems链表中,dfb_system_lookup()根据configure 中指定system 确定最终的选用system是哪个(比较module的名字,上面标红的字段),然后将没用的module关闭。而选中的sytem及其函数表会记录在两个全局变量中:system_module()和system_funcs。
另外, 它还会调用system_funcs函数表中的GetSystemInfo(),得到该graphics system 的一些基本信息,这些信息也记录在一个全局变量system_info中, 其实这些信息中我们最关心的就是其中的caps, 它记录了该系统是否支持硬件加速。