From 0b266bf61944ab69dd1615779506e899eb814d21 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 4 Oct 2021 22:12:28 -0400 Subject: [PATCH] cmd/acme: fix undo, fix wait chan mostly Edit |date still hangs. --- cmd/acme/acme.go | 38 +++++++++++++++++--------------- cmd/acme/dat.h.go | 1 - cmd/acme/internal/edit/ecmd.go | 5 +++++ cmd/acme/internal/exec/exec.go | 32 +++++++++++++++++---------- cmd/acme/internal/file/file.go | 2 ++ cmd/acme/internal/util/util.go | 40 ++++++++++++++++++++++++---------- cmd/acme/internal/wind/text.go | 1 + 7 files changed, 78 insertions(+), 41 deletions(-) diff --git a/cmd/acme/acme.go b/cmd/acme/acme.go index d9f6cbf..e0c22ee 100644 --- a/cmd/acme/acme.go +++ b/cmd/acme/acme.go @@ -145,6 +145,8 @@ func main() { ui.Textcomplete = fileloadpkg.Textcomplete editpkg.Putfile = exec.Putfile + editpkg.BigLock = bigLock + editpkg.BigUnlock = bigUnlock editpkg.Run = func(w *wind.Window, s string, rdir []rune) { exec.Run(w, s, rdir, true, nil, nil, true) } @@ -583,14 +585,14 @@ func mousethread() { * This structure keeps a list of processes that have exited we haven't heard of. */ -type Pid struct { - pid int - msg string - next *Pid +type Proc struct { + proc *os.Process + err error + next *Proc } func waitthread() { - var pids *Pid + var pids *Proc bigLock() defer bigUnlock() @@ -624,12 +626,13 @@ func waitthread() { alog.Printf("Kill: no process %s\n", string(cmd)) } - case w := <-cwait: + case w := <-exec.Cwait: +println("Cwait") bigLock() - pid := w.pid + proc := w.Proc var c, lc *exec.Command for c = command; c != nil; c = c.Next { - if c.Pid == pid { + if c.Proc == proc { if lc != nil { lc.Next = c.Next } else { @@ -643,9 +646,9 @@ func waitthread() { t := &wind.TheRow.Tag wind.Textcommit(t, true) if c == nil { - p := new(Pid) - p.pid = pid - p.msg = w.msg + p := new(Proc) + p.proc = proc + p.err = w.Err p.next = pids pids = p } else { @@ -653,8 +656,8 @@ func waitthread() { wind.Textdelete(t, t.Q0, t.Q1, true) wind.Textsetselect(t, 0, 0) } - if w.msg[0] != 0 { - warning(c.Mntdir, "%s: exit %s\n", string(c.Name[:len(c.Name)-1]), w.msg) + if w.Err != nil { + warning(c.Mntdir, "%s: exit %s\n", string(c.Name[:len(c.Name)-1]), w.Err) } adraw.Display.Flush() } @@ -664,11 +667,11 @@ func waitthread() { case c = <-exec.Ccommand: bigLock() // has this command already exited? - var lastp *Pid + var lastp *Proc for p := pids; p != nil; p = p.next { - if p.pid == c.Pid { - if p.msg[0] != 0 { - warning(c.Mntdir, "%s\n", p.msg) + if p.proc == c.Proc { + if p.err != nil { + warning(c.Mntdir, "%s\n", p.err) } if lastp == nil { pids = p.next @@ -694,6 +697,7 @@ func waitthread() { Freecmd: if c != nil { if c.IsEditCmd { +println("Cedit send") editpkg.Cedit <- 0 } fsysdelid(c.Mntdir) diff --git a/cmd/acme/dat.h.go b/cmd/acme/dat.h.go index e98ce10..5720d92 100644 --- a/cmd/acme/dat.h.go +++ b/cmd/acme/dat.h.go @@ -85,7 +85,6 @@ type Waitmsg struct { var ( cplumb = make(chan *plumb.Message) - cwait = make(chan *Waitmsg) cxfidalloc = make(chan *Xfid) // TODO bidi cxfidfree = make(chan *Xfid) cnewwindow = make(chan *wind.Window) // TODO bidi diff --git a/cmd/acme/internal/edit/ecmd.go b/cmd/acme/internal/edit/ecmd.go index 77db6ba..31c7ba1 100644 --- a/cmd/acme/internal/edit/ecmd.go +++ b/cmd/acme/internal/edit/ecmd.go @@ -31,6 +31,9 @@ import ( "9fans.net/go/cmd/acme/internal/wind" ) +var BigLock = func() {} +var BigUnlock = func() {} + var Glooping int var nest int var Enoname = "no file name given" @@ -549,7 +552,9 @@ func runpipe(t *wind.Text, cmd rune, cr []rune, state int) { wind.Winunlock(t.W) } wind.TheRow.Lk.Unlock() + BigUnlock() <-Cedit + BigLock() var q *util.QLock /* * The editoutlk exists only so that we can tell when diff --git a/cmd/acme/internal/exec/exec.go b/cmd/acme/internal/exec/exec.go index 6a58311..09c5af8 100644 --- a/cmd/acme/internal/exec/exec.go +++ b/cmd/acme/internal/exec/exec.go @@ -48,6 +48,13 @@ var Fsysmount = func([]rune, [][]rune) *base.Mntdir { return nil } var Fsysdelid = func(*base.Mntdir) {} var Xfidlog = func(*wind.Window, string) {} +var Cwait = make(chan Waitmsg) + +type Waitmsg struct { + Proc *os.Process + Err error +} + /* * These functions get called as: * @@ -908,7 +915,7 @@ func tab(et, _, argt *wind.Text, _, _ bool, arg []rune) { } } -func runproc(win *wind.Window, s string, rdir []rune, newns bool, argaddr, xarg *string, c *Command, cpid chan int, iseditcmd bool) { +func runproc(win *wind.Window, s string, rdir []rune, newns bool, argaddr, xarg *string, c *Command, cpid chan *os.Process, iseditcmd bool) { t := strings.TrimLeft(s, " \n\t") name := t if i := strings.IndexAny(name, " \n\t"); i >= 0 { @@ -1056,8 +1063,11 @@ func runproc(win *wind.Window, s string, rdir []rune, newns bool, argaddr, xarg err := cmd.Start() if err == nil { if cpid != nil { - cpid <- cmd.Process.Pid // TODO(rsc): send cmd.Process + cpid <- cmd.Process // TODO(rsc): send cmd.Process } + go func() { + Cwait <- Waitmsg{cmd.Process, cmd.Wait()} + }() return } goto Fail @@ -1086,7 +1096,7 @@ Hard: err := cmd.Start() if err == nil { if cpid != nil { - cpid <- cmd.Process.Pid // TODO(rsc): send cmd.Process + cpid <- cmd.Process // TODO(rsc): send cmd.Process } return } @@ -1096,14 +1106,14 @@ Hard: Fail: if cpid != nil { // TODO(rsc): is it always non-nil? - cpid <- 0 + cpid <- nil } } -func runwaittask(c *Command, cpid chan int) { - c.Pid = <-cpid +func runwaittask(c *Command, cproc chan *os.Process) { + c.Proc = <-cproc c.av = nil - if c.Pid != 0 { // successful exec + if c.Proc != nil { // successful exec Ccommand <- c } else if c.IsEditCmd { edit.Cedit <- 0 @@ -1115,10 +1125,10 @@ func Run(win *wind.Window, s string, rdir []rune, newns bool, argaddr, xarg *str return } c := new(Command) - cpid := make(chan int, 0) - go runproc(win, s, rdir, newns, argaddr, xarg, c, cpid, iseditcmd) + cproc := make(chan *os.Process, 0) + go runproc(win, s, rdir, newns, argaddr, xarg, c, cproc, iseditcmd) // mustn't block here because must be ready to answer mount() call in run() - go runwaittask(c, cpid) + go runwaittask(c, cproc) } func fsopenfd(fs *client.Fsys, name string, mode uint8) (*os.File, error) { @@ -1148,7 +1158,7 @@ func fsopenfd(fs *client.Fsys, name string, mode uint8) (*os.File, error) { } type Command struct { - Pid int + Proc *os.Process Name []rune text string av []string diff --git a/cmd/acme/internal/file/file.go b/cmd/acme/internal/file/file.go index 8ca7cb7..7fcc198 100644 --- a/cmd/acme/internal/file/file.go +++ b/cmd/acme/internal/file/file.go @@ -46,6 +46,8 @@ type File struct { mod bool } +func (f *File) SetView(v View) { f.view = v } + type View interface { Insert(int, []rune) Delete(int, int) diff --git a/cmd/acme/internal/util/util.go b/cmd/acme/internal/util/util.go index 236f28e..27a028f 100644 --- a/cmd/acme/internal/util/util.go +++ b/cmd/acme/internal/util/util.go @@ -17,6 +17,7 @@ package util import ( "log" "sync/atomic" + "sync" ) func Min(a int, b int) int { @@ -37,28 +38,43 @@ func Fatal(s string) { log.Fatalf("acme: %s\n", s) } +var locks struct { + mu sync.Mutex + cond sync.Cond +} + +func init() { + locks.cond.L = &locks.mu +} + type QLock struct { - held chan bool + held uint32 } func (l *QLock) TryLock() bool { - if l.held == nil { - panic("missing held") - } - select { - case l.held <- true: - return true - default: - return false - } + return atomic.CompareAndSwapUint32(&l.held, 0, 1) } func (l *QLock) Unlock() { - <-l.held + v := atomic.SwapUint32(&l.held, 0) + if v == 0 { + panic("Unlock of unlocked lock") + } + if v > 1 { + locks.cond.Broadcast() + } } func (l *QLock) Lock() { - l.held <- true + if atomic.AddUint32(&l.held, 1) == 1 { + return + } + locks.mu.Lock() + defer locks.mu.Unlock() + + for atomic.AddUint32(&l.held, 1) != 1 { + locks.cond.Wait() + } } func Incref(p *uint32) { atomic.AddUint32(p, 1) } diff --git a/cmd/acme/internal/wind/text.go b/cmd/acme/internal/wind/text.go index fa20b05..504731f 100644 --- a/cmd/acme/internal/wind/text.go +++ b/cmd/acme/internal/wind/text.go @@ -946,6 +946,7 @@ func ishtmlend(t *Text, q int, q0 *int) int { func fileaddtext(f *File, t *Text) *File { if f == nil { f = &File{File: new(file.File)} + f.File.SetView((*fileView)(f)) f.Unread = true } f.Text = append(f.Text, t)