contributed by < eleanorLYJ
>
依據指定格式書寫
編譯核心模組時,$ make -C /lib/modules/
uname -r/build M=
pwd modules
出現出現以下訊息,表示我的編譯器版本與kernel開發套件所用的編譯器版本版本不一致。
我主要跟著 stackoverflow 的 how to install gcc-12 on ubuntu 這篇的的方法
在執行 $ sudo apt-get install libmpfrc++-dev
的部分,會出現錯誤訊息表示被 dpkg 中斷。
接著我手動跑 $ sudo dpkg --configure -a
,會出現以下的訊息,並且運行了超過 1 小時仍卡在此訊息。
為了解決這一部分,我尋找了許多方法,最終根據 askubuntu 上的 Pregenerating ConTeXt MarkIV format. This may take some time… takes forever此貼文的方法,刪除 texlive-full 等的封包,再次跑$ sudo dpkg --configure -a
就能順利繼續更新 GCC 版本。
閱讀 Linux Device Drivers 的 chapter 2: Building and Running Modules
insmod 功用是將核心模組的載入到 kernel中,並且模組的符號表(symbol table)會與的 kernel 中的符號表相接。
閱讀 LKMPG 的 4.4 Licensing and Module Documentation 與 Linux 核心模組運作原理
能知道這部份的簡單結論,就是 MODULE_XXX 系列的巨集的參數會被合併成字串,之後把字串放到 .modinfo 的部分
MODULE_LICENSE("Dual MIT/GPL")
變成 "license = Dual MIT/GPL"
Each worker-pool bound to an actual CPU implements concurrency management by hooking into the scheduler.
As long as there are one or more runnable workers on the CPU, the worker-pool doesn’t start execution of a new work, but, when the last running worker goes to sleep, it immediately schedules a new worker so that the CPU doesn’t sit idle while there are pending work items.
在 LKMPG 14.2 Work queues 提到
Work queues To add a task to the scheduler we can use a workqueue. The kernel then uses the Completely Fair Scheduler (CFS) to execute work within the queue.
接著閱讀 Demystifying the Linux CPU Scheduler 的 2.3 Completely Fair Scheduler (CFS)
TODO 補充筆記
首先從作業說明得知,ksort 的設計。
ksort 設計為一個 character device,可理解是個能夠循序存取檔案,透過定義相關的函式,可利用存取檔案的系統呼叫以存取 (即 open, read, write, mmap 等等)。因此,使用者層級 (user-level 或 userspace) 的程式可透過 read 系統呼叫來得到輸出。
使用CMWQ 中幾個重要 API,能夠創造出一個工作佇列,能夠自己管理工作任務與 CPU 資源
alloc_workqueue()
: 創建 workqueueINIT_WORK()
: 建立一個工作結構變數queue_work()
: 調度工作,若工作結構已經在佇列中返回 False, 否則加到與某 CPU 中,倘若 CPU 死掉了,會被其他 CPU 接手執行;schedule_work
: 會把工作放到全域的工作佇列 (global workqueue)drain_workqueue()
: 清空工作佇列; destroy_workqueue()
釋放工作佇列相關的資源。接著細看 ksort 的程式碼,其中除了 CMWQ 的部分,也理解了 character device 的實作。
要載入核心模組,會使用 insmod 這命令。 而 insmod 命令內部會呼叫 init_module,而這 module_init 就可以呼叫自己寫的函式(這裡為 sort_init
)。
在 sort_init 中,我想要得知關於排序呼叫的地方與 CMWQ 如何被使用。
在 sort_init 中能看到初始化 character device,並註冊了這 character device 要使用的函式,另外中創建一個 workqueue。
閱讀 Character device drivers 理解 charater device
charater device 是由 struct cdev 表示
實作charater device,代表是對特定的檔案做system call
implementation of a character device driver means implementing the system calls specific to files: open, close, read, write, lseek, mmap, etc. These operations are described in the fields of the struct file_operations structure
以上,除了 sort_read 其他函式目前都沒有實作。
接著看 實作在 sort_impl.c
的 sort_main()
接著看 init_qsort
的實作,並且疑惑 qsort_algo()
的參數為甚麼是 work_struct
而不是 qsort *
,這些答案能從追 INIT_WORK 此函式得到答案
INIT_WORK 被實作在 workqueue.h 中
在__INIT_WORK_KEY
中設定工作結構的相關屬性後,初始化工作結構中的鏈結串列的頭,這用於將工作結構插入到工作佇列中。最後設置工作結構中的 func 指針,指向要執行的工作函式func
。
(圖中的所有函數,我都省略 simrupt 前娺)
兩個會受到 mutex_lock 保護的資料結構
第一個 kfifo rx_fifo
第二 為 struct circ_buf fast_buf,從註解得知 circ_buf 是一個能快速儲存的結構。 在 simrupt 將 中斷內容存到 rx_fifo 之前 會先存到 fast_buf 中。
整理 simrupt 值的流動過程
process_data
的 fast_bug_put
存一個 update_simrupt_data()
產生的值進 fast_buf 中fast_buf_get()
中取得 fast_buf 當前tail 的值produce_data()
存值進 rx_fifo 中timer_handler()
中呼叫的 process_data()
fast_bug_get()
存 update_simrupt_data()
產生的值進 fast_buf 開頭的位置。
之後 tasklet_schedule()
調度一次 simrupt_tasklet
在 tasklet handler 中將工作提交到工作佇列中。
回頭看工作任務
在 simrupt_work_func 看 mutex_lock 被使用。
consumer_lock 保護 fast_buf_get() 這 critical section,確保只有一個執行緒存取 fast_buf。
producer_lock 保護 produce_data(val) 這 critical section,確保只有一個執行緒能存取 rx_fifo。
mutex_lock
一樣鎖定互斥鎖。如果已取得互斥鎖則回傳0,或休眠直到互斥鎖變得可用。 如果在等待鎖定時有訊號到達,則函數傳回 -EINTR。在simrupt_read()
中,如果沒有得到 read_lock ,就會得到 read_lock,之後進入迴圈中並執行以下兩個函式
kfifo_to_user
: 作用於 從 kfifo 複製 buf 大小到 user space中。wait_event_interruptible(wq, condition);
: 以下情境,在 kfifo_len(&rx_fifo) > 0 之前,rx_wait 要等待。此函數如果被中斷會回傳 -ERESTARTSYS,如果 condition 成立就會回傳 0。跳出迴圈解開 read_lock,這代表著 rx_fifo 中至少有一值能讀。