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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
package atom
import (
"fmt"
"sync"
"xgob"
"xgob/xproto"
)
type state struct {
c *xgob.Connection
name map[xproto.Atom]string
atom map[string]xproto.Atom
pendingAtom map[string]chan xproto.InternAtomReply
}
var lock sync.RWMutex
var db = make(map[*xgob.Connection]state)
func newState (c *xgob.Connection) state {
var rv state
rv.c = c
rv.name = make(map[xproto.Atom]string)
rv.atom = make(map[string]xproto.Atom)
rv.pendingAtom = make(map[string]chan xproto.InternAtomReply)
return rv
}
/* internAtom must be called under a write lock */
func (s *state) internAtom (name string) xproto.Atom {
c, ok := s.pendingAtom[name]
if ok {
s.pendingAtom[name] = nil, false
} else {
c = xproto.InternAtom(s.c, false, name)
}
reply, ok := <- c
if !ok {
s.c.Flush()
reply = <- c
}
if reply.Error == nil {
s.name[reply.Atom] = name
s.atom[name] = reply.Atom
} else {
println("Atom Error",reply.Error.Error)
}
return reply.Atom
}
func getState(c *xgob.Connection, writelocked bool) *state {
s, ok := db[c]
if !ok {
// Grab write lock, recheck, create state, downgrade to read lock
if !writelocked {
lock.RUnlock()
lock.Lock()
s, ok = db[c]
}
if !ok {
db[c] = newState(c)
s, ok = db[c]
}
if !writelocked {
lock.Unlock()
lock.RLock()
}
}
return &s
}
func PreloadAtom(c *xgob.Connection, name string) {
lock.Lock()
s := getState(c, true)
_, ok := s.atom[name]
if !ok {
_, ok := s.pendingAtom[name]
if !ok {
s.pendingAtom[name] = xproto.InternAtom(c, false, name)
}
}
lock.Unlock()
}
func Atom (c *xgob.Connection, name string) xproto.Atom {
lock.RLock()
s := getState(c, false)
atom, ok := s.atom[name]
lock.RUnlock()
if !ok {
// Grab write lock, recheck, InternAtom
lock.Lock()
atom, ok = s.atom[name]
if !ok {
atom = s.internAtom(name)
}
lock.Unlock()
}
return atom
}
func AtomName (c *xgob.Connection, atom xproto.Atom) string {
return fmt.Sprintf("0x%X", atom) // TODO
}
|