mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
make fsm's thread safe
This commit is contained in:
parent
89d53bbb75
commit
940a46fcfd
@ -10,6 +10,7 @@ previously called FSM.py (now called ClassicFSM.py).
|
|||||||
from direct.showbase.DirectObject import DirectObject
|
from direct.showbase.DirectObject import DirectObject
|
||||||
from direct.directnotify import DirectNotifyGlobal
|
from direct.directnotify import DirectNotifyGlobal
|
||||||
from direct.showbase import PythonUtil
|
from direct.showbase import PythonUtil
|
||||||
|
from direct.stdpy.threading import RLock
|
||||||
import types
|
import types
|
||||||
import string
|
import string
|
||||||
|
|
||||||
@ -142,6 +143,7 @@ class FSM(DirectObject):
|
|||||||
defaultTransitions = None
|
defaultTransitions = None
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
|
self.lock = RLock()
|
||||||
self.name = name
|
self.name = name
|
||||||
self._serialNum = FSM.SerialNum
|
self._serialNum = FSM.SerialNum
|
||||||
FSM.SerialNum += 1
|
FSM.SerialNum += 1
|
||||||
@ -166,9 +168,13 @@ class FSM(DirectObject):
|
|||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
# A convenience function to force the FSM to clean itself up
|
# A convenience function to force the FSM to clean itself up
|
||||||
# by transitioning to the "Off" state.
|
# by transitioning to the "Off" state.
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
assert self.state
|
assert self.state
|
||||||
if self.state != 'Off':
|
if self.state != 'Off':
|
||||||
self.__setState('Off')
|
self.__setState('Off')
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def setBroadcastStateChanges(self, doBroadcast):
|
def setBroadcastStateChanges(self, doBroadcast):
|
||||||
self._broadcastStateChanges = doBroadcast
|
self._broadcastStateChanges = doBroadcast
|
||||||
@ -183,18 +189,28 @@ class FSM(DirectObject):
|
|||||||
# Returns the current state if we are in a state now, or the
|
# Returns the current state if we are in a state now, or the
|
||||||
# state we are transitioning into if we are currently within
|
# state we are transitioning into if we are currently within
|
||||||
# the enter or exit function for a state.
|
# the enter or exit function for a state.
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
if self.state:
|
if self.state:
|
||||||
return self.state
|
return self.state
|
||||||
return self.newState
|
return self.newState
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def isInTransition(self):
|
def isInTransition(self):
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
return self.state == None
|
return self.state == None
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def forceTransition(self, request, *args):
|
def forceTransition(self, request, *args):
|
||||||
"""Changes unconditionally to the indicated state. This
|
"""Changes unconditionally to the indicated state. This
|
||||||
bypasses the filterState() function, and just calls
|
bypasses the filterState() function, and just calls
|
||||||
exitState() followed by enterState()."""
|
exitState() followed by enterState()."""
|
||||||
|
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
assert isinstance(request, types.StringTypes)
|
assert isinstance(request, types.StringTypes)
|
||||||
self.notify.debug("%s.forceTransition(%s, %s" % (
|
self.notify.debug("%s.forceTransition(%s, %s" % (
|
||||||
self.name, request, str(args)[1:]))
|
self.name, request, str(args)[1:]))
|
||||||
@ -206,6 +222,8 @@ class FSM(DirectObject):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.__setState(request, *args)
|
self.__setState(request, *args)
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def demand(self, request, *args):
|
def demand(self, request, *args):
|
||||||
"""Requests a state transition, by code that does not expect
|
"""Requests a state transition, by code that does not expect
|
||||||
@ -219,6 +237,8 @@ class FSM(DirectObject):
|
|||||||
sequence.
|
sequence.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
assert isinstance(request, types.StringTypes)
|
assert isinstance(request, types.StringTypes)
|
||||||
self.notify.debug("%s.demand(%s, %s" % (
|
self.notify.debug("%s.demand(%s, %s" % (
|
||||||
self.name, request, str(args)[1:]))
|
self.name, request, str(args)[1:]))
|
||||||
@ -230,6 +250,8 @@ class FSM(DirectObject):
|
|||||||
|
|
||||||
if not self.request(request, *args):
|
if not self.request(request, *args):
|
||||||
raise RequestDenied, "%s (from state: %s)" % (request, self.state)
|
raise RequestDenied, "%s (from state: %s)" % (request, self.state)
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def request(self, request, *args):
|
def request(self, request, *args):
|
||||||
"""Requests a state transition (or other behavior). The
|
"""Requests a state transition (or other behavior). The
|
||||||
@ -254,6 +276,8 @@ class FSM(DirectObject):
|
|||||||
which will queue these requests up and apply when the
|
which will queue these requests up and apply when the
|
||||||
transition is complete)."""
|
transition is complete)."""
|
||||||
|
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
assert isinstance(request, types.StringTypes)
|
assert isinstance(request, types.StringTypes)
|
||||||
self.notify.debug("%s.request(%s, %s" % (
|
self.notify.debug("%s.request(%s, %s" % (
|
||||||
self.name, request, str(args)[1:]))
|
self.name, request, str(args)[1:]))
|
||||||
@ -278,6 +302,8 @@ class FSM(DirectObject):
|
|||||||
self.__setState(*result)
|
self.__setState(*result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def defaultEnter(self, *args):
|
def defaultEnter(self, *args):
|
||||||
""" This is the default function that is called if there is no
|
""" This is the default function that is called if there is no
|
||||||
@ -353,25 +379,37 @@ class FSM(DirectObject):
|
|||||||
|
|
||||||
def setStateArray(self, stateArray):
|
def setStateArray(self, stateArray):
|
||||||
"""array of unique states to iterate through"""
|
"""array of unique states to iterate through"""
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
self.stateArray = stateArray
|
self.stateArray = stateArray
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def requestNext(self, *args):
|
def requestNext(self, *args):
|
||||||
"""request the 'next' state in the predefined state array"""
|
"""request the 'next' state in the predefined state array"""
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
assert self.state in self.stateArray
|
assert self.state in self.stateArray
|
||||||
|
|
||||||
curIndex = self.stateArray.index(self.state)
|
curIndex = self.stateArray.index(self.state)
|
||||||
newIndex = (curIndex + 1) % len(self.stateArray)
|
newIndex = (curIndex + 1) % len(self.stateArray)
|
||||||
|
|
||||||
self.request(self.stateArray[newIndex], args)
|
self.request(self.stateArray[newIndex], args)
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
def requestPrev(self, *args):
|
def requestPrev(self, *args):
|
||||||
"""request the 'previous' state in the predefined state array"""
|
"""request the 'previous' state in the predefined state array"""
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
assert self.state in self.stateArray
|
assert self.state in self.stateArray
|
||||||
|
|
||||||
curIndex = self.stateArray.index(self.state)
|
curIndex = self.stateArray.index(self.state)
|
||||||
newIndex = (curIndex - 1) % len(self.stateArray)
|
newIndex = (curIndex - 1) % len(self.stateArray)
|
||||||
|
|
||||||
self.request(self.stateArray[newIndex], args)
|
self.request(self.stateArray[newIndex], args)
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
|
||||||
|
|
||||||
def __setState(self, newState, *args):
|
def __setState(self, newState, *args):
|
||||||
@ -441,9 +479,13 @@ class FSM(DirectObject):
|
|||||||
"""
|
"""
|
||||||
Print out something useful about the fsm
|
Print out something useful about the fsm
|
||||||
"""
|
"""
|
||||||
|
self.lock.acquire()
|
||||||
|
try:
|
||||||
className = self.__class__.__name__
|
className = self.__class__.__name__
|
||||||
if self.state:
|
if self.state:
|
||||||
str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state))
|
str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state))
|
||||||
else:
|
else:
|
||||||
str = ('%s FSM:%s not in any state' % (className, self.name))
|
str = ('%s FSM:%s not in any state' % (className, self.name))
|
||||||
return str
|
return str
|
||||||
|
finally:
|
||||||
|
self.lock.release()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user