blob: 60bd066d049efb5ef2f1a2a93b89e671f78ec402 [file] [log] [blame]
David K. Bainbridge528b3182017-01-23 08:51:59 -08001// Copyright 2011, 2012, 2013 Canonical Ltd.
2// Licensed under the LGPLv3, see LICENCE file for details.
3
4package utils
5
6import (
7 "fmt"
8)
9
10type empty struct{}
11type limiter chan empty
12
13// Limiter represents a limited resource (eg a semaphore).
14type Limiter interface {
15 // Acquire another unit of the resource.
16 // Acquire returns false to indicate there is no more availability,
17 // until another entity calls Release.
18 Acquire() bool
19 // AcquireWait requests a unit of resource, but blocks until one is
20 // available.
21 AcquireWait()
22 // Release returns a unit of the resource. Calling Release when there
23 // are no units Acquired is an error.
24 Release() error
25}
26
27func NewLimiter(max int) Limiter {
28 return make(limiter, max)
29}
30
31// Acquire requests some resources that you can return later
32// It returns 'true' if there are resources available, but false if they are
33// not. Callers are responsible for calling Release if this returns true, but
34// should not release if this returns false.
35func (l limiter) Acquire() bool {
36 e := empty{}
37 select {
38 case l <- e:
39 return true
40 default:
41 return false
42 }
43}
44
45// AcquireWait waits for the resource to become available before returning.
46func (l limiter) AcquireWait() {
47 e := empty{}
48 l <- e
49}
50
51// Release returns the resource to the available pool.
52func (l limiter) Release() error {
53 select {
54 case <-l:
55 return nil
56 default:
57 return fmt.Errorf("Release without an associated Acquire")
58 }
59}