aerc/aerc.go
Simon Ser de122b16ee lib/ui: fix UI.Exit race condition
UI.Exit can be accessed from goroutines drawing, goroutines executing
commands and goroutines waiting for events.

    Write at 0x00c0002b2040 by main goroutine:
      main.main.func1()
          /home/simon/src/aerc2/aerc.go:76 +0x33d
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).BeginExCommand.func1()
          /home/simon/src/aerc2/widgets/aerc.go:245 +0x89
      git.sr.ht/~sircmpwn/aerc2/widgets.(*ExLine).Event()
          /home/simon/src/aerc2/widgets/exline.go:131 +0x442
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).Event()
          /home/simon/src/aerc2/widgets/aerc.go:116 +0x83c
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).simulate()
          /home/simon/src/aerc2/widgets/aerc.go:109 +0x12a
      git.sr.ht/~sircmpwn/aerc2/widgets.(*Aerc).Event()
          /home/simon/src/aerc2/widgets/aerc.go:142 +0x722
      git.sr.ht/~sircmpwn/aerc2/lib/ui.(*UI).Tick()
          /home/simon/src/aerc2/lib/ui/ui.go:75 +0x33f
      main.main()
          /home/simon/src/aerc2/aerc.go:94 +0x497

    Previous read at 0x00c0002b2040 by goroutine 19:
      git.sr.ht/~sircmpwn/aerc2/lib/ui.Initialize.func1()
          /home/simon/src/aerc2/lib/ui/ui.go:45 +0x97

    Goroutine 19 (running) created at:
      git.sr.ht/~sircmpwn/aerc2/lib/ui.Initialize()
          /home/simon/src/aerc2/lib/ui/ui.go:44 +0x372
      main.main()
          /home/simon/src/aerc2/aerc.go:87 +0x3a9
2019-05-05 01:07:44 -04:00

99 lines
1.9 KiB
Go

package main
import (
"io"
"io/ioutil"
"log"
"os"
"time"
"github.com/mattn/go-isatty"
"git.sr.ht/~sircmpwn/aerc2/config"
"git.sr.ht/~sircmpwn/aerc2/commands"
"git.sr.ht/~sircmpwn/aerc2/commands/account"
"git.sr.ht/~sircmpwn/aerc2/commands/msgview"
"git.sr.ht/~sircmpwn/aerc2/commands/terminal"
libui "git.sr.ht/~sircmpwn/aerc2/lib/ui"
"git.sr.ht/~sircmpwn/aerc2/widgets"
)
func getCommands(selected libui.Drawable) []*commands.Commands {
switch selected.(type) {
case *widgets.AccountView:
return []*commands.Commands{
account.AccountCommands,
commands.GlobalCommands,
}
case *widgets.MessageViewer:
return []*commands.Commands{
msgview.MessageViewCommands,
commands.GlobalCommands,
}
case *widgets.Terminal:
return []*commands.Commands{
terminal.TerminalCommands,
commands.GlobalCommands,
}
default:
return []*commands.Commands{commands.GlobalCommands}
}
}
func main() {
var (
logOut io.Writer
logger *log.Logger
)
if !isatty.IsTerminal(os.Stdout.Fd()) {
logOut = os.Stdout
} else {
logOut = ioutil.Discard
}
logger = log.New(logOut, "", log.LstdFlags)
logger.Println("Starting up aerc")
conf, err := config.LoadConfig(nil)
if err != nil {
panic(err)
}
var (
aerc *widgets.Aerc
ui *libui.UI
)
aerc = widgets.NewAerc(conf, logger, func(cmd string) error {
cmds := getCommands(aerc.SelectedTab())
for i, set := range cmds {
err := set.ExecuteCommand(aerc, cmd)
if _, ok := err.(commands.NoSuchCommand); ok {
if i == len(cmds) - 1 {
return err
} else {
continue
}
} else if _, ok := err.(commands.ErrorExit); ok {
ui.Exit()
return nil
} else if err != nil {
return err
} else {
break
}
}
return nil
})
ui, err = libui.Initialize(conf, aerc)
if err != nil {
panic(err)
}
defer ui.Close()
for !ui.ShouldExit() {
if !ui.Tick() {
// ~60 FPS
time.Sleep(16 * time.Millisecond)
}
}
}