| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 | // Package gls implements goroutine-local storage.package glsimport (	"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()}
 |