/usr/share/gocode/src/github.com/jtolds/gls/context.go is in golang-github-jtolds-gls-dev 4.2.0-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | // Package gls implements goroutine-local storage.
package gls
import (
"sync"
)
const (
maxCallers = 64
)
var (
stackTagPool = &idPool{}
mgrRegistry = make(map[*ContextManager]bool)
mgrRegistryMtx sync.RWMutex
)
// Values is simply a map of key types to value types. Used by SetValues to
// set multiple values at once.
type Values map[interface{}]interface{}
// ContextManager is the main entrypoint for interacting with
// Goroutine-local-storage. You can have multiple independent ContextManagers
// at any given time. ContextManagers are usually declared globally for a given
// class of context variables. You should use NewContextManager for
// construction.
type ContextManager struct {
mtx sync.RWMutex
values map[uint]Values
}
// NewContextManager returns a brand new ContextManager. It also registers the
// new ContextManager in the ContextManager registry which is used by the Go
// method. ContextManagers are typically defined globally at package scope.
func NewContextManager() *ContextManager {
mgr := &ContextManager{values: make(map[uint]Values)}
mgrRegistryMtx.Lock()
defer mgrRegistryMtx.Unlock()
mgrRegistry[mgr] = true
return mgr
}
// Unregister removes a ContextManager from the global registry, used by the
// Go method. Only intended for use when you're completely done with a
// ContextManager. Use of Unregister at all is rare.
func (m *ContextManager) Unregister() {
mgrRegistryMtx.Lock()
defer mgrRegistryMtx.Unlock()
delete(mgrRegistry, m)
}
// SetValues takes a collection of values and a function to call for those
// values to be set in. Anything further down the stack will have the set
// values available through GetValue. SetValues will add new values or replace
// existing values of the same key and will not mutate or change values for
// previous stack frames.
// SetValues is slow (makes a copy of all current and new values for the new
// gls-context) in order to reduce the amount of lookups GetValue requires.
func (m *ContextManager) SetValues(new_values Values, context_call func()) {
if len(new_values) == 0 {
context_call()
return
}
tags := readStackTags(1)
m.mtx.Lock()
values := new_values
for _, tag := range tags {
if existing_values, ok := m.values[tag]; ok {
// oh, we found existing values, let's make a copy
values = make(Values, len(existing_values)+len(new_values))
for key, val := range existing_values {
values[key] = val
}
for key, val := range new_values {
values[key] = val
}
break
}
}
new_tag := stackTagPool.Acquire()
m.values[new_tag] = values
m.mtx.Unlock()
defer func() {
m.mtx.Lock()
delete(m.values, new_tag)
m.mtx.Unlock()
stackTagPool.Release(new_tag)
}()
addStackTag(new_tag, context_call)
}
// GetValue will return a previously set value, provided that the value was set
// by SetValues somewhere higher up the stack. If the value is not found, ok
// will be false.
func (m *ContextManager) GetValue(key interface{}) (value interface{}, ok bool) {
tags := readStackTags(1)
m.mtx.RLock()
defer m.mtx.RUnlock()
for _, tag := range tags {
if values, ok := m.values[tag]; ok {
value, ok := values[key]
return value, ok
}
}
return "", false
}
func (m *ContextManager) getValues() Values {
tags := readStackTags(2)
m.mtx.RLock()
defer m.mtx.RUnlock()
for _, tag := range tags {
if values, ok := m.values[tag]; ok {
return values
}
}
return nil
}
// Go preserves ContextManager values and Goroutine-local-storage across new
// goroutine invocations. The Go method makes a copy of all existing values on
// all registered context managers and makes sure they are still set after
// kicking off the provided function in a new goroutine. If you don't use this
// Go method instead of the standard 'go' keyword, you will lose values in
// ContextManagers, as goroutines have brand new stacks.
func Go(cb func()) {
mgrRegistryMtx.RLock()
defer mgrRegistryMtx.RUnlock()
for mgr, _ := range mgrRegistry {
values := mgr.getValues()
if len(values) > 0 {
mgr_copy := mgr
cb_copy := cb
cb = func() { mgr_copy.SetValues(values, cb_copy) }
}
}
go cb()
}
|