github.com/windmilleng/wat@v0.0.2-0.20180626175338-9349b638e250/cli/wat/cleanup.go (about) 1 package wat 2 3 import ( 4 "os" 5 "os/signal" 6 "sync" 7 "syscall" 8 ) 9 10 var cleanupMu = &sync.Mutex{} 11 var cleanupFuncs []*func() 12 var cleanupCh chan os.Signal 13 14 // Create a cleanup script that runs even if the process gets a SIGINT/SIGTERM 15 // 16 // Intended to be used like: 17 // tearDown := createCleanup(func() { ...critical cleanup... }) 18 // defer tearDown() 19 // 20 // The critical cleanup will get executed in tearDown() 21 func createCleanup(f func()) (tearDown func()) { 22 cleanupMu.Lock() 23 defer cleanupMu.Unlock() 24 25 fptr := &f 26 27 cleanupFuncs = append(cleanupFuncs, fptr) 28 if cleanupCh == nil { 29 cleanupCh = make(chan os.Signal, 1) 30 signal.Notify(cleanupCh, os.Interrupt, syscall.SIGTERM) 31 go func() { 32 _, ok := <-cleanupCh 33 if !ok { 34 // The channel closed normally 35 return 36 } 37 38 cleanupMu.Lock() 39 defer cleanupMu.Unlock() 40 41 for _, fp := range cleanupFuncs { 42 f := *fp 43 f() 44 } 45 os.Exit(1) 46 }() 47 } 48 49 return func() { 50 f() 51 52 cleanupMu.Lock() 53 defer cleanupMu.Unlock() 54 55 for i, fp := range cleanupFuncs { 56 if fp == fptr { 57 cleanupFuncs = append(cleanupFuncs[:i], cleanupFuncs[i+1:]...) 58 break 59 } 60 } 61 62 if len(cleanupFuncs) == 0 { 63 signal.Stop(cleanupCh) 64 close(cleanupCh) 65 cleanupCh = nil 66 } 67 } 68 }