摘要:重點(diǎn)分析其中宏,返回表的,后面用來作為索引查詢的依據(jù)。中資源的解析比中解析簡單快捷很多,得益于其結(jié)構(gòu)的改變。先從逆向通過其在中索引層層關(guān)聯(lián),找到該類資源的釋放回調(diào)函數(shù),然后對(duì)該資源執(zhí)行釋放回調(diào)函數(shù)。
PHP7 使用資源包裹第三方擴(kuò)展原理分析 注冊(cè)資源類型源碼PHP 擴(kuò)展開發(fā)的文章,我均已更新至《TIPI》
本篇承接上篇 PHP7 使用資源包裹第三方擴(kuò)展的實(shí)現(xiàn)
[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_destructors 的 arData 中,而 zv 的 value.ptr 卻指向了 zend_rsrc_list_dtors_entry *lde ,lde中包含的該種資源釋放函數(shù)指針、持久資源的釋放函數(shù)指針,資源類型名稱,該資源在 hashtable 中的索引依據(jù) (resource_id)等。
而這里的 resource_id 則是該函數(shù)的返回值,所以后面我們?cè)诮馕鲈擃愋妥兞繒r(shí),都需要將 resource_id 帶上。
整個(gè)的注冊(cè)步驟可以總結(jié)為下圖:
[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_resource的type與我們預(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逆向通過其type在list_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
摘要:釋放用于在不同請(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)容閱讀的前提。...
摘要:也就是說該函數(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 ...
摘要:業(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ì)的地方...
摘要:如果現(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)之性能壓榨 注...
摘要:那些瑣碎的知識(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í)...
閱讀 3813·2021-10-12 10:11
閱讀 3637·2021-09-13 10:27
閱讀 2540·2019-08-30 15:53
閱讀 1972·2019-08-29 18:33
閱讀 2189·2019-08-29 14:03
閱讀 994·2019-08-29 13:27
閱讀 3316·2019-08-28 18:07
閱讀 763·2019-08-26 13:23