| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144 | 
							- // 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()
 
- }
 
 
  |