为Linux内核添加系统调用

来源:岁月联盟 编辑:exp 时间:2011-10-29

目标:向内核添加系统调用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;

  1. 		include/linux/sched.h  
  2. 		 
  3. 		task_struct {  
  4. 		 
  5. 		    .........  
  6. 		 
  7. 		    unsigned long sched_times;  
  8. 		 
  9. 		    ..........  
  10. 		 
  11. 		};  

在创建新进程时将sched_times初始化为0

  1. 		kernel/fork.c   do_fork()函数  
  2. 		 
  3. 		long do_fork(unsigned long clone_flags,  
  4. 		              unsigned long stack_start,  
  5. 		              struct pt_regs *regs,  
  6. 		              unsigned long stack_size,  
  7. 		              int __user *parent_tidptr,  
  8. 		              int __user *child_tidptr)  
  9. 		{  
  10. 		        struct task_struct *p;  
  11. 		        int trace = 0;  
  12. 		        struct pid *pid = alloc_pid();  
  13. 		        long nr;  
  14. 		        ............  
  15. 		 
  16. 		        p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr, nr);  
  17. 		        p->sched_times = 0;  
  18. 		        ................  
  19. 		 
  20. 		}  

 

进程调度时,sched_times ++

 

  1. 		kernel/sched.c  scheduale()函数  
  2. 		 
  3. 		asmlinkage void __sched schedule(void)  
  4. 		 
  5. 		{   
  6. 		 
  7. 		        ........  
  8. 		 
  9. 		        idx = sched_find_first_bit(array->bitmap);  
  10. 		        queue = array->queue + idx;  
  11. 		        next = list_entry(queue->next, struct task_struct, run_list);  
  12. 		        next->sched_times ++;  
  13. 		        if (!rt_task(next) && interactive_sleep(next->sleep_type)) {  
  14. 		                unsigned long long delta = now - next->timestamp;  
  15. 		                if (unlikely((long long)(now - next->timestamp) < 0))  
  16. 		                        delta = 0;  
  17. 		        .........  
  18. 		 
  19. 		}  
  20. 		 

添加系统调用

  1. 		kernel/sys.c 最后边  
  2. 		 
  3. 		asmlinkage long sys_get_sched_times(unsigned long * addr)  
  4. 		 
  5. 		{  
  6. 		            printk(KERN_ALERT "get_sched_times called,sched_times=%d",current->sched_times);
  7. 		            return copy_to_user(addr,&(current->sched_times),sizeof(long));  
  8. 		 
  9. 		}  

添加系统调用号 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(系统调用号,参数...)

  1. 		 
  2. 		#include <stdio.h>  
  3. 		 
  4. 		int main()  
  5. 		{  
  6. 		        unsigned long num;  
  7. 		        int i,x,sum=0;  
  8. 		 
  9. 		        scanf("%d",&x);  
  10. 		        for(i=0;i<x*100;i++)  
  11. 		                sum = sum +i;  
  12. 		        printf("%d/n",sum);  
  13. 		 
  14. 		        if(syscall(318,&num))  
  15. 		                printf("Failed/n");  
  16. 		        else 
  17. 		                printf("sched_times =%d/n",num);  
  18. 		        return 0;  
  19. 		}  

运行结果:

用户层

/

内核层

/

 

 

 

 

 

 

 

 

 

本文出自 “牛哥的博客” 博客