tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: netbsd-6: pagedaemon freeze when low on memory



On Mon, Mar 04, 2013 at 02:43:47PM -0500, Richard Hansen wrote:
> With the patch applied, the pagedaemon no longer freezes.  However, LWPs
> start piling up in vmem_alloc() waiting for memory to become available.
>  So it seems like this change is necessary but not sufficient.

vmem_alloc(..., VM_SLEEP) will sleep forever while resources are not
available to fulfill the request, and I think that's good.  It looks to me
like vmem_alloc() needs to wake from its sleep and retry in either of
two conditions.

Condition 1: the backend has new memory available for vmem to add to
    the arena

    I don't think vmem_alloc() will ever wake in this condition,
    because I don't see any way for a backend to signal to the vmem
    that memory is available.

    To fix this problem, add a new vmem(9) method,
    vmem_backend_ready(vmem_t *, ...) and add a couple of vm_flag_t's,
    VM_SLEEPING and VM_WAKING.  Before vmem_alloc() starts to wait
    on its condition variable, let it call the backend's import
    callback with the VM_SLEEPING flag.  Now the backend knows the
    arena is sleeping and the parameters of the region it waits
    for.  If a region that may satisfy the VM_SLEEPING call is
    freed, let it call vmem_backend_ready() on the arena.  Let
    vmem_alloc() call the import function again with VM_WAKING when
    it has satisfied the request that it was VM_SLEEPING for.

Condition 2: the vmem arena was replenished with vmem_free() or vmem_xfree()

    vmem_alloc() sometimes will wake in this condition, however,
    I'm not sure that it will wake reliably, because it does not
    continuously hold a lock both while it checks the out-of-memory
    condition and while it waits on a condition variable for the
    out-of-memory condition to change.  There's a race condition:
    it's possible for a thread to alleviate the out-of-memory
    condition after vmem_alloc() tests for it but before vmem_alloc()
    does VMEM_LOCK(vm); VMEM_CONDVAR_WAIT(vm).  If that happens,
    then vmem_alloc() could wait forever for the out-of-memory
    condition to end.

    It's undesirable for vmem_alloc() to VMEM_LOCK(vm) unless it's
    strictly necessary, and testing the out-of-memory condition
    a second time after VMEM_LOCK() but before VMEM_CONDVAR_WAIT()
    seems redundant.

    Maybe we can avoid unnecessary locking or redundancy using a
    generation number?  Add a generation number to the vmem_t,
    
        volatile uint64_t vm_gen;

    Increase a vmem_t's generation number every
    time that vmem_free(), vmem_xfree(), or vmem_backend_ready() is
    called:

        VMEM_LOCK(vm);  /* have to hold lock to modify vm_gen */
        vm->vm_gen++;
        VMEM_CONDVAR_BROADCAST(vm);
        VMEM_UNLOCK(vm);

    Before testing the out-of-memory condition in vmem_alloc(),
    read the generation number:

    again:
        gen = vm->vm_gen;
        membar_consumer();

        ... memory available? if so, return.  otherwise ...

        VMEM_LOCK(vm);
        while (gen == vm->vm_gen)
                VMEM_CONDVAR_WAIT(vm);
        VMEM_UNLOCK(vm);
        goto again;

Dave

-- 
David Young
dyoung%pobox.com@localhost    Urbana, IL    (217) 721-9981


Home | Main Index | Thread Index | Old Index