Chinaunix首页 | 论坛 | 博客
  • 博客访问: 839152
  • 博文数量: 109
  • 博客积分: 650
  • 博客等级: 上士
  • 技术积分: 1483
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-01 17:29
文章分类

全部博文(109)

文章存档

2016年(5)

2015年(21)

2014年(16)

2013年(38)

2012年(29)

分类: 系统运维

2012-05-06 09:53:20

进程可以跳转到的内核位置叫做sysem_call。这个过程检查系统调用号,这个号码告诉内核进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入口地址。接着,就调用函数,等返回后,做一些系统检查,最后返回到进程(或到其他进程,如果这个进程时间用尽)。如果你希望读这段代码,它在<内核源码目录>/kernel/entry.S,Entry(system_call)的下一行。

如何使用系统调用?

先来看一个例子:


 

点击(此处)折叠或打开

  1. #include<linux/unistd.h> /*定义宏_syscall1*/
  2. #include<time.h> /*定义类型time_t*/
  3. _syscall1(time_t,time,time_t *,tloc) /*宏,展开后得到time()函数的原型*/
  4. main()
  5. {
  6.         time_t the_time;
  7.         the_time=time((time_t *)0); /*调用time系统调用*/
  8.         printf("The time is %ld\n",the_time);
  9. }


 

系统调用time返回从格林尼治时间1970年1月1日0:00开始到现在的秒数。

这是最标准的系统调用的形式,宏_syscall1()展开来得到一个函数原型,稍后我会作详细解释。但事实上,如果把程序改成下面的样子,程序也可以运行得同样的结果。


 

点击(此处)折叠或打开

  1. #include<time.h>
  2. main()
  3. {
  4.         time_t the_time;
  5.         the_time=time((time_t *)0); /*调用time系统调用*/
  6.         printf("The time is %ld\n",the_time);
  7. }


 

这是因为在time.h中实际上已经用库函数的形式实现了time这个系统调用,替我们省掉了调用_syscall1宏展开得到函数原型这一步。

大多数系统调用都在各种C语言函数库中有所实现,所以在一般情况下,我们都可以像调用普通的库函数那样调用系统调用,只在极个别的情况下,我们才有机会用到_syscall*()这几个宏。

_syscall*()是什么?

在unistd.h里定义了7个宏,分别是

_syscall0(type,name)
_syscall1(type,name,type1,arg1)
_syscall2(type,name,type1,arg1,type2,arg2)
_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
_syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4)
_syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5)
_syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,t

它们看起来似乎不太像宏,但其实质和

#define MAXSIZE 100

里面的MAXSIZE没有任何区别。

它们的作用是形成相应的系统调用函数原型,供我们在程序中调用。我们很容易就能发现规律,_syscall后面的数字和typeN,argN的数目一样多。事实上,_syscall后面跟的数字指明了展开后形成函数的参数的个数,让我们看一个实例,就是刚刚用过的time系统调用:

_syscall1(time_t,time,time_t *,tloc)

展开后的情形是这样:


 

点击(此处)折叠或打开

  1. time_t time(time_t * tloc)
  2. {
  3.     long __res;
  4.     __asm__ volatile("int $0x80" : "=a" (__res) : "0" (13),"b" ((long)(tloc)));
  5.     do {
  6.         if ((unsigned long)(__res) >= (unsigned long)(-125)) {
  7.             errno = -(__res);
  8.             __res = -1;
  9.         }
  10.         return (time_t) (__res);
  11.     } while (0) ;
  12. }


 

可以看出,_syscall1(time_t,time,time_t *,tloc)展开成一个名为time的函数,原参数time_t就是函数的返回类型,原参数time_t *和tloc分别构成新函数的参数。事实上,程序中用到的time函数的原型就是它。

errno是什么?

为防止和正常的返回值混淆,系统调用并不直接返回错误码,而是将错误码放入一个名为errno的全局变量中。如果一个系统调用失败,你可以读出errno的值来确定问题所在。

errno不同数值所代表的错误消息定义在errno.h中,你也可以通过命令"man 3 errno"来察看它们。

需要注意的是,errno的值只在函数发生错误时设置,如果函数不发生错误,errno的值就无定义,并不会被置为0。另外,在处理errno前最好先把它的值存入另一个变量,因为在错误处理过程中,即使像printf()这样的函数出错时也会改变errno的值。

阅读(1750) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~