AsyncPath improvments

fixed occasional data race in Close() function. added Destroy()
interface to window manager
This commit is contained in:
JetSetIlly 2024-04-29 17:37:10 +01:00
parent 3a5f7c79da
commit 2d974cc9c1
5 changed files with 61 additions and 43 deletions

View file

@ -24,6 +24,7 @@ type FilenameSetter interface {
type AsyncResults struct {
Entries []Node
Selected string
IsDir bool
Dir string
Base string
}
@ -31,7 +32,10 @@ type AsyncResults struct {
// AsyncPath provides asynchronous access to an archivefs
type AsyncPath struct {
setter FilenameSetter
afs Path
Set chan string
Close chan bool
Destroy chan bool
results chan AsyncResults
err chan error
@ -42,40 +46,48 @@ type AsyncPath struct {
// NewAsyncPath is the preferred method of initialisation for the AsyncPath type
func NewAsyncPath(setter FilenameSetter) AsyncPath {
return AsyncPath{
pth := AsyncPath{
setter: setter,
Set: make(chan string, 1),
Close: make(chan bool, 1),
Destroy: make(chan bool, 1),
results: make(chan AsyncResults, 1),
err: make(chan error, 1),
}
}
// Close any open zip files and reset path
func (pth *AsyncPath) Close() {
// not sure how safe this is if it is called when the Set() goroutine is running
pth.afs.Close()
}
// Set archivefs path. Process() must be called in order to retreive the results
// of the Set()
func (pth *AsyncPath) Set(path string) error {
go func() {
pth.afs.Set(path)
var afs Path
var done bool
entries, err := pth.afs.List()
if err != nil {
pth.err <- err
return
}
for !done {
select {
case <-pth.Destroy:
done = true
pth.results <- AsyncResults{
Entries: entries,
Selected: pth.afs.String(),
Dir: pth.afs.Dir(),
Base: pth.afs.Base(),
case <-pth.Close:
afs.Close()
case path := <-pth.Set:
afs.Set(path)
entries, err := afs.List()
if err != nil {
pth.err <- err
return
}
pth.results <- AsyncResults{
Entries: entries,
Selected: afs.String(),
IsDir: afs.IsDir(),
Dir: afs.Dir(),
Base: afs.Base(),
}
}
}
}()
return nil
return pth
}
// Process asynchronous requests. Must be called in order to receive the results
@ -89,7 +101,7 @@ func (pth *AsyncPath) Process() error {
pth.Results = results
if pth.setter != nil {
if pth.afs.IsDir() {
if pth.Results.IsDir {
pth.setter.SetSelectedFilename("")
} else {
pth.setter.SetSelectedFilename(pth.Results.Selected)

View file

@ -138,6 +138,14 @@ func newManager(img *SdlImgui) (*manager, error) {
return wm, nil
}
func (wm *manager) destroy() {
for _, w := range wm.windows {
if c, ok := w.(windowDestroy); ok {
c.destroy()
}
}
}
func (wm *manager) draw() {
// there's no good place to call the managedWindow.init() function except
// here when we know everything else has been initialised

View file

@ -32,6 +32,11 @@ type window interface {
id() string
}
// windows that require special destruction implement the windowDestroy interface
type windowDestroy interface {
destroy()
}
// information about the window, including window geometry
//
// is embedded in playmodeWin and debuggerWin interfaces. for window type that

View file

@ -276,6 +276,8 @@ func (img *SdlImgui) Destroy() {
logger.Log("sdlimgui", err.Error())
}
img.wm.destroy()
err = img.plt.destroy()
if err != nil {
logger.Log("sdlimgui", err.Error())

View file

@ -137,22 +137,22 @@ func newSelectROM(img *SdlImgui) (window, error) {
func (win *winSelectROM) init() {
}
func (win *winSelectROM) destroy() {
win.path.Destroy <- true
}
func (win winSelectROM) id() string {
return winSelectROMID
}
func (win *winSelectROM) setOpen(open bool) {
if !open {
win.path.Close()
win.path.Close <- true
return
}
// open at the most recently selected ROM
recent := win.img.dbg.Prefs.RecentROM.String()
err := win.path.Set(recent)
if err != nil {
logger.Logf("sdlimgui", err.Error())
}
win.path.Set <- win.img.dbg.Prefs.RecentROM.String()
}
func (win *winSelectROM) playmodeSetOpen(open bool) {
@ -285,10 +285,7 @@ func (win *winSelectROM) draw() {
}()
if imgui.Button("Parent") {
err := win.path.Set(filepath.Dir(win.path.Results.Dir))
if err != nil {
logger.Logf("sdlimgui", err.Error())
}
win.path.Set <- filepath.Dir(win.path.Results.Dir)
win.scrollToTop = true
}
@ -331,10 +328,7 @@ func (win *winSelectROM) draw() {
}
if imgui.Selectable(s.String()) {
err := win.path.Set(filepath.Join(win.path.Results.Dir, e.Name))
if err != nil {
logger.Logf("sdlimgui", err.Error())
}
win.path.Set <- filepath.Join(win.path.Results.Dir, e.Name)
win.scrollToTop = true
}
}
@ -380,10 +374,7 @@ func (win *winSelectROM) draw() {
}
if imgui.SelectableV(e.Name, selected, 0, imgui.Vec2{0, 0}) {
err := win.path.Set(filepath.Join(win.path.Results.Dir, e.Name))
if err != nil {
logger.Logf("sdlimgui", err.Error())
}
win.path.Set <- filepath.Join(win.path.Results.Dir, e.Name)
}
if imgui.IsItemHovered() && imgui.IsMouseDoubleClicked(0) {
win.insertCartridge()