1 信號和進程
Reference
APUE P240
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
#include <signal.h>
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 sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
sigprocmask() is used to fetch and/or change the signal mask of the calling thread.The signal mask is the set of signals whose delivery iscurrently blocked for the caller (see also signal(7) for more details).
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
The sigaction() system call is used to change the action taken by a process on receipt of a specific signal. (See signal(7) for an overview of signals.)Example:
void sig_segv(int sig, siginfo_t *info, void *puc)
{
if (sig != SIGSEGV)
error("signal");
longjmp(jmp_env, 1);
}
void test_signal(void)
{
struct sigaction act;
struct itimerval it, oit;
/* timer test */
alarm_count = 0;
act.sa_handler = sig_alarm;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
chk_error(sigaction(SIGALRM, &act, NULL));
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 10 * 1000;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 10 * 1000;
chk_error(setitimer(ITIMER_REAL, &it, NULL));
chk_error(getitimer(ITIMER_REAL, &oit));
if (oit.it_value.tv_sec != it.it_value.tv_sec ||
oit.it_value.tv_usec != it.it_value.tv_usec)
error("itimer");
while (alarm_count < 5) {
usleep(10 * 1000);
}
it.it_interval.tv_sec = 0;
it.it_interval.tv_usec = 0;
it.it_value.tv_sec = 0;
it.it_value.tv_usec = 0;
memset(&oit, 0xff, sizeof(oit));
chk_error(setitimer(ITIMER_REAL, &it, &oit));
if (oit.it_value.tv_sec != 0 ||
oit.it_value.tv_usec != 10 * 1000)
error("setitimer");
/* SIGSEGV test */
act.sa_sigaction = sig_segv;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_SIGINFO;
chk_error(sigaction(SIGSEGV, &act, NULL));
if (setjmp(jmp_env) == 0) {
*(uint8_t *)0 = 0;
}
act.sa_handler = SIG_DFL;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
chk_error(sigaction(SIGSEGV, &act, NULL));
}
2 信號和線程
A 線程會繼承父線程的信號屏蔽字
例子:該函數很好的說明了屬性A 的用法。效果是子線程屏蔽了所有信號,而主線程還是保留原來的屏蔽字。
void qemu_thread_create(QemuThread *thread,
void *(*start_routine)(void*),
void *arg, int mode)
{
sigset_t set, oldset;
int err;
pthread_attr_t attr;
err = pthread_attr_init(&attr);
if (err) {
error_exit(err, __func__);
}
if (mode == QEMU_THREAD_DETACHED) {
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (err) {
error_exit(err, __func__);
}
}
/* Leave signal handling to the iothread. */
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, &oldset);
err = pthread_create(&thread->thread, &attr, start_routine, arg);
if (err)
error_exit(err, __func__);
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
pthread_attr_destroy(&attr);
}
B 每個線程可以有自己的信號屏蔽字,即線程可以調用pthread_sigmask 來設置自己的信號屏蔽字。
#include <signal.h>
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
Compile and link with -pthread.
DESCRIPTION
The pthread_sigmask() function is just like sigprocmask(2), with the difference that its use in multithreaded programs is explicitly speci‐
fied by POSIX.1-2001. Other differences are noted in this page.
C 信號的處理是進程中所有線程共享的。
當線程修改了與某個信號相關的處理行爲後,所有的線程都必須共享這個處理行爲的改變。
D 進程中的信號是遞送到單個線程的。 如果信號是與硬件或者計時器超時有關,該信號就被髮送到引起該事件的線程中去,而其他的信號則被髮送到任意一個線程。
(3要素)引起該事件的線程, 接受該事件的線程, 建立信號處理函數的線程
信號處理函數是共享的,在哪個線程建立似乎不重要
注意,如果一個線程屏蔽了只有它才能接受的信號,該信號將不會觸發信號處理函數
E sigwait
等待處於未決狀態的信號