owned this note
owned this note
Published
Linked with GitHub
contributed by `<stevendd543>`
### Simrupt
Soft-IRQ: linux 系統中將 ISR 分成 top-half 與 bottom-half,優先要先完成的 ISR 就屬於 top-half,那較次要的 routing 就必須另外排程執行,因此就有 Soft-IRQ、Tasklet、Workqueue 等等來做排程。 **Simrupt** 是一個用來模擬 character device 中斷 ,在UNIX 中使用者是使用 device file 來存取硬體,作業系統會根據 system calls 來幫助使用者與硬體溝通。device driver 中其中一個類別是 [character device](https://linux-kernel-labs.github.io/refs/heads/master/labs/device_drivers.html),是一種透過 stream 結構來讀寫資料的一種方法。
Simrupt 本身儲存是用 circular buffer 結構來做快速讀寫,但這個讀寫過程必須要使用 mutex lock 保護共享資源,因此使用 `simrupt_read()` 來實現將 character device 的資料讀取到 user space,其中若 kfifo 中沒有資料可以取得程式碼將使用`mutex_lock_interruptible` 讓程序進入休眠來等待資料,因此使用了 mutex lock 後即使被中斷也能確保已經上鎖。
`alloc_chrdev_region()` linux 主動幫你尋找**主設備號**下還沒被占用得來賦予申請次設備號,且`class_create` 會在 sys/class 建立一個 class 結構供給 `device_create` 來自動創建設備節點於 /dev 文件下,這有別於手動用命令 mknod 來創建節點
lock free : 不是沒有 lock
Softirq 由 kernel 軟體實現且執行在 interrupt context ,所以他不能在執行期間使用 blocking function 否則會造成 deadlock,若執行期間無法輕量化這個處理過程,就必須推遲(deferred work)給 kernel thread or tasklet 另外排程。而且他的數量是在 compile time 就固定,保留在特定 kernel 子系統使用, **timer** 和 **tasklet** 就是其中之二。
```
enum {
HI_SOFTIRQ = 0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
IRQ_POLL_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
HRTIMER_SOFTIRQ,
RCU_SOFTIRQ,
NR_SOFTIRQS
};
```
Tasklet 是一種 deferred work 形式,它可以動態地創建給 device driver 使用,而且他在單核心中不需考慮 concurret 的問題,易用性會比 softirq 好,但性能就相對較差。
Simrupt 使用 `static DECLARE_TASKLET_OLD(simrupt_tasklet, simrupt_tasklet_func)` 來初始化 tasklet,並且在`tasklet_schedule(&simrupt_tasklet)` 被調用的時候執行 deferred work 的排程,不過在`simrupt_tasklet_func`調用了 workqueue 的函式 `queue_work` 這裡**就不清楚他的關聯性(待補),**
TODO: wake_up_interruptible 機制
在加入 kfifo 之前用來快速儲存中斷的 context
### CMWQ
### queue_work
Memory-ordering properties
[queue_work](https://elixir.bootlin.com/linux/latest/source/include/linux/workqueue.h#L545) 主要是將 work 加入到 workqueue 中等待。
* @wq: workqueue to use
* @work: work to queue
```c
static inline bool queue_work(struct workqueue_struct *wq,
struct work_struct *work)
{
return queue_work_on(WORK_CPU_UNBOUND, wq, work);
}
```
整個 softirq context 內的操作有簡化成,1、創建 workqueue,2、定義 work struct ,3、將 work 加入 queue 等待系統執行。
回到 ksort 可以看到 qsort 的結構中有定義 struct work_struct 用於日後安排給 workqueue 去執行 qsort_algo 這個函式。
```c
static void init_qsort(struct qsort *q,
void *elems,
size_t size,
struct common *common)
{
INIT_WORK(&q->w, qsort_algo);
q->a = elems;
q->n = size;
q->common = common;
}
```
除了本身執行 qsort 會加入 workqueue 等待系統分配 cpu 執行緒外,在排序實作中也有判斷當資料量較多的時候也會推遲排序工作。
```c
if (nl > 100 && nr > 100) {
struct qsort *q = kmalloc(sizeof(struct qsort), GFP_KERNEL);
init_qsort(q, a, nl, c);
queue_work(workqueue, &q->w);
}
```