Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 May 1998 03:54:42 -0700 (PDT)
From:      will@iki.fi
To:        freebsd-gnats-submit@FreeBSD.ORG
Subject:   kern/6587: SMP idle cpl breaks signal forwarding
Message-ID:  <199805111054.DAA19200@hub.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         6587
>Category:       kern
>Synopsis:       SMP idle cpl breaks signal forwarding
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:
>Keywords:
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon May 11 04:00:02 PDT 1998
>Last-Modified:
>Originator:     Ville-Pertti Keinonen
>Organization:
>Release:        -current
>Environment:
Should occur on any SMP machine.
Current versions to at least May 4th.

>Description:
The cpl either should always be 0 when entering the kernel from user
mode or no code should rely on it being 0.

Currently, some code relies on it, some doesn't, and at least in the
case where the other cpu is idle, it may not correspond to what is set
when going to user mode.

This sometimes breaks signal forwarding if the signal occurs in an
interrupt handler.

What seems to be happening is this:

 - A clock interrupt occurs on an idle cpu.
 - The signal is set and forwarded.
 - Xcpuast is entered by the cpu running the process (waits on lock).
 - The idle cpu returns from the interrupt to an idle state, leaving
the cpl as SWI_AST_MASK.
 - Xcpuast continues, sets the ast in ipending and branches to _doreti
with the cpl left by the other cpu -- the ast isn't processed.
 - The cpl eventually gets cleared, the ast in ipending is probably
processed by the cpu that was idle.

I'm not sure where exactly the cpl becomes SWI_AST_MASK (I only looked
at what was going on with the cpu that was running the process that
was supposed to get the signal, the rest is speculation), but my guess
is it's restored when returning from the interrupt to the idle state
(it seems that in the idle state the cpl is set by a call to spl0).

>How-To-Repeat:
On a mostly idle SMP machine, run the following program:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>

void
handler(int signo)
{
    printf("got signal\n");
    exit(0);
}

int
main(int argc, char **argv)
{
    signal(SIGALRM, handler);
    alarm(1);
    for (;;)
        ;
}

Repeat several times, run it using time(1) to verify that it's
definitely not doing what it's supposed to (it should be obvious
enough, in any case -- for me it usually takes ten seconds or more
for the signal to arrive if I do nothing).

>Fix:
One workaround (this could be done many ways) is to always return the
cpl to 0 before returning from an exception to user mode in _doreti.

This is not the correct way to fix the problem.

Adding the following lines to _doreti (in sys/i386/isa/ipl.s) seems
to work.  (From memory, not a real patch, sorry)

_doreti:
#ifdef SMP
        TEST_CIL
#endif
        FAKE_MCOUNT(_bintr)             /* init "from" _bintr -> _doreti */
        addl    $4,%esp                 /* discard unit number */
        popl    %eax                    /* cpl or cml to restore */
+	testb	$3,52(%esp)		/* going back to user mode?  */
+	jz	1f
+	xorl	%eax,%eax		/* yup, cpl should be 0.  */
+1:
doreti_next:

Note that this makes the equivalent tests done for some traps
redundant.

>Audit-Trail:
>Unformatted:

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-bugs" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805111054.DAA19200>