tls

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2020 License: MIT Imports: 9 Imported by: 4

README

go-tls: TLS for any goroutine

Build Status GoDoc

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 with os.Exit(0) instead of calling goexit. See main() in src/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 of g. It stores stack memory range of a g.
  • 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 by runtime.topofstack). As a workaround, I hacks function symbol table to set _func.pcsp of the hacked goexit to 0 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.

Documentation

Overview

Package tls creates a TLS for a goroutine and release all resources at goroutine exit.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AtExit

func AtExit(f func())

AtExit runs f when current goroutine is exiting. The f is called in FILO order.

func Del

func Del(key interface{})

Del data by key.

func ID

func ID() int64

ID returns a unique ID for a goroutine. If it's not possible to get the value, ID returns 0.

It's guaranteed to be unique and consistent for one goroutine, unless it's called after Unload, which completely resets TLS stub. To be clear, it's not goid used by Go runtime.

func Reset

func Reset()

Reset clears TLS data and releases all resources for current goroutine. It doesn't remove any AtExit handlers.

func Set

func Set(key interface{}, data Data)

Set data for key.

func Unload

func Unload()

Unload completely unloads TLS and clear all data and AtExit handlers.

Types

type Data

type Data interface {
	io.Closer
	Value() interface{}
}

Data holds a value in TLS.

func Get

func Get(key interface{}) (d Data, ok bool)

Get data by key.

func MakeData

func MakeData(data interface{}) Data

MakeData wraps data to Data. If data implements io.Closer, Data#Close will call data.Close().

Directories

Path Synopsis
g
Package g exposes goroutine struct g to user space.
Package g exposes goroutine struct g to user space.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL