Create a commands.process function which runs a function inside a separate process.

This is the only way to limit the execution time of a possibly long-running python statement.
Use this on String.re, due to the possibility of pathologically long re matching in python.
This allows us to remove the 'trusted-only' restriction on string.re.
In the future, this should probably be used in other places that take user-supplied regexps,
such as 'misc last --regexp', for example, as well as other potentially long-running tasks
that can block the bot.

Conflicts:

	plugins/String/plugin.py
	src/commands.py
This commit is contained in:
Daniel Folkinshteyn 2010-08-05 01:20:46 -04:00 committed by Valentin Lorentz
parent 0d97adadc4
commit 37597bfe94
5 changed files with 32 additions and 1 deletions

View File

@ -33,12 +33,14 @@ import binascii
import supybot.utils as utils import supybot.utils as utils
from supybot.commands import * from supybot.commands import *
import supybot.commands as commands
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
from supybot.i18n import PluginInternationalization, internationalizeDocstring from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('String') _ = PluginInternationalization('String')
import multiprocessing
class String(callbacks.Plugin): class String(callbacks.Plugin):
@internationalizeDocstring @internationalizeDocstring

View File

@ -988,6 +988,23 @@ class CommandThread(world.SupyThread):
finally: finally:
self.cb.threaded = self.originalThreaded self.cb.threaded = self.originalThreaded
class CommandProcess(world.SupyProcess):
"""Just does some extra logging and error-recovery for commands that need
to run in processes.
"""
def __init__(self, target=None, args=(), kwargs={}):
self.command = args[0]
self.cb = target.im_self
procName = 'Process #%s (for %s.%s)' % (world.processesSpawned,
self.cb.name(),
self.command)
log.debug('Spawning process %s (args: %r)', procName, args)
self.__parent = super(CommandProcess, self)
self.__parent.__init__(target=target, name=procName,
args=args, kwargs=kwargs)
def run(self):
self.__parent.run()
class CanonicalString(registry.NormalizedString): class CanonicalString(registry.NormalizedString):
def normalize(self, s): def normalize(self, s):

View File

@ -37,6 +37,8 @@ import types
import getopt import getopt
import inspect import inspect
import threading import threading
import multiprocessing #python2.6 or later!
import Queue
import supybot.log as log import supybot.log as log
import supybot.conf as conf import supybot.conf as conf

View File

@ -1,3 +1,3 @@
"""stick the various versioning attributes in here, so we only have to change """stick the various versioning attributes in here, so we only have to change
them once.""" them once."""
version = '0.83.4.1+limnoria (2011-08-13T01:59:18+0200)' version = '0.83.4.1+limnoria (2011-08-15T17:24:33+0200)'

View File

@ -37,6 +37,7 @@ import sys
import time import time
import atexit import atexit
import threading import threading
import multiprocessing # python 2.6 and later!
if sys.version_info >= (2, 5, 0): if sys.version_info >= (2, 5, 0):
import re as sre import re as sre
@ -67,6 +68,15 @@ class SupyThread(threading.Thread):
super(SupyThread, self).__init__(*args, **kwargs) super(SupyThread, self).__init__(*args, **kwargs)
log.debug('Spawning thread %q.', self.getName()) log.debug('Spawning thread %q.', self.getName())
processesSpawned = 1 # Starts at one for the initial process.
class SupyProcess(multiprocessing.Process):
def __init__(self, *args, **kwargs):
global processesSpawned
processesSpawned += 1
super(SupyProcess, self).__init__(*args, **kwargs)
log.debug('Spawning process %q.', self.name)
commandsProcessed = 0 commandsProcessed = 0
ircs = [] # A list of all the IRCs. ircs = [] # A list of all the IRCs.