免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: 雨丝风片
打印 上一主题 下一主题

[FreeBSD] 【FreeBSD system programming 】中文翻译计划及所有异义提交处 [复制链接]

论坛徽章:
0
121 [报告]
发表于 2006-02-20 13:01 |只看该作者
原帖由 gvim 于 2006-2-20 11:23 发表
4.4 信号处理
现在我们知道何时会产生信号,也知道如何发送信号,那么我们怎么处理它们呢?

signal函数

signal系统函数调用提供了一种最简单的范例。然而,由于C原形声明的缘故使它看起 ...



快啦快啦!我剩下的那点儿也要赶快了。。。

论坛徽章:
0
122 [报告]
发表于 2006-02-20 17:08 |只看该作者
***继续,麻烦楼主帮忙调整一下相关代码的格式,我不会使用这个论坛的跟格式相关的功能***

5.3文件上锁

当多个进程试图写同一个文件,将发生什么?它们相互冲突,已知的事情像文件上锁。结果就是每个文件描都有自己的描述符跟偏移量,当每个进程写自己的文件时,偏移量预先独立导致没有进程知道其他的进程也正在执行写操作。最后的文件将因为多个独立写文件的操作使混合后的文件变得相当于垃圾,直接给文件上锁是解决这个问题的一种方式。在任意时刻只能让一个进程能够写到文件,另一种办法是允许在一个叫做高级文件锁的scheme里的文件内部进行区域锁定。fcntl函数能够提供这个功能,通常来说,锁有两种,一种是写,另一种是写,不同之处在于读锁不会干扰其它进程读取文件,但是特定的区域只能一个写锁存在。

当使用顾问锁的时候,下面的结构用作fcntl的第三个参数。

  1.   struct flock {
  2.             off_t   l_start;    /* starting offset */
  3.             off_t   l_len;      /* len = 0 means until end of file */
  4.             pid_t   l_pid;      /* lock owner */
  5.             short   l_type;     /* lock type:   */
  6.             short   l_whence;   /* type of l_start */
  7.     };
复制代码


让我们继续讨论每个元素的细节。

l_start

这是一个相对于l_whence,单位为字节的偏移量,换句话说,要求的位置实际上是l_whence + l_start

l_len

需设置为期望位置的长度,单位为字节,锁将从l_whence + l_start开始锁定l_len字节,如果你想整个文件用一把锁,那么设定l_len的值为0,如果l_len的值是一个负数,结果是不可预测的。

l_pid

需要设置为工作在锁上的进程的ID

l_type

需要设置为期望的锁的类型,下面是能够使用的值

    * F_RDLCK - 读锁定
    * F_WRLCK - 写锁定
    * F_UNLCK - 用作清除锁定

l_whence

这是这个系统调用里面最混乱的部分,这个字段将决定l_start位置的偏移量,需要设为:
    * SEEK_CUR - 在当前位置
    * SEEK_SET - 在文件开始
    * SEEK_END - 在文件末尾

fcntl的命令

下面的可用作fcntl的命令

  1. #define  F_GETLK      7
复制代码


F_GETLK命令尝试检查否能上锁,当使用这个命令,fnctl将检查是否有相冲突的锁,如果存在相冲突的锁,fnctl将改写flock结构,用冲突锁消息通过检查,如果没有相冲突的锁,那么在flock结构最初的信息将被保留,除非l_type字段被设成F_UNLCK

  1. #define  F_SETLK      8
复制代码


F_SETLK命令试图获得flock结构描述的锁,如果锁不被承认,本次调用将不被阻塞。不管怎样,fcntl将直接返回EAGAIN,同时将设置相应的errno,当flock结构的l_type被设置为F_UNLCK时,你能够使用这个命令清除一个锁。

  1. #define  F_SETLKW     9
复制代码


F_GETLK命令试图获得flock结构描述的锁,它将命令fnctl阻塞,直到赋予一个锁

[ 本帖最后由 雨丝风片 于 2006-2-27 12:25 编辑 ]

论坛徽章:
0
123 [报告]
发表于 2006-02-20 17:24 |只看该作者
原帖由 horseman 于 2006-2-20 17:08 发表
***继续,麻烦楼主帮忙调整一下相关代码的格式,我不会使用这个论坛的跟格式相关的功能***

5.3文件上锁
当多个进程试图写同一个文件,将发生什么?它们相互冲突,已知的事情像文件上锁。结果就是每个文件描都 ...


紧挨着你的编辑框的上面不是有一排按钮么,上面都有提示的,连猜带摸索不就会了?呵呵!

论坛徽章:
0
124 [报告]
发表于 2006-02-21 12:33 |只看该作者
偶负责的第六章还差20%了,

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
125 [报告]
发表于 2006-02-21 13:26 |只看该作者
原帖由 雨丝风片 于 2006-2-21 12:33 发表
偶负责的第六章还差20%了,


我也还差10%左右了。

论坛徽章:
0
126 [报告]
发表于 2006-02-23 12:13 |只看该作者
建议翻译完成后能不能由CU组织印制,然后由我们来邮购,反正也是要打印出来看的。钱可以分给译者、CU等,也算是作为对译者辛苦的一点回报。以后再接再劢译出更多好的文章。

论坛徽章:
2
亥猪
日期:2014-03-19 16:36:35午马
日期:2014-11-23 23:48:46
127 [报告]
发表于 2006-02-25 02:31 |只看该作者
4.6 自定义行为

一些时候程序要求信号处理句柄运行在一个特定的堆栈上。为了实现这个目的,一个备用(alternate)堆栈区间必须用signaltstack函数指出来。这个函数使用的数据结构为signaltstack:
  1. int    sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
复制代码

它的结构成员解释如下。
  1. char    *ss_sp;
复制代码

该成员指向一个被用作堆栈的区域。系统中有个MINSIGSTKSZ常量,它定义了进行信号处理时所需的最小内存空间。系统中还有一个SIGSTKSZ常量,它定义了通常情况下处理时所需内存空间。该内存空间需要在调用signaltstack函数之间分配。
  1. size_t  ss_size;
复制代码

数据成员ss_size指出新堆栈的大小。如果这个值是错误的(inaccurate),当信号处理句柄执行时,它的行为就变得不可预知(你不能明确知道系统怎样处理这个信号)。
  1. int     ss_flags;
复制代码

根据调用环境(calling circumstances),数据成员ss_flags可以具有少数几个不同的值。首先,当进程希望停用备用堆栈的时候,ss_flags会被设为SS_DISABLE。在这个情况下,ss_sp和ss_size被忽略,备用堆栈被禁止。注意,备用堆栈只能在当前句柄没有处理时禁止。

如果使用一个non-null值作为oss的实参去调用signaltstack,ss_flags将包含指示当前状态的信息。它们是:
  1. SS_DISABLE: 备用堆栈被停用。
  2. SS_ONSTACK: 备用堆栈当前正在被使用,并且现在不可以停用。
复制代码

如果调用signaltstack 的oss实参不是null,会返回当前状态。调用成功返回0,否则返回-1。如果调用失败,errno也会相应的被设置。因为信号可以在任何一点被交付,所以很难被预测。出于这个原因,4.2BSD的缺省行为是:重新开始被中断的系统调用,重新提供还没有被转送的数据。在大多数时候这个行为是很不错的,并且也是所有BSD系统采用的缺省行为。可是,也有一些罕见的情况,你可能需要将这个特性关掉。你可以使用siginterrupt函数完成需求。使用很简单:
  1. int   siginterrupt(int sig, int flag);
复制代码

将sig参数设置为目标信号,并且设置flag为真(在这个情况下是1)。如果flag参数被设为假(在这个情况下是0),那么缺省行为是重新启动系统调用。

4.7 等待信号

sigsuspend函数可以暂时将当前阻塞信号集改变为由sigmask指定的信号集。改变后,sigsuspend会等待,直到一个信号被交付。一旦一个信号被交付后,原先的信号集被恢复。由于sigsuspend调用在信号交付之后总是被终止,它的返回值总是-1,errno总是EINTR。下面是它的语法:
  1. int     sigsuspend(const sigset_t *sigmask);
复制代码

sigwait函数用set参数指定的信号集作为信号掩码。它会检查包含在这个特定集合内的是否有任何挂起信号,如果有的话,它将清除这个挂起的信号,并在sig参数中返回这个被清除信号的数值。如果没有信号挂起,sigwait将一直等待直到指定信号集合中的任何一个信号产生。下面是它的语法:
  1. int    sigwait(const sigset_t *set, int *sig);
复制代码

当信号被交付给进程(该进程安装了相应信号的处理句柄)时,进程将会切换到信号处理句柄中执行。例如,假设你的程序监听一个由配置文件设定的端口。你的进程安装了一个捕获SIGHUP信号的处理句柄来重新读取配置文件。一旦SIGHUP信号被交付给你的程序,进程将会执行信号处理句柄来重新读取配置文件。这里存在一个问题,你没有办法知道在进程执行过程中信号被交付的确切地点。你虽然可以使用一些下面列出的函数来将范围缩小,但是如果碰到像打开套接字,打开链接,或者其它那些首先需要清理后才能在新端口上监听 这些情况的时候呢?你怎样确定清理活动在那里开始,什么时候开始?如果你的程序正在等到输入,并且没有数据被传进来的时候,系统调用将被重启(system call will be restarted),所以从SIGHUP的返回将会继续等待。

这是使用setjmp和longjmp函数的一些情况,这些函数提供非本地分支(non-local branching)。为了使用这些setjmp函数,需要提供一个evn参数,如下:
  

  1. jmp_buff  env;
  2.   int    sigsetjmp(sigjmp_buf env, int savemask);
  3.   void   siglongjmp(sigjmp_buf env, int val);
  4.   int    setjmp(jmp_buf env);
  5.   void   longjmp(jmp_buf env, int val);
  6.   int     _setjmp(jmp_buf env);
  7.   void    _longjmp(jmp_buf env, int val);
  8.   void    longjmperror(void);
复制代码

首先,调用setjmp的返回为0,当前的环境将被保存在env中。接着,你可以在信号处理句柄内部调用对应的longjmp。一旦调用了longjmp,它将把执行环境恢复为env中保存的环境,并返回到最初setjmp被调用时的环境中。最初的setjmp调用返回那个传递给longjmp的va参数的值。

关于setjmp和longjmp函数一些说明:首先,这两个是不能混杂使用。也就是说,调用setjmp时保存的env变量不能传递给_longjmp调用。另外,调用setjmp的函数返回后,接下来调用longjmp将会发生错误。
The different calls have specific actions that they take. These actions are listed below:
不同的调用有特定的行为。这些行为在下面列出来:
  1. jmp和longjmp: 他们会保存(恢复)信号掩码,寄存器组和堆栈。
复制代码
  1. _setjmp和_longjmp: 他们只保存(恢复)寄存器组和堆栈。
复制代码
  1. sigsetjmp和siglongjmp: 只要savemask参数不是0,他们就保存(恢复)寄存器组,堆栈和信号掩码。
复制代码

由于一些原因,如果env参数保存的东西被破坏,或者调用setjmp的函数返回了,longjmp函数将会调用longjmperror函数。如果longjmperror也返回了,程序将被异常终止。你可以使用与longjmperror有相同原形的函数来自定义longjmperror函数。缺省的longjmperror会在标准错误上输出”longjmp botch”,然后返回。
4.8 Alarms
  1. unsigned int   alarm(unsigned int seconds);
复制代码

alarm函数基本上是一个简单的闹钟时钟(alarm clock),同时也是一个很有用的函数。它允许进程在经过指定秒数之后收到一个通知。一旦闹钟时间到,进程将收到一个SIGALRM信号。任何随后的alarm调用都会覆盖原先的调用设定。alarm不像sleep函数,它不会被阻塞。

它有一些返回值需要值得你注意:首先,如果进程没有设定定时器,那么返回值是0。其次,如果有一个定时器被设定但还没有超时的话,那么会返回前一个调用到现在还有的剩余时间。

现在可以设定的最大时间是100,000,000秒 --- 已经是相当长的时间了。
  1. int getitimer(int which, struct itimerval *value);
复制代码


getitimer函数会检索由第一个参数(which参数)描述的itimerval结构。第一个参数可选的选项将在下面说明:
  1. int  setitimer(int which, const struct itimerval *value,  struct itimerval *ovalue);
复制代码

setitmer比先前的alarm调用提供了更稳定的接口。在BSD系统上,每个进程可以提供三种不同时间间隔的定时器。他们在下面讲述:
  1. #define ITIMER_REAL      0
复制代码

实时时钟实时的递减而不管进程在CPU上的实际花销时间(换句话说,它追踪自然时间natural time)。这允许进程设置一个基于自然实时时间(based on  atural real time)的定时器。当实时定时器超时的时候,进程会收到SIGALRM信号。
  1. #define ITIMER_VIRTUAL   1
复制代码

虚拟定时器仅只递减进程在CPU上的执行时间,允许进程设定一个基于CPU使用率的定时器。当虚拟定时器超时的时候,进程收到SIGVTALRM信号
  1. #define ITIMER_PROF      2
复制代码

Profile定时器递减在CPU上的执行时间和代表进程执行的系统调用的时间。这对于那些要求静态剖析的解释程序是很有帮助的。当profile定时器超时的时候,进程收到SIGPROF信号。然而并不像实时和虚拟定时器那样,SIGPROF可以在系统调用的时候被发送;进程应该准备好重新执行被中断的系统调用。

本章将焦点放在了信号库上。这些信号及他们的使用方法对于系统编程是很重要的。信号允许系统管理员通知应用程序重新读取配置文件,从而使程序更稳定。其它重要的信号处理挂起在打开的文件描述符上的I/O操作。下一章讲述怎样利用这些I/O相关的信号。

(最近一段时间很忙,由于明天可以睡懒觉,所以今天下力气把它翻译完了。我负责的这部分中还有很多值得商榷的地方,欢迎大家多多批评指教。)

[ 本帖最后由 gvim 于 2006-2-25 02:38 编辑 ]

论坛徽章:
0
128 [报告]
发表于 2006-02-25 08:28 |只看该作者
原帖由 gvim 于 2006-2-25 02:31 发表
4.6 自定义行为

一些时候程序要求信号处理句柄运行在一个特定的堆栈上。为了实现这个目的,一个备用(alternate)堆栈区间必须用signaltstack函数指出来 ...


为了BSD工作到凌晨两点半?感动ing。。。
偶还有点小尾巴,这两天把它弄完!

论坛徽章:
1
寅虎
日期:2013-09-29 23:15:15
129 [报告]
发表于 2006-02-25 22:15 |只看该作者
原帖由 雨丝风片 于 2006-2-25 08:28 发表


为了BSD工作到凌晨两点半?感动ing。。。
偶还有点小尾巴,这两天把它弄完!

呵~~兄弟要注意身体!

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
130 [报告]
发表于 2006-02-25 22:59 |只看该作者
搞完了,这段时间工作上有些变化,所以担搁了,Sorry!!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP