From: "Gábor Melis" <mega@retes.hu>
To: Oleg Nesterov <oleg@redhat.com>
Cc: linux-kernel@vger.kernel.org, Andrew Morton <akpm@linux-foundation.org>
Subject: Re: Signal delivery order
Date: Sun, 15 Mar 2009 23:06:52 +0100 [thread overview]
Message-ID: <200903152306.53031.mega@retes.hu> (raw)
In-Reply-To: <20090315172926.GA21095@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 2098 bytes --]
On Domingo 15 Marzo 2009, Oleg Nesterov wrote:
> On 03/15, Gábor Melis wrote:
> > On Domingo 15 Marzo 2009, Oleg Nesterov wrote:
> > > If test_signal (SIGUSR1) is blocked, this means it is already
> > > delivered, and the handler will be invoked when we return from
> > > sigsegv_handler(), please see below.
> >
> > SIGUSR1 is delivered, its sigmask is added to the current mask but
> > the handler is not yet invoked and in this instant synchronous
> > sigsegv is delivered, its handler invoked?
>
> Can't understand the question. Could you reiterate?
No need, my question was answered below.
> > > When sigprocmask(SIG_UNBLOCK) returns, both signals are
> > > delivered. The kernel deques 1 first, then 2. This means that the
> > > handler for "2" will be called first.
> >
> > My mental model that matches what I quickly glean from the sources
> > (from kernel/signal.c, arch/x86/kernel/signal_32.c) goes like this:
> >
> > - signal 1 and signal 2 are generated and made pending
> > - they are unblocked by sigprocmask
> > - signal 1 is delivered: signals in its mask (only itself here) are
> > blocked
>
> yes.
>
> the kernel changes ip (instruction pointer) to sig_1.
>
> > its handler is invoked
>
> no.
>
> We never return to user-space with a pending signal. We dequeue
> signal 2 too, and change ip to sig_2.
>
> Now, since there are no more pending signals, we return to the user
> space, and start sig_2().
I see. I guess in addition to changing the ip, the stack frobbing magic
arranges that sig_2 returns to sig_1 or some code that calls sig_1.
From the point of view of sig_2 it seems that sig_1 is already invoked
because it has its sigmask in effect and the ip in the ucontext of
sig_2 points to sig_1 as the attached signal-test.c shows:
sig_1=80485a7
sig_2=80485ed
2 1
eip: 80485a7
1 0
eip: b7fab424
The revised signal-delivery-order.c (also attached) outputs:
test_handler=8048727
sigsegv_handler=804872c
eip: 8048727
esp: b7d94cb8
which shows that sigsegv_handler also has incorrect eip in the context.
[-- Attachment #2: signal-delivery-order.c --]
[-- Type: text/x-csrc, Size: 2195 bytes --]
#include <signal.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/ucontext.h>
#include <unistd.h>
int test_signal;
int *page_address;
pthread_t tid;
int is_signal_blocked(int signum)
{
sigset_t set;
pthread_sigmask(SIG_BLOCK, 0, &set);
return (sigismember(&set, signum));
}
void *eip(struct ucontext *context)
{
return (void *)context->uc_mcontext.gregs[14];
}
void test_handler(int signal, siginfo_t *info, void *context)
{
}
void sigsegv_handler(int signal, siginfo_t *info, void *context)
{
/* The test signal is blocked only in test_handler. */
if (is_signal_blocked(test_signal)) {
printf("eip: %x\n", eip(context));
_exit(27);
}
mprotect(page_address, 4096, PROT_READ | PROT_WRITE);
}
void *make_faults(void *arg)
{
while (1) {
mprotect(page_address, 4096, PROT_NONE);
*page_address = 1;
}
}
void *reserve_page(void)
{
int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
void *actual = mmap(0, 4096, PROT_NONE, flags, -1, 0);
if (actual == MAP_FAILED) {
perror("mmap");
return 0;
}
return actual;
}
void install_handlers(void)
{
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = test_handler;
sigaction(test_signal, &sa, 0);
sa.sa_sigaction = sigsegv_handler;
sigaction(SIGSEGV, &sa, 0);
}
void test_with_pthread_kill()
{
page_address = (int *)reserve_page();
install_handlers();
if (pthread_create(&tid, 0, make_faults, 0) < 0)
perror("pthread_create");
while(1) {
pthread_kill(tid, test_signal);
}
}
void test_with_kill()
{
pid_t pid = fork();
if (pid == 0) {
page_address = (int *)reserve_page();
install_handlers();
make_faults(0);
} else {
while (1) {
kill(pid, test_signal);
}
}
}
int main(void)
{
test_signal = SIGUSR1;
printf("test_handler=%x\n", test_handler);
printf("sigsegv_handler=%x\n", sigsegv_handler);
test_with_pthread_kill();
/* Forking and kill()ing works as expected: */
/* test_with_kill(); */
}
[-- Attachment #3: signal-test.c --]
[-- Type: text/x-csrc, Size: 1180 bytes --]
#include <syscall.h>
#include <signal.h>
#include <stdio.h>
#include <ucontext.h>
int is_blocked(int sig)
{
sigset_t set;
sigprocmask(SIG_BLOCK, NULL, &set);
return sigismember(&set, sig);
}
void *eip(struct ucontext *context)
{
return (void *)context->uc_mcontext.gregs[14];
}
void sig_1(int sig, siginfo_t *info, struct ucontext *context)
{
printf("%d %d\n", sig, is_blocked(2));
printf("eip: %x\n", eip(context));
}
void sig_2(int sig, siginfo_t *info, struct ucontext *context)
{
printf("%d %d\n", sig, is_blocked(1));
printf("eip: %x\n", eip(context));
}
int tkill(int tid, int sig)
{
syscall(SYS_tkill, tid, sig);
}
int main(void)
{
sigset_t set;
struct sigaction sa;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = sig_1;
sigaction(1, &sa, 0);
sa.sa_sigaction = sig_2;
sigaction(2, &sa, 0);
sigemptyset(&set);
sigaddset(&set, 1);
sigaddset(&set, 2);
printf("sig_1=%x\n", sig_1);
printf("sig_2=%x\n", sig_2);
sigprocmask(SIG_BLOCK, &set, NULL);
kill(getpid(), 1);
kill(getpid(), 2);
sigprocmask(SIG_UNBLOCK, &set, NULL);
return 0;
}
next prev parent reply other threads:[~2009-03-15 22:07 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-14 16:50 Signal delivery order Gábor Melis
2009-03-15 9:44 ` Oleg Nesterov
2009-03-15 14:40 ` Gábor Melis
2009-03-15 17:29 ` Oleg Nesterov
2009-03-15 22:06 ` Gábor Melis [this message]
2009-03-16 0:28 ` Oleg Nesterov
2009-03-16 8:34 ` Gábor Melis
2009-03-16 21:13 ` Oleg Nesterov
2009-03-16 22:56 ` Chris Friesen
2009-03-17 4:13 ` Q: SEGSEGV && uc_mcontext->ip (Was: Signal delivery order) Oleg Nesterov
2009-03-17 4:25 ` Oleg Nesterov
2009-03-17 8:23 ` Gábor Melis
2009-03-17 9:25 ` Oleg Nesterov
2009-03-17 10:20 ` Gábor Melis
2009-03-17 10:43 ` Oleg Nesterov
2009-03-17 15:56 ` Linus Torvalds
2009-03-17 19:20 ` Q: SEGSEGV && uc_mcontext->ip David Miller
2009-03-18 9:58 ` Q: SEGSEGV && uc_mcontext->ip (Was: Signal delivery order) Gábor Melis
2009-03-18 7:59 ` Roland McGrath
2009-03-18 9:02 ` RT signal queue overflow (Was: Q: SEGSEGV && uc_mcontext->ip (Was: Signal delivery order)) Gábor Melis
2009-03-18 14:52 ` Linus Torvalds
2009-03-18 15:23 ` Gábor Melis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=200903152306.53031.mega@retes.hu \
--to=mega@retes.hu \
--cc=akpm@linux-foundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=oleg@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.