make fsm's thread safe

This commit is contained in:
David Rose 2008-10-29 22:02:18 +00:00
parent 89d53bbb75
commit 940a46fcfd

View File

@ -10,6 +10,7 @@ previously called FSM.py (now called ClassicFSM.py).
from direct.showbase.DirectObject import DirectObject
from direct.directnotify import DirectNotifyGlobal
from direct.showbase import PythonUtil
from direct.stdpy.threading import RLock
import types
import string
@ -142,6 +143,7 @@ class FSM(DirectObject):
defaultTransitions = None
def __init__(self, name):
self.lock = RLock()
self.name = name
self._serialNum = FSM.SerialNum
FSM.SerialNum += 1
@ -166,9 +168,13 @@ class FSM(DirectObject):
def cleanup(self):
# A convenience function to force the FSM to clean itself up
# by transitioning to the "Off" state.
self.lock.acquire()
try:
assert self.state
if self.state != 'Off':
self.__setState('Off')
finally:
self.lock.release()
def setBroadcastStateChanges(self, doBroadcast):
self._broadcastStateChanges = doBroadcast
@ -183,18 +189,28 @@ class FSM(DirectObject):
# Returns the current state if we are in a state now, or the
# state we are transitioning into if we are currently within
# the enter or exit function for a state.
self.lock.acquire()
try:
if self.state:
return self.state
return self.newState
finally:
self.lock.release()
def isInTransition(self):
self.lock.acquire()
try:
return self.state == None
finally:
self.lock.release()
def forceTransition(self, request, *args):
"""Changes unconditionally to the indicated state. This
bypasses the filterState() function, and just calls
exitState() followed by enterState()."""
self.lock.acquire()
try:
assert isinstance(request, types.StringTypes)
self.notify.debug("%s.forceTransition(%s, %s" % (
self.name, request, str(args)[1:]))
@ -206,6 +222,8 @@ class FSM(DirectObject):
return
self.__setState(request, *args)
finally:
self.lock.release()
def demand(self, request, *args):
"""Requests a state transition, by code that does not expect
@ -219,6 +237,8 @@ class FSM(DirectObject):
sequence.
"""
self.lock.acquire()
try:
assert isinstance(request, types.StringTypes)
self.notify.debug("%s.demand(%s, %s" % (
self.name, request, str(args)[1:]))
@ -230,6 +250,8 @@ class FSM(DirectObject):
if not self.request(request, *args):
raise RequestDenied, "%s (from state: %s)" % (request, self.state)
finally:
self.lock.release()
def request(self, request, *args):
"""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
transition is complete)."""
self.lock.acquire()
try:
assert isinstance(request, types.StringTypes)
self.notify.debug("%s.request(%s, %s" % (
self.name, request, str(args)[1:]))
@ -278,6 +302,8 @@ class FSM(DirectObject):
self.__setState(*result)
return result
finally:
self.lock.release()
def defaultEnter(self, *args):
""" This is the default function that is called if there is no
@ -353,25 +379,37 @@ class FSM(DirectObject):
def setStateArray(self, stateArray):
"""array of unique states to iterate through"""
self.lock.acquire()
try:
self.stateArray = stateArray
finally:
self.lock.release()
def requestNext(self, *args):
"""request the 'next' state in the predefined state array"""
self.lock.acquire()
try:
assert self.state in self.stateArray
curIndex = self.stateArray.index(self.state)
newIndex = (curIndex + 1) % len(self.stateArray)
self.request(self.stateArray[newIndex], args)
finally:
self.lock.release()
def requestPrev(self, *args):
"""request the 'previous' state in the predefined state array"""
self.lock.acquire()
try:
assert self.state in self.stateArray
curIndex = self.stateArray.index(self.state)
newIndex = (curIndex - 1) % len(self.stateArray)
self.request(self.stateArray[newIndex], args)
finally:
self.lock.release()
def __setState(self, newState, *args):
@ -441,9 +479,13 @@ class FSM(DirectObject):
"""
Print out something useful about the fsm
"""
self.lock.acquire()
try:
className = self.__class__.__name__
if self.state:
str = ('%s FSM:%s in state "%s"' % (className, self.name, self.state))
else:
str = ('%s FSM:%s not in any state' % (className, self.name))
return str
finally:
self.lock.release()