看源码绝对是一种享受.
Programmer view the source code , something like detective find the truth!
-- jason leaster
/* Signal number definitions. Linux version. Copyright (C) 1995,1996,1997,1998,1999,2003 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ #ifdef _SIGNAL_H /* Fake signal functions. */ #define SIG_ERR ((__sighandler_t) -1) /* Error return. */ #define SIG_DFL ((__sighandler_t) 0) /* Default action. */ #define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */ #ifdef __USE_UNIX98 # define SIG_HOLD ((__sighandler_t) 2) /* Add signal to hold mask. */ #endif /* Signals. */ #define SIGHUP 1 /* Hangup (POSIX). */ #define SIGINT 2 /* Interrupt (ANSI). */ #define SIGQUIT 3 /* Quit (POSIX). */ #define SIGILL 4 /* Illegal instruction (ANSI). */ #define SIGTRAP 5 /* Trace trap (POSIX). */ #define SIGABRT 6 /* Abort (ANSI). */ #define SIGIOT 6 /* IOT trap (4.2 BSD). */ #define SIGBUS 7 /* BUS error (4.2 BSD). */ #define SIGFPE 8 /* Floating-point exception (ANSI). */ #define SIGKILL 9 /* Kill, unblockable (POSIX). */ #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */ #define SIGSEGV 11 /* Segmentation violation (ANSI). */ #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */ #define SIGPIPE 13 /* Broken pipe (POSIX). */ #define SIGALRM 14 /* Alarm clock (POSIX). */ #define SIGTERM 15 /* Termination (ANSI). */ #define SIGSTKFLT 16 /* Stack fault. */ #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */ #define SIGCHLD 17 /* Child status has changed (POSIX). */ #define SIGCONT 18 /* Continue (POSIX). */ #define SIGSTOP 19 /* Stop, unblockable (POSIX). */ #define SIGTSTP 20 /* Keyboard stop (POSIX). */ #define SIGTTIN 21 /* Background read from tty (POSIX). */ #define SIGTTOU 22 /* Background write to tty (POSIX). */ #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ #define SIGPOLL SIGIO /* Pollable event occurred (System V). */ #define SIGIO 29 /* I/O now possible (4.2 BSD). */ #define SIGPWR 30 /* Power failure restart (System V). */ #define SIGSYS 31 /* Bad system call. */ #define SIGUNUSED 31 #define _NSIG 65 /* Biggest signal number + 1 (including real-time signals). */ #define SIGRTMIN (__libc_current_sigrtmin ()) #define SIGRTMAX (__libc_current_sigrtmax ()) /* These are the hard limits of the kernel. These values should not be used directly at user level. */ #define __SIGRTMIN 32 #define __SIGRTMAX (_NSIG - 1) #endif /* <signal.h> included. */
一开始很畏惧这家伙,但是我后来就明白了,很多事情是因为不了解所以畏惧。
Just test it, I am not afraid
The simplest interface to the signal features of the UNIX System is the signal function.
#include <signal.h> void (*signal(int signo,void (*func )(int)))(int); Returns: previous disposition of signal (see following) if OK, SIG_ERRon error
APUE给的demo:
#include"apue.h" #include"stdio.h" #include"myerr.h" static void sig_usr(int); int main() { if(signal(SIGUSR1,sig_usr) == SIG_ERR) { err_sys("signal error\n"); } if(signal(SIGUSR2,sig_usr) == SIG_ERR) { err_sys("can't catch SIGUSR2"); } for(;;) { pause(); } return 0; } static void sig_usr(int signo) { if(signo == SIGUSR1) { printf("received SIGUSR1\n"); } else if(signo == SIGUSR2) { printf("received SIGUSR2\n"); } else { err_dump("received signal %d\n",signo); } }
这段代码创建了一个signal handler处理两种信号,SIGUSR1和SIGUSR2 然后for循环里面暂停pause() 关于这个函数, 我很详细的在这里讨论了
http://blog.csdn.net/cinmyheart/article/details/22655659
不再赘述
In earlier versions of the UNIX System (such as Version 7),signals were unreliable.
The problem with this code fragment is that there is awindow of time —after the signal has occurred, but before the call to signal in the signal handler —when the interrupt signal could occur another time. This second signal would cause the default action to occur,which for this signal terminates the process.
虽然APUE这么说,仅仅只是从表面上指出这种现象,真正的会default 导致termination的是这个signalhandler是建立在stack上面的。我的详细http://blog.csdn.net/cinmyheart/article/details/22655659
Another problem with these earlier systemswas that the process was unable to turn a signal off when it didn’t wantthe signal to occur.
关闭信号,让这个信号会被触发,貌似我现在还木有想到为什么不要触发这个信号。。。忽略掉不就好了么。。。
还是在讲早期Unix的事情。。。
注意system call 和function的区别。
Here, we have to differentiate betweena system call and a function. It is a system call within the kernel thatis interrupted when a signal is caught。
有些行为可能导致系统调用一直block 那个它想捕捉的signal。
The slow system calls are those that can block forever.Included in this category are
The Single UNIXSpecification specifies the functions that are guaranteed to be safe to call from within a signal handler.These functions are reentrant and arecalled async-signal safe by the Single UNIX Specification.
就是说,类似于malloc之类的函数,他是可以申请动态内存的,并且有malloc来维护,而这个过程中就可能会对当前进程造成破坏(你说malloc出来的内存如果内存泄漏怎么办,malloc出来的内存越界了怎么办,所以说很危险,不安全。。。)
从安全角度出发,不包含全局变量,和malloc family 和free的函数,我们觉得他是安全的。变量都是内部的,函数在stack上面活动,于是这个时候函数是被使用完pop之后,还可以再次被load到stack上面,执行完全一样的功能。不改变堆和全局变量。安全的对信号做出进行处理。
Most of the functions that are not included in follow are missing because (a) they are known to use static data structures, (b) they call malloc or free, or (c) they are part of the standard I/O library.
值得注意的就是errno 这个变量。是个全局变量,前提是include <errno.h>
多个进程都可能修改这个东东,所以使用的时候记得copy一下,用个中间变量保存到当前的作用域中
if we call a nonreentrant function from a signalhandler, the results are unpredictable
Two signals that continually generate confusion are SIGCLD and SIGCHLD
linux不存在混淆,他们被定义为同样的值。。。
This older handling ofSIGCLD consists of the following behavior:
If the process specifically setsits disposition to SIG_IGN, children of the calling process will not generate zombie processes.
If we set the disposition ofSIGCLD to be caught, the kernel immediately checks whether any child processes are ready to be waited for and, if so, calls the SIGCLD handler
子进程结束之后是会触发SIGCHID的,父进程可以通过waitpid捕捉这个信号。也可以通过pause 挂起当前进程,等待信号重新唤醒当前进程。
demo:
#include "apue.h"
#include "sys/wait.h"
#include "stdio.h"
#include "myerr.h"
static void sig_cld(int signo);
int main()
{
pid_t pid;
if(signal(SIGCLD,sig_cld) == SIG_ERR)
{
perror("signal error\n");
}
if((pid = fork()) < 0)
{
perror("fork error\n");
}
else if(pid == 0)
{
sleep(2);
_exit(0);
}
pause();
exit(0);
}
static void
sig_cld(int signo)
{
pid_t pid;
int status;
printf("SIGCLD received\n");
if(signal(SIGCLD,sig_cld) == SIG_ERR)
{
printf("signal error\n");
}
if((pid = wait(&status)) < 0)
{
printf("wait error\n");
}
printf("pid %d\n",pid);
}
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_10$ ./a.out
SIGCLD received
pid 4449
A signal is generated for a process (or sent to a process) when the event that causes the signal occurs.
We say that a signal is delivered to a process when the action for a signal is taken.
During the time between the generation of a signal and its delivery ,the signal is said to be pending.
If a signal that is blocked is generated for a process, and if the action for that signal is either the default action or to catch the signal, then the signal remains pending for the process until the process either (a) unblocks the signal or (b) changes the action to ignore the signal.
对于一个进程在处理信号之前同时接收到多个相同的信号怎么处理呢?
POSIX.1 allows the system to deliver the signal either once or more than once. If the system delivers the signal more than once, we say that the signals are queued. Most UNIX systems, however,do not queue signals unless they support the real-time extensions to POSIX.1. Instead, the UNIX kernel simply delivers the signal once.
如果有多个信号同时送给同一个进程呢?
POSIX.1 does not specify the order in which the signals are delivered to the process. The Rationale for POSIX.1 does suggest, how ever ,that signals related to the current state of the process be delivered before other signals. (SIGSEGV is one such signal.)
Each process has a signal mask that defines the set of signals currently blocked from delivery to that process.
The kill function sends a signal to a process or a group of processes. The raise function allows a process to send asignal to itself
#include <signal.h>
int kill(pid_t pid,int signo);
int raise(int signo);
Both return: 0 if OK, −1 on error
The call
raise(signo);
is equivalent to the call
kill(getpid(), signo);
kill 第一个参数pid的四种情况:
There are f our different conditions for the pid argument to kill.
pid > 0 The signal is sent to the process whose process ID is pid.
pid == 0 The signal is sent to all processes whose process group ID equals the process group ID of the sender and for which the sender has permission to send the signal. Note that the term all processes excludes an implementation-defined set of system processes. For most UNIX systems, this set of system processes includes the kernel processes and init (pid 1).
pid < 0The signal is sent to all processes whose process group ID equals the absolute value of pid and for which thesender has permission to send the signal. Again, the set of all processes excludes certain system processes, as described earlier.
pid == −1 The signal is sent to all processes on the system for which the sender has permission to send the signal. As before, the set of processes excludes certain system processes.
我有一点比较不明白的是 <0 和 -1 这两个情况划分可能不是很好,虽然软件上可以通过if else if 语句实现,但是我觉得还是不太好,逻辑上
One special case for the permission testing also exists: if the signal being sent is SIGCONT, a process cansend it to any other process in the same session.
值得注意的是process group ID是有循环的,以前的group ID和现在新的group ID可能是一样的,但是不是同一个group 了。以前的group 已经更改ID或者挂掉了。
Be aware, however ,that UNIX systems recycle process IDs after some amount of time, so the existence of a process with a given process ID does not necessarily mean that it’s the process that you think it is.
The alarm function allows us to set a timer that will expire at a specified time in the future. When the timer expires, the SIGALRM signal isgenerated. If we ignore or don’t catch this signal, its default action is to terminate the process.
#include <unistd.h> unsigned int alarm(unsigned int seconds); Returns: 0 or number of seconds until previously set alarm
The seconds value is the number of clockseconds in the future when the signal should be generated.
If when we call alarm more than once. That previouslyregistered alarm clock is replaced by the new value.
we need to be careful to install its signal handler before calling alarm.
The pause function suspends the calling process until a signal is caught.
#include <unistd.h>
int pause(void);
Returns: −1 with errno set to EINTR
The only time pause returns is if a signal handler is executed and that handler returns.
In that case, pause returns −1 with errno set to EINTR.
Code one:
#include"unistd.h" static void sig_alrm() { // } unsigned int sleep1(unsigned int nsecs) { if(signal(SIGALRM,sig_alrm) == SIG_ERR) { return (nsecs); } alarm(nsecs); pause(); return (alarm(0)); }
Code two:
#include"apue.h" #include"signal.h" #include"unistd.h" #include"setjmp.h" static jmp_buf env_alrm; static void sig_alrm(int signo) { longjmp(env_alrm,1); } unsigned int sleep2(unsigned int nsecs) { if(signal(SIGALRM,sig_alrm) == SIG_ERR) { return (nsecs); } if(setjmp(env_alrm) == 0) { alarm(nsecs); pause(); } return (alarm(0)); }
Code two 很好的消除了race condition。。。。想了很久才明白,确实这招很妙,消除race condition
首先说明为什么代码一有竞争
由于alarm(nsecs)和pause()指令太接近了。如果nsecs太小,可能发生一种情况,就是alarm的时间短,而在这个短时间内,pause还没开始执行,alarm就执行完毕,并产生了SIGALRM信号,此时pause尚未执行,于是信号被丢失,这样以来,接下来的pause会把进程永久性挂起(没有其他信号被接受的话)
代码二为什么就能解决竞争?
巧妙的利用了setjmp 和longjmp
if(setjmp(env_alrm) == 0)
{
alarm(nsecs);
pause();
}
这段代码简直是漂亮。Setjmp 没有被longjmp直接返回的情况下是返回0的,于是进入if语句,这是开启alarm
还是上面那样分析
如果时间很长,自然不用说,alarm时间长,于是接下来执行pause挂起进程,然后alarm时间到了之后,触发SIGALRM,这个时候signal handler里的longjmp就会当前被执行过的指令的下一个指令,程序正常继续执行。
如果时间很短,alarm立刻触发SIGALRM然后signal handler处理,longjmp直接跳回当前被执行过的指令的下一个指令(就是if语句后面)这个时候就没有pause了!!!
Even if the pause is never executed, thesleep2 function returns when the SIGALRM occurs.
熬了一两个小时。。。终于明白了。。。
设置block的时间上限,防止slow system call 引起的超长时间的block。
#include <apue.h> #include <myerr.h> #include <setjmp.h> static void sig_alrm(int); static jmp_buf env_alrm; int main() { int n; char line[MAXLINE]; if(signal(SIGALRM,sig_alrm) == SIG_ERR) { err_sys("signal (SIGALRM) error\n"); } if(setjmp(env_alrm) != 0) { err_sys("read timeout\n"); } printf("hi! input something no more than 10 secons\n"); alarm(10); if((n = read(STDIN_FILENO,line,MAXLINE)) < 0) { err_sys("read error\n"); } alarm(0); write(STDOUT_FILENO,line,n); return 0; } static void sig_alrm(int signo) { longjmp(env_alrm,1); }
We need a data type to represent multiple signals —a signal set .We’ll use this data type with such functions as sigprocmask (in the next section) to tell the kernel not to allow any of the signals in the set to occur
#include <signal.h> int sigemptyset(sigset_t *set); int sigfillset(sigset_t *set); int sigaddset(sigset_t *set,int signo); int sigdelset(sigset_t *set,int signo); All four return: 0 if OK,−1 on error int sigismember(const sigset_t *set,int signo); Returns: 1 if true, 0 if false, −1 on error
linux里面宏定义实现的。。。
/* Clear all signals from SET. */ extern int sigemptyset (sigset_t *__set) __THROW __nonnull ((1)); /* Set all signals in SET. */ extern int sigfillset (sigset_t *__set) __THROW __nonnull ((1)); /* Add SIGNO to SET. */ extern int sigaddset (sigset_t *__set, int __signo) __THROW __nonnull ((1)); /* Remove SIGNO from SET. */ extern int sigdelset (sigset_t *__set, int __signo) __THROW __nonnull ((1)); /* Return 1 if SIGNO is in SET, 0 if not. */ extern int sigismember (const sigset_t *__set, int __signo) __THROW __nonnull ((1));
/* A `sigset_t' has a bit for each signal. */ # define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int))) typedef struct { unsigned long int __val[_SIGSET_NWORDS]; } __sigset_t; #endif # if defined __GNUC__ && __GNUC__ >= 2 # define __sigemptyset(set) \ (__extension__ ({ int __cnt = _SIGSET_NWORDS; sigset_t *__set = (set); while (--__cnt >= 0) __set->__val[__cnt] = 0; 0; })) # define __sigfillset(set) \ (__extension__ ({ int __cnt = _SIGSET_NWORDS; \ sigset_t *__set = (set); \ while (--__cnt >= 0) __set->__val[__cnt] = ~0UL; \ 0; }))
我实在没搞懂那个
__THROW __nonnull ((1));
什么意思。。。
#include <apue.h> #include <signal.h> int main() { sigset_t hehe; printf("return value of sigemptyset :%x\n",sigemptyset(&hehe)); printf("return value of sigefillset :%x\n",sigfillset(&hehe)); printf("now we insert the (SIGINT)\n"); printf("return value of sigeaddset :%d\n",sigaddset(&hehe,SIGCLD)); return 0; }正确执行返回值是0,于是这里返回值都是0
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_10$ ./a.out
return value of sigemptyset :0
return value of sigefillset :0
now we insert the (SIGINT)
return value of sigeaddset :0
#include <signal.h> int sigprocmask(int how ,const sigset_t *restrict set,sigset_t *restrict oset ); Returns: 0 if OK,−1 on errorif oset is a non-null pointer ,t he current signal mask for the process is returned through oset . Second, if set is a non-null pointer ,the how argument indicates how the current signal mask is modified.
if set is a non-null pointer ,the how argument indicates how the current signal mask is modified.
how 的宏定义在/usr/include/x86**/bits/sigaction.h里面。。。。
/* Values for the HOW argument to `sigprocmask'. */
#define SIG_BLOCK 0 /* Block signals. */
#define SIG_UNBLOCK 1 /* Unblock signals. */
#define SIG_SETMASK 2 /* Set the set of blocked signals. */
If set is a null pointer ,the signal mask of the process is not changed, and how is ignored.
The sigpending function returns the set of signals that are blocked from delivery and currently pending for the calling process. The set of signals is returned through the set argument.
#include <signal.h> int sigpending(sigset_t *set); Returns: 0 if OK,−1 on error
以后所有的demo都不再使用signal,instead of sigaction!
伤心伤透了。。。T-T
#include <signal.h>
int sigaction(int signo,const struct sigaction *restrict act,struct sigaction *restrict oact );
Returns: 0 if OK,−1 on error
struct sigaction { /* Signal handler. */ #ifdef __USE_POSIX199309 union { /* Used if SA_SIGINFO is not set. */ __sighandler_t sa_handler; /* Used if SA_SIGINFO is set. */ void (*sa_sigaction) (int, siginfo_t *, void *); } __sigaction_handler; # define sa_handler __sigaction_handler.sa_handler # define sa_sigaction __sigaction_handler.sa_sigaction #else __sighandler_t sa_handler; #endif /* Additional set of signals to be blocked. */ __sigset_t sa_mask; /* Special flags. */ int sa_flags; /* Restore handler. */ void (*sa_restorer) (void); };
/* Used if SA_SIGINFO is set. */ void (*sa_sigaction) (int, siginfo_t *, void *);
上面的定义中可以看到,linux是选择性的使用siginfo的
结构体定义如下:
typedef struct
{
int si_signo; /* Signal number. */
int si_errno; /* If non-zero, an errno value associated with
this signal, as defined in <errno.h>. */
int si_code; /* Signal code. */
union
{
int _pad[__SI_PAD_SIZE];
/* kill(). */
struct
{
__pid_t si_pid; /* Sending process ID. */
__uid_t si_uid; /* Real user ID of sending process. */
} _kill;
/* POSIX.1b timers. */
struct
{
int si_tid; /* Timer ID. */
int si_overrun; /* Overrun count. */
sigval_t si_sigval; /* Signal value. */
} _timer;
/* POSIX.1b signals. */
struct
{
__pid_t si_pid; /* Sending process ID. */
__uid_t si_uid; /* Real user ID of sending process. */
sigval_t si_sigval; /* Signal value. */
} _rt;
/* SIGCHLD. */
struct
{
__pid_t si_pid; /* Which child. */
__uid_t si_uid; /* Real user ID of sending process. */
int si_status; /* Exit value or signal. */
__sigchld_clock_t si_utime;
__sigchld_clock_t si_stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS. */
struct
{
void *si_addr; /* Faulting insn/memory ref. */
} _sigfault;
/* SIGPOLL. */
struct
{
long int si_band; /* Band event for SIGPOLL. */
int si_fd;
} _sigpoll;
/* SIGSYS. */
struct
{
void *_call_addr; /* Calling user insn. */
int _syscall; /* Triggering system call number. */
unsigned int _arch; /* AUDIT_ARCH_* of syscall. */
} _sigsys;
} _sifields;
} siginfo_t __SI_ALIGNMENT;
/* X/Open requires some more fields with fixed names. */ # define si_pid _sifields._kill.si_pid # define si_uid _sifields._kill.si_uid # define si_timerid _sifields._timer.si_tid # define si_overrun _sifields._timer.si_overrun # define si_status _sifields._sigchld.si_status # define si_utime _sifields._sigchld.si_utime # define si_stime _sifields._sigchld.si_stime # define si_value _sifields._rt.si_sigval # define si_int _sifields._rt.si_sigval.sival_int # define si_ptr _sifields._rt.si_sigval.sival_ptr # define si_addr _sifields._sigfault.si_addr # define si_band _sifields._sigpoll.si_band # define si_fd _sifields._sigpoll.si_fd # define si_call_addr _sifields._sigsys._call_addr # define si_syscall _sifields._sigsys._syscall # define si_arch _sifields._sigsys._arch
/********************************************************************************* code writer :EOF code date : 2014.04.01 e-mail:[email protected] code purpose : I would like to share my code with people who is interesting in APUE. Sharing make our improve together. If you find there is something wrong with my code, please touch me by e-mail. Thank you. *********************************************************************************/ #include <stdio.h> #include <signal.h> void signal_handler(int signo); int main() { struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0;//don't use flags if(sigaction(SIGUSR1,&act,NULL) < 0) { printf("sigaction error\n"); } kill(getpid(),SIGUSR1); sleep(2);//avoid to exit rapaidly so that the signal handler didn't finish return 0; } void signal_handler(int signo) { printf("signal received\n"); }
To allow either form of behavior , POSIX.1 does not specify the effect of setjmp and longjmp on signal masks. Instead, two new functions, sigsetjmp and siglongjmp, are defined by POSIX.1. These two functions should always be used when branching from a signal handler.
#include <setjmp.h> int sigsetjmp(sigjmp_buf env ,int savemask ); Returns: 0 if called directly ,nonzero if returning from a call to siglongjmp void siglongjmp(sigjmp_buf env ,int val);
The only difference between these functions and the setjmp and longjmp functions is that sigsetjmp has an additional argument. If save mask is nonzero, then sigsetjmp also saves the current signal mask of the process in env .When siglongjmp is called, if the env argument was saved by a call to sigsetjmp with a nonzero save mask ,then siglongjmp restores the saved signal mask.
/********************************************************************************* code writer : EOF code date : 2014.04.01 e-mail: [email protected] code purpose : just a demo for siglongjmp and sigsetjmp I would like to share my code with someone. Sharing make our imporve together. Just share your code with us. Open source make our world better and better. If there are something wrong with my code, please touch me by e-mail. Thank you. I am glad to receive your feedback. *********************************************************************************/ #include <setjmp.h> #include <time.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include <myerr.h> static void sig_usr1(int),sig_alrm(int); static sigjmp_buf jmpbuf; static volatile sig_atomic_t canjump; void pr_mask(const char* str); int main() { struct sigaction act_usr,act_alrm; act_usr.sa_flags = 0; act_alrm.sa_flags = 0;//you may initialize the sa_flags. There are some bit operation on these varibles. act_usr.sa_handler = sig_usr1; sigemptyset(&act_usr.sa_mask); act_usr.sa_flags = 0; if(sigaction(SIGUSR1,&act_usr,NULL) <0) { printf("sigaction error\n"); } act_alrm.sa_handler = sig_alrm; sigemptyset(&act_alrm.sa_mask); act_alrm.sa_flags |= SA_INTERRUPT; if(sigaction(SIGALRM,&act_alrm,NULL) < 0) { printf("sigaction error\n"); } pr_mask("starting main:\n"); if(sigsetjmp(jmpbuf,1)) //reset the signal mask if the second parameter of sigsetjmp is non-zero. //If the second parameter is zero,the maskwould be leave. { pr_mask("ending main\n"); exit(0); } canjump = 1;//now setjmp is OK for( ; ;) { pause(); } } static void sig_usr1(int signo) { time_t starttime; if(canjump == 0) { return; } pr_mask("starting usr1:\n"); alarm(3); starttime = time(NULL); for( ; ;) { if(time(NULL) > starttime +5) { break; } } pr_mask("finishing sig_usr1:\n"); canjump = 0; siglongjmp(jmpbuf,1); } static void sig_alrm(int signo) { pr_mask("in sig_alrm\n"); } void pr_mask(const char* str) { sigset_t sigset; int errno_save; errno_save = errno; if(sigprocmask(0,NULL,&sigset) < 0) { err_sys("sigprocmask error\n"); } printf("%s",str); if(sigismember(&sigset,SIGINT)) { printf("SIGINT\n"); } if(sigismember(&sigset,SIGQUIT)) { printf("SIGQUIT\n"); } if(sigismember(&sigset,SIGUSR1)) { printf("SIGUSR1\n"); } if(sigismember(&sigset,SIGALRM)) { printf("SIGALRM\n"); } errno = errno_save; }
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_10$ ./a.out &
[1] 5357
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_10$ starting main:
kill -USR1 5357
starting usr1:
SIGUSR1
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_10$ in sig_alrm
SIGUSR1
SIGALRM
finishing sig_usr1:
SIGUSR1
ending main
[1]+ Done ./a.out
值得注意的是,SIGALRM的mask会被自动的清零,当alarm到达预定时间之后。
如果sigsetjmp 的第二个参数是0,那么最后的mask里面会有SIGUSR1
#include <signal.h> int sigsuspend(const sigset_t *sigmask); Returns: −1with errnoset to EINTR
The signal mask of the process is set to the value pointed to by sigmask.Then the process is suspended until a signal is caught or until a signal occurs that terminates the process. If asignal is caught and if the signal handler returns, then sigsuspend returns, and the signal mask of the process is set to its value before the call to sigsuspend
demo:
#include <setjmp.h> #include <myerr.h> #include <errno.h> #include <signal.h> #include <stdio.h> #include </Ad_Pro_in_Unix/chapter_10/pro_10_14.c> //pro_10_14.c is the implementation of pr_mask. I have show the definition of pr_mask in this blog. static void sig_int(int signo); int main() { sigset_t newmask,oldmask,waitmask; struct sigaction act_int,oact_int; sigemptyset(&act_int.sa_mask); sigemptyset(&newmask); sigemptyset(&oldmask); sigemptyset(&waitmask);//initialize the signal mask. act_int.sa_handler = sig_int; act_int.sa_flags = 0;//I don't use flags. You know, it is bits operation and nothing would be set if the flag is zero. pr_mask("program start: \n"); if(sigaction(SIGINT,&act_int,NULL) < 0) { printf("sigaction error\n"); } sigemptyset(&waitmask); sigaddset(&waitmask,SIGUSR1); sigemptyset(&newmask); sigaddset(&newmask,SIGINT); if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0)//add the newmask's bits into oldmask { printf("sigprocmask error\n"); } pr_mask("in critical region\n"); if(sigsuspend(&waitmask) != -1)// suspend the signal in waitmask. { err_sys("sigprocmask error\n"); } pr_mask("after return from sigsuspend\n"); if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0) { printf("sigprocmask error\n"); } pr_mask("program exit\n"); return 0; } static void sig_int(int signo) { pr_mask("\nin sig_int\n"); }
test result:
liuzjian@ubuntu:/Ad_Pro_in_Unix/chapter_10$ ./a.out
program start:
in critical region
SIGINT
^C
in sig_int
SIGINT
SIGUSR1
after return from sigsuspend
SIGINT
program exit
another demo:
#include <apue.h> volatile sig_atomic_t quitflag = 0; static void sig_int(int signo) { if(signo == SIGINT) { printf("\ninterrupt\n"); } else if(signo == SIGQUIT) { quitflag = 1; } } int main() { sigset_t newmask,oldmask,zeromask; struct sigaction act_int,act_qt; sigemptyset(&act_int.sa_mask); sigemptyset(&act_qt.sa_mask); act_int.sa_flags = 0; act_qt.sa_flags = 0; sigemptyset(&newmask); sigemptyset(&oldmask); sigemptyset(&zeromask); act_int.sa_handler = sig_int; act_qt.sa_handler = sig_int; if(sigaction(SIGINT,&act_int,NULL) < 0) { printf("sigaction error\n"); } if(sigaction(SIGQUIT,&act_qt,NULL) < 0) { printf("sigaction error\n"); } sigemptyset(&act_int.sa_mask); sigemptyset(&act_qt.sa_mask); sigaddset(&act_int.sa_mask,SIGINT); sigaddset(&act_qt.sa_mask,SIGQUIT); if(sigprocmask(SIG_BLOCK,&newmask,&oldmask) < 0) { printf("SIG_BLOCK error\n"); } while(quitflag == 0) { sigsuspend(&zeromask); } quitflag = 0; if(sigprocmask(SIG_SETMASK,&oldmask,NULL) < 0) { printf("sigprocmask error\n"); } exit(0); }
jasonleaster@ubuntu:/Ad_Pro_in_Unix/chapter_10$ ./a.out
^C
interrupt
^C
interrupt
^C
interrupt
^C
interrupt
^\
#include <stdlib.h> void abort(void); This function never returns
If the process doesn’t terminate itself from this signal handler, POSIX.1 states that, when the signal handler returns, abort terminates the process.
The ISO C specification of this function leaves it up to the implementation as to whether output streams are flushed and whether temporary files (Section 5.13) are deleted. POSIX.1 goes further and allows an implementation to call fclose on open standard I/O streams before terminating if the call to abort terminates the process.
对于这种不同标准要求不同,我只能说无奈。。。
这个POXIS标准的实现我木有看懂,热心的viewer知道的话,希望能帮忙讨论
#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> void abort(void) { sigset_t mask; struct sigaction action; sigaction(SIGABRT,NULL,&action); if(action.sa_handler == SIG_IGN) { action_sa_handler = SIG_DFL; sigaction(SIGABRT,&action,NULL); } if(action.sa_handler == SIG_DFL) { fflush(NULL); } sigfillset(&mask); sigdelset(&mask,SIGABRT); sigprocmask(SIG_SETMASK,&mask,NULL); kill(getpid(),SIGABRT); fflush(NULL); action.sa_handler = SIG_DFL; sigaction(SIGABRT,&action,NULL); sigprocmask(SIG_SETMASK,&mask,NULL); kill(getpid(),SIGABRT); exit(1); }
#include <apue.h> static void sig_int(int signo) { printf("caught SIGINT\n"); } static void sig_child(int signo) { printf("caught SIGCHILD\n"); } int main() { struct sigaction act_int,act_child; act_int.sa_flags = 0; act_child.sa_flags = 0; sigemptyset(&act_int.sa_mask); sigemptyset(&act_child.sa_mask); act_int.sa_handler = sig_int; act_child.sa_handler = sig_child; if(sigaction(SIGINT,&act_int,NULL) < 0) { printf("sigaction error\n"); } if(sigaction(SIGCHLD,&act_child,NULL) < 0) { printf("sigaction error\n"); } if(system("/bin/ed") < 0) { printf("system() error\n"); } exit(0); }
对于ed的操作我也不熟悉。。。所以。。。如果这个demo看不懂就看APUE书上的解释吧。。。
system Function
#include <apue.h> static void sig_int(int signo) { printf("caught SIGINT\n"); } static void sig_child(int signo) { printf("caught SIGCHILD\n"); } int main() { struct sigaction act_int,act_child; act_int.sa_flags = 0; act_child.sa_flags = 0; sigemptyset(&act_int.sa_mask); sigemptyset(&act_child.sa_mask); act_int.sa_handler = sig_int; act_child.sa_handler = sig_child; if(sigaction(SIGINT,&act_int,NULL) < 0) { printf("sigaction error\n"); } if(sigaction(SIGCHLD,&act_child,NULL) < 0) { printf("sigaction error\n"); } if(system("/bin/ed") < 0) { printf("system() error\n"); } exit(0); }
对于ed的操作我也不熟悉。。。所以。。。如果这个demo看不懂就看APUE书上的解释吧。。。
关于abort function sleep function和system functon很多实现都是用信号实现的,例如sleep 函数实现的时候就用到了alarm 和SIGARLM,但是我觉得我写程序还是不会涉及到具体这些函数是怎么实现的,所以就没有继续死磕实现的代码了。
#include <signal.h> void psignal(int signo,const char *msg);
#include <stdio.h> #include <signal.h> int main() { psignal(SIGCHLD,"hello world"); return 0; }
#include <signal.h> void psiginfo(const siginfo_t *info ,const char *msg);
#include <signal.h> int sig2str(int signo,char *str); int str2sig(const char *str,int *signop ); Both return: 0 if OK, −1 on error
So 这个章节。。。终于告一段落了。。。