Deleted:
/trunk/contrib/uthread.py
Modified:
/trunk/bootstrap.py
/trunk/contrib/events.py
/trunk/contrib/livecoding/namespace.py
/trunk/contrib/livecoding/reloader.py
/trunk/contrib/stacklesslib/NOTES
/trunk/contrib/stacklesssocket.py
/trunk/games/roguelike/services/world.py
/trunk/games/roguelike/shells/login.py
/trunk/games/roguelike/shells/roguelike.py
/trunk/games/sandbox/services/entityMap2D.py
/trunk/games/sandbox/services/entityVoid.py
/trunk/games/sandbox/services/world.py
/trunk/games/sandbox/services/worldVoid.py
/trunk/games/sandbox/worldMap2D/entity.py
/trunk/games/sandbox/worldVoid/entity.py
/trunk/mudlib/services/intermud3.py
/trunk/mudlib/services/net/connectionTelnet.py
/trunk/mudlib/services/net.py
/trunk/mudlib/services/opencyc.py
/trunk/mudlib/services/service.py
=======================================
--- /trunk/contrib/uthread.py Wed Mar 31 02:05:33 2010
+++ /dev/null
@@ -1,988 +0,0 @@
-"""Python Microthread Library, version 1.0
-
-Stackless adds tasklets to Python, a more modern form of the
-microthreads this library originally provided. This modified
-version of the original uthread library provides a range of
-useful functions and classes.
-
-Use of this class generally requires a certain approach to
-using Stackless. Use only the provided 'uthread.sleep()' and
-'uthread.benice()' functions to yield and never
-'stackless.schedule()'. The reason for this is that each
-tasklet scheduled is expected to be removed from the scheduler
-when it either yields or exits. This way the watchdog can be
-relied upon to exit pretty much immediately, and will only
-hit the instruction count timeout when a runaway tasklet
-does not yield because of bad programming.
-
-Do not use 'stackless.run()'. Instead use 'uthread.run()' as
-it takes care of scheduling tasklets that are sleeping and
-being nice.
-
-Permission was granted by Halldor Fannar Gudjonsson, Chief
-Technical Officer of CCP Games to Richard Tew to release the
-modified version of the original uthread library which they
-use internally. Changes have been made to replace functionality
-provided by the EVE game framework by Richard Tew.
-"""
-
-__version__ = "1.0"
-
-__license__ = \
-"""Python Microthread Library version 1.0
-Copyright (C)2000 Will Ware, Christian Tismer
-Copyright (C)2000-2006 CCP Games
-Copytight (C)2006 Richard Tew
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose and without fee is hereby granted,
-provided that the above copyright notice appear in all copies and that
-both that copyright notice and this permission notice appear in
-supporting documentation, and that the names of the authors not be
-used in advertising or publicity pertaining to distribution of the
-software without specific, written prior permission.
-
-WILL WARE AND CHRISTIAN TISMER DISCLAIM ALL WARRANTIES WITH REGARD TO
-THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
-FITNESS. IN NO EVENT SHALL WILL WARE OR CHRISTIAN TISMER BE LIABLE FOR
-ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-"""
-
-import stackless
-import sys
-import time
-import types
-import weakref
-import traceback
-import copy
-import logging
-
-# This is a simple replacement for what CCP uses which is linked into our
-# framework.
-def WriteTraceback(text, tb):
- logging.error(text)
- for s in traceback.format_tb(tb):
- logging.error(s.strip())
- logging.error(str(excInstance))
-
-def LogTraceback(text):
- if text is None:
- text = "Traceback:"
- tb = traceback.extract_stack()
- WriteTraceback(text, tb)
-
-def StackTrace(text=None):
- excClass, excInstance, tb = sys.exc_info()
- if excClass:
- if text is None:
- text = "Stacktrace:"
- WriteTraceback(text, tb)
- else:
- LogTraceback(text)
-
-# Internal Stackless functionality.
-schedule = stackless.schedule
-
-# We need to subclass it so that we can store attributes on it.
-class Tasklet(stackless.tasklet):
- def __call__(self, *args, **kwargs):
- oldFunction = self.tempval
- def newFunction(oldFunction, args, kwargs):
- try:
- oldFunction(*args, **kwargs)
- except Exception, e:
- traceback.print_exc()
- raise e
- self.tempval = newFunction
- stackless.tasklet.setup(self, oldFunction, args, kwargs)
- return self
-
-def new(func, *args, **kw):
- return Tasklet(func)(*args, **kw)
-
-def newWithoutTheStars(func, args, kw):
- return Tasklet(func)(*args, **kw)
-
-idIndex = 0
-
-def uniqueId():
- """Microthread-safe way to get unique numbers, handy for
- giving things unique ID numbers"""
- global idIndex
- ## CCP is cutting out atomic as we never preemtivly schedule and
stackless was crashing there
- #tmp = stackless.atomic()
- z = idIndex
- idIndex += 1
- return z
-
-def irandom(n):
- """Microthread-safe version of random.randrange(0,n)"""
- import random
- ## CCP is cutting out atomic as we never preemtivly schedule and
stackless was crashing there
- #tmp = stackless.atomic()
- n = random.randrange(0, n)
- return n
-
-synonyms = {}
-
-def MakeSynonymOf(threadid, synonym_threadid):
- global synonyms
- key = (threadid, synonym_threadid)
- if key not in synonyms:
- synonyms[key] = 1
- else:
- synonyms[key] += 1
-
-def MakeCurrentSynonymOf(synonym_threadid):
- return MakeSynonymOf(id(stackless.getcurrent()), synonym_threadid)
-
-def RemoveSynonymOf(threadid, synonym_threadid):
- global synonyms
- key = (threadid, synonym_threadid)
- if key not in synonyms:
- StackTrace("RemoveSynonymOf unexpected call threadid:%s
synonym_threadid:%s" % key)
- return
- synonyms[key] -= 1
- if 0 == synonyms[key]:
- del synonyms[key]
-
-def RemoveCurrentSynonymOf(synonym_threadid):
- return RemoveSynonymOf(id(stackless.getcurrent()), synonym_threadid)
-
-def IsSynonymOf(threadid, synonym_threadid):
- global synonyms
- key = (threadid, synonym_threadid)
- return key in synonyms
-
-def IsCurrentSynonymOf(synonym_threadid):
- return IsSynonymOf(id(stackless.getcurrent()), synonym_threadid)
-
-# Sleeping related logic.
-
-sleepingTasklets = []
-
-def Sleep(secondsToWait):
- '''
- Yield the calling tasklet until the given number of seconds have
passed.
- '''
- global sleepingTasklets
- channel = stackless.channel()
- endTime = time.time() + secondsToWait
- sleepingTasklets.append((endTime, channel))
- sleepingTasklets.sort()
- # Block until we get sent an awakening notification.
- channel.receive()
-
-def CheckSleepingTasklets():
- '''
- Function for internal uthread.py usage.
- '''
- global sleepingTasklets
- if len(sleepingTasklets):
- endTime = sleepingTasklets[0][0]
- if endTime <= time.time():
- channel = sleepingTasklets[0][1]
- del sleepingTasklets[0]
- # We have to send something, but it doesn't matter what as it
is not used.
- # Handle the case where the tasklet has been prematurely
killed, otherwise
- # the caller will be blocked indefinitely.
- if channel.balance:
- channel.send(None)
-
-def KillSleepingTasklets():
- global sleepingTasklets
- if len(sleepingTasklets):
- for timestamp, channel in sleepingTasklets:
- t = channel.queue
- while t is not None:
- toBeKilled = t
- t = t.next
- toBeKilled.raise_exception(TaskletExit)
- sleepingTasklets = []
-
-# Being nice related logic.
-
-yieldChannel = stackless.channel()
-yieldChannel.preference = 1
-
-def BeNice():
- '''
- Yield the calling tasklet. Use instead of schedule in order to keep
- the scheduler empty.
- '''
- global yieldChannel
- yieldChannel.receive()
-
-# We need to have a tasklet of our own calling this, then the watchdog.
-def RunNiceTasklets():
- '''
- Function for internal uthread.py usage.
- '''
- global yieldChannel
- # Only schedule as many tasklets as there are waiting when
- # we start. This is because some of the tasklets we awaken
- # may BeNice their way back onto the channel.
- n = -yieldChannel.balance
- while n > 0:
- yieldChannel.send(None)
- n -= 1
-
-# Scheduling related logic.
-
-class TimeoutException(Exception):
- pass
-
-def Run():
- '''
- Use instead of stackless.run() in order.to allow Sleep and BeNice
- to work. If this is not called and BeNice is used and RunNiceTasklets
- is not called or Sleep is used and CheckSleepingTasklets is not called,
- then any tasklets which call BeNice or Sleep respectively will block
- indefinitely as there will be nothing to wake them up.
-
- This function will exit when there are no remaining tasklets to run,
- whether being nice or sleeping.
- '''
- while yieldChannel.balance or len(sleepingTasklets) or
stackless.runcount > 1:
- RunNiceTasklets()
- t = stackless.run(500000)
- if t is not None:
- print "*** Uncooperative tasklet", t, "detected ***"
- traceback.print_stack(t.frame)
- print "*** Uncooperative tasklet", t, "being sent exception
***"
- t.raise_exception(TimeoutException)
- CheckSleepingTasklets()
-
-semaphores = weakref.WeakKeyDictionary({})
-
-def GetSemaphores():
- return semaphores
-
-class Semaphore:
- """Semaphores protect globally accessible resources from
- the effects of context switching."""
-
- def __init__(self, semaphoreName=None, maxcount=1, strict=True):
- global semaphores
-
- semaphores[self] = 1
-
- self.semaphoreName = semaphoreName
- self.maxcount = maxcount
- self.count = maxcount
- self.waiting = stackless.channel()
- self.thread = None
- self.lockedWhen = None
- self.strict = strict
-
- def IsCool(self):
- '''
- returns true if and only if nobody has, or is waiting for,
this lock
- '''
- return self.count==self.maxcount
-
- def __str__(self):
- return "Semaphore("+ str(self.semaphoreName) +")"
-
- def __del__(self):
- if not self.IsCool():
- logger.error("Semaphore "+ str(self) +" is being destroyed in
a locked or waiting state")
-
- def acquire(self):
- if self.strict:
- assert self.thread is not stackless.getcurrent()
- if self.thread is stackless.getcurrent():
- raise RuntimeError, "tasklet deadlock, acquiring tasklet
holds strict semaphore"
- self.count -= 1
- if self.count < 0:
- self.waiting.receive()
-
- self.lockedWhen = time.time()
- self.thread = stackless.getcurrent()
-
- claim = acquire
-
- def release(self):
- if self.strict:
- assert self.thread is stackless.getcurrent()
- if self.thread is not stackless.getcurrent():
- raise RuntimeError, "wrong tasklet releasing strict
semaphore"
-
- self.count += 1
- self.thread = None
- self.lockedWhen = None
- if self.count <= 0:
-
PoolWorker("uthread::Semaphore::delayed_release",self.__delayed_release)
-
- #This allows the release thread to continue without being interrupted
- def __delayed_release(self):
- self.waiting.send(None)
-
-class CriticalSection(Semaphore):
- def __init__(self, semaphoreName = None, strict=True):
- Semaphore.__init__(self, semaphoreName)
- self.__reentrantRefs = 0
-
- def acquire(self):
- # MEB: if (self.count<=0) and (self.thread is
stackless.getcurrent() or stackless.getcurrent() is synonymof self.thread):
- if (self.count<=0) and (self.thread is stackless.getcurrent() or
IsCurrentSynonymOf(self.thread)):
- self.__reentrantRefs += 1
- else:
- Semaphore.acquire(self)
-
- def release(self):
- if self.__reentrantRefs:
- # MEB: assert self.thread is stackless.getcurrent()
- assert self.thread is stackless.getcurrent() or
IsCurrentSynonymOf(self.thread)
- # MEB: if self.thread is not stackless.getcurrent():
- if not (self.thread is stackless.getcurrent() or
IsCurrentSynonymOf(self.thread)):
- raise RuntimeError, "wrong tasklet releasing reentrant
CriticalSection"
- self.__reentrantRefs -= 1
- else:
- Semaphore.release(self)
-
-def FNext(f):
- first = stackless.getcurrent()
- try:
- cursor = first.next
- while cursor != first:
- if cursor.frame.f_back == f:
- return FNext(cursor.frame)
- cursor = cursor.next
- return f
- finally:
- first = None
- cursor = None
-
-class SquidgySemaphore:
- '''
- This is a semaphore which allows exclusive locking
- '''
-
- def __init__(self, lockName):
- self.__outer__ = Semaphore(lockName)
- self.lockers = {}
- self.__wierdo__ = 0
-
- def IsCool(self):
- '''
- returns true if and only if nobody has, or is waiting for,
this lock
- '''
- while 1:
- lockers = []
- try:
- for each in self.lockers:
- return 0
- break
- except:
- StackTrace()
- sys.exc_clear()
- return self.__outer__.IsCool() and not self.__wierdo__
-
- def acquire_pre_friendly(self):
- '''
- Same as acquire, but with respect for pre_acquire_exclusive
- '''
- while 1:
- if self.__wierdo__:
- Sleep(0.5)
- else:
- self.acquire()
- if self.__wierdo__:
- self.release()
- else:
- break
-
- def pre_acquire_exclusive(self):
- '''
- Prepares the lock for an acquire_exclusive call, so that
- acquire_pre_friendly will block on the dude.
- '''
- self.__wierdo__ += 1
-
- def acquire_exclusive(self):
- i = 0
- while 1:
- self.__outer__.acquire()
- theLocker = None
- try:
- # self.lockers is a dict, and we just want one entry from
it.
- # for each in/break is a convenient way to get one entry.
- for each in self.lockers:
- theLocker = each
- break
- except:
- StackTrace()
- sys.exc_clear()
-
- if theLocker is not None:
- self.__outer__.release() # yielding to the sucker is fine,
since we're waiting for somebody anyhow.
- if i and ((i%(3*4*60))==0):
- logger.error("Acquire-exclusive is waiting for the
inner lock (%d seconds total, lockcount=%d)" % (i/4, len(self.lockers)))
- LogTraceback("This acquire_exclusive is taking a
considerable amount of time")
- logger.error("This dude has my lock:")
- logger.error("tasklet: "+str(theLocker))
- for s in
traceback.format_list(traceback.extract_stack(FNext(theLocker.frame),40)):
- for n in range(0,10120,253): # forty lines max.
- if n==0:
- if len(s)<=255:
- x = s
- else:
- x = s[:(n+253)]
- else:
- x = " - " + s[n:(n+253)]
- logger.error(x, 4)
- if (n+253)>=len(s):
- break
- Sleep(0.500)
- else:
- break
- i += 1
-
- def release_exclusive(self):
- self.__outer__.release()
- self.__wierdo__ -= 1
-
- def acquire(self):
- # you don't need the outer lock to re-acquire
- self.__outer__.acquire()
- self.__acquire_inner()
- self.__outer__.release()
-
- def release(self, t=None):
- if t is None:
- t = stackless.getcurrent()
- self.__release_inner(t)
-
- def __acquire_inner(self):
- while 1:
- try:
- if self.lockers.has_key(stackless.getcurrent()):
- self.lockers[stackless.getcurrent()] += 1
- else:
- self.lockers[stackless.getcurrent()] = 1
- break
- except:
- StackTrace()
- sys.exc_clear()
-
- def __release_inner(self, t):
- while 1:
- try:
- if self.lockers.has_key(t):
- self.lockers[t] -= 1
- if self.lockers[t]==0:
- del self.lockers[t]
- else:
- StackTrace("You can't release a lock you didn't
acquire")
- break
- except:
- StackTrace()
- sys.exc_clear()
-
-channels = weakref.WeakKeyDictionary()
-
-def GetChannels():
- return channels
-
-class Channel:
- """
- A Channel is a stackless.channel() with administrative spunk
- """
-
- def __init__(self,channelName=None):
- global channels
- self.channelName = channelName
- self.channel = stackless.channel()
- self.send = self.channel.send
- self.send_exception = self.channel.send_exception
- channels[self] = 1
-
- def receive(self):
- return self.channel.receive()
-
- def __getattr__(self,k):
- return getattr(self.channel,k)
-
-
-
-
-#
-----------------------------------------------------------------------------------
-# FIFO Class
-#
-----------------------------------------------------------------------------------
-class FIFO(object):
-
- __slots__ = ('data',)
-
- #
-----------------------------------------------------------------------------------
- # FIFO - Constructor
- #
-----------------------------------------------------------------------------------
- def __init__(self):
- self.data = [[], []]
-
- #
-----------------------------------------------------------------------------------
- # FIFO - push
- #
-----------------------------------------------------------------------------------
- def push(self, v):
- self.data[1].append(v)
-
- #
-----------------------------------------------------------------------------------
- # FIFO - pop
- #
-----------------------------------------------------------------------------------
- def pop(self):
- d = self.data
- if not d[0]:
- d.reverse()
- d[0].reverse()
- return d[0].pop()
-
- #
-----------------------------------------------------------------------------------
- # FIFO - __nonzero__
- #
-----------------------------------------------------------------------------------
- # NB: Please don't define this function, as it will break some legacy
code in client
- # Use the len() function instead
- #def __nonzero__(self):
- # d = self.data
- # return not (not (d[0] or d[1]))
-
- #
-----------------------------------------------------------------------------------
- # FIFO - __contains__
- #
-----------------------------------------------------------------------------------
- def __contains__(self, o):
- d = self.data
- return (o in d[0]) or (o in d[1])
-
-
- #
-----------------------------------------------------------------------------------
- # FIFO - Length
- #
-----------------------------------------------------------------------------------
- def Length(self):
- d = self.data
- return len(d[0]) + len(d[1])
-
- #
-----------------------------------------------------------------------------------
- # FIFO - clear
- #
-----------------------------------------------------------------------------------
- def clear(self):
- self.data = [[], []]
-
- #
-----------------------------------------------------------------------------------
- # FIFO - clear
- #
-----------------------------------------------------------------------------------
- def remove(self, o):
- d = self.data
- try:
- d[0].remove(o)
- except ValueError:
- sys.exc_clear()
-
- try:
- d[1].remove(o)
- except ValueError:
- sys.exc_clear()
-
-
-#
-----------------------------------------------------------------------------------
-# Queue - QueueCheck
-#
-----------------------------------------------------------------------------------
-def QueueCheck(o):
-
- while True:
- try:
- o.pump()
- except ReferenceError:
- sys.exc_clear()
- break
- except StandardError:
- StackTrace()
- sys.exc_clear()
-
- Sleep(0.1)
-
-
-#
-----------------------------------------------------------------------------------
-# Queue Class
-#
-----------------------------------------------------------------------------------
-class Queue(FIFO):
- """A queue is a microthread-safe FIFO."""
-
- #
-----------------------------------------------------------------------------------
- # Queue - Constructor
- #
-----------------------------------------------------------------------------------
- def __init__(self):
- FIFO.__init__(self)
- self.channel = stackless.channel()
- self.blockingThreadRunning = False
-
- #
-----------------------------------------------------------------------------------
- # Queue - put
- #
-----------------------------------------------------------------------------------
- def put(self, x):
- self.push(x)
- self.pump()
-
- #
-----------------------------------------------------------------------------------
- # Queue - pump
- #
-----------------------------------------------------------------------------------
- def pump(self):
-
- while self.channel.queue and self.Length() and
self.channel.balance < 0:
- o = self.pop()
- self.channel.send(o)
-
- #
-----------------------------------------------------------------------------------
- # Queue - non_blocking_put
- #
-----------------------------------------------------------------------------------
- def non_blocking_put(self, x):
-
- # Create a non blocking worker thread if this is the first time
this gets called
- if not self.blockingThreadRunning:
- self.blockingThreadRunning = True
- new(QueueCheck, weakref.proxy(self)).context
= "uthread::QueueCheck"
-
- self.push(x)
-
- #
-----------------------------------------------------------------------------------
- # Queue - get
- #
-----------------------------------------------------------------------------------
- def get(self):
- if self.Length():
- return self.pop()
-
- return self.channel.receive()
-
-
-# --------------------------------------------------------------------
-class Event:
-
- # --------------------------------------------------------------------
- def __init__(self, manual=1, signaled=0):
- self.channel = stackless.channel()
- self.manual = manual
- self.signaled = signaled
-
- # --------------------------------------------------------------------
- def Wait(self, timeout=-1):
- if timeout != -1:
- raise RuntimeError("No timeouts supported in Event")
-
- if not self.signaled:
- self.channel.receive()
-
- # --------------------------------------------------------------------
- def SetEvent(self):
- if self.manual:
- self.signaled = 1
-
- while self.channel.queue:
- self.channel.send(None)
-
- # --------------------------------------------------------------------
- def ResetEvent(self):
- self.signaled = 0
-
-
-
-def LockCheck():
- global semaphores
- while 1:
- each = None
- Sleep(5 * 60)
- now = time.time()
- try:
- for each in semaphores.keys():
- BeNice()
- if (each.count<=0) and (each.waiting.balance < 0) and
(each.lockedWhen and (now - each.lockedWhen)>=(5*MIN)):
- logger.error("Semaphore %s appears to have threads in
a locking conflict."%id(each))
- logger.error("holding thread:")
- try:
- for s in
traceback.format_list(traceback.extract_stack(each.thread.frame,40)):
- logger.error(s)
- except:
- sys.exc_clear()
- first = each.waiting.queue
- t = first
- while t:
- logger.error("waiting thread %s:"%id(t),4)
- try:
- for s in
traceback.format_list(traceback.extract_stack(t.frame,40)):
- logger.error(s,4)
- except:
- sys.exc_clear()
- t = t.next
- if t is first:
- break
- logger.error("End of locking conflict log")
- except StandardError:
- StackTrace()
- sys.exc_clear()
-
-# new(LockCheck).context = "uthread::LockCheck"
-
-__uthread__queue__ = None
-def PoolHelper(queue):
- t = stackless.getcurrent()
- t.localStorage = {}
- respawn = True
- try:
- try:
- while 1:
- BeNice()
- ctx, callingContext, func, args, keywords = queue.get()
- if (queue.channel.balance >= 0):
- new(PoolHelper, queue).context = "uthread::PoolHelper"
- #SetLocalStorage(loc)
- # _tmpctx = t.PushTimer(ctx)
- try:
- apply( func, args, keywords )
- finally:
- ctx = None
- callingContext = None
- func = None
- #t.localStorage = {}
- #loc = None
- args = None
- keywords = None
- # t.PopTimer(_tmpctx)
- except SystemExit:
- respawn = False
- raise
- except:
- if callingContext is not None:
- extra = "spawned at %s %s(%s)"%callingContext
- else:
- extra = ""
- StackTrace("Unhandled exception in %s%s" % (ctx, extra))
- sys.exc_clear()
- finally:
- if respawn:
- del t
- new(PoolHelper, queue).context = "uthread::PoolHelper"
-
-def PoolWorker(ctx,func,*args,**keywords):
- '''
- Same as uthread.pool, but without copying local storage, thus
resetting session, etc.
-
- Should be used for spawning worker threads.
- '''
- return PoolWithoutTheStars(ctx,func,args,keywords,0,1)
-
-def PoolWorkerWithoutTheStars(ctx,func,args,keywords):
- '''
- Same as uthread.worker, but without copying local storage, thus
resetting session, etc.
-
- Should be used for spawning worker threads.
- '''
- return PoolWithoutTheStars(ctx,func,args,keywords,0,1)
-
-def PoolWithoutTheStars(ctx,func,args,keywords,unsafe=0,worker=0):
- if type(ctx) not in types.StringTypes:
- StackTrace("uthread.pool must be called with a context string as
the first parameter")
- global __uthread__queue__
- callingContext = None
- if ctx is None:
- if unsafe:
- ctx = "uthread::PoolHelper::UnsafeCrap"
- else:
- tb = traceback.extract_stack(limit=2)[0]
- ctx = getattr(stackless.getcurrent(), "context", "")
- callingContext = tb[2], tb[0], tb[1] #function , file, lineno
- del tb
-
- if __uthread__queue__ is None:
- __uthread__queue__ = Queue()
- for i in range(60):
- new(PoolHelper, __uthread__queue__).context
= "uthread::PoolHelper"
- #if unsafe or worker:
- # st = None
- #else:
- # st = copy.copy(GetLocalStorage())
- __uthread__queue__.non_blocking_put( (str(ctx), callingContext, func,
args, keywords,) )
- return None
-
-def Pool(ctx,func,*args,**keywords):
- '''
- Executes apply(args, keywords) on a new uthread. The uthread in
question is taken
- from a thread pool, rather than created one-per-shot call. ctx is
used as the
- thread context. This should generally be used for short-lived
threads to reduce
- overhead.
- '''
- return PoolWithoutTheStars(ctx,func,args,keywords)
-
-def UnSafePool(ctx,func,*args,**keywords):
- '''
- uthread.pool, but without any dangerous calls to
stackless.getcurrent(), which could
- have dramatic and drastic effects in the wrong context.
- '''
- return PoolWithoutTheStars(ctx,func,args,keywords,1)
-
-def ParallelHelper(ch,idx,what):
- ch, threadid = ch
- MakeCurrentSynonymOf(threadid)
- try:
- ei = None
- try:
- if len(what)==3:
- ret = (idx, apply(what[0], what[1], what[2] ))
- if ch.balance < 0 :
- ch.send( (1, ret) )
- else:
- ret = (idx, apply(what[0], what[1] ))
- if ch.balance < 0:
- ch.send( (1, ret) )
- except StandardError:
- ei = sys.exc_info()
- sys.exc_clear()
-
- if ei:
- if ch.balance < 0:
- ch.send((0,ei))
- del ei
- finally:
- RemoveCurrentSynonymOf(threadid)
-
-def Parallel(funcs,exceptionHandler=None,maxcount=30):
- '''
- Executes in parallel all the function calls specified in the
list/tuple 'funcs', but returns the
- return values in the order of the funcs list/tuple. If an
exception occurs, only the first exception
- will reach you. The rest will dissapear in a puff of logic.
-
- Each 'func' entry should be a tuple/list of:
- 1. a function to call
- 2. a tuple of arguments to call it with
- 3. optionally, a dict of keyword args to call it with.
- '''
- if not funcs:
- return
-
- context
= "ParallelHelper::"+getattr(stackless.getcurrent(),"context","???")
- ch = stackless.channel(), id(stackless.getcurrent())
- ret = [ None ] * len(funcs)
- n = len(funcs)
- if n > maxcount:
- n = maxcount
- for i in range(n):
- if type(funcs[i]) != types.TupleType:
- raise RuntimeError("Parallel requires a list/tuple of
(function, args tuple, optional keyword dict,)")
- Pool(context, ParallelHelper, ch, i, funcs[i])
- for i in range(len(funcs)):
- ok, bunch = ch[0].receive()
- if ok:
- idx,val = bunch
- if len(funcs[i])==4:
- ret[idx] = (funcs[i][3], val,)
- else:
- ret[idx] = val
- else:
- try:
- raise bunch[0],bunch[1],bunch[2]
- except StandardError:
- if exceptionHandler:
- exctype, exc, tb = sys.exc_info()
- try:
- try:
- apply( exceptionHandler, (exc,) )
- except StandardError:
- raise exc, None, tb
- finally:
- exctype, exc, tb = None, None, None
- else:
- StackTrace()
- raise
-
- if n<len(funcs):
- if type(funcs[n]) != types.TupleType:
- raise RuntimeError("Parallel requires a list/tuple of
(function, args tuple, optional keyword dict,)")
- Pool(context, ParallelHelper, ch, n, funcs[n])
- n+=1
- return ret
-
-locks = {}
-def Lock(object, *args):
- '''
- Blocks the calling tasklet until a specific globally accessible lock is
- acquired. The lock acquired is defined by the arguments passed to this
- function. The lock is not reentrant and any attempt by a tasklet to
- reacquire the lock it already holds will result in a deadlock related
error.
- '''
- global locks
- t = (id(object), args)
- if t not in locks:
- locks[t] = Semaphore(t, strict=False)
- locks[t].acquire()
-
-def TryLock(object, *args):
- '''
- Attempts to acquire a specific globally accessible lock. The lock to
be
- acquired is defined by the arguments passed to this function. If the
lock
- is not currently available, then False will be returned. If the lock
is
- available, it will be acquired and True will be returned.
- '''
- global locks
- t = (id(object), args)
- if t not in locks:
- locks[t] = Semaphore(t, strict=False)
- if not locks[t].IsCool():
- return False
- locks[t].acquire()
- return True
-
-def ReentrantLock(object, *args):
- '''
- Blocks the calling tasklet until a specific globally accessible lock is
- acquired, unless the calling tasklet has already acquired it in which
- case it is reacquired in a reentrant manner. The lock to be acquired
is
- defined by the arguments passed to this function.
- '''
- global locks
- t = (id(object), args)
- if t not in locks:
- locks[t] = CriticalSection(t)
- locks[t].acquire()
-
-def UnLock(object, *args):
- '''
- Releases a lock which the calling tasklet has previously acquired. The
- lock to be released is defined by the arguments passed to this
function.
- If the calling tasklet has acquired the lock several times reentrantly
- then the lock will not be released unblocking other waiting tasklets
- until all the reentrant locking actions have been matched with
unlocking
- actions.
- '''
- global locks
- t = (id(object), args)
- locks[t].release()
- if (t in locks) and (locks[t].IsCool()): # may be gone or changed by
now
- del locks[t]
-
-def with_instance_locking(f):
- '''
- Decorator which provides instance level locking.
- When used on an instance method locks the instance for the duration
- of the function call. Requires that the first argument is the
- instance the lock belongs to, which will be implicit with decorated
- instance methods.
- '''
- def new_f(self, *args, **kwds):
- Lock(self)
- try:
- return f(self, *args, **kwds)
- finally:
- UnLock(self)
- return new_f
-
-
-# Exported names.
-parallel = Parallel
-worker = PoolWorker
-workerWithoutTheStars = PoolWorkerWithoutTheStars
-unsafepool = UnSafePool
-pool = Pool
-poolWithoutTheStars = PoolWithoutTheStars
-
-sleep = Sleep
-benice = BeNice
-run = Run
=======================================
--- /trunk/bootstrap.py Tue Sep 7 04:44:04 2010
+++ /trunk/bootstrap.py Fri Jan 7 05:23:18 2011
@@ -78,9 +78,10 @@
# Monkey-patch in the stackless-compatible sockets.
import stacklesssocket
- import uthread, uthread2
- stacklesssocket._schedule_func = uthread.BeNice
- stacklesssocket._sleep_func = uthread.Sleep
+ import uthread2
+ import stacklesslib.main as stacklesslibmain
+ stacklesssocket._schedule_func = lambda delay=0:
stacklesslibmain.sleep(delay)
+ stacklesssocket._sleep_func = stacklesslibmain.sleep
stacklesssocket.install()
# Install the global event handler.
@@ -96,8 +97,8 @@
# Register the mudlib and game script directories with the livecoding
# module. This will compile and execute them all.
import reloader
- #gamePath = os.path.join("games", "room - simple")
- gamePath = os.path.join("games", "roguelike")
+ gamePath = os.path.join("games", "room - simple")
+ #gamePath = os.path.join("games", "roguelike")
gameScriptPath = os.path.join(dirPath, gamePath)
mudlibScriptPath = os.path.join(dirPath, "mudlib")
@@ -120,13 +121,13 @@
svcSvc.Register()
svcSvc.Start()
del svcSvc
-
+
stackless.getcurrent().block_trap = False
bootstrapState = STATE_RUNNING
manualShutdown = False
try:
- uthread.Run()
+ stacklesslibmain.mainloop.run()
except KeyboardInterrupt:
print
print '** EXITING: Server manually stopping.'
@@ -137,17 +138,18 @@
uthread2.PrintTaskletChain(stackless.current)
print
- if uthread.yieldChannel.queue:
- print "Yielded tasklets:"
- uthread2.PrintTaskletChain(uthread.yieldChannel.queue)
- print
-
- for timestamp, channel in uthread.sleepingTasklets:
- if channel.queue:
- print "Sleep channel (%d) tasklets:" % id(channel)
- uthread2.PrintTaskletChain(channel.queue)
+ if False:
+ for entry in stacklesslibmain.event_queue.queue_a:
+ print "Sleeping tasklets:"
+ uthread2.PrintTaskletChain(uthread.yieldChannel.queue)
print
+ for timestamp, channel in uthread.sleepingTasklets:
+ if channel.queue:
+ print "Sleep channel (%d) tasklets:" % id(channel)
+ uthread2.PrintTaskletChain(channel.queue)
+ print
+
manualShutdown = True
finally:
cr.EndMonitoring()
@@ -157,15 +159,16 @@
if manualShutdown:
class HelperClass:
def ShutdownComplete(self):
+ stacklesslibmain.mainloop.stop()
managerTasklet.kill()
helper = HelperClass()
events.ShutdownComplete.Register(helper.ShutdownComplete)
- uthread.new(sorrows.services.Stop)
+ stackless.tasklet(sorrows.services.Stop)()
# We have most likely killed the stacklesssocket tasklet.
managerTasklet = stacklesssocket.StartManager()
- uthread.Run()
+ stacklesslibmain.mainloop.run()
logging.info("Shutdown complete")
=======================================
--- /trunk/contrib/events.py Mon Mar 1 21:30:45 2010
+++ /trunk/contrib/events.py Fri Jan 7 05:23:18 2011
@@ -27,7 +27,7 @@
"""
import unittest, traceback, types, weakref, logging
-import uthread
+import stackless
logger = logging.getLogger("events")
@@ -73,7 +73,7 @@
class NonBlockingEvent(Event):
def __call__(self, *args, **kwargs):
- uthread.new(self.Broadcast, *args, **kwargs)
+ stackless.tasklet(self.Broadcast)(*args, **kwargs)
return self
# EVENT HANDLER:
=======================================
--- /trunk/contrib/livecoding/namespace.py Wed Sep 8 03:11:07 2010
+++ /trunk/contrib/livecoding/namespace.py Fri Jan 7 05:23:18 2011
@@ -150,7 +150,10 @@
# Skip actual builtin objects.
elif v in builtinValues or issubclass(v,
unittest.TestCase):
exportable = False
-
+ elif valueType is types.FunctionType:
+ funcFile = v.func_globals.get("__file__")
+ if funcFile:
+ exportable = funcFile.startswith(self.filePath)
yield k, v, valueType, exportable
=======================================
--- /trunk/contrib/livecoding/reloader.py Wed Sep 8 03:11:07 2010
+++ /trunk/contrib/livecoding/reloader.py Fri Jan 7 05:23:18 2011
@@ -7,9 +7,10 @@
import weakref
import time
import gc
+import traceback
logger = logging.getLogger("reloader")
-# logger.setLevel(logging.DEBUG)
+#logger.setLevel(logging.DEBUG)
# TODO: rename 'namespace.py' to 'namespaces.py' ... need to think about
it...
import namespace as namespaces
@@ -284,7 +285,9 @@
namespaceContributions = set()
- for attrName, ((oldValue, oldType), (newValue, newType)) in
attributeChanges.iteritems():
+ for attrName, ((oldValue, oldType), t2) in
attributeChanges.iteritems():
+ newValue, newType = t2
+
# No new value -> the old value is being leaked.
if newValue is NonExistentValue:
continue
@@ -292,6 +295,14 @@
if newType is types.ClassType or newType is types.TypeType:
self.UpdateClass(scriptFile, oldValue, newValue, globals_)
+ instances = self.FindClassInstances(newValue)
+ if len(instances):
+ logger.warn("Found %d instances of the %s class that
will be in the wild" % (len(instances), newValue.__name__))
+ # Try and patch the instances, in a naive way.
+ # - Should really check that oldValue is suited for
use.
+ for instance in instances:
+ instance.__class__ = oldValue
+
# If there was an old value, it is updated.
if oldValue and oldValue is not NonExistentValue:
logger.debug("Encountered existing class '%s' %s",
attrName, oldValue)
@@ -308,10 +319,10 @@
logger.debug("Skipped unchanged attribute '%s'", attrName)
continue
elif isinstance(newValue, types.FunctionType):
- logger.debug("Rebound method '%s'", attrName)
+ logger.debug("Updated and rebound function '%s'", attrName)
newValue = RebindFunction(newValue, globals_)
elif isinstance(newValue, types.UnboundMethodType) or
isinstance(newValue, types.MethodType):
- logger.debug("Rebound method '%s' to function", attrName)
+ logger.debug("Updated and rebound method '%s' to
function", attrName)
newValue = RebindFunction(newValue.im_func, globals_)
else:
logger.debug("Updated changed attribute '%s'", attrName)
@@ -328,10 +339,6 @@
def UpdateClass(self, scriptFile, value, newValue, globals_):
logger.debug("Updating class %s:%s from %s:%s", value,
hex(id(value)), newValue, hex(id(newValue)))
- instances = self.FindClassInstances(newValue)
- if len(instances):
- logger.warn("Found %d instances of the %s class that will be
in the wild" % (len(instances), newValue.__name__))
-
if value is None or value is NonExistentValue:
authoritativeValue = newValue
else:
@@ -380,11 +387,40 @@
except Exception:
logger.exception("Error broadcasting class update")
- def FindClassInstances(self, class_):
+ def FindClassInstances(self, class_, *knownReferences):
+ #cGlobals = None
+ #for v in class_.__dict__.itervalues():
+ # if type(v) is types.FunctionType:
+ # cGlobals = v.func_globals
+ # break
+
instances = []
- for referrer in gc.get_referrers(class_):
- if type(referrer) is types.InstanceType or type(referrer) is
class_:
- instances.append(referrer)
+ referrers1 = gc.get_referrers(class_)
+ for referrer1 in referrers1:
+ if type(referrer1) is types.InstanceType or type(referrer1) is
class_:
+ instances.append(referrer1)
+
+ #referrers2 = gc.get_referrers(referrer1)
+ #for referrer2 in referrers2:
+ # if referrer2 in [ instances, referrers2,
sys._getframe(), cGlobals, referrers1 ]:
+ # continue
+ # if referrer2 in knownReferences:
+ # continue
+
+ # print id(referrer1), "REFERRER2", type(referrer2),
hex(id(cGlobals))
+ # if type(referrer2) is list:
+ # # print "LIST", self.CountReferences(referrer2,
0, referrers2, *knownReferences), [ x for x in referrer2 ], "LIST_"
+ # print "LIST", [ x for x in referrer2 ], "LIST_"
+ # elif type(referrer2) is tuple:
+ # # print "TUPLE", self.CountReferences(referrer2,
0, referrers2, *knownReferences), [ x for x in referrer2 ], "TUPLE_"
+ # print "TUPLE", hex(id(referrer2)), [ x for x in
referrer2 ], "TUPLE_", [ hex(id(v)) for v in knownReferences ]
+ # elif type(referrer2) is dict:
+ # if "__file__" in referrer2:
+ # print "MODULE-DICT", referrer2["__file__"]
+ # else:
+ # print "DICT", hex(id(referrer2)),
referrer2.keys()
+ # else:
+ # print "????", type(referrer2)
return instances
#
------------------------------------------------------------------------
=======================================
--- /trunk/contrib/stacklesslib/NOTES Fri Jan 7 04:35:56 2011
+++ /trunk/contrib/stacklesslib/NOTES Fri Jan 7 05:23:18 2011
@@ -1,6 +1,12 @@
##
# 2011-01-07 - Richard
#
-# Entries in the event queue are abstracted away behind a wakeup function
-# so it is not possible enumerate all the blocked tasklets directly.
-#
+# - Entries in the event queue are abstracted away behind a wakeup
function
+# so it is not possible enumerate all the blocked tasklets directly.
+#
+# - Tasklets are created via stackless.tasklet(), might be a good idea to
+# provide a centralised location through which tasklets can be created.
+# Perhaps also allow a tasklet class to be registered.
+# - Top level exception catching in tasklets to prevent them from being
+# raised out.
+#
=======================================
--- /trunk/contrib/stacklesssocket.py Wed Dec 29 04:52:53 2010
+++ /trunk/contrib/stacklesssocket.py Fri Jan 7 05:23:18 2011
@@ -8,6 +8,11 @@
#
# Remaining work:
#
+# = Test suite that verifies that emulated behaviour is correct.
+# = When closing the socket, pending senders are sent ECONNRESET.
+# This was obtained by opening a server socket, connecting a
+# client and then closing the server. Then the client did a
+# send and got ECONNRESET.
# = Asyncore does not add that much to this module. In fact, its
# limitations and differences between implementations in different Python
# versions just complicate things.
@@ -32,8 +37,8 @@
# internal version of this module in use at CCP Games.
#
-import stackless
-import asyncore, weakref, time, select, types
+import stackless #, logging
+import asyncore, weakref, time, select, types, sys, gc
from collections import deque
# If you pump the scheduler and wish to prevent the scheduler from staying
@@ -57,7 +62,8 @@
import socket as stdsocket # We need the "socket" name for the function we
export.
try:
from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, \
- ENOTCONN, ESHUTDOWN, EINTR, EISCONN, EBADF, ECONNABORTED
+ ENOTCONN, ESHUTDOWN, EINTR, EISCONN, EBADF, ECONNABORTED, \
+ ECONNREFUSED
except Exception:
# Fallback on hard-coded PS3 constants.
EALREADY = 37
@@ -70,6 +76,7 @@
EISCONN = 56
EBADF = 9
ECONNABORTED = 53
+ ECONNREFUSED = 61
# If we are to masquerade as the socket module, we need to provide the
constants.
if "__all__" in stdsocket.__dict__:
@@ -170,6 +177,17 @@
accept.__doc__ = _socketobject_old.accept.__doc__
+def make_blocking_socket(family=AF_INET, type=SOCK_STREAM, proto=0):
+ """
+ Sometimes you may want to create a normal Python socket, even when
+ monkey-patching is in effect. One use case might be when you are
trying to
+ do socket operations on the last runnable tasklet, if these socket
+ operations are on small writes on a non-connected UDP socket then you
+ might as well just use a blocking socket, as the effect of blocking
+ is negligible.
+ """
+ _sock = _realsocket_old(family, type, proto)
+ return _socketobject_old(_sock=_sock)
def install(pi=None):
@@ -185,6 +203,65 @@
stdsocket._realsocket = _realsocket_old
stdsocket.socket = stdsocket.SocketType = stdsocket._socketobject =
_socketobject_old
+READY_TO_SCHEDULE_TAG = "_SET_ASIDE"
+
+def ready_to_schedule(flag):
+ """
+ There may be cases where it is desirable to have socket operations
happen before
+ an application starts up its framework, which would then poll
asyncore. This
+ function is intended to allow all sockets to be switched between
working
+ "stacklessly" or working directly on their underlying socket objects
in a
+ blocking manner.
+
+ Note that sockets created while this is in effect lack attribute
values that
+ asyncore or this module may have set if the sockets were created in a
full
+ monkey patched manner.
+ """
+
+ def reroute_wrapper(funcName):
+ def reroute_call(self, *args, **kwargs):
+ if READY_TO_SCHEDULE_TAG not in _fakesocket.__dict__:
+ return
+ return getattr(self.socket, funcName)(*args, **kwargs)
+ return reroute_call
+
+ def update_method_referrers(methodName, oldClassMethod,
newClassMethod):
+ """
+ The instance methods we need to update are stored in slots on
instances of
+ socket._socketobject (actually our replacement subclass
_socketobject_new).
+ """
+ for referrer1 in gc.get_referrers(oldClassMethod):
+ if isinstance(referrer1, types.MethodType):
+ for referrer2 in gc.get_referrers(referrer1):
+ if isinstance(referrer2, _socketobject_new):
+ setattr(referrer2, methodName,
types.MethodType(newClassMethod, referrer1.im_self, referrer1.im_class))
+
+ # Guard against removal if not in place.
+ if flag:
+ if READY_TO_SCHEDULE_TAG not in _fakesocket.__dict__:
+ return
+ del _fakesocket.__dict__[READY_TO_SCHEDULE_TAG]
+ else:
+ _fakesocket.__dict__[READY_TO_SCHEDULE_TAG] = None
+ # sys.__stdout__.write("READY_TO_SCHEDULE %s\n" % flag)
+
+ # Play switcheroo with the attributes to get direct socket usage, or
normal socket usage.
+ for attributeName in dir(_realsocket_old):
+ if not attributeName.startswith("_"):
+ storageAttributeName = attributeName +"_SET_ASIDE"
+ if flag:
+ storedValue =
_fakesocket.__dict__.pop(storageAttributeName, None)
+ if storedValue is not None:
+ rerouteValue = _fakesocket.__dict__[attributeName]
+ # sys.__stdout__.write("___ RESTORING %s (AS %s)
(WAS %s)\n" % (attributeName, storedValue, rerouteValue))
+ _fakesocket.__dict__[attributeName] = storedValue
+ update_method_referrers(attributeName, rerouteValue,
storedValue)
+ else:
+ if attributeName in _fakesocket.__dict__:
+ # sys.__stdout__.write("___ STORING %s = %s\n" %
(attributeName, _fakesocket.__dict__[attributeName]))
+ _fakesocket.__dict__[storageAttributeName] =
_fakesocket.__dict__[attributeName]
+ _fakesocket.__dict__[attributeName] =
reroute_wrapper(attributeName)
+
class _fakesocket(asyncore.dispatcher):
connectChannel = None
@@ -434,23 +511,23 @@
self.connected = False
self.accepting = False
- self.writeQueue = []
# Clear out all the channels with relevant errors.
while self.acceptChannel and self.acceptChannel.balance < 0:
- self.acceptChannel.send_exception(error, 9, 'Bad file
descriptor')
+ self.acceptChannel.send_exception(stdsocket.error, EBADF, 'Bad
file descriptor')
while self.connectChannel and self.connectChannel.balance < 0:
- self.connectChannel.send_exception(error, 10061, 'Connection
refused')
- self._clear_read_queue()
-
- def _clear_read_queue(self, *args):
- for t in self.readQueue:
+ self.connectChannel.send_exception(stdsocket.error,
ECONNREFUSED, 'Connection refused')
+ self._clear_queue(self.writeQueue, stdsocket.error, ECONNRESET)
+ self._clear_queue(self.readQueue)
+
+ def _clear_queue(self, queue, *args):
+ for t in queue:
if t[0].balance < 0:
if len(args):
t[0].send_exception(*args)
else:
t[0].send("")
- self.readQueue = []
+ queue.clear()
# asyncore doesn't support this. Why not?
def fileno(self):
@@ -503,6 +580,11 @@
# Asyncore says its done but self.readBuffer may be non-empty
# so can't close yet. Do nothing and let 'recv' trigger the close.
def handle_close(self):
+ # These do not interfere with ongoing reads, but should prevent
+ # sends and the like from going through.
+ self.connected = False
+ self.accepting = False
+
# This also gets called in the case that a non-blocking connect
gets
# back to us with a no. If we don't reject the connect, then all
# connect calls that do not connect will block indefinitely.
@@ -595,14 +677,17 @@
try:
result = self.socket.send(data, flags)
return result
- except socket.error, why:
+ except stdsocket.error, why:
+ # logging.root.exception("SOME SEND ERROR")
if why.args[0] == EWOULDBLOCK:
return 0
- elif why.args[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN,
ECONNABORTED):
+
+ # Ensure the sender appears to have directly received
this exception.
+ channel.send_exception(why.__class__, *why.args)
+
+ if why.args[0] in (ECONNRESET, ENOTCONN, ESHUTDOWN,
ECONNABORTED):
self.handle_close()
- return 0
- else:
- raise
+ return 0
nbytes = asyncore_send(self, data, flags)
if channel.balance < 0:
@@ -767,6 +852,10 @@
finally:
uninstall()
+ if "notready" in sys.argv:
+ sys.argv.remove("notready")
+ ready_to_schedule(False)
+
if len(sys.argv) == 2:
if sys.argv[1] == "client":
print "client started"
=======================================
--- /trunk/games/roguelike/services/world.py Tue Sep 14 06:55:50 2010
+++ /trunk/games/roguelike/services/world.py Fri Jan 7 05:23:18 2011
@@ -18,7 +18,9 @@
# Encapsulate a world.
-import os, random, time, collections, uthread, copy, weakref
+import os, random, time, collections, copy, weakref
+import stackless
+from stacklesslib.main import sleep as tasklet_sleep
from mudlib import Service
from game.world import Body, Object
@@ -160,7 +162,7 @@
self.mapWidth = len(self.mapRows[0])
self.mapHeight = len(self.mapRows)
- uthread.new(self.ManageFloraAndFauna)
+ stackless.tasklet(self.ManageFloraAndFauna)()
# Events
-----------------------------------------------------------------
@@ -356,13 +358,13 @@
# the dungeon freely. Two second tick for movement.
def ManageFloraAndFauna(self):
- uthread.new(self.RunNPC, CUBE_TILE, COLOUR_YELLOW)
- uthread.Sleep(10.0)
- uthread.new(self.RunNPC, DRAGON_TILE, COLOUR_GREEN)
- uthread.Sleep(10.0)
- uthread.new(self.RunNPC, DRAGON_TILE, COLOUR_GREEN)
- uthread.Sleep(10.0)
- uthread.new(self.RunNPC, DRAGON_TILE, COLOUR_GREEN)
+ stackless.tasklet(self.RunNPC, CUBE_TILE, COLOUR_YELLOW)()
+ tasklet_sleep(10.0)
+ stackless.tasklet(self.RunNPC, DRAGON_TILE, COLOUR_GREEN)()
+ tasklet_sleep(10.0)
+ stackless.tasklet(self.RunNPC, DRAGON_TILE, COLOUR_GREEN)()
+ tasklet_sleep(10.0)
+ stackless.tasklet(self.RunNPC, DRAGON_TILE, COLOUR_GREEN)()
def RunNPC(self, tile, fgColour, bgColour=None):
@@ -377,7 +379,7 @@
def OnObjectMoved(self, object_, oldPosition, newPosition):
if object_ is self:
if oldPosition is None:
- uthread.new(self.Wander)
+ stackless.tasklet(self.Wander)()
def Wander(self):
lastPosition = self.position
@@ -390,7 +392,7 @@
lastPosition = currentPosition
sorrows.world._MoveObject(self, random.choice(matches))
- uthread.Sleep(2.5 + -random.random())
+ tasklet_sleep(2.5 + -random.random())
class FireObject(Object):
@@ -404,7 +406,7 @@
self.components = []
self.componentsByPosition = {}
- uthread.new(self.ManageFire)
+ stackless.tasklet(self.ManageFire)()
def ManageFire(self):
fireObject = FireObject()
@@ -415,14 +417,14 @@
self.componentsByPosition[self.position] = fireObject
self.idx = -1
- uthread.Sleep(1.0)
+ tasklet_sleep(1.0)
while hasattr(sorrows, "world") and sorrows.world.IsRunning() and
len(self.components):
if self.position is None:
self.DieOut()
else:
self.Spread()
- uthread.Sleep(1.0 + -random.random() * 0.5)
+ tasklet_sleep(1.0 + -random.random() * 0.5)
def Spread(self):
lowWatermark = self.idx
=======================================
--- /trunk/games/roguelike/shells/login.py Fri Sep 10 22:00:18 2010
+++ /trunk/games/roguelike/shells/login.py Fri Jan 7 05:23:18 2011
@@ -1,5 +1,5 @@
-import logging
-import uthread
+import logging, stackless
+from stacklesslib.main import sleep as tasklet_sleep
from mudlib import InputHandler, Shell
import mudlib.shells
@@ -51,7 +51,7 @@
handler.Setup(self, self.ReceiveInput, self.WritePrompt, 0)
self.stack.SetShell(handler)
- uthread.new(self.StartTelnetNegotiation)
+ stackless.tasklet(self.StartTelnetNegotiation)()
def StartTelnetNegotiation(self):
telneg = self.user.connection.telneg
=======================================
--- /trunk/games/roguelike/shells/roguelike.py Tue Sep 14 06:55:50 2010
+++ /trunk/games/roguelike/shells/roguelike.py Fri Jan 7 05:23:18 2011
@@ -29,8 +29,9 @@
# - Clean up use of ViewedTileRange() so it can be degeneratorised.
#
-import random, array, math, StringIO, time
-import uthread, fov
+import random, array, math, StringIO, time, stackless
+from stacklesslib.main import sleep as tasklet_sleep
+import fov
from mudlib import Shell, InputHandler
# ASCII CODES
-----------------------------------------------------------------
@@ -249,7 +250,7 @@
# The way to differentiate is to use a timeout to wait
for
# the rest of the escape sequence, and if nothing
arrives
# to assume it is a keypress.
- self.escapeTasklet =
uthread.new(self.ReceiveInput_EscapeTimeout)
+ self.escapeTasklet =
stackless.tasklet(self.ReceiveInput_EscapeTimeout)()
return
if s[1] != '[':
@@ -281,7 +282,7 @@
# print "** ReceiveInput - DONE"
def ReceiveInput_EscapeTimeout(self):
- uthread.Sleep(0.1)
+ tasklet_sleep(0.1)
self.ReceiveInput("", flush=True)
def DispatchInputSequence(self, s):
=======================================
--- /trunk/games/sandbox/services/entityMap2D.py Fri Jan 8 11:31:29 2010
+++ /trunk/games/sandbox/services/entityMap2D.py Fri Jan 7 05:23:18 2011
@@ -15,4 +15,4 @@
def CreateEntity(self):
entity = game.worldMap2D.Entity(self)
self.entities.append(entity)
- uthread.new(entity.Run)
+ stackless.tasklet(entity.Run)()
=======================================
--- /trunk/games/sandbox/services/entityVoid.py Fri Jan 8 11:31:29 2010
+++ /trunk/games/sandbox/services/entityVoid.py Fri Jan 7 05:23:18 2011
@@ -19,7 +19,7 @@
def StartSimulation(self, startTime):
for entity in self.entities:
- uthread.new(entity.Run, startTime)
+ stackless.tasklet(entity.Run, startTime)()
def EndSimulation(self, startTime):
for entity in self.entities:
=======================================
--- /trunk/games/sandbox/services/world.py Fri Jan 8 11:31:29 2010
+++ /trunk/games/sandbox/services/world.py Fri Jan 7 05:23:18 2011
@@ -3,6 +3,7 @@
# Can only have one terrain.
import math, random, weakref, stackless
+from stacklesslib.main import sleep as tasklet_sleep
from mudlib import Service
class WorldService(Service):
@@ -36,7 +37,7 @@
return (vec[0] *height, vec[1]*height, vec[2] * height) + color
# return
x,y,self.example.GetSurfaceHeight(vec)-self.example.radius
- uthread.new(renderer.Render, getV)
+ stackless.tasklet(renderer.Render, getV)()
# Planet representation..
=======================================
--- /trunk/games/sandbox/services/worldVoid.py Tue Apr 29 15:59:16 2008
+++ /trunk/games/sandbox/services/worldVoid.py Fri Jan 7 05:23:18 2011
@@ -2,6 +2,7 @@
import os, random, time
+from stacklesslib.main import sleep as tasklet_sleep
from mudlib import Service
from game.worldVoid import Body
@@ -54,7 +55,7 @@
print "Simulation: Start", startTime, "period (s)", seconds
sorrows.entityVoid.StartSimulation(startTime)
endTime = startTime + seconds
- uthread.Sleep(seconds)
+ tasklet_sleep(seconds)
self.simulationStartTime = None
print "Simulation: End", endTime, "period (s)", seconds
=======================================
--- /trunk/games/sandbox/worldMap2D/entity.py Tue Apr 29 15:59:16 2008
+++ /trunk/games/sandbox/worldMap2D/entity.py Fri Jan 7 05:23:18 2011
@@ -1,4 +1,4 @@
-import uthread
+from stacklesslib.main import sleep as tasklet_sleep
class Entity:
def __init__(self, service):
@@ -12,4 +12,4 @@
# At mid-afternoon, have the entity head back home.
# That requires some sort of time service.
while self.service.IsRunning():
- uthread.Sleep(10)
+ tasklet_sleep(10)
=======================================
--- /trunk/games/sandbox/worldVoid/entity.py Mon Feb 22 01:00:45 2010
+++ /trunk/games/sandbox/worldVoid/entity.py Fri Jan 7 05:23:18 2011
@@ -1,7 +1,7 @@
# processing action has to take an amount of time.
# movement action has to take an amount of time.
-import uthread
+from stacklesslib.main import sleep as tasklet_sleep
import math
import game
@@ -129,7 +129,7 @@
self.Debug("bake", flourCount, "bread")
else:
self.Debug("wait for customer")
- uthread.Sleep(sleepDelay)
+ tasklet_sleep(sleepDelay)
self.Debug("done")
def FindEntitiesByProfession(self, profession):
=======================================
--- /trunk/mudlib/services/intermud3.py Wed Jan 13 21:55:08 2010
+++ /trunk/mudlib/services/intermud3.py Fri Jan 7 05:23:18 2011
@@ -1,4 +1,5 @@
-import socket, stackless, uthread
+import socket, stackless
+from stacklesslib.main import sleep as tasklet_sleep
from mudlib import Service
from mudlib.services import intermud3
@@ -31,7 +32,7 @@
self.desiredListenChannels = [ "imud_gossip", "discworld-chat" ]
self.connection = None
- uthread.new(self.ConnectToRouter)
+ stackless.tasklet(self.ConnectToRouter)()
#
-----------------------------------------------------------------------
# OnStop - Event indicating the service is being stopped
@@ -60,7 +61,7 @@
try:
currentSocket.connect((config.host, config.getint("port")))
except socket.error:
- uthread.new(self.ReconnectToRouter)
+ stackless.tasklet(self.ReconnectToRouter)()
return
self.LogInfo("Connected")
@@ -75,7 +76,7 @@
delay = float(sorrows.data.config.intermud3.reconnectiondelay)
self.LogInfo("Retrying router connection in %d seconds", delay)
- uthread.Sleep(delay)
+ tasklet_sleep(delay)
self.LogInfo("Reconnecting")
self.ConnectToRouter()
@@ -115,7 +116,7 @@
self.connection.Release()
self.connection = None
- uthread.new(self.ReconnectToRouter)
+ stackless.tasklet(self.ReconnectToRouter)()
def HandlePacket(self, config):
rawPacket = self.connection.ReadPacket()
@@ -145,7 +146,7 @@
self.routerName = packet.mudfrom
# Tell the router we want to listen to specific channels.
- uthread.new(self.SendChannelListenPackets,
self.desiredListenChannels)
+
stackless.tasklet(self.SendChannelListenPackets)(self.desiredListenChannels)
elif packet.__class__ is intermud3.MudlistPacket:
#if len(packet.infoByName) < 10:
=======================================
--- /trunk/mudlib/services/net/connectionTelnet.py Sat Sep 11 02:12:33 2010
+++ /trunk/mudlib/services/net/connectionTelnet.py Fri Jan 7 05:23:18 2011
@@ -1,4 +1,5 @@
-import stackless, uthread
+import stackless
+from stacklesslib.main import sleep as tasklet_sleep
from mudlib.services.net import Connection
from mudlib import User
@@ -23,12 +24,12 @@
if False:
self.user = None
self.preLoginBuffer = StringIO.StringIO()
- uthread.new(self._ManageConnectionPreLogin)
+ stackless.tasklet(self._ManageConnectionPreLogin)()
self.user = User(self, "login")
self.user.SetupInputStack()
- uthread.new(self.ManageConnection)
+ stackless.tasklet(self.ManageConnection)()
def SetPasswordMode(self, flag):
if flag:
@@ -119,7 +120,7 @@
# print "RECEIVED AFTER", slept, "DATA", data
del dataQueue[:]
- uthread.Sleep(0.01)
+ tasklet_sleep(0.01)
slept += 0.01
def OnDisconnection(self):
=======================================
--- /trunk/mudlib/services/net.py Tue Mar 16 20:38:04 2010
+++ /trunk/mudlib/services/net.py Fri Jan 7 05:23:18 2011
@@ -3,7 +3,8 @@
# get the external intermud service working on it seems a bit
hodgepodge.
# ?
-import uthread, asyncore, socket
+import stackless
+import asyncore, socket
from mudlib.services.net import TelnetConnection, MudConnection, Connection
from mudlib import User
from mudlib import Service
@@ -25,7 +26,7 @@
listenSocket.bind((host, port))
listenSocket.listen(5)
self.LogInfo("Listening on address %s:%s", host, port)
- uthread.new(self.AcceptTelnetConnections, listenSocket)
+ stackless.tasklet(self.AcceptTelnetConnections)(listenSocket)
def AcceptTelnetConnections(self, listenSocket):
acceptNonLocal = int(sorrows.data.config.net.acceptnonlocal)
=======================================
--- /trunk/mudlib/services/opencyc.py Fri Jan 8 11:31:29 2010
+++ /trunk/mudlib/services/opencyc.py Fri Jan 7 05:23:18 2011
@@ -42,7 +42,7 @@
self.LogInfo("Connected.")
self.connection = connection
- uthread.new(self.ManageConnection)
+ stackless.tasklet(self.ManageConnection)()
#
-----------------------------------------------------------------------
# OnDisconnection - A socket disconnected.
=======================================
--- /trunk/mudlib/services/service.py Wed Jan 20 18:35:16 2010
+++ /trunk/mudlib/services/service.py Fri Jan 7 05:23:18 2011
@@ -1,7 +1,7 @@
from mudlib import Service
import types, random, weakref
import stackless
-import uthread
+from stacklesslib.main import sleep as tasklet_sleep
class ServiceService(Service):
@@ -101,7 +101,7 @@
# Give tasklets that are no longer valid due to the
stopping of their
# service a chance to exit before further services in the
dependency
# order are stopped next.
- uthread.BeNice()
+ tasklet_sleep(0)
cnt -= 1
if not cnt:
self.LogError("Unable to stop services: %s",
self.runningServices.keys())