实验三:进程管理
任务1:创建并运行内核线程
编写kthread.c和Makefile文件 kthread.c
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/delay.h>
MODULE_LICENSE("GPL");
#define BUF_SIZE 20
static struct task_struct *myThread = NULL;
static int print(void *data)
{
while(!kthread_should_stop()){
printk("New kthread is running.");
msleep(2000);
}
return 0;
}
static int __init kthread_init(void)
{
printk("Create kernel thread!\n");
myThread = kthread_run(print, NULL, "new_kthread");
return 0;
}
static void __exit kthread_exit(void)
{
printk("Kill new kthread.\n");if(myThread)
kthread_stop(myThread);
}
module_init(kthread_init);
module_exit(kthread_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := kthread.o
else
KERNELDIR ?= /root/kernel-5.10.0-13.0.0
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
执行make以及模块加载:
卸载模块:
任务2:打印输出当前系统 CPU 负载情况
编写cpu_loadavg.c:
#include <linux/module.h>
#include <linux/fs.h>
MODULE_LICENSE("GPL");
char tmp_cpu_load[5] = {'\0'};
static int get_loadavg(void)
{
struct file *fp_cpu;
loff_t pos = 0;
char buf_cpu[10];
fp_cpu = filp_open("/proc/loadavg", O_RDONLY, 0);
if (IS_ERR(fp_cpu)){
printk("Failed to open loadavg file!\n");
return -1;
}
kernel_read(fp_cpu, buf_cpu, sizeof(buf_cpu), &pos);
strncpy(tmp_cpu_load, buf_cpu, 4);
filp_close(fp_cpu, NULL);
return 0;
}
static int __init cpu_loadavg_init(void)
{
printk("Start cpu_loadavg!\n");
if(0 != get_loadavg()){
printk("Failed to read loadarvg file!\n");
return -1;
}
printk("The cpu loadavg in one minute is: %s\n", tmp_cpu_load);
return 0;
}
static void __exit cpu_loadavg_exit(void)
{
printk("Exit cpu_loadavg!\n");
}
module_init(cpu_loadavg_init);
module_exit(cpu_loadavg_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := cpu_loadavg.o
else
KERNELDIR ?= /root/kernel-5.10.0-13.0.0
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
内核模块加载结果
任务3:打印输出当前处于运行状态的进程的 PID 和名字
process_info.c
#include <linux/module.h>
#include <linux/sched/signal.h>
#include <linux/sched.h>
MODULE_LICENSE("GPL");
struct task_struct *p;
static int __init process_info_init(void)
{
printk("Start process_info!\n");
for_each_process(p){
if(p->state == 0)
printk("1)name:%s 2)pid:%d 3)state:%ld\n", p->comm, p->pid, p->state);
}
return 0;
}
static void __exit process_info_exit(void)
{
printk("Exit process_info!\n");
}
module_init(process_info_init);
module_exit(process_info_exit);
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := process_info.o
else
KERNELDIR ?= /root/kernel-5.10.0-13.0.0
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
内核模块加载结果
任务4:使用 cgroup 实现限制 CPU 核数
1、挂载tmpfs格式的cgroup文件夹
在root权限执行以下命令:
mkdir /cgroup
mount -t tmpfs tmpfs /cgroup
cd /cgroup
挂载tmpfs文件类型:tmpfs是直接建立在VM之上的,用一个简单的mount命令就可以创建tmpfs文件系统了。速度快,可以动态分配文件系统大小。
2、挂载cpuset管理子系统
挂载某一个 cgroups 子系统到挂载点之后,就可以通过在挂载点下面建立文件夹或者使用cgcreate命令的方法创建 cgroups 层级结构中的节点/控制组;对应的删除则使用 rmdir删除文件夹,或使用cgdelete命令删除。
mkdir cpuset
mount -t cgroup -o cpuset cpuset /cgroup/cpuset #挂载cpuset子系统
cd cpuset
mkdir mycpuset #创建一个控制组,删除用 rmdir 命令
cd mycpuset
3、设置cpu核数
echo 0 > cpuset.mems #设置0号内存结点。mems默认为空,因此需要填入值。
echo 0-2 > cpuset.cpus #这里的0-2指的是使用cpu的0、1、2三个核。实现了只是用这三个核。
4、简单的死循环C源文件while_long.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
while (1){}
printf("Over");
exit(0);
}
5、测试验证
(1)打开一个终端,执行以下命令:
## 编译上述C源文件
gcc while_long.c -o while_long
## 指定在cpuset子系统的mycpuset控制组中运行while_long,使用 ctrl+c 退出运行
cgexec -g cpuset:mycpuset ./while_long
执行如下:
(2)不要关闭上述终端,另打开一个终端,执行以下命令:
top #查看程序while_long的PID, 假设为4064。输入q 退出当前查看状态
taskset -p 4064 # 显示的如果是7(111),则测试限制cpu核数成功。
执行如下:
遇到问题
cgexec: command not found
需对libcgroup进行安装