Chinaunix首页 | 论坛 | 博客
  • 博客访问: 993162
  • 博文数量: 200
  • 博客积分: 5011
  • 博客等级: 大校
  • 技术积分: 2479
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-27 15:07
文章分类

全部博文(200)

文章存档

2009年(12)

2008年(190)

我的朋友

分类:

2008-12-08 11:43:21

10.6 reentrant functions

这个话题总是与signal关联在一起。

发生reentrant问题的情况:

1.内存分配,或者处理全局数据时

当我们在malloc一段内存,当我们再用getpwnam来获取用户帐户的信息(这个函数会使用static缓冲),总之当我们在处理一段全局的数据结构的时候(这里的全局值得不仅仅是具有全局的作用域,还包括了全局的生命周期比如static缓冲),我们被一个signal打断,signal handler执行了,在这个handler内部也对该数据进行操作,这个数据就乱套了。Malloc维护的pagelist会乱套,getpwnamstatic 缓冲会乱套。

2.使用标准库

我们知道,printfstandard i/o library其实使用了自己的全局的缓冲,所以,当我们调用printf的时候,如果收到一个signal 那么,如果,signal handler里面调用了printf,也会将standard i/o library的缓冲搅乱。

3Errno

Errno本身是个全局量,所以说,你甚至可以认为说有使用了errno的函数都不是可重入的函数。当然这也要求太高了,所以,有一个建议,在你的signal handler里面,如果有操作要改变errno,那么在signal handler的开头,将errno保存一下,在退出handler之前,将其restore

4Longjmpsiglongjmp的作用

我们在处理一个全局数据,此时signal来了,在signal handler里面,没有return,而是调用longjmp或者siglongjmp调到别处执行去了,这样就会使正在被处理的全局数据成处理到了一半。如果我们的signal handler里面的确一定要调用siglongjmp这样的函数,那么我们应该保证我们处理全局数据的时候,该signal不会发生,即我们可以将该signal block一会儿。

上述函数都不是可reentrant的函数。

Single unix specification指定如下函数应该是reentrant函数:

Figure 10.4. Reentrant functions that may be called from a signal handler

accept

fchmod

lseek

sendto

stat

access

fchown

lstat

setgid

symlink

aio_error

fcntl

mkdir

setpgid

sysconf

aio_return

fdatasync

mkfifo

setsid

tcdrain

aio_suspend

fork

open

setsockopt

tcflow

alarm

fpathconf

pathconf

setuid

tcflush

bind

fstat

pause

shutdown

tcgetattr

cfgetispeed

fsync

pipe

sigaction

tcgetpgrp

cfgetospeed

ftruncate

poll

sigaddset

tcsendbreak

cfsetispeed

getegid

posix_trace_event

sigdelset

tcsetattr

cfsetospeed

geteuid

pselect

sigemptyset

tcsetpgrp

chdir

getgid

raise

sigfillset

time

chmod

getgroups

read

sigismember

timer_getoverrun

chown

getpeername

readlink

signal

timer_gettime

clock_gettime

getpgrp

recv

sigpause

timer_settime

close

getpid

recvfrom

sigpending

times

connect

getppid

recvmsg

sigprocmask

umask

creat

getsockname

rename

sigqueue

uname

dup

getsockopt

rmdir

sigset

unlink

dup2

getuid

select

sigsuspend

utime

execle

kill

sem_post

sleep

wait

execve

link

send

socket

waitpid

_Exit & _exit

listen

sendmsg

socketpair

write

下面是一个例子,它使用每秒钟一次的alarm signal,调用getpwname函数:

Figure 10.5. Call a nonreentrant function from a signal handler
#include "apue.h"
#include 
 
static void
my_alarm(int signo)
{
    struct passwd   *rootptr;
 
    printf("in signal handler\n");
    if ((rootptr = getpwnam("root")) == NULL)
            err_sys("getpwnam(root) error");
    alarm(1);
}
 
int
main(void)
{
    struct passwd   *ptr;
 
    signal(SIGALRM, my_alarm);
    alarm(1);
    for ( ; ; ) {
        if ((ptr = getpwnam("sar")) == NULL)
            err_sys("getpwnam error");
        if (strcmp(ptr->pw_name, "sar") != 0)
            printf("return value corrupted!, pw_name = %s\n",
                    ptr->pw_name);
    }
}

过一段时间,就会出错,甚至会出现SIGSEGV

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