File: resource_id.go

package info (click to toggle)
golang-github-linuxdeepin-go-x11-client 0.6.3-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye, sid
  • size: 1,656 kB
  • sloc: python: 944; sh: 38; makefile: 17
file content (90 lines) | stat: -rw-r--r-- 1,597 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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package x

import (
	"errors"
	"math/big"
	"sync"
)

func (c *Conn) AllocID() (uint32, error) {
	return c.ridAllocator.alloc()
}

func (c *Conn) FreeID(rid uint32) error {
	return c.ridAllocator.free(rid)
}

func (c *Conn) IDUsedCount() int {
	return c.ridAllocator.usedCount()
}

type resourceIdAllocator struct {
	mu           sync.Mutex
	base         uint32
	mask         uint32
	last         uint32
	bitmap       *big.Int
	allAllocated bool
}

func (ra *resourceIdAllocator) init(base, mask uint32) {
	ra.base = base
	ra.mask = mask
	ra.bitmap = big.NewInt(0)
}

var errOutOfResourceIds = errors.New("out of resource ids")

func (ra *resourceIdAllocator) alloc() (uint32, error) {
	ra.mu.Lock()
	defer ra.mu.Unlock()

	if ra.allAllocated {
		return 0, errOutOfResourceIds
	}

	i := ra.last
	for ra.bitmap.Bit(int(i)) == 1 {
		i++
		if i > ra.mask {
			i = 0
		}
		if i == ra.last {
			ra.allAllocated = true
			return 0, errOutOfResourceIds
		}
	}
	ra.bitmap.SetBit(ra.bitmap, int(i), 1)
	ra.last = i
	return ra.base | i, nil
}

func (ra *resourceIdAllocator) free(rid uint32) error {
	ra.mu.Lock()
	defer ra.mu.Unlock()

	i := rid & ra.mask
	if rid-i != ra.base {
		return errors.New("resource id outside range")
	}

	if ra.bitmap.Bit(int(i)) == 0 {
		return errors.New("resource id not used")
	}
	ra.bitmap.SetBit(ra.bitmap, int(i), 0)
	ra.allAllocated = false
	return nil
}

func (ra *resourceIdAllocator) usedCount() int {
	ra.mu.Lock()
	count := 0
	bitLen := ra.bitmap.BitLen()
	for i := 0; i < bitLen; i++ {
		if ra.bitmap.Bit(i) == 1 {
			count++
		}
	}
	ra.mu.Unlock()
	return count
}