# 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, &param, 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, &param, MODULE_NAME); ```