Skip to content

synopsys-sig/gls

 
 

Repository files navigation

gls

Fast goroutine local storage

WARNING

There is extensive documentation and discussion on why implementing and using thread-local storage in Go - actually, goroutine-local storage - is a bad idea.

See for example the Go FAQ on goroutine id and context.Context, which is how you're encouraged to solve problems that would require a goroutine-local storage.

The main obstacle in adopting context.Context is that all of your functions must have a new first argument. So, if that horrifies you or is simply not feasible for your use case, feel free to ignore this warning and read on.

Just remember that, if some Go programmers frowns at your use of goroutine-local storage, there are good reasons.

Why?

To retrieve per-goroutine data that some function did not - or could not - pass through the call chain, down to where you need it.

Other goroutine-local libraries, as jtolds/gls and tylerb/gls explain the reasons and use cases for goroutine-local storage more in detail.

Status

Beta.

Lightly tested on 386, amd64, arm, arm64, mips, ppc64le with Go 1.10.1.
Other architectures (mipsle, mips64, ppc64, s390x) supported in theory but not tested.

How it works

Go runtime has an internal, i.e. unexported, goroutine-local runtime.g struct. It is used for several purposes, including defer(), recover(), by the goroutine scheduler, and it even has an unexported goid field, i.e. a goroutine ID.

Several other goroutine-local libraries extract this goroutine ID with various tricks, most notably from runtime.Stack() textual output.

Instead, we use a tiny bit of assembler code to retrieve the address of the runtime.g struct and return it converted to an opaque uintptr.

We use it as the key in a global variable containing per-goroutine data.

This is also fast, probably orders of magnitude faster than most other solutions.

Why not the same goroutine ID?

To avoid fiddling with the internal layout of runtime.g struct, we only take its address.

Accessing the goid field would require knowing its offset within the struct, which is both tedious and error-prone to retrieve, since it's an unexported field of an unexported struct type.

Documentation

See the autogenerated API docs at http://godoc.org/github.com/cosmos72/gls

License

BSD 3-Clause License

Releases

No releases published

Packages

No packages published

Languages

  • Go 66.4%
  • Assembly 33.6%