Skip to content

Instantly share code, notes, and snippets.

@corebreaker
Last active March 11, 2018 16:15
Show Gist options
  • Save corebreaker/9e3f93bd0829a74dfdbe870f81d3c90a to your computer and use it in GitHub Desktop.
Save corebreaker/9e3f93bd0829a74dfdbe870f81d3c90a to your computer and use it in GitHub Desktop.
GO: AtExit function without modification in main
// A litte example
package main
import (
"fmt"
"progtrailer"
)
func main() {
defer func() {
fmt.Println("Defered fonction in main")
}()
fmt.Println("Start of program")
progtrailer.AtExit(func() {
fmt.Println("Executed at exit by AtExit")
})
fmt.Println("End of program")
// Friendly Exit
progtrailer.Exit(0)
// After this, Code not executed
fmt.Println("Not Executed")
}
/* This package has an AtExit function without modification in neither in `main` package, neither in `main` function
Too, it has an Exit funtion which allow defer functions in the `main` function:
```
func main() {
defer func() {
// It will be executed
}()
progtrailer.Exit(0)
}
```
*/
package progtrailer
import (
"os"
"runtime"
"sync"
"sync/atomic"
"time"
)
// Synchronized list for avoiding races
type tSyncHandlerList struct {
list []func()
m sync.Mutex
}
func (l *tSyncHandlerList) Add(h func()) {
l.m.Lock()
defer l.m.Unlock()
l.list = append(l.list, h)
}
func (l *tSyncHandlerList) Get() []func() {
l.m.Lock()
defer l.m.Unlock()
res := make([]func(), len(l.list))
copy(res, l.list)
return res
}
var exitCode int64
var handlers tSyncHandlerList
func init() {
go func() {
t := time.NewTicker(500 * time.Millisecond)
for _ = range t.C {
if runtime.NumGoroutine() < 2 {
t.Stop()
for _, h := range handlers.Get() {
h()
}
os.Exit(int(atomic.LoadInt64(&exitCode)))
}
}
}()
}
// A exit function that allow defers in main function
func Exit(code int) {
atomic.StoreInt64(&exitCode, int64(code))
runtime.Goexit()
}
func AtExit(handler func()) {
handlers.Add(handler)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment