func (self *ResourceSemaphore) UpdateActual(n int64) int64 {
	self.mu.Lock()
	actualSize := n + self.reserved
	oldSize := self.curSize
	if actualSize > self.maxSize {
		self.curSize = self.maxSize
	} else {
		self.curSize = actualSize
	}
	if oldSize < self.curSize {
		self.runJobs()
	}
	self.mu.Unlock()
	return actualSize - self.maxSize
}
Set the current actual availability, e.g. by checking free memory.
Returns the difference between the unreserved and actual.  A negative return
value indicates either a job which is using more memory than it reserved,
or some other process on the system is using memory.
package core
import (
	"fmt"
	"strconv"
	"sync"
	"github.com/martian-lang/martian/martian/util"
)
type waiter struct {
	amount int64
	ready  chan<- struct{}  
}
type ResourceSemaphore struct {
	Formatter ResourceFormatter
	maxSize int64
	curSize int64
	reserved int64
	mu       sync.Mutex
	waiters []waiter
}
type ResourceFormatter func(size int64) string
func DefaultResourceFormatter(name string) ResourceFormatter {
	return func(size int64) string {
		buf := make([]byte, 0, 64)
		buf = strconv.AppendInt(buf, size, 10)
		buf = append(buf, ' ')
		buf = append(buf, name...)
		return string(buf)
	}
}
func NewResourceSemaphore(size int64, formatter ResourceFormatter) *ResourceSemaphore {
	return &ResourceSemaphore{
		Formatter: formatter,
		maxSize:   size,
		curSize:   size,
	}
}
func (self *ResourceSemaphore) Acquire(n int64) error {
	self.mu.Lock()
	if self.curSize-self.reserved >= n && len(self.waiters) == 0 {
		self.reserved += n
		self.mu.Unlock()
		return nil
	}
	if n > self.maxSize {
		self.mu.Unlock()
		return fmt.Errorf("Tried to acquire %s, when the maximum is %s.",
			self.Formatter(n), self.Formatter(self.maxSize))
	}
	if len(self.waiters) == 0 && self.curSize-self.reserved > 0 {
		util.LogInfo("jobmngr",
			"Need %s to start the next job (%s available).  Waiting for jobs to complete.",
			self.Formatter(n), self.Formatter(self.curSize-self.reserved))
	}
	ready := make(chan struct{})
	w := waiter{amount: n, ready: ready}
	self.waiters = append(self.waiters, w)
	self.mu.Unlock()
	<-ready
	return nil
}
func (self *ResourceSemaphore) Release(n int64) {
	self.mu.Lock()
	defer self.mu.Unlock()
	self.reserved -= n
	if self.reserved < 0 {
		panic("semaphore: bad release")
	}
	self.runJobs()
}
func (self *ResourceSemaphore) runJobs() {
	for i, waiter := range self.waiters {
		if self.curSize-self.reserved < waiter.amount {
			if self.curSize-self.reserved > 0 {
				util.LogInfo("jobmngr",
					"Need %s to start the next job (%s available). "+
						"Waiting for jobs to complete.",
					self.Formatter(waiter.amount),
					self.Formatter(self.curSize-self.reserved))
			}
			self.waiters = self.waiters[i:]
			return
		}
		self.reserved += waiter.amount
		close(waiter.ready)
		waiter.ready = nil
	}
	if cap(self.waiters) < 2+2*len(self.waiters) {
		self.waiters = nil
	} else {
		self.waiters = self.waiters[len(self.waiters):]
	}
}
func (self *ResourceSemaphore) InUse() int64 {
	self.mu.Lock()
	used := self.maxSize - self.curSize + self.reserved
	self.mu.Unlock()
	return used
}
func (self *ResourceSemaphore) Reserved() int64 {
	self.mu.Lock()
	res := self.reserved
	self.mu.Unlock()
	return res
}
func (self *ResourceSemaphore) Available() int64 {
	self.mu.Lock()
	res := self.curSize - self.reserved
	self.mu.Unlock()
	return res
}
func (self *ResourceSemaphore) CurrentSize() int64 {
	self.mu.Lock()
	res := self.curSize
	self.mu.Unlock()
	return res
}
func (self *ResourceSemaphore) QueueLength() int {
	self.mu.Lock()
	length := len(self.waiters)
	self.mu.Unlock()
	return length
}