Browse Source

make semaphores O(1) in storage

tags/v1.2.0-rc1
Shivaram Lingamneni 4 years ago
parent
commit
45476079a1
1 changed files with 23 additions and 10 deletions
  1. 23
    10
      irc/utils/semaphores.go

+ 23
- 10
irc/utils/semaphores.go View File

4
 package utils
4
 package utils
5
 
5
 
6
 import (
6
 import (
7
+	"context"
7
 	"log"
8
 	"log"
8
 	"runtime/debug"
9
 	"runtime/debug"
9
 	"time"
10
 	"time"
10
 )
11
 )
11
 
12
 
12
-// Semaphore is a counting semaphore. Note that a capacity of n requires O(n) storage.
13
+type e struct{}
14
+
15
+// Semaphore is a counting semaphore.
13
 // A semaphore of capacity 1 can be used as a trylock.
16
 // A semaphore of capacity 1 can be used as a trylock.
14
-type Semaphore (chan bool)
17
+type Semaphore (chan e)
15
 
18
 
16
 // Initialize initializes a semaphore to a given capacity.
19
 // Initialize initializes a semaphore to a given capacity.
17
 func (semaphore *Semaphore) Initialize(capacity int) {
20
 func (semaphore *Semaphore) Initialize(capacity int) {
18
-	*semaphore = make(chan bool, capacity)
19
-	for i := 0; i < capacity; i++ {
20
-		(*semaphore) <- true
21
-	}
21
+	*semaphore = make(chan e, capacity)
22
 }
22
 }
23
 
23
 
24
 // Acquire acquires a semaphore, blocking if necessary.
24
 // Acquire acquires a semaphore, blocking if necessary.
25
 func (semaphore *Semaphore) Acquire() {
25
 func (semaphore *Semaphore) Acquire() {
26
-	<-(*semaphore)
26
+	(*semaphore) <- e{}
27
 }
27
 }
28
 
28
 
29
 // TryAcquire tries to acquire a semaphore, returning whether the acquire was
29
 // TryAcquire tries to acquire a semaphore, returning whether the acquire was
30
 // successful. It never blocks.
30
 // successful. It never blocks.
31
 func (semaphore *Semaphore) TryAcquire() (acquired bool) {
31
 func (semaphore *Semaphore) TryAcquire() (acquired bool) {
32
 	select {
32
 	select {
33
-	case <-(*semaphore):
33
+	case (*semaphore) <- e{}:
34
 		return true
34
 		return true
35
 	default:
35
 	default:
36
 		return false
36
 		return false
47
 
47
 
48
 	timer := time.NewTimer(timeout)
48
 	timer := time.NewTimer(timeout)
49
 	select {
49
 	select {
50
-	case <-(*semaphore):
50
+	case (*semaphore) <- e{}:
51
 		acquired = true
51
 		acquired = true
52
 	case <-timer.C:
52
 	case <-timer.C:
53
 		acquired = false
53
 		acquired = false
56
 	return
56
 	return
57
 }
57
 }
58
 
58
 
59
+// AcquireWithContext tries to acquire a semaphore, blocking at most until
60
+// the context expires. It returns whether the acquire was successful.
61
+// Note that if the context is already expired, the acquire may succeed anyway.
62
+func (semaphore *Semaphore) AcquireWithContext(ctx context.Context) (acquired bool) {
63
+	select {
64
+	case (*semaphore) <- e{}:
65
+		acquired = true
66
+	case <-ctx.Done():
67
+		acquired = false
68
+	}
69
+	return
70
+}
71
+
59
 // Release releases a semaphore. It never blocks. (This is not a license
72
 // Release releases a semaphore. It never blocks. (This is not a license
60
 // to program spurious releases.)
73
 // to program spurious releases.)
61
 func (semaphore *Semaphore) Release() {
74
 func (semaphore *Semaphore) Release() {
62
 	select {
75
 	select {
63
-	case (*semaphore) <- true:
76
+	case <-(*semaphore):
64
 		// good
77
 		// good
65
 	default:
78
 	default:
66
 		// spurious release
79
 		// spurious release

Loading…
Cancel
Save