国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

PHP 進(jìn)階之路 - PHP7 使用資源包裹第三方擴(kuò)展原理分析

ctriptech / 1609人閱讀

摘要:重點(diǎn)分析其中宏,返回表的,后面用來作為索引查詢的依據(jù)。中資源的解析比中解析簡單快捷很多,得益于其結(jié)構(gòu)的改變。先從逆向通過其在中索引層層關(guān)聯(lián),找到該類資源的釋放回調(diào)函數(shù),然后對(duì)該資源執(zhí)行釋放回調(diào)函數(shù)。

PHP 擴(kuò)展開發(fā)的文章,我均已更新至《TIPI》
本篇承接上篇 PHP7 使用資源包裹第三方擴(kuò)展的實(shí)現(xiàn)

PHP7 使用資源包裹第三方擴(kuò)展原理分析 注冊(cè)資源類型源碼
[c]
ZEND_API int zend_register_list_destructors_ex(rsrc_dtor_func_t ld, rsrc_dtor_func_t pld, const char *type_name, int module_number)
{
   zend_rsrc_list_dtors_entry *lde;
   zval zv;
 
   lde = malloc(sizeof(zend_rsrc_list_dtors_entry));
   lde->list_dtor_ex = ld;
   lde->plist_dtor_ex = pld;
   lde->module_number = module_number;
   lde->resource_id = list_destructors.nNextFreeElement;
   lde->type_name = type_name;
   ZVAL_PTR(&zv, lde);
 
   if (zend_hash_next_index_insert(&list_destructors, &zv) == NULL) {
      return FAILURE;
   }
   return list_destructors.nNextFreeElement-1;
}

其中

[c]
ZVAL_PTR(&zv, lde);

等價(jià)于

[c]
zv.value.ptr = (lde);
zv.u1.type_info = IS_PTR;

list_destructors 是一個(gè)全局靜態(tài) HashTable,資源類型注冊(cè)時(shí),將一個(gè) zval 結(jié)構(gòu)體變量 zv 存放入 list_destructorsarData 中,而 zvvalue.ptr 卻指向了 zend_rsrc_list_dtors_entry *ldelde中包含的該種資源釋放函數(shù)指針、持久資源的釋放函數(shù)指針,資源類型名稱,該資源在 hashtable 中的索引依據(jù) (resource_id)等。
而這里的 resource_id 則是該函數(shù)的返回值,所以后面我們?cè)诮馕鲈擃愋妥兞繒r(shí),都需要將 resource_id 帶上。
整個(gè)的注冊(cè)步驟可以總結(jié)為下圖:

資源的注冊(cè)
[c]
ZEND_API zend_resource* zend_register_resource(void *rsrc_pointer, int rsrc_type)
{
   zval *zv;
 
   zv = zend_list_insert(rsrc_pointer, rsrc_type);
 
   return Z_RES_P(zv);
}

該函數(shù)的功能則是將 zend_list_insert 返回的 zval 中的資源指針返回。Z_RES_P 宏在 Zend/zend_types.h 中定義。
重點(diǎn)分析 zend_list_insert

[c]
ZEND_API zval *zend_list_insert(void *ptr, int type)
{
   int index;
   zval zv;

   index = zend_hash_next_free_element(&EG(regular_list));
   if (index == 0) {
      index = 1;
   }
   ZVAL_NEW_RES(&zv, index, ptr, type);
   return zend_hash_index_add_new(&EG(regular_list), index, &zv);
}

其中zend_hash_next_free_element宏,返回&EG(regular_list)表的nNextFreeElement,后面用來作為索引查詢的依據(jù)。
ZVAL_NEW_RES宏是 PHP7 新增的一套東西,把一個(gè)資源裝載到zval里去,因?yàn)镻HP7 中Bucket只能存zval了。

[c]
#define ZVAL_NEW_RES(z, h, p, t) do {                            
        zend_resource *_res =                                    
        (zend_resource *) emalloc(sizeof(zend_resource));        
        zval *__z;                                            
        GC_REFCOUNT(_res) = 1;                                    
        GC_TYPE_INFO(_res) = IS_RESOURCE;                        
        _res->handle = (h);                                        
        _res->type = (t);                                        
        _res->ptr = (p);                                        
        __z = (z);                                            
        Z_RES_P(__z) = _res;                                    
        Z_TYPE_INFO_P(__z) = IS_RESOURCE_EX;                    
    } while (0)

代碼比較清晰,首先根據(jù)h,p,t新建了一個(gè)資源,然后一起存入了z這個(gè)zval的結(jié)構(gòu)體。(最后兩個(gè)宏前面剛剛討論過了)
最后就是zend_hash_index_add_new宏了,追蹤代碼發(fā)現(xiàn)其最后等價(jià)于調(diào)用的是

[c]
_zend_hash_index_add_or_update_i(&EG(regular_list), index, &zv, HASH_ADD | HASH_ADD_NEW ZEND_FILE_LINE_RELAY_CC)

關(guān)于PHP7 HashTable的具體操作,這里暫不做細(xì)致的分析,后期更新前面的數(shù)據(jù)結(jié)構(gòu)的章節(jié)。注冊(cè)的整個(gè)邏輯如下圖:

解析資源源碼分析
[c]
ZEND_API void *zend_fetch_resource(zend_resource *res, const char *resource_type_name, int resource_type)
{
   if (resource_type == res->type) {
      return res->ptr;
   }
 
   if (resource_type_name) {
      const char *space;
      const char *class_name = get_active_class_name(&space);
      zend_error(E_WARNING, "%s%s%s(): supplied resource is not a valid %s resource", class_name, space, get_active_function_name(), resource_type_name);
   }
 
   return NULL;
}

在上面的例子中我們是這樣解析的

[c]
(FILE *)zend_fetch_resource(Z_RES_P(filehandle), TIPI_FILE_TYPE, le_tipi_file)

首先通過Z_RES_P宏,獲取filehandle這個(gè)zval變量中的zend_resource。然后zend_fetch_resource中只是對(duì)比了zend_resourcetype與我們預(yù)想的資源類型是否一致,然后返回了zend_resource*ptr,最后轉(zhuǎn)換成FILE *指針。
PHP7 中資源的解析比 PHP5中解析簡單快捷很多,得益于其 zval 結(jié)構(gòu)的改變。
原來PHP5中則需要通過EG(regular_list)查找,如下圖所示:

而現(xiàn)在 PHP7的解析則直接從zval里解析出zend_resource,如下圖所示:

刪除資源源碼分析
[c]
ZEND_API int zend_list_close(zend_resource *res)
{
   if (GC_REFCOUNT(res) <= 0) {
      return zend_list_free(res);
   } else if (res->type >= 0) {
      zend_resource_dtor(res);
   }
   return SUCCESS;
}

與PHP5 不同的地方,這里不是每次都進(jìn)來將其引用計(jì)數(shù)減一操作,而是直接調(diào)用zend_resource_dtor函數(shù)。

[c]
static void zend_resource_dtor(zend_resource *res)
{
   zend_rsrc_list_dtors_entry *ld;
   zend_resource r = *res;

   res->type = -1;
   res->ptr = NULL;

   ld = zend_hash_index_find_ptr(&list_destructors, r.type);
   if (ld) {
      if (ld->list_dtor_ex) {
         ld->list_dtor_ex(&r);
      }
   } else {
      zend_error(E_WARNING, "Unknown list entry type (%d)", r.type);
   }
}

如果引用計(jì)數(shù)已經(jīng)等于0或者小于0了,那么才從EG(regular_list)中刪除

[c]
ZEND_API int zend_list_free(zend_resource *res)
{
   if (GC_REFCOUNT(res) <= 0) {
      return zend_hash_index_del(&EG(regular_list), res->handle);
   } else {
      return SUCCESS;
   }
}

原理圖還是引用上面的注冊(cè)資源類型、并注冊(cè)資源的圖。
先從zend_resource逆向通過其typelist_destructors中索引層層關(guān)聯(lián),找到該類資源的釋放回調(diào)函數(shù),然后對(duì)該資源執(zhí)行釋放回調(diào)函數(shù)。
而后面的從EG(regular_list)中刪除,則是通過res->handler做為索引的依據(jù)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/23257.html

相關(guān)文章

  • PHP 進(jìn)階之路 - PHP7 使用資源包裹三方擴(kuò)展的實(shí)現(xiàn)

    摘要:釋放用于在不同請(qǐng)求中始終存在的永久資源的函數(shù)。這是新增的數(shù)據(jù)結(jié)構(gòu),在則是。這使得引擎做一些例如資源類型,注冊(cè)變量等的一次初始化。也就是說該函數(shù)的返回值為指針。會(huì)將返回值的設(shè)為,設(shè)為。資源的刪除資源刪除傳入需要被刪除的資源即可。 PHP 擴(kuò)展開發(fā)的文章,我均已更新至《TIPI》 在閱讀下面的內(nèi)容之前,我們假定你已經(jīng)對(duì) PHP 7 基本的數(shù)據(jù)結(jié)構(gòu) 都有大致的了解了,這是下面內(nèi)容閱讀的前提。...

    caozhijian 評(píng)論0 收藏0
  • PHP7 使用資源包裹三方擴(kuò)展的實(shí)現(xiàn)及其源碼解讀

    摘要:也就是說該函數(shù)的返回值為指針。會(huì)將返回值的設(shè)為,設(shè)為。而這里的則是該函數(shù)的返回值,所以后面我們?cè)诮馕鲈擃愋妥兞繒r(shí),都需要將帶上。 在閱讀下面的內(nèi)容之前,我們假定你已經(jīng)對(duì) PHP 7 基本的數(shù)據(jù)結(jié)構(gòu)都有大致的了解了,這是下面內(nèi)容閱讀的前提。 我們分為兩大塊: 首先實(shí)現(xiàn)一個(gè)自定義的文件打開、讀取、寫入、關(guān)閉的文件操作擴(kuò)展; 然后分析各個(gè)操作背后的實(shí)現(xiàn)原理,其中某些部分的實(shí)現(xiàn)我會(huì)和 PHP ...

    williamwen1986 評(píng)論0 收藏0
  • PHP 進(jìn)階之路 - 億級(jí) pv 網(wǎng)站架構(gòu)實(shí)戰(zhàn)之性能壓榨

    摘要:業(yè)務(wù)和架構(gòu)不分家,架構(gòu)是建立在對(duì)業(yè)務(wù)的理解之上的。主鍵最好保持順序遞增,隨機(jī)主鍵會(huì)導(dǎo)致聚簇索引樹頻繁分裂,隨機(jī)增多,數(shù)據(jù)離散,性能下降。沒有索引的更新,可能會(huì)導(dǎo)致全表數(shù)據(jù)都被鎖住。 本博客并非全部原創(chuàng),其實(shí)是一個(gè)知識(shí)的歸納和匯總,里面我引用了很多網(wǎng)上、書上的內(nèi)容。也給出了相關(guān)的鏈接。 本文涉及的知識(shí)點(diǎn)比較多,大家可以根據(jù)關(guān)鍵字去搜索相關(guān)的內(nèi)容和購買相應(yīng)的書籍進(jìn)行系統(tǒng)的學(xué)習(xí)。不對(duì)的地方...

    SnaiLiu 評(píng)論0 收藏0
  • PHP 進(jìn)階之路 - 揭開 PHP 線程安全的神秘面紗

    摘要:如果現(xiàn)有子進(jìn)程中的線程總數(shù)不能滿足負(fù)載,控制進(jìn)程將派生新的子進(jìn)程。為解決線程的并發(fā)問題,引入了線程安全資源管理器。的全拼,用來存放各個(gè)線程的鏈表。 PHP 進(jìn)階之路 - 零基礎(chǔ)構(gòu)建自己的服務(wù)治理框架(上) PHP 進(jìn)階之路 - 零基礎(chǔ)構(gòu)建自己的服務(wù)治理框架(下) PHP 進(jìn)階之路 - 億級(jí) pv 網(wǎng)站架構(gòu)的技術(shù)細(xì)節(jié)與套路 PHP 進(jìn)階之路 - 億級(jí) pv 網(wǎng)站架構(gòu)實(shí)戰(zhàn)之性能壓榨 注...

    pepperwang 評(píng)論0 收藏0
  • PHP小知識(shí)點(diǎn)

    摘要:那些瑣碎的知識(shí)點(diǎn)作者記錄的的很奇特很難記的知識(shí)點(diǎn)。易錯(cuò)知識(shí)點(diǎn)整理注意和的區(qū)別中和都是輸出的作用,但是兩者之間還是有細(xì)微的差別。今天手頭不忙,總結(jié)一下,分享過程中掌握的知識(shí)點(diǎn)。 深入理解 PHP 之:Nginx 與 FPM 的工作機(jī)制 這篇文章從 Nginx 與 FPM 的工作機(jī)制出發(fā),探討配置背后的原理,讓我們真正理解 Nginx 與 PHP 是如何協(xié)同工作的。 PHP 那些瑣碎的知識(shí)...

    hover_lew 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

ctriptech

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<