发布时间:2014-09-05 16:55:58作者:知识屋
SA_RESTART
-----------------------------------------
设置信号S的SA_RESTART属性, 如果系统调用被信号S中断, 当信号处理函数返回后,
将自动恢复该系统调用
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
void sig_handler(int signum)
{
printf("at handler/n");
sleep(10);
printf("leave handler/n");
}
int main(int argc, char **argv)
{
char buf[100];
int ret;
struct sigaction action, old_action;
action.sa_handler = sig_handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
action.sa_flags |= SA_RESTART; /* 设置或者不设置此属性 */
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGINT, &action, NULL);
}
bzero(buf, 100);
ret = read(0, buf, 100);
if (ret == -1) {
perror("read");
}
printf("read %d bytes:/n", ret);
printf("%s/n", buf);
return 0;
}
若不设置, 从标准输入读数据的时候,如果按下ctrl+c, 则read系统调用被中断, 返回-1
若设置, 信号处理函数返回后, 恢复read系统调用, 但信号处理返回之前, read是无法读取数据的
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
int sigsuspend(const sigset_t *mask);
int sigpending(sigset_t *set);
屏蔽进程的某些信号
-------------------------------------
所谓屏蔽, 并不是禁止递送信号, 而是暂时阻塞信号的递送,
解除屏蔽后, 信号将被递送, 不会丢失
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
void sig_handler(int signum)
{
printf("catch sigint/n");
}
int main(int argc, char **argv)
{
sigset_t block;
struct sigaction action, old_action;
action.sa_handler = sig_handler;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGINT, &action, NULL);
}
sigemptyset(&block);
sigaddset(&block, SIGINT);
printf("block sigint/n");
sigprocmask(SIG_BLOCK, &block, NULL);
sleep(5);
/* unblock信号后, 之前触发的信号将被递送, 如果之前被
* 触发多次, 只会递送一次 */
sigprocmask(SIG_UNBLOCK, &block, NULL);
printf("unblock sigint/n");
sleep(5);
return 0;
}
在信号处理函数内, 屏蔽某些信号
----------------------------------------
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <error.h>
#include <string.h>
void sig_handler(int signum)
{
printf("in handle...sigterm is blocked/n");
sleep(5);
printf("handle done/n");
}
void handle_term(int signum)
{
printf("catch sigterm and exit../n");
exit(0);
}
int main(int argc, char **argv)
{
struct sigaction action, old_action;
/* 设置SIGINT */
action.sa_handler = sig_handler;
sigemptyset(&action.sa_mask);
sigaddset(&action.sa_mask, SIGTERM);
action.sa_flags = 0;
sigaction(SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGINT, &action, NULL);
}
/* 设置SIGTERM */
action.sa_handler = handle_term;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGTERM, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGTERM, &action, NULL);
}
printf("pid = %d/n", getpid());
while (1) {
sleep(1);
}
return 0;
}
按下ctrl+c, 收到SIGINT后, 进入sig_handler, 阻塞掉SIGTERM, 此时
kill掉该进程, 程序收不到SIGTERM信号, 等sig_handler返回后, 才收到
SIGTERM信号, 然后退出程序
int setjmp(jmp_buf env);
int sigsetjmp(sigjmp_buf env, int savesigs);
void longjmp(jmp_buf env, int val);
void siglongjmp(sigjmp_buf env, int val);
--------------------------------------------------------
setjmp()会保存目前堆栈环境,然后将目前的地址作一个记号,而在程序其他地方调用
longjmp时便会直接跳到这个记号位置,然后还原堆栈,继续程序好执行。
setjmp调用有点fork的味道, setjmp()return 0 if returning directly,
and non-zero when returning from longjmp using the saved context.
if (setjmp(jmpbuf)) {
printf("return from jmp/n");
} else {
printf("return directly/n");
}
setjmp和sigsetjmp的唯一区别是: setjmp不一定会恢复信号集合, 而sigsetjmp可以
保证恢复信号集合
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <setjmp.h>
void sig_alrm(int signum);
void sig_usr1(int signum);
void print_mask(const char *str);
static sigjmp_buf jmpbuf;
static volatile sig_atomic_t canjmp;
static int sigalrm_appear;
int main(int argc, char **argv)
{
struct sigaction action, old_action;
/* 设置SIGUSR1 */
action.sa_handler = sig_usr1;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGUSR1, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGUSR1, &action, NULL);
}
/* 设置SIGALRM */
action.sa_handler = sig_alrm;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
sigaction(SIGALRM, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN) {
sigaction(SIGALRM, &action, NULL);
}
printf("pid = %d/n", getpid());
print_mask("starting main:");
sleep(10);
if (sigsetjmp(jmpbuf, 1) != 0) {
print_mask("ending main:");
} else {
printf("setjmp return/n");
canjmp = 1;
while (1) {
sleep(1);
}
}
return 0;
}
void sig_usr1(int signum)
{
time_t starttime;
if (canjmp == 0) {
printf("please set jmp first/n");
return;
}
print_mask("starting sig_usr1:");
alarm(3);
while (!sigalrm_appear);
print_mask("finishing sig_usr1:");
canjmp = 0;
siglongjmp(jmpbuf, 1);
}
void sig_alrm(int signum)
{
print_mask("in sig_alrm:");
sigalrm_appear = 1;
return;
}
void print_mask(const char *str)
{
sigset_t sigset;
int i, errno_save, flag = 0;
errno_save = errno;
if (sigprocmask(0, NULL, &sigset) < 0) {
printf("sigprocmask error/n");
exit(0);
}
printf("%s/n", str);
fflush(stdout);
for (i = 1; i < NSIG; i++) {
if (sigismember(&sigset, i)) {
flag = 1;
psignal(i, "blocked");
}
}
if (!flag) {
printf("no blocked signal/n");
}
printf("/n");
errno = errno_save;
}
程序运行后, 使用 kill -USR1 <pid> 发送信号
程序收到SIGUSR1, 进入sig_usr1, 自动屏蔽掉SIGUSR1信号, 然后开启一个
定时器, 到时间后, 产生SIGALRM信号, 进入sig_alrm, 此时自动屏蔽SIGUSR1和SIGALRM,
返回到main函数后, 信号屏蔽恢复原状
作者“kenby”
linux一键安装web环境全攻略 在linux系统中怎么一键安装web环境方法
Linux网络基本网络配置方法介绍 如何配置Linux系统的网络方法
Linux下DNS服务器搭建详解 Linux下搭建DNS服务器和配置文件
对Linux进行详细的性能监控的方法 Linux 系统性能监控命令详解
linux系统root密码忘了怎么办 linux忘记root密码后找回密码的方法
Linux基本命令有哪些 Linux系统常用操作命令有哪些
Linux必学的网络操作命令 linux网络操作相关命令汇总
linux系统从入侵到提权的详细过程 linux入侵提权服务器方法技巧
linux系统怎么用命令切换用户登录 Linux切换用户的命令是什么
在linux中添加普通新用户登录 如何在Linux中添加一个新的用户
2012-07-10
CentOS 6.3安装(详细图解教程)
Linux怎么查看网卡驱动?Linux下查看网卡的驱动程序
centos修改主机名命令
Ubuntu或UbuntuKyKin14.04Unity桌面风格与Gnome桌面风格的切换
FEDORA 17中设置TIGERVNC远程访问
StartOS 5.0相关介绍,新型的Linux系统!
解决vSphere Client登录linux版vCenter失败
LINUX最新提权 Exploits Linux Kernel <= 2.6.37
nginx在网站中的7层转发功能