go-tls: TLS for any goroutine
β οΈ This package doesn't support Go1.17.* due to Go runtime changes. Don't use this package until #10 is resolved.
WARNING: It's not recommended to use this package in any production environment. It may crash you at any time. Use context
instead when possible.
Package tls
provides TLS for any goroutine by hijacking runtime.goexit
on stack. Comparing with other similar packages, this package avoids any potential resource leak in TLS.
Install
Use go get
to install this package.
go get github.com/huandu/go-tls
Use TLS
Set arbitrary data and get it later.
k := "my key"
v := 1234
tls.Set(k, tls.MakeData(v))
// Get data by k.
d, ok := tls.Get(k)
assert(ok)
assert(d.Value().(int) == v)
// Get a unique ID for current goroutine.
// It's guaranteed to be unique.
id := tls.ID()
// Delete data by k.
tls.Del(k)
// Reset TLS so that all keys are removed and all data is closed if necessary.
// It doesn't remove any AtExit handler.
tls.Reset()
// Completely unload TLS and discard all data and AtExit handlers.
// If TLS method is called after Unload, a new TLS stub will be created.
// The ID() will return a different value.
tls.Unload()
If the data implements io.Closer
, it will be called automatically when Reset
is called or goroutine exits. It's not allowed to use any TLS methods in the Close
method of TLS data. It will cause permanent memory leak.
Execute code when goroutine exits
AtExit
pushes a function to a slice of at-exit handlers and executes them when goroutine is exiting in FILO order. All TLS data is still available when calling at-exit handlers.
AtExit
doesn't work on main goroutine as it doesn't exit at all.
tls.AtExit(func() {
// Do something when goroutine is exiting...
})
Limitations
Several limitations so far.
- Works with Go 1.7 or newer.
AtExit
doesn't work on main goroutine, as this goroutine always exits withos.Exit(0)
instead of callinggoexit
. Seemain()
insrc/runtime/proc.go
.
How it works
It's quite a long story I don't have time to write everything down right now.
TL; DR. Package tls
uses goroutine's g
struct pointer to identify a goroutine and hacks runtime.goexit
to do house clean work when goroutine exits.
This approach is relatively safe, because all technics are based on runtime types which doesn't change since Go1.0.
Following runtime types are used.
- The
g.stack
: It's the first field ofg
. It stores stack memory range of ag
. - Function symbol table: When Go runtime allocates more stack, it validates all return addresses on stack. If I change
runtime.goexit
to another function pc, runtime will complain it as it's not a valid top of stack function (checked byruntime.topofstack
). As a workaround, I hacks function symbol table to set_func.pcsp
of the hacked goexit to0
to skip checks.
Similar packages
- github.com/jtolds/gls: Goroutine local storage on current goroutine's stack. We must start goroutines with
Go
func explicitly before using any context methods. - github.com/v2pro/plz/gls: Use
goid
as a unique key for any goroutine and store contextual information.
License
This package is licensed under MIT license. See LICENSE for details.