contributed by < nickyanggg
>
linux2020
strtok
功能的函式實作。stack
上data
15 - space_left
求得data[15] == '\0'
,然而位於最後一個 byte 的 space_left
卻不受影響,因為此時 space_left
剛好為 is_ptr
為 heap
上ptr
分析以下程式碼,並判斷 AAA
內容為何。
if
的 block 中將字串儲存於 heap
中,而 else
則是將字串 copy 至 data
中,可知前者為字串長度 的狀況,而後者則是長度 的狀況。len
為一個字串真正用到的空間長度,也就是涵蓋結束字元,因此可判斷 AAA
應為 。分析以下程式碼,並判斷 BBB
及 CCC
內容為何。
mask
set_bit
中可知 ascii 每八個一組對應到 mask[]
中。mask[65/8]
會被 assign 成 mask[65/8] | 1 << (65 % 8)
,也就是 mask[8] |= 2
,也就是 mask[8]
會等於 xxxxxx1x (二進制),x 為其他字元所對應到的值,若是欲刪除字元會被設為 1,否則為 0。mask
中的每個值代表著一個 byte,那每個字元都會對應到其中一個 byte 中的其中一個 bit。set_bit
時,若以二進制來看的話每次做 |=
都不會影響其他字元所代表的值。set_bit
mask
的 bit 更新為 1。byte
轉型成 uint8_t
,可知 byte
範圍落在 0 ~ 255,再加上 ascii 範圍為 0 ~ 255,因此 BBB
值為 32 才不會出現 index out of range 的狀況。check_bit
mask
中去看說自己是否為欲刪除字元,因此將 dataptr
中的字元一一丟入 check_bit
,若將自己的 bit 的位置設成 1 其他 bit 為 0 的值去和 mask
上自己對應到的 byte 做 CCC
時回傳值為 1 代表著為欲刪除字元,因此 for
迴圈繼續,若回傳值為 0 則跳出迴圈。CCC
是在做 &
運算。reference counter
的位置來實作 CoW
。xs_new
、xs_grow
在 malloc 一塊空間給長度 的字串時,都會保證即使在極端狀況也會保留最後一個 byte
沒被使用,也就是 '\0'
頂多位在可使用空間中的倒數第二個 byte。size == 30
=> malloc(32)
size == 31
=> malloc(64)
size == 62
=> malloc(64)
size == 63
=> malloc(128)
byte
足以讓我們儲存 的 reference counter
。reference counter
255 可能會稍嫌不足,但我這邊就不另外要空間或是開變數去儲存更大的 reference counter
,重點可能放在如何在 reference counter
只有 255 的情況之下避免 memory leak 以及處理 reference counter
不夠用的狀況。xs_new
xs_ref_counter
為取結束字元後的下一個 byte 的值,也就是我們定義的 reference counter
。xs_new
中,若存放在 heap
中則賦予 xs_ref_counter
初始值 1。xs_copy
src
的內容複製到 dest
。src
的字串長度 ,先更新原先的 reference counter
,若變為 0 則代表沒有共享空間,就可以釋放掉。src
copy 的次數達到極限 (255 次),因此 duplicate 出一個新的。reference counter
,只需要更新其中一個,因為此時 dest
和 ref
的 reference counter
是存在相同的地址。xs_cow
reference counter
,則會觸發。reference counter
。xs_concat
xs_cow
。reference counter
並沒有一併被維護到,因此最後檢查是否需要維護 reference counter
。xs_trim
xs_concat
注意事項。reference counter
僅記錄 1 ~ 255,因此一旦被複製了 254 次,接下來每次的複製都會直接 malloc 一塊新的空間,而不會自動去連接才剛 malloc 且 reference counter
為 1 的那塊,也就是第 255 次複製的時候會先去 malloc 一塊空間,而第 256 次複製的時候其實可以跑去和第 255 次複製的共享空間,而非又去 malloc 一塊新的,實作方式如下。
xs_new
的時候,就把下一段的儲存空間先指向自己 malloc 出來的空間,也就是 circular linked list 只有一個 node 的狀況 (指向自己)。reference counter
滿的時候,就去儲存的下一段空間找找看,若發現下一段的 reference counter
也滿的時候就再去看下一段…以此類推,一旦發現 traverse 到第一個看的空間時 (也就是走訪了一圈每個 reference counter
都滿了),就 malloc 一塊新的空間,並且將它加入這個 circular linked list。reference counter
,像是多開的 8 個 byte 就可以計數到 ,何必像上面說的那樣搞得那麼麻煩,但我個人認為不管 reference counter
能到多大,都不能保證它一定不會滿,而一旦滿的時候若沒妥善處理仍然會浪費掉許多空間,所以才提出上面那種解決辦法。xs_trim
若字串長度 且有共享空間的話,就一定會去 malloc 一塊新的空間,但其實也可以透過改變自己的 ptr
、size
就可以達成,當然還是需要注意一些細節如下才能實作出來。
reference counter
儲存在擁有空間的最後一個 byte
,而非 '\0' 後的下一個 byte,這樣共享成員才可以輕鬆去 access 到 reference counter
(因為各個共享成員的 size
可能都不一樣,但仍可透過 capacity
去取得最後一位元)。ptr
被改成指向自己的字串開頭),所以在 malloc 的時候也要再多增加 8 個 byte 來儲存。xs_copy
來達到 type 為 char*
的 assign。xs_trim
的 set_bit
、check_bit
來實作 strspn
以及 strcspn
。reference counter
一定要在 old
複製完後才能維護,否則下次呼叫 xs_tok
的回傳值開頭很有可能會變成上一個 token 的 reference counter
。xs_trim
的狀況雷同,可以不必去 malloc
一塊新的空間,改進方式也大同小異。簡單測試以下功能是否正常,並且檢查是否確實實施 CoW,以及處理 reference counter
達到極值的狀況。
xs_copy
xs_trim
xs_concat
xs_tok
TODO:
reference counter
極限值) 次。reference counter
達到 255 時才會再去要空間。xs_copy_max
一樣複製 254 次。xs_copy_max
str_copy_max
可以發現 str_copy_max
所耗費的空間遠大於 xs_copy_max
許多。
xs_copy_max
str_copy_max
可以發現 xs_copy_max
在 D1 的命中率高於 str_copy_max
,我們再使用 perf 測試看看。
xs_copy_max
str_copy_max
可以明顯地看出 xs_copy_max
的 cache 命中率是遠優於 str_copy_max
。
參考 copy on write、fork.c、memory.c、fork 流程、page fault 處理。
fork
完後,子行程去呼叫 exec
。
exec
後,不會用到父行程的資料。fork
後都要去複製一份父行程的資料給子行程,結果子行程卻完全沒有用到的話,就浪費了許多時間和空間。fork
後,若子行程不對記憶體空間寫入,則不複製一份。copy_page_range
、copy_pud_range
、copy_pmd_range
、copy_pte_range
都是在 copy 相對應的頁表。