github.com/brownsys/tracing-framework-go@v0.0.0-20161210174012-0542a62412fe/other/internal/gls/gls_shim.go (about)

     1  // +build !goid
     2  
     3  package gls
     4  
     5  import (
     6  	"fmt"
     7  	"runtime"
     8  	"unsafe"
     9  )
    10  
    11  func _go(f func()) {
    12  	go base(f)
    13  }
    14  
    15  type shim func([]shim)
    16  
    17  func base(f func()) {
    18  	m := make(map[interface{}]interface{})
    19  	ptr := uintptr(unsafe.Pointer(&m))
    20  
    21  	var s []shim
    22  
    23  	switch runtime.GOARCH {
    24  	case "386":
    25  		s = make([]shim, 4)
    26  		s[0] = shims[int((ptr>>8)&0xFF)]
    27  		s[1] = shims[int((ptr>>16)&0xFF)]
    28  		s[2] = shims[int((ptr>>24)&0xFF)]
    29  	case "amd64":
    30  		s = make([]shim, 8)
    31  		s[0] = shims[int((ptr>>8)&0xFF)]
    32  		s[1] = shims[int((ptr>>16)&0xFF)]
    33  		s[2] = shims[int((ptr>>24)&0xFF)]
    34  		s[3] = shims[int((ptr>>32)&0xFF)]
    35  		s[4] = shims[int((ptr>>40)&0xFF)]
    36  		s[5] = shims[int((ptr>>48)&0xFF)]
    37  		s[6] = shims[int((ptr>>56)&0xFF)]
    38  	default:
    39  		panic(fmt.Errorf("gls: unsupported GOARCH %v", runtime.GOARCH))
    40  	}
    41  	s[len(s)-1] = func(_ []shim) { f() }
    42  
    43  	shims[int(ptr&0xFF)](s)
    44  
    45  	// use m so the compiler can't optimize
    46  	// it away (since we're using an unsafe pointer)
    47  	m[1] = 1
    48  }
    49  
    50  var basePtr uintptr
    51  
    52  func init() {
    53  	skip := 3
    54  	switch runtime.GOARCH {
    55  	case "386":
    56  		skip += 4
    57  	case "amd64":
    58  		skip += 8
    59  	default:
    60  		panic(fmt.Errorf("gls: unsupported GOARCH %v", runtime.GOARCH))
    61  	}
    62  	f := func() {
    63  		pcs := make([]uintptr, 16)
    64  		runtime.Callers(skip, pcs)
    65  		basePtr = pcs[0]
    66  	}
    67  	base(f)
    68  }
    69  
    70  var pcToUintptr = make(map[uintptr]uintptr)
    71  
    72  var shimPCOffset uintptr
    73  
    74  // getPtr computes the current goroutine's
    75  // goroutine-local pointer
    76  func getPtr() uintptr {
    77  	var pcs [16]uintptr
    78  	// we know we can at least skip this
    79  	// call and the call to getPtr
    80  	i := runtime.Callers(2, pcs[:])
    81  
    82  	if i < 2 || pcs[i-2] != basePtr {
    83  		panic("gls: no local storage associated with this goroutine")
    84  	}
    85  	// we don't care about runtime.goexit or base,
    86  	// and we want i to be the index of the last
    87  	// element, not the length
    88  	i -= 3
    89  
    90  	var ptr uintptr
    91  	switch runtime.GOARCH {
    92  	case "386":
    93  		ptr |= pcToUintptr[pcs[i]]
    94  		ptr |= pcToUintptr[pcs[i-1]] << 8
    95  		ptr |= pcToUintptr[pcs[i-2]] << 16
    96  		ptr |= pcToUintptr[pcs[i-3]] << 24
    97  	case "amd64":
    98  		ptr |= pcToUintptr[pcs[i]]
    99  		ptr |= pcToUintptr[pcs[i-1]] << 8
   100  		ptr |= pcToUintptr[pcs[i-2]] << 16
   101  		ptr |= pcToUintptr[pcs[i-3]] << 24
   102  		ptr |= pcToUintptr[pcs[i-4]] << 32
   103  		ptr |= pcToUintptr[pcs[i-5]] << 40
   104  		ptr |= pcToUintptr[pcs[i-6]] << 48
   105  		ptr |= pcToUintptr[pcs[i-7]] << 56
   106  	default:
   107  		panic(fmt.Errorf("gls: unsupported GOARCH %v", runtime.GOARCH))
   108  	}
   109  
   110  	return ptr
   111  }
   112  
   113  func put(k, v interface{}) {
   114  	ptr := getPtr()
   115  	m := *(*map[interface{}]interface{})(unsafe.Pointer(ptr))
   116  	m[k] = v
   117  }
   118  
   119  func get(k interface{}) (interface{}, bool) {
   120  	ptr := getPtr()
   121  	m := *(*map[interface{}]interface{})(unsafe.Pointer(ptr))
   122  	v, ok := m[k]
   123  	return v, ok
   124  }
   125  
   126  func del(k interface{}) {
   127  	ptr := getPtr()
   128  	m := *(*map[interface{}]interface{})(unsafe.Pointer(ptr))
   129  	delete(m, k)
   130  }