Re: puzzling code in pcpu stuff

From: Christoph Mallon <christoph.mallon_at_gmx.de>
Date: Sun, 02 Aug 2009 12:34:09 +0200
Julian Elischer schrieb:
> I simplified the output of the preprocessor for a PCPU_SET(xx, newval)
> (to look at it).
> 
> I came down to: (after formatting) for i386..
> {
>         __typeof(((struct pcpu *)0)->pc_xx) __val;
>         struct __s
>         {
>                 u_char __b[(((sizeof(__val)) < (4)) ?
>                                    (sizeof(__val)) : (4))];
>         } __s;
> 
>         __val = (newval); /* aligned */
> 
>         if (sizeof(__val) == 1
>         || sizeof(__val) == 2
>         || sizeof(__val) == 4) {
>                 __s = *(struct __s *)(void *)&__val;
>                 __asm volatile("mov %1,%%fs:%0" : "=m"
>                   (*(struct __s *)(__builtin_offsetof(
>                        struct pcpu,  pc_xx))) : "r" (__s));
>         } else {
>                 *__extension__ (
>                 {
>                         __typeof(__val) *__p;
>                         __asm volatile("movl %%fs:%1,%0;
>                         addl %2,%0" : "=r" (__p) : "m"
>   (*(struct pcpu *)(__builtin_offsetof(struct pcpu, pc_prvspace))),
>   "i"
>   (__builtin_offsetof(struct pcpu, pc_xx)));
>    __p;
>                 }) = __val;
>         }
> }
> 
> having had my brain explode on this several times,
> I can't figure out exactly what teh clause after the else is doing.
> 
> anyone better at reading __asm better than me care to explain it in
> simple words?

First, ({}) is a statement expression - a GCC extension (not to be 
confused with expression statement, which is an expression followed by a 
semicolon). It wraps a compound statement, i.e. {}, and turns it into an 
expression. The value of the last statement is the value of the 
expression. In this case it's __p;.

The per-cpu information can be accessed in two ways: Either by accessing 
it in the %fs segment (the then clause does it) or reading its address 
from %fs:pc_prvspace and then accessing it in the normal (i.e. %ds) 
segment (the else clause does this).

Let's have a closer look at the else clause: The asm reads the pointer 
to per-cpu information into __p and the statement expression returns it. 
This pointer gets dereferenced (mind the * before __extension__ - 
__extension__ does nothing, it just marks that the following is a GCC 
extension) and __val is assigned.
This else clause is for assignment for things which are not 1, 2 or 4 
bytes in size. For sizes 1, 2 and 4 better code can be generated for by 
not first getting the pointer, but directly assigning the value into the 
%fs mappinf of the per-cpu info.

Regards
	Christoph
Received on Sun Aug 02 2009 - 09:00:53 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:53 UTC