github.com/brownsys/tracing-framework-go@v0.0.0-20161210174012-0542a62412fe/other/internal/gls/gls_goid.go (about) 1 // +build goid 2 3 package gls 4 5 import ( 6 "runtime" 7 "sync" 8 ) 9 10 type bucket struct { 11 locals map[int64]*local 12 sync.RWMutex 13 } 14 15 type local struct { 16 m map[interface{}]interface{} 17 sync.RWMutex 18 } 19 20 var buckets = make([]bucket, 8*runtime.NumCPU()) 21 22 func init() { 23 for i := range buckets { 24 buckets[i].locals = make(map[int64]*local) 25 } 26 } 27 28 func getLocal() *local { 29 goid := runtime.Goid() 30 bkt := &buckets[int(goid%int64(len(buckets)))] 31 bkt.RLock() 32 l, ok := bkt.locals[goid] 33 bkt.RUnlock() 34 if !ok { 35 panic("gls: no goroutine-local storage; goroutine was not spawned with Go") 36 } 37 return l 38 } 39 40 func _go(f func()) { 41 go base(f) 42 } 43 44 func base(f func()) { 45 goid := runtime.Goid() 46 bkt := &buckets[int(goid%int64(len(buckets)))] 47 48 l := &local{m: make(map[interface{}]interface{})} 49 bkt.Lock() 50 bkt.locals[goid] = l 51 bkt.Unlock() 52 53 defer func() { 54 bkt.Lock() 55 delete(bkt.locals, goid) 56 bkt.Unlock() 57 }() 58 59 f() 60 } 61 62 func put(k, v interface{}) { 63 l := getLocal() 64 l.Lock() 65 // defer in case k is an invalid 66 // map key and the next line panics 67 defer l.Unlock() 68 l.m[k] = v 69 } 70 71 func get(k interface{}) (interface{}, bool) { 72 l := getLocal() 73 l.RLock() 74 // defer in case k is an invalid 75 // map key and the next line panics 76 defer l.RUnlock() 77 v, ok := l.m[k] 78 return v, ok 79 } 80 81 func del(k interface{}) { 82 l := getLocal() 83 l.Lock() 84 // defer in case k is an invalid 85 // map key and the next line panics 86 defer l.Unlock() 87 delete(l.m, k) 88 }