Top Mud Sites Forum

Top Mud Sites Forum (http://www.topmudsites.com/forums/index.php)
-   MUD Coding (http://www.topmudsites.com/forums/forumdisplay.php?f=9)
-   -   Making your MUD less prone to infinite looping (http://www.topmudsites.com/forums/showthread.php?t=292)

erdos 10-15-2003 09:48 PM

Many modern codebases are set up so if the MUD crashes, it will automatically reboot without an admin having to go into the shell.  However, the same is not true of infinite loops.  When these crop up, you're sh!t out of luck until a very high admin comes along and kills it in the shell.  But there is a possible alternative.
The basic strategy is to have numerous instances of the MUD running simultaneously;  however, all except the main instance are lying low and waiting for a cue before even going into the basic bootup routine (and thus they take no significant RAM).
Meanwhile, the main mud is set up slightly differently than usual with regard to socket handling.  Rather than the master socket being told to listen once, and left there until the MUD shuts down, the master is periodically told to listen, wait briefly, accept ALL connections (which would require some looping and multiple pollings) (actually you'd want to limit the number of connections, if more than 50 connections are pending in a single instant it's probably someone trying to crash you), then after putting those connections on a different port, the master socket is unbound and turned off, to await the next polling.
Now, the other instances which have not yet been fully activated all connect to the main mud on a separate port (since it's all on the same computer you could use a firewall to prevent players from getting to that port), and merely occasionally "ping" the main mud to make sure it's still up.  As long as this is the case, all goes smoothly.  (If the connection goes down, it means the main mud merely crashed, as opposed to infinite looping.. in this case the main mud should be coming back up anyway shortly so just try to reestablish communications)
But when the main mud goes into an infinite loop, it stops responding to the lesser mud instances.  After a given period of time, the next mud instance realizes the main one is stuck, and so it sends out signals to all the others, letting them know that now IT is the main mud, and proceeds to boot itself up and begin listening for connections to the playport.  It also sends a signal to the suspiciously unresponsive instance notifying it that it is no longer in charge- so that in the rare event it's not a real infinite loop but just some massive (multiple minute long) lag, when the lag finally stops the old main mud will quietly shut itself down and let the new main mud continue being in charge.
There are, of course, alot of issues to work out, and I myself (being employed full time AND in college full time) have no time for coding myself these days.  Thus this is all untested, it was merely an idea that came to me the other day.  Once a true coder, you will thenceforth never cease to periodically recieve coding inspirations, long after retiring.

the_logos 10-15-2003 11:21 PM

Rapture automatically catches infinite loops. If it doesn't get around to being able to process any player-input for X seconds it will skip the problem and kick up an error for review later. The time-period before it exits the infinite loop is settable by a user so, for instance, we give the daily backups a lot more leeway than most of the player verbs and regular game tasks and such.

--matt

Kylotan 10-28-2003 11:08 AM

Not true; Smaug demonstrates how it's possible to use the alarm signal to break out of potentially infinitely-long operations. Generally though, your infinite loops are only gonna be in scripts, and it should be easy enough to implement a way to monitor scripts and ensure they complete within a specified period of time.

Derk 10-28-2003 03:13 PM

Basic process accounting, for a unix admin. There are runaway process catcher... they notice processes using 100% cpu and kill them...

The mud could restart when its killed.. easy.

Any situation where loops like that can happen is bad design in my opinion.. but whatever.

Kastagaar 11-06-2003 05:02 AM

The most probable cause for infinite looping is, in my opinion, bad design. DikuMUDs in particular suffer from this because of their linked-list design. They use the idiom of "a data element in the list is a node in the list". Consider:

[code] a -> b -> c -> a[/quote]

We can see that iterating this is an infinite loop, because the node a points to the node b. Now consider using the "list node and data element are distinct" option:

[code]
node -> node -> node -> node
a b c a
[/quote]

(Eh? the code tag is not monospaced?)

Even though a is incorrectly in the list twice, there is no infinite loop when iterating over the list because the last node is still the last node.

This approach has its drawbacks, though: it takes more memory and probably more (although negligible) processor time when iterating. It also requires more memory management, because each node must be dynamically created.

erdos 11-06-2003 07:42 AM

[/quote]
Having coded on DIKU derivatives for years, I've never found that to be a problem. It takes only a smidgen of discipline to keep from linking the same thing to a list multiple times. Truly problematic infinite loops are usually a lot more convoluted. For example:
a player steps into a nofloor room and enters freefall, eventually landing, several rooms below, in a teleport room with 0 teleport delay that whisks them... right back where they started, to repeat the process.

With more cluttered codebases, codebases with tons and tons of features, it becomes ever more difficult for a coder to perceive all the possibilities. Often, an infinite loop requires the participation of a careless builder. There are diverse ways to make infinite loops with mob progs, despite coded attempts to reduce such risk.

If things are showing up twice in your linked lists, then infinite looping is the least of your worries! ;)

Kastagaar 11-11-2003 06:24 AM

I actually speak from experience. One particularly hard-to-find bug was caused by people putting up their corpses ( ! ) for automatic auction, and not having them bought. Since the crash appeared a couple of minutes after the bug occurred, it was exceedingly hard to track down.

Not that I'm saying either implementation is strictly better, just that with the distinct list-node/object paradigm, the error is detectable at insertion time.

Shanks 11-11-2003 08:40 PM

On Ancient Anguish one doesn't have to worry quite so much about infinite loops, as the mud doesn't usually crash as a result. Ancient Anguish is based on Amylaar LPMud 3.2.1@141.

Consider the following object:

[code] #pragma strict_types
inherit "obj/treasure";

void create()
{
;;create();
set_short("a looper");
set_long("This is an object that performs an infinite loop with the loop comm
nd.");
set_name("looper");
}

void init()
{
;;init();

add_action("do_loop", "loop");
}

int do_loop(string what)
{
// INFINITE LOOP;
while (1)
;
}[/quote]

What happens when you invoke the loop command?

[code] > loop
Too long evaluation. Execution aborted.
program; w/shanks/looper.c, object; w/shanks/looper#69319 line 21[/quote]

-Shanks

Samson 01-19-2004 07:01 AM

If infinite loop protection is what you're after, as Kylotan suggested Smaug has a set_alarm function. Using that, the following little tidbits will do the trick:

Top of game_loop, with other signal stuff:

signal( SIGALRM, caught_alarm );

In game_loop, after the new_descriptor call:

set_alarm( 30 );

And again at the bottom of game_loop, to reset it ( not sure if this is needed ):

set_alarm( 0 );

The set_alarm function itself, which is just a wrapper:

[code]
void set_alarm( long seconds )
{
alarm( seconds );
}
[/quote]

And caught_alarm:

[code]
/*
* LAG alarm! -Thoric
*/
static void caught_alarm( int signum )
{
bug( 'ALARM CLOCK! In section %s', alarm_section );
echo_to_all( AT_IMMORT, 'Alas, the hideous malevalent entity known only as 'Lag' rises once more!', ECHOTAR_IMM );
if( newdesc )
{
FD_CLR( newdesc, &in_set );
FD_CLR( newdesc, &out_set );
FD_CLR( newdesc, &exc_set );
log_string( 'clearing newdesc' );
}

game_loop();

/* Clean up the loose ends. */
close_mud( );

/*
* That's all, folks.
*/
log_string( 'Normal termination of game.' );
log_string( 'Cleaning up Memory.&d' );
cleanup_memory();
exit( 0 );
}
[/quote]

I've tested this out with a deliberate infinite loop command, it caught it and was able to restart game_loop. Smaug does not handle this use of the alarm stock, I added that part, but they were already using it in new_descriptor to break up connection problems. So I figured why not?


All times are GMT -4. The time now is 01:58 AM.

Powered by vBulletin® Version 3.6.7
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Copyright Top Mud Sites.com 2022