Linux驱动学习——进程管理

背景

关于进程管理的介绍参考Linux内核学习——进程管理

内核线程

  • 编写一个内核模块,创建一组内核线程,每个CPU一个内核线程
  • 在每个内核线程中,打印当前CPU的状态
  • 在每个内核线程中,打印当前进程的优先级等信息

代码

kthread.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/delay.h>

// 指定license版本
MODULE_LICENSE("GPL");
// 作者信息
MODULE_AUTHOR("Marvin");
// 模块描述
MODULE_DESCRIPTION("process kthread demo");
// 提供别名
MODULE_ALIAS("processkthread");

static struct task_struct *tsk[NR_CPUS];

static void show_prio(void)
{
	struct task_struct *task = current;

	printk("%s pid:%d, nice:%d prio:%d static_prio:%d normal_prio:%d\n",
			task->comm, task->pid,
			PRIO_TO_NICE(task->static_prio),
			task->prio, task->static_prio,
			task->normal_prio);
}

static void print_cpu(char *s)
{
	preempt_disable();
	pr_info("%s cpu=%d.\n", s, smp_processor_id());
	preempt_enable();
}

static int thread_fun(void *t)
{
	do {
		print_cpu("SLEEP in Thread Function ");
		msleep_interruptible(2000);
		print_cpu("msleep over in Thread Function");
		print_cpu("running");
		show_prio();
	} while (!kthread_should_stop());
	return 0;
}

static int __init my_init(void)
{
	int i;
	print_cpu("Loading module");
	for_each_online_cpu(i) {
		tsk[i] = kthread_create(thread_fun, NULL, "kdemo/%d", i);
		if (!tsk[i]) {
			pr_info("Failed to generate a kernel thread\n");
			return -1;
		}
		kthread_bind(tsk[i], i);
		pr_info("About to wake up and run the thread for cpu=%d\n", i);
		wake_up_process(tsk[i]);
		pr_info("Staring thread for cpu %d", i);
		print_cpu("on");
	}
	return 0;
}

static void __exit my_exit(void)
{
	int i;
	for_each_online_cpu(i) {
		pr_info(" Kill Thread %d", i);
		kthread_stop(tsk[i]);
		print_cpu("Kill was done on ");
	}
	pr_info("goodbye\n");
}

module_init(my_init);
module_exit(my_exit);

测试

sudo insmod processkthread.ko
sudo rmmod processkthread.ko

内核日志

[ 2553.129572] Loading module cpu=2.
[ 2553.129676] About to wake up and run the thread for cpu=0
[ 2553.129680] Staring thread for cpu 0
[ 2553.129681] on cpu=2.
[ 2553.129717] About to wake up and run the thread for cpu=1
[ 2553.129720] Staring thread for cpu 1
[ 2553.129721] on cpu=2.
[ 2553.129721] SLEEP in Thread Function  cpu=0.
[ 2553.129723] SLEEP in Thread Function  cpu=1.
[ 2553.129745] About to wake up and run the thread for cpu=2
[ 2553.129747] Staring thread for cpu 2
[ 2553.129748] on cpu=2.
[ 2553.129753] SLEEP in Thread Function  cpu=2.
[ 2553.129774] About to wake up and run the thread for cpu=3
[ 2553.129777] Staring thread for cpu 3
[ 2553.129778] on cpu=2.
[ 2553.129779] SLEEP in Thread Function  cpu=3.
[ 2555.136273] msleep over in Thread Function cpu=1.
[ 2555.136273] msleep over in Thread Function cpu=2.
[ 2555.136276] running cpu=1.
[ 2555.136277] running cpu=2.
[ 2555.136277] kdemo/1 pid:3390, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2555.136278] kdemo/2 pid:3391, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2555.136279] SLEEP in Thread Function  cpu=1.
[ 2555.136279] SLEEP in Thread Function  cpu=2.
[ 2555.136281] msleep over in Thread Function cpu=3.
[ 2555.136283] running cpu=3.
[ 2555.136283] kdemo/3 pid:3392, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2555.136284] SLEEP in Thread Function  cpu=3.
[ 2555.136286] msleep over in Thread Function cpu=0.
[ 2555.136288] running cpu=0.
[ 2555.136289] kdemo/0 pid:3389, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2555.136290] SLEEP in Thread Function  cpu=0.
[ 2557.184343] msleep over in Thread Function cpu=1.
[ 2557.184343] msleep over in Thread Function cpu=2.
[ 2557.184344] msleep over in Thread Function cpu=3.
[ 2557.184346] running cpu=3.
[ 2557.184346] running cpu=2.
[ 2557.184347] kdemo/3 pid:3392, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2557.184347] running cpu=1.
[ 2557.184347] kdemo/2 pid:3391, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2557.184349] SLEEP in Thread Function  cpu=2.
[ 2557.184348] kdemo/1 pid:3390, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2557.184349] SLEEP in Thread Function  cpu=3.
[ 2557.184350] SLEEP in Thread Function  cpu=1.
[ 2557.184389] msleep over in Thread Function cpu=0.
[ 2557.184390] running cpu=0.
[ 2557.184391] kdemo/0 pid:3389, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2557.184392] SLEEP in Thread Function  cpu=0.
[ 2559.232335] msleep over in Thread Function cpu=0.
[ 2559.232335] msleep over in Thread Function cpu=2.
[ 2559.232335] msleep over in Thread Function cpu=1.
[ 2559.232346] running cpu=0.
[ 2559.232346] running cpu=2.
[ 2559.232346] kdemo/0 pid:3389, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2559.232347] running cpu=1.
[ 2559.232347] kdemo/2 pid:3391, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2559.232348] SLEEP in Thread Function  cpu=0.
[ 2559.232347] msleep over in Thread Function cpu=3.
[ 2559.232348] kdemo/1 pid:3390, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2559.232349] running cpu=3.
[ 2559.232349] SLEEP in Thread Function  cpu=2.
[ 2559.232350] kdemo/3 pid:3392, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2559.232350] SLEEP in Thread Function  cpu=1.
[ 2559.232351] SLEEP in Thread Function  cpu=3.
[ 2561.245601]  Kill Thread 0
[ 2561.245653] msleep over in Thread Function cpu=0.
[ 2561.245656] running cpu=0.
[ 2561.245656] kdemo/0 pid:3389, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2561.245665] Kill was done on  cpu=1.
[ 2561.245666]  Kill Thread 1
[ 2561.245670] msleep over in Thread Function cpu=1.
[ 2561.245671] running cpu=1.
[ 2561.245671] kdemo/1 pid:3390, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2561.245676] Kill was done on  cpu=1.
[ 2561.245677]  Kill Thread 2
[ 2561.245718] msleep over in Thread Function cpu=2.
[ 2561.245720] running cpu=2.
[ 2561.245720] kdemo/2 pid:3391, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2561.245728] Kill was done on  cpu=1.
[ 2561.245729]  Kill Thread 3
[ 2561.245774] msleep over in Thread Function cpu=3.
[ 2561.245776] running cpu=3.
[ 2561.245776] kdemo/3 pid:3392, nice:0 prio:120 static_prio:120 normal_prio:120
[ 2561.245784] Kill was done on  cpu=1.
[ 2561.245785] goodbye

同时可以在命令行中查看:

$ ps -ef | grep kdemo
root        2294       2  0 11:36 ?        00:00:00 [kdemo/0]
root        2295       2  0 11:36 ?        00:00:00 [kdemo/1]
root        2296       2  0 11:36 ?        00:00:00 [kdemo/2]
root        2297       2  0 11:36 ?        00:00:00 [kdemo/3]

后台守护进程

使用daemon函数,创建一个守护进程

代码

daemon.c

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/klog.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>

#define FALLBACK_KLOG_BUF_SHIFT 17 /* CONFIG_LOG_BUF_SHIFT in kernel */
#define FALLBACK_KLOG_BUF_LEN (1 << FALLBACK_KLOG_BUF_SHIFT)

#define KLOG_CLOSE 0
#define KLOG_OPEN 1
#define KLOG_READ 2
#define KLOG_READ_ALL 3
#define KLOG_READ_CLEAR 4
#define KLOG_CLEAR 5
#define KLOG_CONSOLE_OFF 6
#define KLOG_CONSOLE_ON 7
#define KLOG_CONSOLE_LEVEL 8
#define KLOG_SIZE_UNREAD 9
#define KLOG_SIZE_BUFFER 10

/* we use 'Linux version' string instead of Oops in this lab */
// #define OOPS_LOG  "Oops"
#define OOPS_LOG "Linux version"

int save_kernel_log(char *buffer) {
  char path[128];
  time_t t;
  struct tm *tm;
  int fd;

  t = time(0);
  tm = localtime(&t);

  snprintf(path, 128, "/tmp/%d.%d.%d.%d.%d.%d.log", tm->tm_year + 1900,
           tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
  printf("%s\n", path);

  fd = open(path, O_WRONLY | O_CREAT, 0644);
  if (fd == -1) {
    printf("open error\n");
    return -1;
  }
  write(fd, buffer, strlen(buffer));
  close(fd);

  return 0;
}

int check_kernel_log() {
  char *buffer;
  char *p;
  ssize_t klog_size;
  int ret = -1;
  int size;

  printf("start kernel log\n");

  klog_size = klogctl(KLOG_SIZE_BUFFER, 0, 0);
  if (klog_size <= 0) {
    klog_size = FALLBACK_KLOG_BUF_LEN;
  }

  printf("kernel log size: %d\n", klog_size);

  buffer = malloc(klog_size + 1);
  if (!buffer)
    return -1;

  size = klogctl(KLOG_READ_ALL, buffer, klog_size);
  if (size < 0) {
    printf("klogctl read error\n");
    goto done;
  }

  buffer[size] = '\0';

  /* check if oops in klog */
  p = strstr(buffer, OOPS_LOG);
  if (p) {
    printf("we found '%s' on kernel log\n", OOPS_LOG);
    save_kernel_log(buffer);
    ret = 0;
  }
done:
  free(buffer);
  return ret;
}

int main(void) {
  if (daemon(0, 0) == -1) {
    printf("daemon error");
    return 0;
  }

  while (1) {
    check_kernel_log();

    sleep(5);
  }

  return 0;
}

测试

gcc daemon.c -o daemon
sudo ./daemon

会在指定的目录下每5s转存下内核日志。

进程权限

编写一个用户程序,限制该程序的一些资源,比如进程的最大虚拟内存空间等。

代码

resource_limit.c

#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
#include <errno.h>

#define DEATH(mess) { perror(mess); exit(errno); }

void do_limit(int limit, const char *limit_string, struct rlimit *rlim)
{
	if (getrlimit(limit, rlim))
		fprintf(stderr, "Failed in getrlimit\n");
	printf("%15s=%2d: cur=%20lu,     max=%20lu\n", limit_string,
	       limit, rlim->rlim_cur, rlim->rlim_max);
}

void print_limits(void)
{
	struct rlimit rlim;
	do_limit(RLIMIT_CPU, "RLIMIT_CPU", &rlim);
	do_limit(RLIMIT_FSIZE, "RLMIT_FSIZE", &rlim);
	do_limit(RLIMIT_DATA, "RLMIT_DATA", &rlim);
	do_limit(RLIMIT_STACK, "RLIMIT_STACK", &rlim);
	do_limit(RLIMIT_CORE, "RLIMIT_CORE", &rlim);
	do_limit(RLIMIT_RSS, "RLIMIT_RSS", &rlim);
	do_limit(RLIMIT_NPROC, "RLIMIT_NPROC", &rlim);
	do_limit(RLIMIT_NOFILE, "RLIMIT_NOFILE", &rlim);
	do_limit(RLIMIT_MEMLOCK, "RLIMIT_MEMLOCK", &rlim);
	do_limit(RLIMIT_AS, "RLIMIT_AS", &rlim);
	do_limit(RLIMIT_LOCKS, "RLIMIT_LOCKS", &rlim);
}

void print_rusage(int who)
{
	struct rusage usage;
	if (getrusage(who, &usage))
		DEATH("getrusage failed");

	if (who == RUSAGE_SELF)
		printf("For RUSAGE_SELF\n");
	if (who == RUSAGE_CHILDREN)
		printf("\nFor RUSAGE_CHILDREN\n");

	printf
	    ("ru_utime.tv_sec, ru_utime.tv_usec = %4d  %4d (user time used)\n",
	     (int)usage.ru_utime.tv_sec, (int)usage.ru_utime.tv_usec);
	printf
	    ("ru_stime.tv_sec, ru_stime.tv_usec = %4d  %4d (system time used)\n",
	     (int)usage.ru_stime.tv_sec, (int)usage.ru_stime.tv_usec);
	printf("ru_maxrss =  %4ld (max resident set size)\n", usage.ru_maxrss);
	printf("ru_ixrss =   %4ld (integral shared memory size)\n",
	       usage.ru_ixrss);
	printf("ru_idrss =   %4ld (integral unshared data size)\n",
	       usage.ru_idrss);
	printf("ru_isrss =   %4ld (integral unshared stack size)\n",
	       usage.ru_isrss);
	printf("ru_minflt =  %4ld (page reclaims)\n", usage.ru_minflt);
	printf("ru_majflt =  %4ld (page faults)\n", usage.ru_majflt);
	printf("ru_nswap =   %4ld (swaps)\n", usage.ru_nswap);
	printf("ru_inblock = %4ld (block input operations)\n",
	       usage.ru_inblock);
	printf("ru_oublock = %4ld (block output operations)\n",
	       usage.ru_oublock);
	printf("ru_msgsnd =  %4ld (messages sent)\n", usage.ru_msgsnd);
	printf("ru_msgrcv =  %4ld (messages received)\n", usage.ru_msgrcv);
	printf("ru_nsignals= %4ld (signals received)\n", usage.ru_nsignals);
	printf("ru_nvcsw=    %4ld (voluntary context switches)\n",
	       usage.ru_nvcsw);
	printf("ru_nivcsw=   %4ld (involuntary context switches)\n",
	       usage.ru_nivcsw);
}

int main(int argc, char *argv[])
{
	struct rlimit rlim;
	pid_t pid = 0;
	int status = 0, nchildren = 3, i;

	/* Print out all limits */

	printf("Printing out all limits for pid=%d:\n", getpid());
	print_limits();

	/* change and printout the limit for core file size */

	printf("\nBefore Modification, this is RLIMIT_CORE:\n");
	do_limit(RLIMIT_CORE, "RLIMIT_CORE", &rlim);
	rlim.rlim_cur = 8 * 1024 * 1024;
	printf("I forked off a child with pid = %d\n", (int)pid);

	setrlimit(RLIMIT_CORE, &rlim);
	printf("\nAfter  Modification, this is RLIMIT_CORE:\n");
	do_limit(RLIMIT_CORE, "RLIMIT_CORE", &rlim);

	/* fork off the nchildren */

	fflush(stdout);
	for (i = 0; i < nchildren; i++) {
		pid = fork();
		if (pid < 0)
			DEATH("Failed in fork");
		if (pid == 0) {	/* any child */
			printf("\nIn child pid= %d this is RLIMIT_CORE:\n",
			       (int)getpid());
			do_limit(RLIMIT_CORE, "RLIMIT_CORE", &rlim);
			fflush(stdout);
			sleep(3);
			exit(EXIT_SUCCESS);
		}
	}

	while (pid > 0) {	/* parent */
		pid = wait(&status);
		printf("Parent got return on pid=%d\n", (int)pid);
	}

	printf(" **************************************************** \n");
	print_rusage(RUSAGE_SELF);
	print_rusage(RUSAGE_CHILDREN);

	exit(EXIT_SUCCESS);
}

测试

gcc resource_limit.c -o resource_limit
./resource_limit 
Printing out all limits for pid=6743:
     RLIMIT_CPU= 0: cur=18446744073709551615,     max=18446744073709551615
    RLMIT_FSIZE= 1: cur=18446744073709551615,     max=18446744073709551615
     RLMIT_DATA= 2: cur=18446744073709551615,     max=18446744073709551615
   RLIMIT_STACK= 3: cur=             8388608,     max=18446744073709551615
    RLIMIT_CORE= 4: cur=18446744073709551615,     max=18446744073709551615
     RLIMIT_RSS= 5: cur=18446744073709551615,     max=18446744073709551615
   RLIMIT_NPROC= 6: cur=               15502,     max=               15502
  RLIMIT_NOFILE= 7: cur=                1024,     max=              524288
 RLIMIT_MEMLOCK= 8: cur=             8388608,     max=             8388608
      RLIMIT_AS= 9: cur=18446744073709551615,     max=18446744073709551615
   RLIMIT_LOCKS=10: cur=18446744073709551615,     max=18446744073709551615

Before Modification, this is RLIMIT_CORE:
    RLIMIT_CORE= 4: cur=18446744073709551615,     max=18446744073709551615
I forked off a child with pid = 0

After  Modification, this is RLIMIT_CORE:
    RLIMIT_CORE= 4: cur=             8388608,     max=18446744073709551615

In child pid= 6744 this is RLIMIT_CORE:
    RLIMIT_CORE= 4: cur=             8388608,     max=18446744073709551615

In child pid= 6745 this is RLIMIT_CORE:
    RLIMIT_CORE= 4: cur=             8388608,     max=18446744073709551615

In child pid= 6746 this is RLIMIT_CORE:
    RLIMIT_CORE= 4: cur=             8388608,     max=18446744073709551615
Parent got return on pid=6744
Parent got return on pid=6745
Parent got return on pid=6746
Parent got return on pid=-1
 **************************************************** 
For RUSAGE_SELF
ru_utime.tv_sec, ru_utime.tv_usec =    0     0 (user time used)
ru_stime.tv_sec, ru_stime.tv_usec =    0   906 (system time used)
ru_maxrss =  15016 (max resident set size)
ru_ixrss =      0 (integral shared memory size)
ru_idrss =      0 (integral unshared data size)
ru_isrss =      0 (integral unshared stack size)
ru_minflt =   107 (page reclaims)
ru_majflt =     0 (page faults)
ru_nswap =      0 (swaps)
ru_inblock =    0 (block input operations)
ru_oublock =    0 (block output operations)
ru_msgsnd =     0 (messages sent)
ru_msgrcv =     0 (messages received)
ru_nsignals=    0 (signals received)
ru_nvcsw=       1 (voluntary context switches)
ru_nivcsw=      0 (involuntary context switches)

For RUSAGE_CHILDREN
ru_utime.tv_sec, ru_utime.tv_usec =    0     0 (user time used)
ru_stime.tv_sec, ru_stime.tv_usec =    0   617 (system time used)
ru_maxrss =  1204 (max resident set size)
ru_ixrss =      0 (integral shared memory size)
ru_idrss =      0 (integral unshared data size)
ru_isrss =      0 (integral unshared stack size)
ru_minflt =   105 (page reclaims)
ru_majflt =     0 (page faults)
ru_nswap =      0 (swaps)
ru_inblock =    0 (block input operations)
ru_oublock =    0 (block output operations)
ru_msgsnd =     0 (messages sent)
ru_msgrcv =     0 (messages received)
ru_nsignals=    0 (signals received)
ru_nvcsw=       6 (voluntary context switches)
ru_nivcsw=      6 (involuntary context switches)

设置优先级

编写一个用户进程,使用setpriority()来修改进程的优先级,然后使用getpriority()函数验证

代码

process_priority.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <errno.h>

int main(int argc, char *argv[])
{
	pid_t mypid;
	int old_prio, new_prio, i, rc;

	if (argc > 1) {
		mypid = atoi(argv[1]);
	} else {
		mypid = getpid();
	}

	printf("\nExamining priorities forPID = %d \n", mypid);
	printf("%10s%10s%10s\n", "Previous", "Requested", "Assigned");

	for (i = -20; i < 20; i += 2) {

		old_prio = getpriority(PRIO_PROCESS, (int)mypid);
		rc = setpriority(PRIO_PROCESS, (int)mypid, i);
		if (rc)
			fprintf(stderr, "setpriority() failed ");

		/* must clear errno before call to getpriority
		   because -1 is a valid return value */
		errno = 0;

		new_prio = getpriority(PRIO_PROCESS, (int)mypid);
		printf("%10d%10d%10d\n", old_prio, i, new_prio);

	}
	exit(EXIT_SUCCESS);
}

测试

sudo ./process_priority
Examining priorities forPID = 7212 
  Previous Requested  Assigned
         0       -20       -20
       -20       -18       -18
       -18       -16       -16
       -16       -14       -14
       -14       -12       -12
       -12       -10       -10
       -10        -8        -8
        -8        -6        -6
        -6        -4        -4
        -4        -2        -2
        -2         0         0
         0         2         2
         2         4         4
         4         6         6
         6         8         8
         8        10        10
        10        12        12
        12        14        14
        14        16        16
        16        18        18

per-cpu变量

创建一个per-cpu变量,并且初始化该per-cpu变量,修改per-cpu变量的值,然后输出这些值
per-cpu变量是Linux内核中同步机制的一种。当系统中所有的CPU都访问共享的一个变量v时,CPU0修改了变量v的值时,CPU1也在同时修改变量v的值,那么就会导致变量v值不正确。一个可行的办法就是CPU0访问变量v时使用原子加锁指令,CPU1访问变量v时只能等待了,可是这会有两个比较明显的缺点。

  • 原子操作是比较耗时的。
  • 现代处理器中,每个CPU都有L1缓存,那么多CPU同时访问同一个变量时会导致缓存一致性问题。当某个CPU对共享数据变量v修改后,其他CPU上对应的缓存行需要做无效操作,这对性能是有所损耗的。
    per-cpu 变量为了解决上述问题出现一种有趣的特性,它为系统中每个处理器都分配该变量的副本。这样在多处理器系统中,当处理器只能访问属于它自己的那个变量副本,不需要考虑与其他处理器的竞争问题,还能充分利用处理器本地的硬件缓存来提升性能。

代码

percpu.c

#include <linux/module.h>
#include <linux/init.h>
#include <linux/percpu.h>
#include <linux/cpumask.h>

// 指定license版本
MODULE_LICENSE("GPL");
// 作者信息
MODULE_AUTHOR("Marvin");
// 模块描述
MODULE_DESCRIPTION("process percpu demo");
// 提供别名
MODULE_ALIAS("processpercpu");

static DEFINE_PER_CPU(long, cpuvar) = 10;
static long __percpu *cpualloc;

static int __init my_init(void)
{
	int cpu;

	pr_info("module loaded at 0x%p\n", my_init);

	/* modify the cpuvar value */
	for_each_possible_cpu(cpu){
		per_cpu(cpuvar, cpu) = 15;
		pr_info("init: cpuvar on cpu%d  = %ld\n",
			cpu, get_cpu_var(cpuvar));
		put_cpu_var(cpuvar);

	}

	__this_cpu_write(cpuvar, 20);

	/* alloc a percpu value */
	cpualloc = alloc_percpu(long);

	/* set all cpu for this value */
	for_each_possible_cpu(cpu){
		*per_cpu_ptr(cpualloc, cpu) = 100;
		pr_info("init: cpu:%d cpualloc = %ld\n",
				cpu, *per_cpu_ptr(cpualloc, cpu));
	}

	return 0;
}

static void __exit my_exit(void)
{
	int cpu;
	pr_info("exit module...\n");

	for_each_possible_cpu(cpu) {
		pr_info("cpuvar cpu%d = %ld\n", cpu, per_cpu(cpuvar, cpu));
		pr_info("exit: cpualloc%d = %ld\n", cpu, *per_cpu_ptr(cpualloc, cpu));
	}

	free_percpu(cpualloc);

	pr_info("Bye: module unloaded from 0x%p\n", my_exit);
}

module_init(my_init);
module_exit(my_exit);

Makefile

ifneq ($(KERNELRELEASE),)
MODULE_NAME = processpercpu
$(MODULE_NAME)-objs := percpu.o
obj-m := $(MODULE_NAME).o
else
KERNEL_DIR = /lib/modules/`uname -r`/build
MODULEDIR := $(shell pwd)
 
.PHONY: modules
default: modules
 
modules:
	make -C $(KERNEL_DIR) M=$(MODULEDIR) modules
 
clean distclean:
	make -C /lib/modules/$(shell uname -r)/build/ M=$(PWD) clean
	rm -f *.o *.mod.c .*.*.cmd *.ko
	rm -rf .tmp_versions
endif

测试

sudo insmod processpercpu.ko
sudo rmmod processpercpu.ko

内核日志

[ 5120.592012] module loaded at 0x00000000e4845e2e
[ 5120.592017] init: cpuvar on cpu0  = 15
[ 5120.592018] init: cpuvar on cpu1  = 15
[ 5120.592019] init: cpuvar on cpu2  = 15
[ 5120.592020] init: cpuvar on cpu3  = 15
[ 5120.592023] init: cpu:0 cpualloc = 100
[ 5120.592024] init: cpu:1 cpualloc = 100
[ 5120.592025] init: cpu:2 cpualloc = 100
[ 5120.592026] init: cpu:3 cpualloc = 100
[ 5129.730217] exit module...
[ 5129.730219] cpuvar cpu0 = 20
[ 5129.730220] exit: cpualloc0 = 100
[ 5129.730221] cpuvar cpu1 = 15
[ 5129.730221] exit: cpualloc1 = 100
[ 5129.730222] cpuvar cpu2 = 15
[ 5129.730223] exit: cpualloc2 = 100
[ 5129.730223] cpuvar cpu3 = 15
[ 5129.730224] exit: cpualloc3 = 100
[ 5129.730225] Bye: module unloaded from 0x00000000cb3a0059

参考

Linux内核学习——进程管理

posted @ 2026-02-26 11:38  main_c  阅读(1)  评论(0)    收藏  举报  来源