amd64/169927: siginfo, si_code for fpe errors when error occurs using the SSE math processor

Bruce Evans brde at optusnet.com.au
Thu Jul 19 17:44:07 UTC 2012


On Thu, 19 Jul 2012, Konstantin Belousov wrote:

> On Thu, Jul 19, 2012 at 01:10:29PM +1000, Bruce Evans wrote:
>> On Wed, 18 Jul 2012, Konstantin Belousov wrote:
>>
>>> On Wed, Jul 18, 2012 at 04:59:38PM +1000, Bruce Evans wrote:
>>>> On Wed, 18 Jul 2012, Konstantin Belousov wrote:
>>>> Putting the definiton in machine/pcpu.h should avoid changing the
>>>> prerequistes for machine/pcb.h.
>>>>
>>>>> #ifndef _KERNEL
>>>>> /* stuff that *used* to be included by user.h, or is now needed */
>>>>>
>>>>> Please note the location in pcb.h an not in machine/pcpu.h, where it
>>>>> cannot work for technical reasons (struct pcpu is not defined yet).
>>>>
>>>> Not applicable -- see above.
>>> No, this cannot work. machine/pcpu.h defines PCPU_MD_FIELDS which is used
>>> to provide md part of the struct pcpu.
>>
>> I see.  Oops.
>>
>> But this problem is easy to avoid.  There are at least the following
>> alternatives:
>> (1) hard-code the offset, as for curthread.  This is ugly, but not too
>>     hard to maintain.  The offset has been 4 * sizeof(struct thread *),
>>     for more than 10 years, and you can't change this without breaking
>>     the ABI.
> I did this, adding CTASSERTs. See the patch below.

Looks good.  I had forgotten that CTASSERT() makes this safe.

>>     To do the same thing for curpcb, provide a PCPU_NONVOLATILE_GET()
>>     which is the same as PCPU_GET() without the volatile in the asm,
>>     and #define curpcb as PCPU_NONVOLATILE_GET(curpcb).  Or maybe
>>     start with the inline function used for curthread, and macroize it.
>>
>>     This could be used for curthread too, but I think we want to keep it
>>     as an inline function since the macro expansions are still horrible.
> I do not like this, prefer the inline functions approach.

Maybe use even more inlines.  I wonder if an inline that is always parsed
but rarely used takes longer to compile than a complicated macro that is
often but not always expanded (where each expansion gives an asm similar
to the inline).

>> BTW, can you explain the locking for the pcpu access functions?  It seems
>> to be quite broken, with the volatile in the asms neither necessary nor
>> sufficient.  PCPU_PTR() seems to be almost unusable, but it is used.
>> ...
>> - [curthread and curpcb are special]
>>   as obviously correctly locked as the above 2.
>> - counter variables.  Now you want the %fs pointer to change to track
>>   the CPU.
> They are 'locked' by the fact that the increment is atomic regarind
> context switches and interrupts, since CPU guarantees that interrupts
> only happen on exact instruction boundaries.

Also, PCPU_INC() only supports 1, 2 and 4-byte variables on i386.  But
I increments of int64_t variables using PCPU_PTR() (or DPCPU_PTR()?)
aren't safe on i386.

>> % 	} else {							\
>> % 		__res = *__PCPU_PTR(name);				\
>>
>> __PCPU_PTR() seems to be almost unusable, and this is not one of the
>> few cases where it is usable.  Here it is used for wide or unusually-sized
>> fields where atomic access is especially problematic, yet it does even
>> less that the above to give atomicity.  First consider using it in all
>> cases to replace the above:
>> ...
>> - PCPU_GET/SET(switchtime) in kern_resource.c.  The accesses are only
>>   proc locked AFAIK.  switchtime is uint64_t, so accesses to it are
>>   non-atomic on 32-bit arches.
> Note that access to switchtime is covered by the process spinlock.
> Spinlocks disable preemption, so this is fine.

I see.  It used to use sched locking, but was optimized.

> Below is the updated patch, with added assert that offset of pc_curthread
> is 0.

> diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
> index 103fa0d..070d8c9 100644
> --- a/sys/amd64/amd64/vm_machdep.c
> +++ b/sys/amd64/amd64/vm_machdep.c
> @@ -90,6 +90,10 @@ static u_int	cpu_reset_proxyid;
> static volatile u_int	cpu_reset_proxy_active;
> #endif
>
> +CTASSERT((struct thread **)OFFSETOF_CURTHREAD ==
> +    &((struct pcpu *)NULL)->pc_curthread);
> +CTASSERT((struct pcb **)OFFSETOF_CURPCB == &((struct pcpu *)NULL)->pc_curpcb);
> +

Hmm, I was hoping that the CTASSERT() would be in a header, closer to
the code.  Unfortunately, it can't go very close, for the same reason
that we can't just use struct pcpu in machine/pcpu.h.  This style seems
to be unpopular -- in <sys> headers, the only CTASSERTs() are in old
disk headers and serial.h.

They should use __offsetof() instead of a home made one.

Bruce


More information about the freebsd-amd64 mailing list