Skip to content

Commit 4109ecb

Browse files
committed
protofsm: add thread-safe IsRunning method to StateMachine
This commit introduces a new `IsRunning()` method to the `StateMachine`. This method allows callers to safely query whether the state machine is currently active after it has been started and before it has been stopped. To ensure thread-safety, the internal `running` status flag is implemented using `atomic.Bool` (from `sync/atomic`). Without atomic operations, concurrent accesses to a simple boolean flag from different goroutines (e.g., one goroutine calling `IsRunning()` while another executes `Start()` or `Stop()`) could lead to stale reads or data races.
1 parent 93a6ab8 commit 4109ecb

File tree

1 file changed

+16
-0
lines changed

1 file changed

+16
-0
lines changed

protofsm/state_machine.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"fmt"
66
"sync"
7+
"sync/atomic"
78
"time"
89

910
"github.com/btcsuite/btcd/btcec/v2"
@@ -150,8 +151,14 @@ type StateMachine[Event any, Env Environment] struct {
150151
gm fn.GoroutineManager
151152
quit chan struct{}
152153

154+
// startOnce and stopOnce are used to ensure that the state machine is
155+
// only started and stopped once.
153156
startOnce sync.Once
154157
stopOnce sync.Once
158+
159+
// running is a flag that indicates if the state machine is currently
160+
// running.
161+
running atomic.Bool
155162
}
156163

157164
// ErrorReporter is an interface that's used to report errors that occur during
@@ -221,6 +228,8 @@ func (s *StateMachine[Event, Env]) Start(ctx context.Context) {
221228
_ = s.gm.Go(ctx, func(ctx context.Context) {
222229
s.driveMachine(ctx)
223230
})
231+
232+
s.running.Store(true)
224233
})
225234
}
226235

@@ -230,6 +239,8 @@ func (s *StateMachine[Event, Env]) Stop() {
230239
s.stopOnce.Do(func() {
231240
close(s.quit)
232241
s.gm.Stop()
242+
243+
s.running.Store(false)
233244
})
234245
}
235246

@@ -333,6 +344,11 @@ func (s *StateMachine[Event, Env]) RemoveStateSub(sub StateSubscriber[
333344
_ = s.newStateEvents.RemoveSubscriber(sub)
334345
}
335346

347+
// IsRunning returns true if the state machine is currently running.
348+
func (s *StateMachine[Event, Env]) IsRunning() bool {
349+
return s.running.Load()
350+
}
351+
336352
// executeDaemonEvent executes a daemon event, which is a special type of event
337353
// that can be emitted as part of the state transition function of the state
338354
// machine. An error is returned if the type of event is unknown.

0 commit comments

Comments
 (0)