[Oberon] Can Active Objects in BB be made to migrate between
servers?
Søren Renner
soren.renner at gmail.com
Mon Oct 23 21:45:17 MEST 2006
This made me wonder:
Being able to add an independent, event driven program to any object
in the world makes scripting in Second Life really intuitive: you add
a script and your object becomes an independent agent able to sense
its world through event handlers, sit and think and then effect the
world through library calls. It's a model that works equally well
whether you're coding a fish which swims around looking for food or an
information post that just hands out notecards whenever it's poked.
It's an approach that quickly leads to lots of running scripts. Some
of the more complex regions constantly run 1000s of scripts. Abbotts
Aerodrome runs around 2000 scripts and while most of these are of the
give notecard when poked variety they could just as well be
calculating PI or running SETI at Home, which means they all need to
behave as if they were independent processes running concurrently
within the simulator.
Supporting such high levels of concurrency has been one of the major
challenges in integrating Mono in to Second Life. Although Mono and
the CLI support the concept of independent threads of execution, each
Mono thread maps on to an operating system thread which tend to be
fairly heavyweight. By default most operating systems reserve
megabytes of memory for each thread and don't cope with more than a
few dozen running concurrently. Even reducing the allocated stack size
to 32K and using the latest thread libraries on Linux doesn't get you
much past 1000 running threads before the system starts to wheeze.
The other difficulty with Second Life scripts is that they can migrate
between simulators while they are running. You are perfectly entitled
to write a script which never stops running and then to tie it to a
rocket that you fire in to another region. This is relatively easy to
do when all of your script state is in a single 16K block, but much
harder when your script has been Just In Time compiled to machine code
and its state is scattered throughout memory, registers and an
operating system thread.
The solution we implemented for Second Life was to use RAIL on top of
.NETs Reflection and Reflection.Emit facilities to inject
microthreading in to the script assemblies, an approach used by the
JavaGoX and Brakes projects to implement mobile agents in Java. Our
microthread injector searches through the script assembly finding
points where the script should yield and inducing the types on the
stack at those points. It can then inject extra opcodes in to the
assembly which copy the stack in to a heap object and cause the script
to yield. Whenever a script yields we can restore another script from
its previously saved heap object and start it running again, allowing
us to schedule many microthreaded scripts on a single operating system
thread. By marking the heap objects as serializable we can then just
use the standard .NET communication facilities to migrate scripts to
remote simulators where they can continue running.
The approach is memory efficient as the memory needed to save the
microthread is allocated when it yields, so a large amount of stack
space doesn't need to be conservatively reserved up front for the
thread. The problems with this approach is that it is expensive in CPU
time spent switching microthreads and the space taken up by injected
opcodes.
An alternative approach to microthreading Mono has been taken by Tomi
Valkeinen who has written some very funky code (inspired by Eve
Online's use of Stackless Python) to save and restore the native stack
to switch between microthreads. This approach should be a lot faster
than opcode injection. We can't currently use Tomi's microthreads for
Second Life as the saved stack may contain pointers which can't be
transferred to a remote machine, but it may be possible in the future
to use Mono's garbage collector to identify the pointers in the native
stack and twizzle them in to a form that can be sent to a remote
machine.
It would be very cool to build a library which automatically switched
between Tomi's microthreading implementation on Mono and Linden Lab
microthreading on .NET. People could then build portable microthreaded
applications which take advantage of Mono's native microthreading when
it's available.
More information about the Oberon
mailing list