dlopen dlclose dlXXX

下載glibc-2.18.tar.gz後  解壓縮

再include/link.h中的

163 unsigned int l_direct_opencount; /* Reference count for dlopen/dlclose.  */

有dlopen的reference count

 

轉載自http://soon0530.blogspot.tw/2012/12/dlopendlclose.html

 

dlopen()/dlclose()原理分析

Question:
之前在寫程式時,有用到dlopen()/dlclose()動態載入libdingo.so來使用。所以好奇他的運作原理是什麼@@?

Trace Code:
主要是了解基本的概念,及什麼時候load libdingo.so和unload libdingo.so

dlfnc.c dlopen()

void *dlopen(const char *filename, int flag)
{
   soinfo *ret; // 這個struct很重要,主要用來看裡面的refcount數量,來知道是不是有一直遞減的現像。

   pthread_mutex_lock(&dl_lock);
   ret = find_library(filename);  // 先看一下這裡做了什麼?
   if (unlikely(ret == NULL)) {
       set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
   } else {
       ret->refcount++; // 看樣子,如果沒有問題,就會把refcount+1,代表現在有1個地方在使用。
   }
   pthread_mutex_unlock(&dl_lock);
   return ret;
}

linker.c find_library()
soinfo *find_library(const char *name)
{
   soinfo *si;
   const char *bname;

#if ALLOW_SYMBOLS_FROM_MAIN
   if (name == NULL)
       return somain;
#else
   if (name == NULL)
       return NULL;
#endif

   bname = strrchr(name, '/');
   bname = bname ? bname + 1 : name;

   for(si = solist; si != 0; si = si->next){
       if(!strcmp(bname, si->name)) {
       if(si->flags & FLAG_ERROR) {
               DL_ERR("%5d '%s' failed to load previously", pid, bname);
               return NULL;
       }
       if(si->flags & FLAG_LINKED) {//這裡很重要,他告訴我們,如果libapi.1.so存在,他就直接return si。
               DL_ERR("[ %5d '%s' is exist!! refcount=%d *si=%p]\n", pid, bname, (si->refcount + 1), si);
               return si;
       }
           DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name);
           return NULL;
       }
   }

   DL_ERR("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
   si = load_library(name);
   if(si == NULL)
       return NULL;
   return init_library(si);
}

dlfnc.c dlclose()
int dlclose(void *handle)
{
   pthread_mutex_lock(&dl_lock);
   (void)unload_library((soinfo*)handle);//直接看一下內容
   pthread_mutex_unlock(&dl_lock);
   return 0;
}

linker.c unload_library()
unsigned unload_library(soinfo *si)
{
   unsigned *d;
   if (si->refcount == 1) { //重點,如果refcount只剩下你的話,library就會就會被unload了。
       TRACE("%5d unloading '%s'\n", pid, si->name);
       call_destructors(si);

       for(d = si->dynamic; *d; d += 2) {
           if(d[0] == DT_NEEDED){
               soinfo *lsi = (soinfo *)d[1];
               d[1] = 0;
               if (validate_soinfo(lsi)) {
                   TRACE("%5d %s needs to unload %s\n", pid, si->name, lsi->name);
                   unload_library(lsi);
               }
               else
                   DL_ERR("%5d %s: could not unload dependent library", pid, si->name);
           }
       }

       munmap((char *)si->base, si->size);
       notify_gdb_of_unload(si);
       free_info(si);
       si->refcount = 0;
   }
   else { // 如果還有人在引用,就只是把count減1而已。
       si->refcount--;
       PRINT("%5d not unloading '%s', decrementing refcount to %d\n", pid, si->name, si->refcount);
   }
   return si->refcount;
}


Comment:
1. dlopen() / dlclose() 只會用到1次I/O,分別是第一次使用時載入,及沒有人去引用時移除(release memory)。
2. 呼叫dlopen() / dlclose() 一定要成雙成對,不然會有下列2問題。
(1) dlopen()比較多,即呼叫的次數 dlopen() > dlclose(),就會無法unload沒有使用的libapi.so
(2) dlclose()比較多,即呼叫的次數dlclose() > dlopen(),就會造成segmentation fault。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值