目标:向内核添加系统调用long get_shed_times(unsigned long * num),程序调用此函数时,将此进程被调度的次数存入num指向的内存单元中,32位整数。
系统环境:CentOS 5.5 32bit + 2.6.18 source code + i386架构
首先在task_struct中添加调度计数变量unsigned long sched_times;
include/linux/sched.h
task_struct {
.........
unsigned long sched_times;
..........
};
在创建新进程时将sched_times初始化为0
kernel/fork.c do_fork()函数
longdo_fork(unsignedlongclone_flags,
unsignedlongstack_start,
structpt_regs *regs,
unsignedlongstack_size,
int__user *parent_tidptr,
int__user *child_tidptr)
{
structtask_struct *p;
inttrace = 0;
structpid *pid = alloc_pid();
longnr;
............
p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);
p->sched_times = 0;
................
}
进程调度时,sched_times ++
kernel/sched.c scheduale()函数
asmlinkagevoid__sched schedule(void)
{
........
idx = sched_find_first_bit(array->bitmap);
queue = array->queue + idx;
next = list_entry(queue->next,structtask_struct, run_list);
next->sched_times ++;
if(!rt_task(next) && interactive_sleep(next->sleep_type)) {
unsignedlonglongdelta = now - next->timestamp;
if(unlikely((longlong)(now - next->timestamp)
delta = 0;
.........
}
添加系统调用
kernel/sys.c 最后边
asmlinkagelongsys_get_sched_times(unsignedlong* addr)
{
printk(KERN_ALERT "get_sched_times called,sched_times=%d",current->sched_times);
returncopy_to_user(addr,&(current->sched_times),sizeof(long));
}
添加系统调用号 include/asm/unistd.h
在最后,加入#define __NR_get_sched_times 318,并将NR_syscalls改为319
在文件中arch/i386/kernel/syscall_table.S最后添加如下内容:
OK,重新编译内核,重启。
测试:
通常,系统调用需要靠C库支持。但是,也可以直接用syscall或者用Linux本身提供的宏
宏: __syscalln() n的范围从0到6,代表需要传给系统调用的参数个数,例如open
long open(const char *filename, int flags,int mode);
#define __NR_open 5
__syscall3(long,open,const char*,filename,int,flags,int,mode)
上述方法在2.6.20以后就去掉了,因为有安全漏洞。
直接使用syscall(系统调用号,参数...)
#include
intmain()
{
unsignedlongnum;
inti,x,sum=0;
scanf("%d",&x);
for(i=0;i
sum = sum +i;
printf("%d\n",sum);
if(syscall(318,&num))
printf("Failed\n");
else
printf("sched_times =%d\n",num);
return0;
}
运行结果:
用户层
内核层