日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux驱动编程 step-by-step (十一)

發(fā)布時間:2024/9/21 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux驱动编程 step-by-step (十一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Linux 內(nèi)核鏈表(2)

之前描述了如何創(chuàng)建內(nèi)核鏈表(INIT_LIST_HEAD)向鏈表中添加節(jié)點(list_add)刪除一個鏈表節(jié)點(list_del)獲取一個鏈表節(jié)點對應(yīng)的結(jié)構(gòu)體(list_entry)等

接下來會介紹幾種操作

替換一個鏈表節(jié)點,合并兩個鏈表,將一個鏈表分成兩段,遍歷鏈表。

替換鏈表節(jié)點

替換節(jié)點很好理解,就是將新的節(jié)點替換老節(jié)點,將新的節(jié)點的對應(yīng)的prev,next指針指向老節(jié)點的prev,next。后將老節(jié)點prev->next指向新節(jié)點,老節(jié)點的next->prev指向新節(jié)點

[cpp]?view plaincopyprint?
  • static?inline?void?list_replace(struct?list_head?*old,??
  • ????????????????struct?list_head?*new)???????????????????????????????????????????????
  • {??
  • ????new->next?=?old->next;??????
  • ????new->next->prev?=?new;??????
  • ????new->prev?=?old->prev;??????
  • ????new->prev->next?=?new;??????
  • }??
  • 此時old節(jié)點的next 與prev指針還是指向 原來的節(jié)點,可以使用以下函數(shù)重新初始化old節(jié)點使其指向 他自身

    [cpp]?view plaincopyprint?
  • static?inline?void?list_replace_init(struct?list_head?*old,??
  • ????????????????????struct?list_head?*new)??
  • {??
  • ????list_replace(old,?new);??
  • ????INIT_LIST_HEAD(old);??
  • }??
  • ...

    更為一般的情況:我們替換鏈表節(jié)點大多都在鏈表頭或者鏈表尾,所以就有了以下函數(shù)

    [cpp]?view plaincopyprint?
  • static?inline?void?list_move(struct?list_head?*list,?struct?list_head?*head)??
  • 替換鏈表頭

    [cpp]?view plaincopyprint?
  • static?inline?void?list_move_tail(struct?list_head?*list,??
  • ??????????????????struct?list_head?*head)??
  • 替換鏈表尾

    鏈表的判斷

    有時候我們需要判斷鏈表是否為空,或者是否已經(jīng)到了鏈表的末尾

    內(nèi)核鏈表已經(jīng)為我們實現(xiàn)了這些判斷函數(shù)。

    檢查鏈表是否為空

    [cpp]?view plaincopyprint?
  • static?inline?int?list_empty(const?struct?list_head?*head)??
  • {??
  • ????return?head->next?==?head;??
  • }??
  • 類似的檢查是否已經(jīng)到了鏈表尾部函數(shù):

    [cpp]?view plaincopyprint?
  • static?inline?int?list_is_last(const?struct?list_head?*list,??
  • ????????????????const?struct?list_head?*head)??
  • 此外還有一個檢測鏈表是否為空的函數(shù)

    [cpp]?view plaincopyprint?
  • static?inline?int?list_empty_careful(const?struct?list_head?*head)??
  • 檢查鏈表為空,并且沒有另外的處理器回去操作它

    合并兩個鏈表

    合并鏈表跟添加一個鏈表節(jié)點差不多,在鏈表頭或鏈表尾添加新鏈表均會調(diào)用到__list_splice

    [cpp]?view plaincopyprint?
  • static?inline?void?__list_splice(const?struct?list_head?*list,??
  • ?????????????????struct?list_head?*prev,??
  • ?????????????????struct?list_head?*next)??
  • {??
  • ????struct?list_head?*first?=?list->next;??
  • ????struct?list_head?*last?=?list->prev;??
  • ??
  • ????first->prev?=?prev;??
  • ????prev->next?=?first;??
  • ??
  • ????last->next?=?next;??
  • ????next->prev?=?last;??
  • }??
  • 即將list 鏈表加到 prev 與 next之間

    在鏈表頭添加新鏈表:

    [cpp]?view plaincopyprint?
  • static?inline?void?list_splice(const?struct?list_head?*list,??
  • ????????????????struct?list_head?*head)??
  • 在鏈表尾部添加新鏈表調(diào)用:

    [cpp]?view plaincopyprint?
  • static?inline?void?list_splice_tail(struct?list_head?*list,??
  • ????????????????struct?list_head?*head)??

  • 拆分一個鏈表

    [cpp]?view plaincopyprint?
  • static?inline?void?list_cut_position(struct?list_head?*list,??
  • ????????struct?list_head?*head,?struct?list_head?*entry)??
  • 以entry為節(jié)點拆分以head為頭的鏈表,拆分后list保存從head到entry的鏈表。head報鏈表是從entry->next 到鏈表尾。

    遍歷鏈表

    創(chuàng)建的鏈表的目的是為了能夠遍歷鏈表得到鏈表結(jié)構(gòu)中的有效數(shù)據(jù)。

    上一篇文中提到 list_entry他只能獲得一個鏈表節(jié)點對應(yīng)的結(jié)構(gòu)體。

    我們可以自己使用for 循環(huán)來遍歷鏈表:

    [cpp]?view plaincopyprint?
  • for?(pos?=?head->next;?pos?!=?head;?pos?=?pos->next){??
  • ?????struct?data_struct?*data?=?list_entry(pos,?struct?data_struct,?list);??
  • ?????...??
  • }??
  • 當然內(nèi)核已經(jīng)為我們提供了一套接口(本質(zhì)就是上邊的 for循環(huán))

    [cpp]?view plaincopyprint?
  • list_for_each(pos,?head)??
  • 到這里 我們想要一個更簡單的: 在循環(huán)的同時 就用list_entry為我們拿到鏈表節(jié)點對應(yīng)的數(shù)據(jù)結(jié)構(gòu)體。所以內(nèi)核工程師給我們一個接口:

    [cpp]?view plaincopyprint?
  • list_for_each_entry(pos,?head,?member)??
  • pos:是數(shù)據(jù)結(jié)構(gòu)體指針, head是鏈表頭,member指在數(shù)據(jù)結(jié)構(gòu)中鏈表成員的名字

    例如現(xiàn)在定義?

    [cpp]?view plaincopyprint?
  • struct?data_struct{??
  • ????struct?list_head?list;??
  • ????Data?data;??
  • };??
  • 我們要遍歷鏈表獲得 此結(jié)構(gòu)

    [cpp]?view plaincopyprint?
  • {??
  • ????...??
  • ????struct?data_struct?*pdata;??
  • ????list_for_each_entry(pdata,?head,?list){??
  • ?????????Data?tmp?=?pdata->data;??
  • ?????????....??
  • ????}??
  • }??
  • 在這些版本的遍歷中我們不能在循環(huán)內(nèi)刪除節(jié)點,如果有刪除操作怎會導(dǎo)致內(nèi)核崩潰(因為刪除節(jié)點時候 node->next被置為了空,如果進行操作.....),但有時候需要在遍歷過程中刪除節(jié)點,所以內(nèi)核NB工程師幫我們做了一個 for_safe的版本,他保存一個節(jié)點的副本,在節(jié)點被刪除后,副本仍有效。

    [cpp]?view plaincopyprint?
  • list_for_each_safe(pos,?n,?head)??
  • [cpp]?view plaincopyprint?
  • list_for_each_entry_safe(pos,?n,?head,?member)??
  • 此處 n用來保存副本

    此外還有逆序遍歷等再次不再贅述……

    請自行查看include/linux/list.h

    總結(jié)

    以上是生活随笔為你收集整理的Linux驱动编程 step-by-step (十一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。