Skip to content

Commit f1a87d8

Browse files
committed
update egui to use a mutex for StopNow and IsRunning (unexported fields, added methods) so it is now race-safe and added helpers to make this logic more consistent.
1 parent 3ea9379 commit f1a87d8

File tree

5 files changed

+87
-46
lines changed

5 files changed

+87
-46
lines changed

egui/gui.go

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package egui
88

99
import (
1010
"io/fs"
11+
"sync"
1112

1213
"cogentcore.org/core/core"
1314
"cogentcore.org/core/enums"
@@ -23,30 +24,36 @@ import (
2324
type GUI struct {
2425
lab.Browser
2526

26-
// how many cycles between updates of cycle-level plots
27+
// CycleUpdateInterval is number of cycles between updates of cycle-level plots.
2728
CycleUpdateInterval int
2829

29-
// true if the GUI is configured and running
30+
// Active is true if the GUI is configured and running
3031
Active bool `display:"-"`
3132

32-
// true if sim is running
33-
IsRunning bool `display:"-"`
34-
35-
// flag to stop running
36-
StopNow bool `display:"-"`
37-
3833
// NetViews are the created netviews.
3934
NetViews []*netview.NetView
4035

41-
// displays Sim fields on left
36+
// SimForm displays the Sim object fields in the left panel.
4237
SimForm *core.Form `display:"-"`
4338

44-
// Body is the content of the sim window
39+
// Body is the entire content of the sim window.
4540
Body *core.Body `display:"-"`
4641

47-
// OnStop is called when running stopped through the GUI.
48-
// Should update the network view.
42+
// OnStop is called when running is stopped through the GUI,
43+
// via the Stopped method. It should update the network view for example.
4944
OnStop func(mode, level enums.Enum)
45+
46+
// isRunning is true if sim is running.
47+
isRunning bool
48+
49+
// stopNow can be set via SetStopNow method under mutex protection
50+
// to signal the current sim to stop running.
51+
// It is not used directly in the looper-based control logic, which has
52+
// its own direct Stop function, but it is set there in case there are
53+
// other processes that are looking at this flag.
54+
stopNow bool
55+
56+
runMu sync.Mutex
5057
}
5158

5259
// UpdateWindow triggers an update on window body,
@@ -69,11 +76,45 @@ func (gui *GUI) GoUpdateWindow() {
6976
gui.UpdateWindow()
7077
}
7178

79+
// StartRun should be called whenever a process starts running.
80+
// It sets stopNow = false and isRunning = true under a mutex.
81+
func (gui *GUI) StartRun() {
82+
gui.runMu.Lock()
83+
gui.stopNow = false
84+
gui.isRunning = true
85+
gui.runMu.Unlock()
86+
}
87+
88+
// IsRunning returns the state of the isRunning flag, under a mutex.
89+
func (gui *GUI) IsRunning() bool {
90+
gui.runMu.Lock()
91+
defer gui.runMu.Unlock()
92+
return gui.isRunning
93+
}
94+
95+
// StopNow returns the state of the stopNow flag, under a mutex.
96+
func (gui *GUI) StopNow() bool {
97+
gui.runMu.Lock()
98+
defer gui.runMu.Unlock()
99+
return gui.stopNow
100+
}
101+
102+
// SetStopNow sets the stopNow flag to true, under a mutex.
103+
func (gui *GUI) SetStopNow() {
104+
gui.runMu.Lock()
105+
gui.stopNow = true
106+
gui.runMu.Unlock()
107+
}
108+
72109
// Stopped is called when a run method stops running,
73110
// from a separate goroutine (do not call from main event loop).
74-
// Updates the IsRunning flag and toolbar.
111+
// Turns off the isRunning flag, calls OnStop with the given arguments,
112+
// and calls GoUpdateWindow to update window state.
75113
func (gui *GUI) Stopped(mode, level enums.Enum) {
76-
gui.IsRunning = false
114+
gui.runMu.Lock()
115+
gui.isRunning = false
116+
gui.stopNow = true // in case anyone else is looking
117+
gui.runMu.Unlock()
77118
if gui.OnStop != nil {
78119
gui.OnStop(mode, level)
79120
}

egui/loopctrl.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,18 +103,18 @@ func (gui *GUI) AddLooperCtrl(p *tree.Plan, loops *looper.Stacks, prefix ...stri
103103
Func: func() {
104104
loops.Stop(etime.Cycle)
105105
// fmt.Println("Stop time!")
106-
gui.StopNow = true
106+
gui.SetStopNow()
107107
},
108108
})
109109

110110
tree.AddAt(p, pfx+"loop-run", func(w *core.Button) {
111111
tb := gui.Toolbar
112112
w.SetText("Run").SetIcon(icons.PlayArrow).
113113
SetTooltip("Run the current mode, picking up from where it left off last time (Init to restart)")
114-
w.FirstStyler(func(s *styles.Style) { s.SetEnabled(!gui.IsRunning) })
114+
w.FirstStyler(func(s *styles.Style) { s.SetEnabled(!gui.IsRunning()) })
115115
w.OnClick(func(e events.Event) {
116-
if !gui.IsRunning {
117-
gui.IsRunning = true
116+
if !gui.IsRunning() {
117+
gui.StartRun()
118118
tb.Restyle()
119119
go func() {
120120
stop := loops.Run(curMode)
@@ -129,12 +129,12 @@ func (gui *GUI) AddLooperCtrl(p *tree.Plan, loops *looper.Stacks, prefix ...stri
129129
w.SetText("Step").SetIcon(icons.SkipNext).
130130
SetTooltip("Step the current mode, according to the following step level and N")
131131
w.FirstStyler(func(s *styles.Style) {
132-
s.SetEnabled(!gui.IsRunning)
132+
s.SetEnabled(!gui.IsRunning())
133133
s.SetAbilities(true, abilities.RepeatClickable)
134134
})
135135
w.OnClick(func(e events.Event) {
136-
if !gui.IsRunning {
137-
gui.IsRunning = true
136+
if !gui.IsRunning() {
137+
gui.StartRun()
138138
tb.Restyle()
139139
go func() {
140140
st := loops.Stacks[curMode]

egui/toolbar.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ func (gui *GUI) AddToolbarItem(p *tree.Plan, item ToolbarItem) {
3030
})
3131
switch item.Active {
3232
case ActiveStopped:
33-
w.FirstStyler(func(s *styles.Style) { s.SetEnabled(!gui.IsRunning) })
33+
w.FirstStyler(func(s *styles.Style) { s.SetEnabled(!gui.IsRunning()) })
3434
case ActiveRunning:
35-
w.FirstStyler(func(s *styles.Style) { s.SetEnabled(gui.IsRunning) })
35+
w.FirstStyler(func(s *styles.Style) { s.SetEnabled(gui.IsRunning()) })
3636
}
3737
})
3838
}

go.mod

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ module github.com/emer/emergent/v2
33
go 1.23.4
44

55
require (
6-
cogentcore.org/core v0.3.10-0.20250424173140-98b1f1ea8624
7-
cogentcore.org/lab v0.1.1-0.20250417215607-52af09a8ee8f
6+
cogentcore.org/core v0.3.10-0.20250429190334-2e6129cfd538
7+
cogentcore.org/lab v0.1.1-0.20250502170537-c2f728058d0f
88
github.com/stretchr/testify v1.10.0
99
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948
1010
)
@@ -48,13 +48,13 @@ require (
4848
github.com/rivo/uniseg v0.4.7 // indirect
4949
github.com/tdewolff/minify/v2 v2.21.3 // indirect
5050
github.com/tdewolff/parse/v2 v2.7.19 // indirect
51-
golang.org/x/crypto v0.36.0 // indirect
51+
golang.org/x/crypto v0.37.0 // indirect
5252
golang.org/x/image v0.25.0 // indirect
5353
golang.org/x/mod v0.20.0 // indirect
54-
golang.org/x/net v0.37.0 // indirect
55-
golang.org/x/sync v0.12.0 // indirect
56-
golang.org/x/sys v0.31.0 // indirect
57-
golang.org/x/text v0.23.0 // indirect
54+
golang.org/x/net v0.39.0 // indirect
55+
golang.org/x/sync v0.13.0 // indirect
56+
golang.org/x/sys v0.32.0 // indirect
57+
golang.org/x/text v0.24.0 // indirect
5858
golang.org/x/tools v0.24.0 // indirect
5959
gonum.org/v1/gonum v0.15.0 // indirect
6060
gopkg.in/yaml.v3 v3.0.1 // indirect

go.sum

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
cogentcore.org/core v0.3.10-0.20250424173140-98b1f1ea8624 h1:Gr9Z/I0WAMee/IEn5VzieEnVHSK6KaBXDcKvTCaYk3Y=
2-
cogentcore.org/core v0.3.10-0.20250424173140-98b1f1ea8624/go.mod h1:dSb8eH/6CsC7Y9S7ZdqLf0TUbvbgPgrBGCUCn/Z1b/0=
3-
cogentcore.org/lab v0.1.1-0.20250417215607-52af09a8ee8f h1:PbnQxiBw82zPlQ7+wtyf+BY/x3pAsgm50SOPtgpMIVM=
4-
cogentcore.org/lab v0.1.1-0.20250417215607-52af09a8ee8f/go.mod h1:g1O98Mxg0ke7P2D7bUR4XCSJQvQ6sIpo6vj/XoTWHwg=
1+
cogentcore.org/core v0.3.10-0.20250429190334-2e6129cfd538 h1:XzdvNkGtyiRDHLudIZqg2FsH+VdmOlwPbfVzaCA6PcE=
2+
cogentcore.org/core v0.3.10-0.20250429190334-2e6129cfd538/go.mod h1:dSb8eH/6CsC7Y9S7ZdqLf0TUbvbgPgrBGCUCn/Z1b/0=
3+
cogentcore.org/lab v0.1.1-0.20250502170537-c2f728058d0f h1:4FnzXrKHpTvdx7FVW86aAfD7YHavCp8/jpUf7XnKqKQ=
4+
cogentcore.org/lab v0.1.1-0.20250502170537-c2f728058d0f/go.mod h1:NtLlJJoAoR6YOFcL9od9kGnLX7AbpjHkdtOZizckA0Y=
55
github.com/Bios-Marcel/wastebasket/v2 v2.0.2 h1:zOgACjeSca1lvhGDRN/dbcpFkY6FT85f5F2CImywPh4=
66
github.com/Bios-Marcel/wastebasket/v2 v2.0.2/go.mod h1:769oPCv6eH7ugl90DYIsWwjZh4hgNmMS3Zuhe1bH6KU=
77
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -133,8 +133,8 @@ github.com/tdewolff/test v1.0.11-0.20240106005702-7de5f7df4739/go.mod h1:XPuWBzv
133133
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
134134
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
135135
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
136-
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
137-
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
136+
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
137+
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
138138
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 h1:kx6Ds3MlpiUHKj7syVnbp57++8WpuKPcR5yjLBjvLEA=
139139
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
140140
golang.org/x/image v0.0.0-20190703141733-d6a02ce849c9/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -143,23 +143,23 @@ golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs
143143
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
144144
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
145145
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
146-
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
147-
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
148-
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
149-
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
146+
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
147+
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
148+
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
149+
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
150150
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
151151
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
152152
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
153153
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
154-
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
155-
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
154+
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
155+
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
156156
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
157-
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
158-
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
157+
golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o=
158+
golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
159159
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
160160
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
161-
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
162-
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
161+
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
162+
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
163163
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
164164
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
165165
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=

0 commit comments

Comments
 (0)