---
tags: linux2022
---
# 2022q1 Homework6 (ktcp)
contributed by < `SmallHanley` >
> [作業說明](https://hackmd.io/@sysprog/linux2022-ktcp)
> [GitHub: kecho](https://github.com/SmallHanley/kecho)
> [CS:APP CH11 Note](https://hackmd.io/@SmallHanley/csapp-ch11)
## 開發環境
```shell
$ cat /proc/version
Linux version 5.13.0-40-generic (buildd@ubuntu)
(gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34)
#45~20.04.1-Ubuntu SMP Mon Apr 4 09:38:31 UTC 2022
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
Address sizes: 39 bits physical, 48 bits virtual
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 142
Model name: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
Stepping: 10
CPU MHz: 1800.000
CPU max MHz: 3400.0000
CPU min MHz: 400.0000
BogoMIPS: 3600.00
Virtualisation: VT-x
L1d cache: 128 KiB
L1i cache: 128 KiB
L2 cache: 1 MiB
L3 cache: 6 MiB
NUMA node0 CPU(s): 0-7
```
___
## 自我檢查清單
### Q1
:::success
參照 [Linux 核心模組掛載機制](https://hackmd.io/@sysprog/linux-kernel-module),解釋 `$ sudo insmod khttpd.ko port=1999` 這命令是如何讓 `port=1999` 傳遞到核心,作為核心模組初始化的參數呢?
> 過程中也會參照到 [你所不知道的 C 語言:連結器和執行檔資訊](https://hackmd.io/@sysprog/c-linker-loader)
:::
參考 [lkmpg 4.5 Passing Command Line Arguments to a Module](https://sysprog21.github.io/lkmpg/?fbclid=IwAR18Okz1l1yBkzaz4z6DjJUxvwcqmp1q9Vs6gleiIGL8bGLdY1dQewsF7S0#passing-command-line-arguments-to-a-module),我們可以從 command line 傳入參數到核心模組。將欲接收傳入值的變數宣告成全域變數,並使用 `module_param()` macro (另外還有 `module_param_array()`、`module_param_string()`)。而 `module_param()` macro 是宣告在 [include/linux/moduleparam.h](https://elixir.bootlin.com/linux/latest/source/include/linux/moduleparam.h#L126):
```c
#define module_param(name, type, perm) \
module_param_named(name, name, type, perm)
#define module_param_named(name, value, type, perm) \
param_check_##type(name, &(value)); \
module_param_cb(name, ¶m_ops_##type, &value, perm); \
__MODULE_PARM_TYPE(name, #type)
```
其中 `param_check_##type()` 會根據 `type` 展開成以下獨一無二名字的函式:
```c
/* All the helper functions */
/* The macros to do compile-time type checking stolen from Jakub
Jelinek, who IIRC came up with this idea for the 2.4 module init code. */
#define __param_check(name, p, type) \
static inline type __always_unused *__check_##name(void) { return(p); }
```
而 `__always_unused` include 至 [include/linux/compiler_attributes.h](https://elixir.bootlin.com/linux/latest/source/include/linux/compiler_attributes.h#L285),展開後是 `__attribute__((__unused__))`,參考 [Common-Function-Attributes](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes) 的 `unused` attribute。
> This attribute, attached to a function, means that the function is meant to be possibly unused. GCC does not produce a warning for this function.
使得程式可以在編譯時期檢查 type 是否為規範的 type。
接著,以下是 `module_param_cb()` 的展開:
```c
/**
* module_param_cb - general callback for a module/cmdline parameter
* @name: a valid C identifier which is the parameter name.
* @ops: the set & get operations for this parameter.
* @arg: args for @ops
* @perm: visibility in sysfs.
*
* The ops can have NULL set or get functions.
*/
#define module_param_cb(name, ops, arg, perm) \
__module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0)
/* This is the fundamental function for registering boot/module
parameters. */
#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \
/* Default value instead of permissions? */ \
static const char __param_str_##name[] = prefix #name; \
static struct kernel_param __moduleparam_const __param_##name \
__used __section("__param") \
__aligned(__alignof__(struct kernel_param)) \
= { __param_str_##name, THIS_MODULE, ops, \
VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } }
```
如果要方便觀察展開內容,可以使用 gcc toolchain 讓 gcc 命令執行到前置處理器結束,尚未進入編譯階段 (使用 `-E` flag):
```bash
$ TREE=/usr/src/linux-headers-`uname -r`
$ gcc -E test.c \
-I$TREE/include \
-I$TREE/arch/x86/include \
-I$TREE/arch/x86/include/generated \
-I$TREE/include/uapi \
> tmp
```
==TODO==
參考 [Linux 核心模組掛載機制](https://hackmd.io/@sysprog/linux-kernel-module#Linux-%E6%A0%B8%E5%BF%83%E6%A8%A1%E7%B5%84%E6%8E%9B%E8%BC%89%E6%A9%9F%E5%88%B6),使用 `strace` 追蹤 `insmod` 的系統呼叫:
```bash
$ sudo strace -o tmp insmod kecho.ko port=1999
$ grep '1999' tmp
execve("/usr/sbin/insmod", ["insmod", "kecho.ko", "port=1999"], 0x7ffd2fb17f10 /* 26 vars */) = 0
finit_module(3, "port=1999", 0) = 0
```
若是傳入多個參數:
```bash
$ sudo strace insmod kecho.ko port=12345 backlog=128 bench=0
...
finit_module(3, "port=12345 backlog=128 bench=0", 0) = 0
...
```
### Q2
:::success
參照 [CS:APP 第 11 章](https://hackmd.io/s/ByPlLNaTG),給定的 kHTTPd 和書中的 web 伺服器有哪些流程是一致?又有什麼是你認為 kHTTPd 可改進的部分?
:::
### Q3
:::success
`htstress.c` 用到 [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html) 系統呼叫,其作用為何?這樣的 HTTP 效能分析工具原理為何?
:::
### Q4
:::success
給定的 `kecho` 已使用 CMWQ,請陳述其優勢和用法
:::
### Q5
:::success
核心文件 [Concurrency Managed Workqueue (cmwq)](https://www.kernel.org/doc/html/latest/core-api/workqueue.html) 提到 "The original create_`*`workqueue() functions are deprecated and scheduled for removal",請參閱 Linux 核心的 git log (不要用 Google 搜尋!),揣摩 Linux 核心開發者的考量
:::
### Q6
:::success
解釋 `user-echo-server` 運作原理,特別是 [epoll](http://man7.org/linux/man-pages/man7/epoll.7.html) 系統呼叫的使用
:::
### Q7
:::success
是否理解 `bench` 原理,能否比較 `kecho` 和 `user-echo-server` 表現?佐以製圖
:::
### Q8
:::success
解釋 `drop-tcp-socket` 核心模組運作原理。`TIME-WAIT` sockets 又是什麼?
:::