# 2022q1 Homework6 (ktcp)
contributed by < [tommy2234](https://github.com/tommy2234/kecho) >
> [題目描述](https://hackmd.io/@sysprog/linux2022-ktcp)
> [GitHub: kecho](https://github.com/tommy2234/kecho)
## kecho 實做分析
### CMWQ
和常見的 multithread web server 不同,在 kecho 中從頭到尾只存在一個 kernel thread ,並且藉由 work queue 來達到 concurrency 的效果。
```c
kecho_wq = alloc_workqueue(MODULE_NAME, bench ? 0 : WQ_UNBOUND, 0);
/* create a kernel thread with the function echo_server_daemon */
echo_server = kthread_run(echo_server_daemon, ¶m, MODULE_NAME);
if (IS_ERR(echo_server)) {
printk(KERN_ERR MODULE_NAME ": cannot start server daemon\n");
close_listen(listen_sock);
}
```
### echo_server_daemon
echo_server_daemon 是 kecho 的核心函式,在函式中會不斷接收連線,收到連線時建立一個新的 worker 並且放到 workqueue 中,每個 worker 負責 handle 一個 socket 連線。
也就是以下 while loop 在做的事。
```c
while (!kthread_should_stop()) {
/* using blocking I/O */
int error = kernel_accept(param->listen_sock, &sock, 0);
if (error < 0) {
if (signal_pending(current))
break;
printk(KERN_ERR MODULE_NAME ": socket accept error = %d\n", error);
continue;
}
if (unlikely(!(work = create_work(sock)))) {
printk(KERN_ERR MODULE_NAME
": create work error, connection closed\n");
kernel_sock_shutdown(sock, SHUT_RDWR);
sock_release(sock);
continue;
}
/* start the server worker, queue the work on the workqueue */
queue_work(kecho_wq, work);
}
```
### create_work
在 echo_server_daemon 中被呼叫,用來建立一個新的 worker ,也就是一個即將放入 workqueue 裡的 work_struct。
一個 worker 對應到一個 socket 連線。
```c
/* create a worker(work_struct) to handle a connection using the given socket */
static struct work_struct *create_work(struct socket *sk)
{
struct kecho *work;
if (!(work = kmalloc(sizeof(struct kecho), GFP_KERNEL)))
return NULL;
work->sock = sk;
INIT_WORK(&work->kecho_work, echo_server_worker);
list_add(&work->list, &daemon.worker);
return &work->kecho_work;
}
```
### echo_server_worker
此函式為每個 worker 的工作內容 — 處理來自 client 的 requests。
在 create_worker() 中會呼叫 INIT_WORK 將其指派給建立的 work_struct。
---
## 傳遞初始化參數到核心
傳遞過程:
```c
module_param(port, ushort, S_IRUGO);
```
module_param() 會將使用者指定的 port assign 給變數 port , 此 port 將被使用來建立參數結構體 echo_server_param 中的 listen_sock。
```c
addr.sin_port = htons(port);
```
然後此結構體 param 會在建立 kernel thread 時作為參數傳遞給 echo_server_daemon 。
```c
echo_server = kthread_run(echo_server_daemon, ¶m, MODULE_NAME);
```