Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread cinap_lenrek
it doesnt matter. p is a pointer to a pointer. the whole
idea of privalloc() is to give you a memory locaiton that
when *dereferenced* can yield different *values* under different
processes, tho the *address* is the same, so it can be passed
arround.

--
cinap



Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread erik quanstrom
On Sat Sep  5 07:06:44 PDT 2015, giac...@tesio.it wrote:

> 2011-05-20 3:30 GMT+02:00 erik quanstrom :

uh, wow.  i hope this wasn't my mailer dragging the past up.

> > one note is that while i'm aware of privalloc(2), i didn't use it.  the
> > implementation doesn't appear correct for shared-memory procs.
> > i think there are two issues
> > - locking is unnecessary.  the only preemptable unit of execution is
> > a process and each process is guarenteed to have its own instance
> > of _privates and _nprivates.
> > - for shared-memory procs, we will run out of privates because
> > the static privinit will be falsely shared.  privinit should be replaced
> > by using a private entry.
> >
> 
> In a set of processes that share memory, I need a single per-process
> location to store the address of structure (which is in turn allocated in
> the global memory space).
> 
> Privalloc(2) seemed what I need, but seem that I can't use it properly.
> 
> In the parent process I do:
> 
> 1) initialialize a global variable p = (MyStruct **)privalloc();
> 2) allocate a MyStruct for every process I'm going to spawn
> 3) spawn processes with rfork(RFMEM|RFPROC)
> 
> The spawn() function that call rfork takes a MyStruct* as argument and
> assign it to *p in the new process.
> For extra safety I added an assert(*p == nil) just after rfork, and after a
> few (apparently?) successful spawns, the assert fails.

hmm.  in /sys/src/libc/amd64/arv0.s _privates and _nprivates are in the bss.

GLOBL   _privates(SB), $8
GLOBL   _nprivates(SB), $4

so they can be set in the parent process.  in /sys/src/libc/amd64/main9.s

#define NPRIVATES   16

TEXT_main(SB), 1, $(2*8+NPRIVATES*8)
MOVQAX, _tos(SB)
LEAQ16(SP), AX
MOVQAX, _privates(SB)
MOVL$NPRIVATES, _nprivates(SB)


we see that the privates and nprivates are on the stack just below _tos.

the only ways i can see your pointer not being nil is
(a) kernel bug -- the stack is not cleared
(b) the the parent has written to the privalloc'd element before forking,
and the stack was copied faithfully.

i think you can tell which case you have by assert(*p == nil) in the parent.

i'm sure there could be other bugs as well.

as to getpid() being "slow", you can always use _tos->pid

- erik



Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread Giacomo Tesio
... and given getpid(2) implementation, a pid based table could be quite
expensive, since MyStruct is accessed very very often.

2015-09-05 16:03 GMT+02:00 Giacomo Tesio :

> 2011-05-20 3:30 GMT+02:00 erik quanstrom :
>
>> one note is that while i'm aware of privalloc(2), i didn't use it.  the
>> implementation doesn't appear correct for shared-memory procs.
>> i think there are two issues
>> - locking is unnecessary.  the only preemptable unit of execution is
>> a process and each process is guarenteed to have its own instance
>> of _privates and _nprivates.
>> - for shared-memory procs, we will run out of privates because
>> the static privinit will be falsely shared.  privinit should be replaced
>> by using a private entry.
>>
>
> In a set of processes that share memory, I need a single per-process
> location to store the address of structure (which is in turn allocated in
> the global memory space).
>
> Privalloc(2) seemed what I need, but seem that I can't use it properly.
>
> In the parent process I do:
>
> 1) initialialize a global variable p = (MyStruct **)privalloc();
> 2) allocate a MyStruct for every process I'm going to spawn
> 3) spawn processes with rfork(RFMEM|RFPROC)
>
> The spawn() function that call rfork takes a MyStruct* as argument and
> assign it to *p in the new process.
> For extra safety I added an assert(*p == nil) just after rfork, and after
> a few (apparently?) successful spawns, the assert fails.
>
> What I need is a sort of thread-local storage for the MyStruct*, so that
> each child process can find it's own dedicated MyStruct.
> I know that could get this with an hashtable based on the pid, but I'd
> prefer to avoid the book keeping if possible.
>
>
> Giacomo
>


[9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread Giacomo Tesio
2011-05-20 3:30 GMT+02:00 erik quanstrom :

> one note is that while i'm aware of privalloc(2), i didn't use it.  the
> implementation doesn't appear correct for shared-memory procs.
> i think there are two issues
> - locking is unnecessary.  the only preemptable unit of execution is
> a process and each process is guarenteed to have its own instance
> of _privates and _nprivates.
> - for shared-memory procs, we will run out of privates because
> the static privinit will be falsely shared.  privinit should be replaced
> by using a private entry.
>

In a set of processes that share memory, I need a single per-process
location to store the address of structure (which is in turn allocated in
the global memory space).

Privalloc(2) seemed what I need, but seem that I can't use it properly.

In the parent process I do:

1) initialialize a global variable p = (MyStruct **)privalloc();
2) allocate a MyStruct for every process I'm going to spawn
3) spawn processes with rfork(RFMEM|RFPROC)

The spawn() function that call rfork takes a MyStruct* as argument and
assign it to *p in the new process.
For extra safety I added an assert(*p == nil) just after rfork, and after a
few (apparently?) successful spawns, the assert fails.

What I need is a sort of thread-local storage for the MyStruct*, so that
each child process can find it's own dedicated MyStruct.
I know that could get this with an hashtable based on the pid, but I'd
prefer to avoid the book keeping if possible.


Giacomo


Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread erik quanstrom
by the way, the following program runs without asserting for me
with or without the waits.

- erik

---

#include 
#include 

void
task(void **p)
{
assert(*p == nil);
*p = (void*)(uintptr)getpid();
}

void
spawn(void (*t)(void**), void **p)
{
int pid;

switch(pid = rfork(RFMEM|RFPROC)){
case -1:
sysfatal("spawn: rfork: %r");
case 0:
t(p);
exits("");
default:
USED(pid);
return;
}
}

void
main(void)
{
int i, k;
void **p;
Waitmsg *w;

p = privalloc();
k = 0;
for(i = 0; i < 1024; i++){
spawn(task, p);
for(k++; k > 16; k--){
if((w = wait()) == nil)
break;
free(w);
}
}
exits("");
}



Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread Charles Forsyth
On 5 September 2015 at 15:03, Giacomo Tesio  wrote:

> For extra safety I added an assert(*p == nil) just after rfork, and after
> a few (apparently?) successful spawns, the assert fails.


The stack is a logical copy of the parent process's stack at rfork, even
with RFMEM, since the stack's not shared,
so if you've previously assigned it in the parent, its child will see the
non-nil value after the fork. It doesn't get a completely fresh stack.


Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread Giacomo Tesio
Nice example thanks.

May be my problem is that p is global in my case?

Giacomo
Il 05/Set/2015 18:50, "erik quanstrom"  ha scritto:

> by the way, the following program runs without asserting for me
> with or without the waits.
>
> - erik
>
> ---
>
> #include 
> #include 
>
> void
> task(void **p)
> {
> assert(*p == nil);
> *p = (void*)(uintptr)getpid();
> }
>
> void
> spawn(void (*t)(void**), void **p)
> {
> int pid;
>
> switch(pid = rfork(RFMEM|RFPROC)){
> case -1:
> sysfatal("spawn: rfork: %r");
> case 0:
> t(p);
> exits("");
> default:
> USED(pid);
> return;
> }
> }
>
> void
> main(void)
> {
> int i, k;
> void **p;
> Waitmsg *w;
>
> p = privalloc();
> k = 0;
> for(i = 0; i < 1024; i++){
> spawn(task, p);
> for(k++; k > 16; k--){
> if((w = wait()) == nil)
> break;
> free(w);
> }
> }
> exits("");
> }
>
>


Re: [9fans] Privalloc(2) and rfork(RFPROC|RFMEM) (was: a pair nec bugs)

2015-09-05 Thread erik quanstrom
> May be my problem is that p is global in my case?

global variables are in the bss, and thus shared. p will have
the same value in each thread, but *p should point into the
stack, and thus the same virtual address will be mapped to
different physical pages of memory.

however, if *p is assigned to a non-zero value before the process
is created, the new page allocated for the new process' stack will
have a copy of the old value, and thus not be 0.

- erik