File: mutex.go

package info (click to toggle)
gitlab-agent 16.1.3-2
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid, trixie
  • size: 6,324 kB
  • sloc: makefile: 175; sh: 52; ruby: 3
file content (44 lines) | stat: -rw-r--r-- 1,273 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package syncz

import "context"

// Mutex is a non-reentrant (like sync.Mutex) mutex that (unlike sync.Mutex) allows to
// acquire the mutex with a possibility to abort the attempt early if a context signals done.
//
// A buffered channel of size 1 is used as the mutex. Think of it as of a box - the party that has put something
// into it has acquired the mutex. To unlock it, remove the contents from the box, so that someone else can use it.
// An empty box is created in the NewMutex() constructor.
//
// TryLock, Lock, and Unlock provide memory access ordering guarantees by piggybacking on channel's "happens before"
// guarantees. See https://golang.org/ref/mem
type Mutex struct {
	box chan struct{}
}

func NewMutex() Mutex {
	return Mutex{
		box: make(chan struct{}, 1), // create an empty box
	}
}

func (m Mutex) TryLock() bool {
	select {
	case m.box <- struct{}{}: // try to put something into the box
		return true
	default: // cannot put immediately, abort
		return false
	}
}

func (m Mutex) Lock(ctx context.Context) bool {
	select {
	case <-ctx.Done(): // abort if context signals done
		return false
	case m.box <- struct{}{}: // try to put something into the box
		return true
	}
}

func (m Mutex) Unlock() {
	<-m.box // take something from the box
}