func (mm *memoryManager) Return(amount uint64) {
	mm.mu.Lock()
	defer mm.mu.Unlock()
	if mm.underflow > 0 && amount <= mm.underflow {
		mm.underflow -= amount
		return
	} else if mm.underflow > 0 && amount > mm.underflow {
		amount -= mm.underflow
		mm.underflow = 0
	}
	mm.available += amount
	if mm.available > mm.base {
		build.Critical("renter memory manager being used incorrectly, too much memory returned")
		mm.available = mm.base
	}
	for len(mm.priorityFifo) > 0 {
		if !mm.try(mm.priorityFifo[0].amount) {
			return
		}
		close(mm.priorityFifo[0].done)
		mm.priorityFifo = mm.priorityFifo[1:]
	}
	for len(mm.fifo) > 0 {
		if !mm.try(mm.fifo[0].amount) {
			return
		}
		close(mm.fifo[0].done)
		mm.fifo = mm.fifo[1:]
	}
}
Return will return memory to the manager, waking any blocking threads which
now have enough memory to proceed.
package renter
import (
	"sync"
	"github.com/NebulousLabs/Sia/build"
)
type memoryManager struct {
	available    uint64
	base         uint64
	fifo         []*memoryRequest
	priorityFifo []*memoryRequest
	mu           sync.Mutex
	stop         <-chan struct{}
	underflow    uint64
}
type memoryRequest struct {
	amount uint64
	done   chan struct{}
}
func (mm *memoryManager) try(amount uint64) bool {
	if mm.available >= amount {
		mm.available -= amount
		return true
	} else if mm.available == mm.base {
		mm.available = 0
		mm.underflow = amount - mm.base
		return true
	}
	return false
}
func (mm *memoryManager) Request(amount uint64, priority bool) bool {
	mm.mu.Lock()
	if len(mm.fifo) == 0 && mm.try(amount) {
		mm.mu.Unlock()
		return true
	}
	myRequest := &memoryRequest{
		amount: amount,
		done:   make(chan struct{}),
	}
	if priority {
		mm.priorityFifo = append(mm.priorityFifo, myRequest)
	} else {
		mm.fifo = append(mm.fifo, myRequest)
	}
	mm.mu.Unlock()
	select {
	case <-myRequest.done:
		return true
	case <-mm.stop:
		return false
	}
}