terraform: Adding a semaphore implementation
This commit is contained in:
parent
8f98a79cf1
commit
ad31023252
|
@ -1,5 +1,47 @@
|
|||
package terraform
|
||||
|
||||
// Semaphore is a wrapper around a channel to provide
|
||||
// utility methods to clarify that we are treating the
|
||||
// channel as a semaphore
|
||||
type Semaphore chan struct{}
|
||||
|
||||
// NewSemaphore creates a semaphore that allows up
|
||||
// to a given limit of simultaneous acquisitions
|
||||
func NewSemaphore(n int) Semaphore {
|
||||
if n == 0 {
|
||||
panic("semaphore with limit 0")
|
||||
}
|
||||
ch := make(chan struct{}, n)
|
||||
return Semaphore(ch)
|
||||
}
|
||||
|
||||
// Acquire is used to acquire an available slot.
|
||||
// Blocks until available.
|
||||
func (s Semaphore) Acquire() {
|
||||
s <- struct{}{}
|
||||
}
|
||||
|
||||
// TryAcquire is used to do a non-blocking acquire.
|
||||
// Returns a bool indicating success
|
||||
func (s Semaphore) TryAcquire() bool {
|
||||
select {
|
||||
case s <- struct{}{}:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Release is used to return a slot. Acquire must
|
||||
// be called as a pre-condition.
|
||||
func (s Semaphore) Release() {
|
||||
select {
|
||||
case <-s:
|
||||
default:
|
||||
panic("release without an acquire")
|
||||
}
|
||||
}
|
||||
|
||||
// strSliceContains checks if a given string is contained in a slice
|
||||
// When anybody asks why Go needs generics, here you go.
|
||||
func strSliceContains(haystack []string, needle string) bool {
|
||||
|
|
|
@ -1,6 +1,36 @@
|
|||
package terraform
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSemaphore(t *testing.T) {
|
||||
s := NewSemaphore(2)
|
||||
timer := time.AfterFunc(time.Second, func() {
|
||||
panic("deadlock")
|
||||
})
|
||||
defer timer.Stop()
|
||||
|
||||
s.Acquire()
|
||||
if !s.TryAcquire() {
|
||||
t.Fatalf("should acquire")
|
||||
}
|
||||
if s.TryAcquire() {
|
||||
t.Fatalf("should not acquire")
|
||||
}
|
||||
s.Release()
|
||||
s.Release()
|
||||
|
||||
// This release should panic
|
||||
defer func() {
|
||||
r := recover()
|
||||
if r == nil {
|
||||
t.Fatalf("should panic")
|
||||
}
|
||||
}()
|
||||
s.Release()
|
||||
}
|
||||
|
||||
func TestStrSliceContains(t *testing.T) {
|
||||
if strSliceContains(nil, "foo") {
|
||||
|
|
Loading…
Reference in New Issue