qmuntal / stateless

Go library for creating finite state machines
BSD 2-Clause "Simplified" License
898 stars 47 forks source link

unaligned 64-bit atomic operation #52

Closed kkettinger closed 1 year ago

kkettinger commented 1 year ago

I'm trying to control the state machine with gin (http server) on a raspberry pi 4, but after firing the first event i get a panic:

2023/01/31 23:18:24 [Recovery] 2023/01/31 - 23:18:24 panic recovered:
POST /api/measure/automatic HTTP/1.1
Host: raspberrypi:8080
Accept: */*
Content-Length: 20
Content-Type: application/json
User-Agent: curl/7.83.1

unaligned 64-bit atomic operation
/usr/local/go/src/runtime/internal/atomic/unaligned.go:8 (0x125f3)
        panicUnaligned: panic("unaligned 64-bit atomic operation")
/usr/local/go/src/runtime/internal/atomic/atomic_arm.s:280 (0x12947)
        Load64: CHECK_ALIGN
/home/kk/go/pkg/mod/github.com/qmuntal/stateless@v1.6.1/statemachine.go:279 (0x177bcb)
        (*StateMachine).Firing: return atomic.LoadUint64(&sm.ops) != 0
/home/kk/go/pkg/mod/github.com/qmuntal/stateless@v1.6.1/statemachine.go:338 (0x177bf4)
        (*StateMachine).internalFireQueued: if sm.Firing() {
/home/kk/go/pkg/mod/github.com/qmuntal/stateless@v1.6.1/statemachine.go:324 (0x177957)
        (*StateMachine).internalFire: return sm.internalFireQueued(ctx, trigger, args...)
/home/kk/go/pkg/mod/github.com/qmuntal/stateless@v1.6.1/statemachine.go:251 (0x17aeb7)
        (*StateMachine).FireCtx: return sm.internalFire(ctx, trigger, args...)
/home/kk/go/pkg/mod/github.com/qmuntal/stateless@v1.6.1/statemachine.go:234 (0x17ae6c)
        (*StateMachine).Fire: return sm.FireCtx(context.Background(), trigger, args...)
/home/kk/repos/custom-app/internal/measure/measure.go:30 (0x17ae74)
        Start: measurement.stateMachine.Fire(triggerStart)
/home/kk/repos/custom-app/internal/restserver/measure.go:46 (0x418d27)
        MeasureEndpointPOST: measure.Start()
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:173 (0x40c3db)
        (*Context).Next: c.handlers[c.index](c)
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/recovery.go:101 (0x40c3b8)
        CustomRecoveryWithWriter.func1: c.Next()
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:173 (0x40b4bb)
        (*Context).Next: c.handlers[c.index](c)
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/logger.go:240 (0x40b498)
        LoggerWithConfig.func1: c.Next()
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/context.go:173 (0x40a433)
        (*Context).Next: c.handlers[c.index](c)
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/gin.go:616 (0x40a128)
        (*Engine).handleHTTPRequest: c.Next()
/home/kk/go/pkg/mod/github.com/gin-gonic/gin@v1.8.2/gin.go:572 (0x409e87)
        (*Engine).ServeHTTP: engine.handleHTTPRequest(c)
/usr/local/go/src/net/http/server.go:2947 (0x2c875f)
        serverHandler.ServeHTTP: handler.ServeHTTP(rw, req)
/usr/local/go/src/net/http/server.go:1991 (0x2c4efb)
        (*conn).serve: serverHandler{c.server}.ServeHTTP(w, w.req)
/usr/local/go/src/runtime/asm_arm.s:831 (0x8008b)
        goexit: MOVW    R0, R0  // NOP

System: Linux raspberrypi 5.15.84-v7l+ #1613 SMP Thu Jan 5 12:01:26 GMT 2023 armv7l GNU/Linux

If i change the ops variable frm uint64 to uint32 and all corresponding atomic methods to uint32 too, it works fine without panic:

type StateMachine struct {
    // ops is accessed atomically so we put it at the beginning of the struct to achieve 64 bit alignment
-   ops                    uint64
+   ops                    uint32
    stateConfig            map[State]*stateRepresentation
    triggerConfig          map[Trigger]triggerWithParameters
    stateAccessor          func(context.Context) (State, error)
    stateMutator           func(context.Context, State) error
    unhandledTriggerAction UnhandledTriggerActionFunc
    onTransitioningEvents  []TransitionFunc
    onTransitionedEvents   []TransitionFunc
    eventQueue             list.List
    firingMode             FiringMode
    firingMutex            sync.Mutex
}
qmuntal commented 1 year ago

Thanks for reporting this bug. I thought I already fixed this issue in #31, wondering why is happening again. Which Go version are you using?

kkettinger commented 1 year ago

I'm using the version go version go1.19.5 linux/arm.

qmuntal commented 1 year ago

Could you check if this branch fixes your issue: https://github.com/qmuntal/stateless/tree/fix-ops

Thanks in advance.

kkettinger commented 1 year ago

Just tested it on the raspberrypi, works without panic. Thanks a lot!