[Stackless] Watchdog and Channel Receiving in C

Dave Butler dave at hoppit.net
Mon Apr 18 19:34:56 CEST 2011

I have been playing around with stackless for a hobby project (MUD) and 
needed some advice with one particular problem I've encountered.  Part 
of my goal was to see if it was possible to write scripts for a 
multi-player game in the same fashion that you would for a blocking, 
single-player game.  Additionally, misbehaving scripts should timeout 
fairly quickly.

The basic MUD driver is written in C++ using boost.asio and stackless 
3.2.  Commands that come in usually create and schedule a new tasklet 
which calls the defined input handler in python.  There is also a 
player.input() function which behaves like the normal blocking input, 
but actually just calls PyChannel_Receive on a connection-specific 
stackless channel in a C function and returns the result.  If there is 
an input channel waiting, then any player input is sent there instead of 
creating a new tasklet.

In my event loop, I call PyStackless_RunWatchdog with a low instruction 
count to allow the rest of the event loop to continue without requiring 
cooperative scheduling inside the game scripts.  If scripts run for X 
amount of time (clock time, rather than instruction count), I kill the 
tasklet.  Otherwise, the tasklet is re-inserted and continues running. 
All of this actually works great, and allows things like the following:

class Player:
	def onConnect(self):
		# calls PyChannel_Receive(...)
		name = self.input("What is your name?")
		self.send("Welcome %s!" % name)

This part works just fine and as expected, even with many players 
connected.  In addition, any infinite loop in normal code will be timed 
out, also as expected.  All the timers fire properly as long as the 
watchdog is running as it should.  However, the code that follows an 
input statement doesn't seem to be running under the watchdog at all. 
Infinite loops run infinitely, code never times out because the main 
event loop is blocked while the code is running - ie, if there were an 
infinite loop BEFORE the input statement above, the script be 
interrupted by the watchdog and killed after a second or two, but not if 
the loop came after the input statement.

I've browsed through some of the stackless code, and I'm not entirely 
sure what is happening in there.  It appears to me that when data is 
received on a channel, it immediately fires off the rest of the function 
rather than scheduling it for execution?  I may be entirely wrong here...

Has anyone encountered this at all?  I'm happy to delve into and make 
changes to the stackless code if necessary, or if someone knows a better 
method to achieve the same thing I would appreciate any pointers.  I 
would prefer to go under the assumption that script-writers do NOT know 
how stackless works and should not be required to do any cooperative 
scheduling themselves.  Feel free to let me know if I was unclear on any 
particular points.

Dave Butler

More information about the Stackless mailing list