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 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome