[opensource-dev] Fwd: State machine class

Aleric Inglewood aleric.inglewood at gmail.com
Sun Feb 14 15:27:15 PST 2010


Ugh, seems this didn't go to the list... forwarding it there.

---------- Forwarded message ----------
From: Aleric Inglewood <aleric.inglewood at gmail.com>
Date: Mon, Feb 15, 2010 at 12:22 AM
Subject: Re: [opensource-dev] State machine class
To: Melinda Green <melinda at superliminal.com>


I am already using it :p.
This proposal is the direct result of practical experience, showing me that
this is needed.

But before I start to write example code that uses it, allow me to stay
abstract.

Didn't get much (other) reactions, so I thought I'd add some more details.

The idea is to have objects that go through a series of (usually) sequential
states:

CONSTRUCTOR
     |
     v
   INIT
     |
     v
custom states --------.
     .                |
     .                |
     .                v
custom states ----->ABORT
     |                |
     |<---------------'
     v
   DONE


'CONSTRUCTOR' would be an uninitialized state and never really executed
(the 'state' variable during construction of the object). Obviously it would
be in balance with it's destructor.

'INIT' would be the first state of the object when 'run'.
If the whole finishes successfully, we end up in the state 'DONE',
which cleanup in balance with INIT, and anything that is expected
to be left over from going to the states successfully.

The ABORT state is a state that will cleanup anything that might
be left-over from an abort.

The main thread ''runs' the object from it's 'Idle' state by calling
gIdleCallbacks.addFunction(...) for this object.

The main loop of such a StateMachine object would then look
like something like:

switch(mState)
{
  case INIT:
    init();
    set_state(WAIT_FOR_FOO);
  case WAIT_FOR_FOO;
    if (!foo())
      idle();
    set_state(DO_MORE);
  case DO_MORE:
    do_it();
    set_state(WAIT_FOR_BAR);
  case WAIT_FOR_BAR:
    if (!bar())
      idle();
    set_state(DONE);
  case DONE:
    cleanup();
}

As you see, this gives a compact and clear code where the flow is intuitive
(top down), but asynchronus and "blocking", without actually blocking the
main loop.

One of the major advantages is these objects are reusable; for example, one
could write an object that checks if some inventory folder exists, if not
creates it, and then (or when it already exists) waits till it's contents
are available. Lets call this object SyncFolder(std::string const& name).

Then another StateMachine object can use it (for example) as follows:

class MyStateMachine : public LLStateMachine {
  SyncFolder mSyncFolder;
...
  virtual void init();
  virtual void abort();
  virtual void done();
};

void MyStateMachine::init()
{
  mSyncFolder.set_name(folder_name);
}

bool MyStateMachine::mainloop()
{
  // INIT, DONE and ABORT are handled by the base class.
  switch(mState)
  {
    case WAIT_FOR_FOO:
      if (!foo())
        idle();
      set_state(SYNC_FOLDER);
    case SYNC_FOLDER:
      if (!mSyncFolder())   // Returns true when DONE
        break;
    case REZ_ITEM_FROM_FOLDER:
      do_rez();
  }
}


One could create a large number of such objects that do simple tasks, and
then use those to build
objects that do more complex tasks.


On Thu, Feb 11, 2010 at 6:56 PM, Melinda Green <melinda at superliminal.com>wrote:

> Sounds like a solution in search of a problem. I suggest that in order to
> get it incorporated as core, that you create at least one compelling
> solution built on it that people want enough to incorporate the whole thing.
> If you can't come up with one then it probably doesn't belong there because
> without a compelling example, nobody is going to realize it's there or to
> trust it or know how to use it.
>
> Just my L$5,
> -Melinda
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.secondlife.com/pipermail/opensource-dev/attachments/20100215/ff35c62a/attachment.htm 


More information about the opensource-dev mailing list