CSDN博客

img sah

分析进程信号队列的结构

发表于2004/10/14 14:27:00  1260人阅读

分类: <!01-Linux-00><b>Linux</b><br><font color='gray'>--All--</font>

每个进程具有一个sigpending结构所描述的信号队列,它有3个成员,head指向第一个sigqueue成员,
tail指向最末的sigqueue成员的next指针,signal描述了此队列中的信号集.

static int send_signal(int sig, struct siginfo *info, struct sigpending *signals);
将信号sig和对应的消息结构info添加到信号队列signal中.
static int collect_signal(int sig, struct sigpending *list, siginfo_t *info);
返回信号sig在队列list中的信息info.

struct task_struct {
...
struct sigpending pending;
...
};
struct sigpending {
struct sigqueue *head, **tail;
sigset_t signal;
};
struct sigqueue {
struct sigqueue *next;
siginfo_t info;
};
// kernel/signal.c
static int send_signal(int sig, struct siginfo *info, struct sigpending *signals)
{
struct sigqueue * q = NULL;

/* Real-time signals must be queued if sent by sigqueue, or
some other real-time mechanism. It is implementation
defined whether kill() does so. We attempt to do so, on
the principle of least surprise, but since kill is not
allowed to fail with EAGAIN when low on memory we just
make sure at least one signal gets delivered and don't
pass on the info struct. */

if (atomic_read(&nr_queued_signals) < max_queued_signals) {
q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC);
}
// nr_queued_signals和max_queued_signals用来限制全局sigqueue成员的数目
if (q) {
atomic_inc(&nr_queued_signals);
q->next = NULL;
*signals->tail = q;
signals->tail = &q->next; tail总是指向最末的信号成员的next指针
switch ((unsigned long) info) {
case 0: // info参数如果为0,表示信号来源于当前用户进程
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_USER;
q->info.si_pid = current->pid;
q->info.si_uid = current->uid;
break;
case 1: // info参数如果为1,表示信号来源于内核本身
q->info.si_signo = sig;
q->info.si_errno = 0;
q->info.si_code = SI_KERNEL;
q->info.si_pid = 0;
q->info.si_uid = 0;
break;
default: // 否则从info指针中拷贝信号
copy_siginfo(&q->info, info);
break;
}
} else if (sig >= SIGRTMIN && info && (unsigned long)info != 1
&& info->si_code != SI_USER) {
; 如果该信号是内核发出的实时信号,就返回错误码
/*
* Queue overflow, abort. We may abort if the signal was rt
* and sent by user using something other than kill().
*/
return -EAGAIN;
}

sigaddset(&signals->signal, sig); 将sig号标记在队列的信号集上
return 0;
}
static int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
{
if (sigismember(&list->signal, sig)) {
/* Collect the siginfo appropriate to this signal. */
struct sigqueue *q, **pp;
pp = &list->head; pp指向第一个信号成员的next指针
while ((q = *pp) != NULL) {
if (q->info.si_signo == sig)
goto found_it;
pp = &q->next;
}

/* Ok, it wasn't in the queue. We must have
been out of queue space. So zero out the
info. */
sigdelset(&list->signal, sig);
info->si_signo = sig;
info->si_errno = 0;
info->si_code = 0;
info->si_pid = 0;
info->si_uid = 0;
return 1;

found_it:
// 将找到信号成员从信号队列中删除
if ((*pp = q->next) == NULL)
list->tail = pp;

/* Copy the sigqueue information and free the queue entry */
copy_siginfo(info, &q->info);
kmem_cache_free(sigqueue_cachep,q);
atomic_dec(&nr_queued_signals);

/* Non-RT signals can exist multiple times.. */
if (sig >= SIGRTMIN) {
while ((q = *pp) != NULL) {
if (q->info.si_signo == sig)
goto found_another;
pp = &q->next;
}
}

sigdelset(&list->signal, sig);
found_another:
return 1;
}
return 0;
}
阅读全文
0 0

相关文章推荐

img
取 消
img