基本概念
信号是软件中断,提供了一种处理异步事件的方法。一个(具有合适权限的)进程能够向另一个进程发送信号。是进程间通讯的原始形式。可向其他进程发送信号,也可向自身发送信号。
信号执行的时机是进程被调度执行时,或进程正在执行时。当进程不想被信号打断时,可将信号添加到进程的信号掩码中。
linux下的/proc/PID/status文件中的包含各种掩码字段,
linux改变信号默认处理行为的方法:sigal和sigaction,其处理的流程方法:
![](https://img-blog.csdnimg.cn/img_convert/a95019816026b8f77724c62a20ae2b26.png)
用于发送信号的方法:kill。
#include <signal.h>
int kill (pid_t pid,int sig)
信号可以发送给指定进程,也可发送给当前调用kill的进程所在的进程组(包括调用kill进程)。还可发送给指定的进程组。最厉害的是可以发送给除init和本身之外的所有进程。其实现方法如下:
![](https://img-blog.csdnimg.cn/img_convert/dd322c892badd093fbc7da8dbe7ce2ac.png)
信号安全处理函数问题
信号的处理会打断当前的进程执行流程,安全问题引入场景是:多进程访问临界区问题包括:调用信号处理函数的进程和其他进程同时访问的问题(其他进程优先级比当前进程要高),信号打断当前进程进行执行流程导致的问题。这就要求信号处理函数要实现所谓的访问安全包括:禁止全局变量的访问、锁的获取和释放避免死锁的问题,任何有加锁操作的函数,除非它们特意使用了可重入锁,都应该被视为非异
步信号安全的,不应在信号处理函数中调用它们。不仅自己实现的处理函数要按照安全函数进行实现,在处理函数实现中调用的C库函数也要用安全的C库函数。
3未使用异步安全函数的案例
/lib/libpthread.so.0(+0x11110) [0x7fdf8cfde110]
/lib/libc.so.6(+0xf51db) [0x7fdf8be5f1db]
/lib/libc.so.6(+0xa9ed4) [0x7fdf8be13ed4]
test.exe(GetClock+0x51) [0x9a97a1] // 信号处理函数中调用GetClock,其调用localtime_r导致线程自锁
test.exe(LinuxSignalHandler+0x160) [0x9469c0] // 线程被信号中断
/lib/libpthread.so.0(+0x11110) [0x7fdf8cfde110]
/lib/libc.so.6(+0xa9ee0) [0x7fdf8be13ee0] // localtime_r获取了时区保护锁
test.exe(GetClock+0x51) [0x9a97a1] // 线程的GetClock调用localtime_r进行时间本地化转换
。。。。。。
程序的正在执行GetClock函数时被信号中断,随后在信号处理函数中再次调用GetClock函数localtime_r获取时区保护锁,导致该线程自锁。
4.哪些C库函数是异步安全函数
可通过man 7 signal-safety 命令来得到对应glibc版本的异步信号安全函数清单。
附录:异步信号安全函数清单(glibc-2.28)
函数名后括号中的数字,表示在linux manual中的分组。比如abort(3), 表示可以通过shell命令man 3 abort 来查看这个接口函数的使用说明。
A | abort(3) accept(2) access(2) aio_error(3) aio_return(3) aio_suspend(3) alarm(2) |
W | wait(2) waitpid(2) wcpcpy(3) wcpncpy(3) wcscat(3) schr(3) wcscmp(3) wcscpy(3) wcscspn(3) wcslen(3) wcsncat(3) wcsncmp(3) wcsncpy(3) wcsnlen(3) wcspbrk(3) wcsrchr(3) wcsspn(3) wcsstr(3) wcstok(3) wmemchr(3) wmemcmp(3) wmemcpy(3) wmemmove(3) wmemset(3) write(2) |
U | umask(2) uname(2) unlink(2) unlinkat(2) utime(2) utimensat(2) utimes(2) |
T | tcdrain(3) tcflow(3) tcflush(3) tcgetattr(3) tcgetpgrp(3) tcsendbreak(3) tcsetattr(3) tcsetpgrp(3) time(2) timer_getoverrun(2) timer_gettime(2) timer_settime(2) times(2) |
S | select(2) em_post(3) send(2) sendmsg(2) sendto(2) setgid(2) setpgid(2) setsid(2) setsockopt(2) setuid(2) shutdown(2) sigaction(2) sigaddset(3) sigdelset(3) sigemptyset(3) sigfillset(3) sigismember(3) siglongjmp(3) signal(2) sigpause(3) sigpending(2) sigprocmask(2) sigqueue(2) sigset(3) sigsuspend(2) sleep(3) sockatmark(3) socket(2) socketpair(2) stat(2) stpcpy(3) stpncpy(3) strcat(3) strchr(3) strcmp(3) strcpy(3) strcspn(3) strlen(3) strncat(3) strncmp(3) strncpy(3) strnlen(3) strpbrk(3) strrchr(3) strspn(3) strstr(3) strtok_r(3) symlink(2) symlinkat(2) |
R | raise(3) read(2) readlink(2) readlinkat(2) recv(2) recvfrom(2) recvmsg(2) rename(2) renameat(2) rmdir(2) |
P | pause(2) pipe(2) poll(2) posix_trace_event(3) pselect(2) pthread_kill(3) pthread_self(3) pthread_sigmask(3) |
O | open(2) openat(2) |
N | ntohl(3) ntohs(3) |
M | memccpy(3) memchr(3) memcmp(3) memcpy(3) memmove(3) memset(3) mkdir(2) mkdirat(2) mkfifo(3) mkfifoat(3) mknod(2) mknodat(2) |
L | link(2) linkat(2) listen(2) longjmp(3) lseek(2) lstat(2) |
K | kill(2) |
H | htonl(3) htons(3) |
G | getegid(2) geteuid(2) getgid(2) getgroups(2) getpeername(2) getpgrp(2) getpid(2) getppid(2) getsockname(2) getsockopt(2) getuid(2) |
F | faccessat(2) fchdir(2) fchmod(2) fchmodat(2) fchown(2) fchownat(2) fcntl(2) fdatasync(2) fexecve(3) ffs(3) fork(2) fstat(2) fstatat(2) fsync(2) ftruncate(2) futimens(3) |
E | execl(3) execle(3) execv(3) execve(2) _exit(2) _Exit(2) |
D | dup(2) dup2(2) |
C | cfgetispeed(3) cfgetospeed(3) cfsetispeed(3) cfsetospeed(3) chdir(2) chmod(2) chown(2) clock_gettime(2) close(2) connect(2) creat(2) |
B | bind(2) |