[DGD]More on atomic fuctions
Felix A. Croes
felix at dworkin.nl
Sun Sep 26 03:13:56 CEST 1999
The atomic function feature is probably the most significant addition
to LPC since mappings. I'll give two examples to explain how it
affects code.
---
The 2.4.5 mudlib for DGD contains the following code in
/dgd/lib/inventory.c:
private void move(object obj, object from, object dest)
{
int light;
light = query_light(obj);
if (from != 0) {
from->_F_rm_inv(obj, light);
}
obj->_F_move(dest);
dest->_F_add_inv(obj, light);
}
This code is called from the move_object() efun to do the actual
movement. If it were to fail halfway through, this would
result in an inconsistency. For example, if the inventory array
of `dest' already has the maximum size, adding the object `obj'
to the inventory of `dest' will result in an error; this will
leave the environment of `obj' set to `dest' while `obj' is not
actually in the inventory of `dest'.
Furthermore, there are some errors that can happen in almost any
code: running out of ticks, or out of stack space for nested
function calls. (It so happens that this particular code snippet
is safe from those errors.)
Now if the function were made atomic, it would either succeed
normally, or fail without making any change at all. The object
is either moved or not moved -- it cannot get stuck in an
intermediate state where it is half moved.
Using atomic is not the only solution. It may be possible to
check for all possible error conditions in advance, and only
execute the code if it's safe. Alternatively, an error occurring
halfway through could be caught, and the already-performed
actions could be undone explicitly. However, using atomic is
always the most simple solution, often the cheapest, and sometimes
the only possible one.
There is a lot of code out there that doesn't check for errors at
all, of course. The atomic function feature could be used to guard
such code from inconsistencies with only minimal rewriting.
---
Another example, not as low-level but still involving movement:
In muds using the 2.4.5 mudlib, sometimes there are rooms with an
error in the reset function -- for example, a monster is cloned
that doesn't exist. If a player moves into such a room and the
room is loaded for the first time, the result is that the player
is stuck in a dark room with no exits (the init() function is never
called).
Now if movement into this room were handled by an atomic function,
the player would still see the "error in fabric of space" message
but without actually moving anywhere. Movement has become an
atomic operation, which either succeeds or doesn't happen at all.
Note that calls to atomic functions may be nested, so that both
low-level object movement and player-level movement can be made
atomic.
---
So when to use atomic, and when to encapsulate code with
rlimits (-1; -1) instead? Use rlimits if you are sure that the
code will succeed if you give it infinite ticks and stack space;
use atomic otherwise. The reason for this is that atomic code
executes somewhat slower than normal code, whereas rlimits has
no effect on execution speed at all.
Unlike rlimits, the use of atomic is not protected by the mudlib.
This makes using atomic functions the best solution in cases where
rlimits might be preferred, but is unavailable.
Regards,
Dworkin
List config page: http://list.imaginary.com/mailman/listinfo/dgd
More information about the DGD
mailing list