Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 Aug 2002 02:38:17 -0400
From:      Jake Burkholder <jake@locore.ca>
To:        Luigi Rizzo <rizzo@icir.org>
Cc:        Peter Wemm <peter@wemm.org>, Terry Lambert <tlambert2@mindspring.com>, smp@FreeBSD.ORG
Subject:   Re: how to create per-cpu variables in SMP kernels ?
Message-ID:  <20020806023816.D76014@locore.ca>
In-Reply-To: <20020805230556.C26751@iguana.icir.org>; from rizzo@icir.org on Mon, Aug 05, 2002 at 11:05:56PM -0700
References:  <20020805015340.A17716@iguana.icir.org> <20020805221415.B0C732A7D6@canning.wemm.org> <20020805230556.C26751@iguana.icir.org>

next in thread | previous in thread | raw e-mail | index | archive | help
Apparently, On Mon, Aug 05, 2002 at 11:05:56PM -0700,
	Luigi Rizzo said words to the effect of;

> Hi Peter,
> thanks for the explaination.
> I still have a few doubts on this (let's restrict to the -current
> case where the code seems more readable):
> 
> --- MINOR DETAIL ---
> 
>   * I wonder why the macro __PCPU_GET() in sys/i386/include/pcpu.h
>     cannot store directly into __result for operand sizes of 1,2,4
>     instead of going through a temporary variable. I.e. what would
>     be wrong in having
> 
>         #define __PCPU_GET(name) ({                                     \
>             __pcpu_type(name) __result;                                 \
>                                                                         \
>             if (sizeof(__result) == 1) {                                \
>                     __asm __volatile("movb %%fs:%1,%0"                  \
>                         : "=r" (__result)                               \
>                         : "m" (*(u_char *)(__pcpu_offset(name))));      \
>             } else if (sizeof(__result) == 2) {                         \
> 
>     Probably the same holds for __PCPU_SET().

The code has to work for all types; if __result is a struct timeval,
having it as an output in the asm statement doesn't compile.  It all
gets optimized out anyway.

> 
> --- OVERALL IMPLEMENTATION OF THE PER-CPU DATA ---
> 
>     Partly following Terry's description, i thought an arrangement
>     like the following could be relatively simple to implement and not
>     require any recourse to assembly code, does not impact the compiler's
>     ability to do optimizations, and does not require an extra
>     segment descriptor to access the struct pcpu.
> 
>     It relies on the following variables, my_pcpu to access the
>     pcpu data of the local processor, all_pcpu to view all pcpu
>     data (including our own, at a different mapping in vm space):
> 
>         struct pcpu *my_pcpu;
> 
>         struct pcpu *all_pcpu[MAXCPU]; /* XXX volatile */
> 
>     Early in the boot process we allocate MAXCPU physical pages,
>     and MAXCPU+1 entries in the VM space. Individual pcpu structs
>     go at the beginning of each of the physical pages, and the
>     VM -> physical mapping of the first MAXCPU VM entries is the
>     same for all processors. Then all_pcpu[i] can be initialized
>     with a pointer to the beginning of the i-th VM page.
> 
>     The MAXCPU+1-th VM entry maps differently on each CPU,
>     so that it effectively permits access to the per-cpu data.
>     my_pcpu can be initialized with a pointer to the MAXCPU+1-th VM page.
> 
>     At this point, curproc and all other per-cpu variables for the
>     local CPU can be accessed through
> 
>         my_pcpu->curproc
> 
>     and similar, whereas we can get to other cpu's data with
> 
>         all_pcpu[i]->curproc
> 
>     without the need for using %fs or special assembly language to
>     access these fields.
> 
>     Then we can discuss how/where to put "volatile" keywords.   
>     In principle, all references through all_pcpu[] should be
>     readonly and treated as volatile, with perhaps the exception of 
>     some section of code at machine startup. On the contrary we could
>     safely assume that references through my_pcpu are non-volatile
>     as the local processor should be the only one to mess with them
> 
> Anything wrong with this description ?

This doesn't work because the page directory is per-process, not per-cpu.
To implement this you would need a fixed page directory entry which pointed
to a different page table page on each cpu, which mapped the different
per-cpu pages to the same virtual address.  If 2 processes which shared
page directories were running concurrently on 2 cpus, they would both
see the same per-cpu data (one of then would get the wrong struct pcpu).
Basically the struct pcpu's cannot all be mapped to the same virtual
address.

Jake

> 
>         cheers
>         luigi
> 
> On Mon, Aug 05, 2002 at 03:14:15PM -0700, Peter Wemm wrote:
> ...
> > Sort-of.  There is both a compile time issue and a runtime issue.
> > 
> > Using the %fs:variable segment overrides doesn't make a lot of difference,
> > but the compiler is effectively wired so that they are treated as volatile.
> ...
> 
> To Unsubscribe: send mail to majordomo@FreeBSD.org
> with "unsubscribe freebsd-smp" in the body of the message

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




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