2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/docs/LICENCE-python.txt Tue Jun 12 01:40:10 2012 +0200
2.3 @@ -0,0 +1,193 @@
2.4 +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
2.5 +--------------------------------------------
2.6 +
2.7 +1. This LICENSE AGREEMENT is between the Python Software Foundation
2.8 +("PSF"), and the Individual or Organization ("Licensee") accessing and
2.9 +otherwise using this software ("Python") in source or binary form and
2.10 +its associated documentation.
2.11 +
2.12 +2. Subject to the terms and conditions of this License Agreement, PSF
2.13 +hereby grants Licensee a nonexclusive, royalty-free, world-wide
2.14 +license to reproduce, analyze, test, perform and/or display publicly,
2.15 +prepare derivative works, distribute, and otherwise use Python
2.16 +alone or in any derivative version, provided, however, that PSF's
2.17 +License Agreement and PSF's notice of copyright, i.e., "Copyright (c)
2.18 +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Python Software Foundation;
2.19 +All Rights Reserved" are retained in Python alone or in any derivative
2.20 +version prepared by Licensee.
2.21 +
2.22 +3. In the event Licensee prepares a derivative work that is based on
2.23 +or incorporates Python or any part thereof, and wants to make
2.24 +the derivative work available to others as provided herein, then
2.25 +Licensee hereby agrees to include in any such work a brief summary of
2.26 +the changes made to Python.
2.27 +
2.28 +4. PSF is making Python available to Licensee on an "AS IS"
2.29 +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
2.30 +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
2.31 +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
2.32 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
2.33 +INFRINGE ANY THIRD PARTY RIGHTS.
2.34 +
2.35 +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
2.36 +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
2.37 +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
2.38 +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
2.39 +
2.40 +6. This License Agreement will automatically terminate upon a material
2.41 +breach of its terms and conditions.
2.42 +
2.43 +7. Nothing in this License Agreement shall be deemed to create any
2.44 +relationship of agency, partnership, or joint venture between PSF and
2.45 +Licensee. This License Agreement does not grant permission to use PSF
2.46 +trademarks or trade name in a trademark sense to endorse or promote
2.47 +products or services of Licensee, or any third party.
2.48 +
2.49 +8. By copying, installing or otherwise using Python, Licensee
2.50 +agrees to be bound by the terms and conditions of this License
2.51 +Agreement.
2.52 +
2.53 +
2.54 +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
2.55 +-------------------------------------------
2.56 +
2.57 +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
2.58 +
2.59 +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
2.60 +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
2.61 +Individual or Organization ("Licensee") accessing and otherwise using
2.62 +this software in source or binary form and its associated
2.63 +documentation ("the Software").
2.64 +
2.65 +2. Subject to the terms and conditions of this BeOpen Python License
2.66 +Agreement, BeOpen hereby grants Licensee a non-exclusive,
2.67 +royalty-free, world-wide license to reproduce, analyze, test, perform
2.68 +and/or display publicly, prepare derivative works, distribute, and
2.69 +otherwise use the Software alone or in any derivative version,
2.70 +provided, however, that the BeOpen Python License is retained in the
2.71 +Software, alone or in any derivative version prepared by Licensee.
2.72 +
2.73 +3. BeOpen is making the Software available to Licensee on an "AS IS"
2.74 +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
2.75 +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
2.76 +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
2.77 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
2.78 +INFRINGE ANY THIRD PARTY RIGHTS.
2.79 +
2.80 +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
2.81 +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
2.82 +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
2.83 +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
2.84 +
2.85 +5. This License Agreement will automatically terminate upon a material
2.86 +breach of its terms and conditions.
2.87 +
2.88 +6. This License Agreement shall be governed by and interpreted in all
2.89 +respects by the law of the State of California, excluding conflict of
2.90 +law provisions. Nothing in this License Agreement shall be deemed to
2.91 +create any relationship of agency, partnership, or joint venture
2.92 +between BeOpen and Licensee. This License Agreement does not grant
2.93 +permission to use BeOpen trademarks or trade names in a trademark
2.94 +sense to endorse or promote products or services of Licensee, or any
2.95 +third party. As an exception, the "BeOpen Python" logos available at
2.96 +http://www.pythonlabs.com/logos.html may be used according to the
2.97 +permissions granted on that web page.
2.98 +
2.99 +7. By copying, installing or otherwise using the software, Licensee
2.100 +agrees to be bound by the terms and conditions of this License
2.101 +Agreement.
2.102 +
2.103 +
2.104 +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
2.105 +---------------------------------------
2.106 +
2.107 +1. This LICENSE AGREEMENT is between the Corporation for National
2.108 +Research Initiatives, having an office at 1895 Preston White Drive,
2.109 +Reston, VA 20191 ("CNRI"), and the Individual or Organization
2.110 +("Licensee") accessing and otherwise using Python 1.6.1 software in
2.111 +source or binary form and its associated documentation.
2.112 +
2.113 +2. Subject to the terms and conditions of this License Agreement, CNRI
2.114 +hereby grants Licensee a nonexclusive, royalty-free, world-wide
2.115 +license to reproduce, analyze, test, perform and/or display publicly,
2.116 +prepare derivative works, distribute, and otherwise use Python 1.6.1
2.117 +alone or in any derivative version, provided, however, that CNRI's
2.118 +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
2.119 +1995-2001 Corporation for National Research Initiatives; All Rights
2.120 +Reserved" are retained in Python 1.6.1 alone or in any derivative
2.121 +version prepared by Licensee. Alternately, in lieu of CNRI's License
2.122 +Agreement, Licensee may substitute the following text (omitting the
2.123 +quotes): "Python 1.6.1 is made available subject to the terms and
2.124 +conditions in CNRI's License Agreement. This Agreement together with
2.125 +Python 1.6.1 may be located on the Internet using the following
2.126 +unique, persistent identifier (known as a handle): 1895.22/1013. This
2.127 +Agreement may also be obtained from a proxy server on the Internet
2.128 +using the following URL: http://hdl.handle.net/1895.22/1013".
2.129 +
2.130 +3. In the event Licensee prepares a derivative work that is based on
2.131 +or incorporates Python 1.6.1 or any part thereof, and wants to make
2.132 +the derivative work available to others as provided herein, then
2.133 +Licensee hereby agrees to include in any such work a brief summary of
2.134 +the changes made to Python 1.6.1.
2.135 +
2.136 +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
2.137 +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
2.138 +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
2.139 +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
2.140 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
2.141 +INFRINGE ANY THIRD PARTY RIGHTS.
2.142 +
2.143 +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
2.144 +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
2.145 +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
2.146 +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
2.147 +
2.148 +6. This License Agreement will automatically terminate upon a material
2.149 +breach of its terms and conditions.
2.150 +
2.151 +7. This License Agreement shall be governed by the federal
2.152 +intellectual property law of the United States, including without
2.153 +limitation the federal copyright law, and, to the extent such
2.154 +U.S. federal law does not apply, by the law of the Commonwealth of
2.155 +Virginia, excluding Virginia's conflict of law provisions.
2.156 +Notwithstanding the foregoing, with regard to derivative works based
2.157 +on Python 1.6.1 that incorporate non-separable material that was
2.158 +previously distributed under the GNU General Public License (GPL), the
2.159 +law of the Commonwealth of Virginia shall govern this License
2.160 +Agreement only as to issues arising under or with respect to
2.161 +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
2.162 +License Agreement shall be deemed to create any relationship of
2.163 +agency, partnership, or joint venture between CNRI and Licensee. This
2.164 +License Agreement does not grant permission to use CNRI trademarks or
2.165 +trade name in a trademark sense to endorse or promote products or
2.166 +services of Licensee, or any third party.
2.167 +
2.168 +8. By clicking on the "ACCEPT" button where indicated, or by copying,
2.169 +installing or otherwise using Python 1.6.1, Licensee agrees to be
2.170 +bound by the terms and conditions of this License Agreement.
2.171 +
2.172 + ACCEPT
2.173 +
2.174 +
2.175 +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
2.176 +--------------------------------------------------
2.177 +
2.178 +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
2.179 +The Netherlands. All rights reserved.
2.180 +
2.181 +Permission to use, copy, modify, and distribute this software and its
2.182 +documentation for any purpose and without fee is hereby granted,
2.183 +provided that the above copyright notice appear in all copies and that
2.184 +both that copyright notice and this permission notice appear in
2.185 +supporting documentation, and that the name of Stichting Mathematisch
2.186 +Centrum or CWI not be used in advertising or publicity pertaining to
2.187 +distribution of the software without specific, written prior
2.188 +permission.
2.189 +
2.190 +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
2.191 +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
2.192 +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
2.193 +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2.194 +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2.195 +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
2.196 +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/lib/threading.py Tue Jun 12 01:40:10 2012 +0200
3.3 @@ -0,0 +1,825 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +Thread module emulating a subset of Java's threading model.
3.8 +
3.9 +See docs/COPYING.txt and docs/LICENCE-python.txt for copyright and licensing
3.10 +information for Python standard library modules.
3.11 +"""
3.12 +
3.13 +import sys as _sys
3.14 +
3.15 +try:
3.16 + import thread
3.17 +except ImportError:
3.18 + del _sys.modules[__name__]
3.19 + raise
3.20 +
3.21 +from time import time as _time, sleep as _sleep
3.22 +from traceback import format_exc as _format_exc
3.23 +from collections import deque
3.24 +
3.25 +# Rename some stuff so "from threading import *" is safe
3.26 +__all__ = ['activeCount', 'Condition', 'currentThread', 'enumerate', 'Event',
3.27 + 'Lock', 'RLock', 'Semaphore', 'BoundedSemaphore', 'Thread',
3.28 + 'Timer', 'setprofile', 'settrace', 'local', 'stack_size']
3.29 +
3.30 +_start_new_thread = thread.start_new_thread
3.31 +_allocate_lock = thread.allocate_lock
3.32 +_get_ident = thread.get_ident
3.33 +ThreadError = thread.error
3.34 +del thread
3.35 +
3.36 +
3.37 +# Support for profile and trace hooks
3.38 +
3.39 +_profile_hook = None
3.40 +_trace_hook = None
3.41 +
3.42 +def setprofile(func):
3.43 + global _profile_hook
3.44 + _profile_hook = func
3.45 +
3.46 +def settrace(func):
3.47 + global _trace_hook
3.48 + _trace_hook = func
3.49 +
3.50 +# Synchronization classes
3.51 +
3.52 +Lock = _allocate_lock
3.53 +
3.54 +def RLock(*args, **kwargs):
3.55 + return _RLock(*args, **kwargs)
3.56 +
3.57 +class _RLock:
3.58 +
3.59 + def __init__(self):
3.60 + self.__block = _allocate_lock()
3.61 + self.__owner = None
3.62 + self.__count = 0
3.63 +
3.64 + def __repr__(self):
3.65 + owner = self.__owner
3.66 + return "<%s(%s, %d)>" % (
3.67 + self.__class__.__name__,
3.68 + owner and owner.getName(),
3.69 + self.__count)
3.70 +
3.71 + def acquire(self, blocking=1):
3.72 + me = currentThread()
3.73 + if self.__owner is me:
3.74 + self.__count = self.__count + 1
3.75 + if __debug__:
3.76 + self._note("%s.acquire(%s): recursive success", self, blocking)
3.77 + return 1
3.78 + rc = self.__block.acquire(blocking)
3.79 + if rc:
3.80 + self.__owner = me
3.81 + self.__count = 1
3.82 + if __debug__:
3.83 + self._note("%s.acquire(%s): initial success", self, blocking)
3.84 + else:
3.85 + if __debug__:
3.86 + self._note("%s.acquire(%s): failure", self, blocking)
3.87 + return rc
3.88 +
3.89 + __enter__ = acquire
3.90 +
3.91 + def release(self):
3.92 + if self.__owner is not currentThread():
3.93 + raise RuntimeError("cannot release un-aquired lock")
3.94 + self.__count = count = self.__count - 1
3.95 + if not count:
3.96 + self.__owner = None
3.97 + self.__block.release()
3.98 + if __debug__:
3.99 + self._note("%s.release(): final release", self)
3.100 + else:
3.101 + if __debug__:
3.102 + self._note("%s.release(): non-final release", self)
3.103 +
3.104 + def __exit__(self, t, v, tb):
3.105 + self.release()
3.106 +
3.107 + # Internal methods used by condition variables
3.108 +
3.109 + def _acquire_restore(self, (count, owner)):
3.110 + self.__block.acquire()
3.111 + self.__count = count
3.112 + self.__owner = owner
3.113 + if __debug__:
3.114 + self._note("%s._acquire_restore()", self)
3.115 +
3.116 + def _release_save(self):
3.117 + if __debug__:
3.118 + self._note("%s._release_save()", self)
3.119 + count = self.__count
3.120 + self.__count = 0
3.121 + owner = self.__owner
3.122 + self.__owner = None
3.123 + self.__block.release()
3.124 + return (count, owner)
3.125 +
3.126 + def _is_owned(self):
3.127 + return self.__owner is currentThread()
3.128 +
3.129 +
3.130 +def Condition(*args, **kwargs):
3.131 + return _Condition(*args, **kwargs)
3.132 +
3.133 +class _Condition:
3.134 +
3.135 + def __init__(self, lock=None):
3.136 + if lock is None:
3.137 + lock = RLock()
3.138 + self.__lock = lock
3.139 + # Export the lock's acquire() and release() methods
3.140 + self.acquire = lock.acquire
3.141 + self.release = lock.release
3.142 + # If the lock defines _release_save() and/or _acquire_restore(),
3.143 + # these override the default implementations (which just call
3.144 + # release() and acquire() on the lock). Ditto for _is_owned().
3.145 + try:
3.146 + self._release_save = lock._release_save
3.147 + except AttributeError:
3.148 + pass
3.149 + try:
3.150 + self._acquire_restore = lock._acquire_restore
3.151 + except AttributeError:
3.152 + pass
3.153 + try:
3.154 + self._is_owned = lock._is_owned
3.155 + except AttributeError:
3.156 + pass
3.157 + self.__waiters = []
3.158 +
3.159 + def __enter__(self):
3.160 + return self.__lock.__enter__()
3.161 +
3.162 + def __exit__(self, *args):
3.163 + return self.__lock.__exit__(*args)
3.164 +
3.165 + def __repr__(self):
3.166 + return "<Condition(%s, %d)>" % (self.__lock, len(self.__waiters))
3.167 +
3.168 + def _release_save(self):
3.169 + self.__lock.release() # No state to save
3.170 +
3.171 + def _acquire_restore(self, x):
3.172 + self.__lock.acquire() # Ignore saved state
3.173 +
3.174 + def _is_owned(self):
3.175 + # Return True if lock is owned by currentThread.
3.176 + # This method is called only if __lock doesn't have _is_owned().
3.177 + if self.__lock.acquire(0):
3.178 + self.__lock.release()
3.179 + return False
3.180 + else:
3.181 + return True
3.182 +
3.183 + def wait(self, timeout=None):
3.184 + if not self._is_owned():
3.185 + raise RuntimeError("cannot wait on un-aquired lock")
3.186 + waiter = _allocate_lock()
3.187 + waiter.acquire()
3.188 + self.__waiters.append(waiter)
3.189 + saved_state = self._release_save()
3.190 + try: # restore state no matter what (e.g., KeyboardInterrupt)
3.191 + if timeout is None:
3.192 + waiter.acquire()
3.193 + if __debug__:
3.194 + self._note("%s.wait(): got it", self)
3.195 + else:
3.196 + # Balancing act: We can't afford a pure busy loop, so we
3.197 + # have to sleep; but if we sleep the whole timeout time,
3.198 + # we'll be unresponsive. The scheme here sleeps very
3.199 + # little at first, longer as time goes on, but never longer
3.200 + # than 20 times per second (or the timeout time remaining).
3.201 + endtime = _time() + timeout
3.202 + delay = 0.0005 # 500 us -> initial delay of 1 ms
3.203 + while True:
3.204 + gotit = waiter.acquire(0)
3.205 + if gotit:
3.206 + break
3.207 + remaining = endtime - _time()
3.208 + if remaining <= 0:
3.209 + break
3.210 + delay = min(delay * 2, remaining, .05)
3.211 + _sleep(delay)
3.212 + if not gotit:
3.213 + if __debug__:
3.214 + self._note("%s.wait(%s): timed out", self, timeout)
3.215 + try:
3.216 + self.__waiters.remove(waiter)
3.217 + except ValueError:
3.218 + pass
3.219 + else:
3.220 + if __debug__:
3.221 + self._note("%s.wait(%s): got it", self, timeout)
3.222 + finally:
3.223 + self._acquire_restore(saved_state)
3.224 +
3.225 + def notify(self, n=1):
3.226 + if not self._is_owned():
3.227 + raise RuntimeError("cannot notify on un-aquired lock")
3.228 + __waiters = self.__waiters
3.229 + waiters = __waiters[:n]
3.230 + if not waiters:
3.231 + if __debug__:
3.232 + self._note("%s.notify(): no waiters", self)
3.233 + return
3.234 + self._note("%s.notify(): notifying %d waiter%s", self, n,
3.235 + n!=1 and "s" or "")
3.236 + for waiter in waiters:
3.237 + waiter.release()
3.238 + try:
3.239 + __waiters.remove(waiter)
3.240 + except ValueError:
3.241 + pass
3.242 +
3.243 + def notifyAll(self):
3.244 + self.notify(len(self.__waiters))
3.245 +
3.246 +
3.247 +def Semaphore(*args, **kwargs):
3.248 + return _Semaphore(*args, **kwargs)
3.249 +
3.250 +class _Semaphore:
3.251 +
3.252 + # After Tim Peters' semaphore class, but not quite the same (no maximum)
3.253 +
3.254 + def __init__(self, value=1):
3.255 + if value < 0:
3.256 + raise ValueError("semaphore initial value must be >= 0")
3.257 + self.__cond = Condition(Lock())
3.258 + self.__value = value
3.259 +
3.260 + def acquire(self, blocking=1):
3.261 + rc = False
3.262 + self.__cond.acquire()
3.263 + while self.__value == 0:
3.264 + if not blocking:
3.265 + break
3.266 + if __debug__:
3.267 + self._note("%s.acquire(%s): blocked waiting, value=%s",
3.268 + self, blocking, self.__value)
3.269 + self.__cond.wait()
3.270 + else:
3.271 + self.__value = self.__value - 1
3.272 + if __debug__:
3.273 + self._note("%s.acquire: success, value=%s",
3.274 + self, self.__value)
3.275 + rc = True
3.276 + self.__cond.release()
3.277 + return rc
3.278 +
3.279 + __enter__ = acquire
3.280 +
3.281 + def release(self):
3.282 + self.__cond.acquire()
3.283 + self.__value = self.__value + 1
3.284 + if __debug__:
3.285 + self._note("%s.release: success, value=%s",
3.286 + self, self.__value)
3.287 + self.__cond.notify()
3.288 + self.__cond.release()
3.289 +
3.290 + def __exit__(self, t, v, tb):
3.291 + self.release()
3.292 +
3.293 +
3.294 +def BoundedSemaphore(*args, **kwargs):
3.295 + return _BoundedSemaphore(*args, **kwargs)
3.296 +
3.297 +class _BoundedSemaphore(_Semaphore):
3.298 + """Semaphore that checks that # releases is <= # acquires"""
3.299 + def __init__(self, value=1):
3.300 + _Semaphore.__init__(self, value)
3.301 + self._initial_value = value
3.302 +
3.303 + def release(self):
3.304 + if self._Semaphore__value >= self._initial_value:
3.305 + raise ValueError, "Semaphore released too many times"
3.306 + return _Semaphore.release(self)
3.307 +
3.308 +
3.309 +def Event(*args, **kwargs):
3.310 + return _Event(*args, **kwargs)
3.311 +
3.312 +class _Event:
3.313 +
3.314 + # After Tim Peters' event class (without is_posted())
3.315 +
3.316 + def __init__(self):
3.317 + self.__cond = Condition(Lock())
3.318 + self.__flag = False
3.319 +
3.320 + def isSet(self):
3.321 + return self.__flag
3.322 +
3.323 + def set(self):
3.324 + self.__cond.acquire()
3.325 + try:
3.326 + self.__flag = True
3.327 + self.__cond.notifyAll()
3.328 + finally:
3.329 + self.__cond.release()
3.330 +
3.331 + def clear(self):
3.332 + self.__cond.acquire()
3.333 + try:
3.334 + self.__flag = False
3.335 + finally:
3.336 + self.__cond.release()
3.337 +
3.338 + def wait(self, timeout=None):
3.339 + self.__cond.acquire()
3.340 + try:
3.341 + if not self.__flag:
3.342 + self.__cond.wait(timeout)
3.343 + finally:
3.344 + self.__cond.release()
3.345 +
3.346 +# Helper to generate new thread names
3.347 +_counter = 0
3.348 +def _newname(template="Thread-%d"):
3.349 + global _counter
3.350 + _counter = _counter + 1
3.351 + return template % _counter
3.352 +
3.353 +# Active thread administration
3.354 +_active_limbo_lock = _allocate_lock()
3.355 +_active = {} # maps thread id to Thread object
3.356 +_limbo = {}
3.357 +
3.358 +
3.359 +# Main class for threads
3.360 +
3.361 +class Thread:
3.362 +
3.363 + __initialized = False
3.364 + # Need to store a reference to sys.exc_info for printing
3.365 + # out exceptions when a thread tries to use a global var. during interp.
3.366 + # shutdown and thus raises an exception about trying to perform some
3.367 + # operation on/with a NoneType
3.368 + __exc_info = _sys.exc_info
3.369 +
3.370 + def __init__(self, group=None, target=None, name=None,
3.371 + args=(), kwargs=None):
3.372 + assert group is None, "group argument must be None for now"
3.373 + if kwargs is None:
3.374 + kwargs = {}
3.375 + self.__target = target
3.376 + self.__name = str(name or _newname())
3.377 + self.__args = args
3.378 + self.__kwargs = kwargs
3.379 + self.__daemonic = self._set_daemon()
3.380 + self.__started = False
3.381 + self.__stopped = False
3.382 + self.__block = Condition(Lock())
3.383 + self.__initialized = True
3.384 + # sys.stderr is not stored in the class like
3.385 + # sys.exc_info since it can be changed between instances
3.386 + self.__stderr = _sys.stderr
3.387 +
3.388 + def _set_daemon(self):
3.389 + # Overridden in _MainThread and _DummyThread
3.390 + return currentThread().isDaemon()
3.391 +
3.392 + def __repr__(self):
3.393 + assert self.__initialized, "Thread.__init__() was not called"
3.394 + status = "initial"
3.395 + if self.__started:
3.396 + status = "started"
3.397 + if self.__stopped:
3.398 + status = "stopped"
3.399 + if self.__daemonic:
3.400 + status = status + " daemon"
3.401 + return "<%s(%s, %s)>" % (self.__class__.__name__, self.__name, status)
3.402 +
3.403 + def start(self):
3.404 + if not self.__initialized:
3.405 + raise RuntimeError("thread.__init__() not called")
3.406 + if self.__started:
3.407 + raise RuntimeError("thread already started")
3.408 + if __debug__:
3.409 + self._note("%s.start(): starting thread", self)
3.410 + _active_limbo_lock.acquire()
3.411 + _limbo[self] = self
3.412 + _active_limbo_lock.release()
3.413 + _start_new_thread(self.__bootstrap, ())
3.414 + self.__started = True
3.415 + _sleep(0.000001) # 1 usec, to let the thread run (Solaris hack)
3.416 +
3.417 + def run(self):
3.418 + if self.__target:
3.419 + self.__target(*self.__args, **self.__kwargs)
3.420 +
3.421 + def __bootstrap(self):
3.422 + # Wrapper around the real bootstrap code that ignores
3.423 + # exceptions during interpreter cleanup. Those typically
3.424 + # happen when a daemon thread wakes up at an unfortunate
3.425 + # moment, finds the world around it destroyed, and raises some
3.426 + # random exception *** while trying to report the exception in
3.427 + # __bootstrap_inner() below ***. Those random exceptions
3.428 + # don't help anybody, and they confuse users, so we suppress
3.429 + # them. We suppress them only when it appears that the world
3.430 + # indeed has already been destroyed, so that exceptions in
3.431 + # __bootstrap_inner() during normal business hours are properly
3.432 + # reported. Also, we only suppress them for daemonic threads;
3.433 + # if a non-daemonic encounters this, something else is wrong.
3.434 + try:
3.435 + self.__bootstrap_inner()
3.436 + except:
3.437 + if self.__daemonic and _sys is None:
3.438 + return
3.439 + raise
3.440 +
3.441 + def __bootstrap_inner(self):
3.442 + try:
3.443 + self.__started = True
3.444 + _active_limbo_lock.acquire()
3.445 + _active[_get_ident()] = self
3.446 + del _limbo[self]
3.447 + _active_limbo_lock.release()
3.448 + if __debug__:
3.449 + self._note("%s.__bootstrap(): thread started", self)
3.450 +
3.451 + if _trace_hook:
3.452 + self._note("%s.__bootstrap(): registering trace hook", self)
3.453 + _sys.settrace(_trace_hook)
3.454 + if _profile_hook:
3.455 + self._note("%s.__bootstrap(): registering profile hook", self)
3.456 + _sys.setprofile(_profile_hook)
3.457 +
3.458 + try:
3.459 + self.run()
3.460 + except SystemExit:
3.461 + if __debug__:
3.462 + self._note("%s.__bootstrap(): raised SystemExit", self)
3.463 + except:
3.464 + if __debug__:
3.465 + self._note("%s.__bootstrap(): unhandled exception", self)
3.466 + # If sys.stderr is no more (most likely from interpreter
3.467 + # shutdown) use self.__stderr. Otherwise still use sys (as in
3.468 + # _sys) in case sys.stderr was redefined since the creation of
3.469 + # self.
3.470 + if _sys:
3.471 + _sys.stderr.write("Exception in thread %s:\n%s\n" %
3.472 + (self.getName(), _format_exc()))
3.473 + else:
3.474 + # Do the best job possible w/o a huge amt. of code to
3.475 + # approximate a traceback (code ideas from
3.476 + # Lib/traceback.py)
3.477 + exc_type, exc_value, exc_tb = self.__exc_info()
3.478 + try:
3.479 + print>>self.__stderr, (
3.480 + "Exception in thread " + self.getName() +
3.481 + " (most likely raised during interpreter shutdown):")
3.482 + print>>self.__stderr, (
3.483 + "Traceback (most recent call last):")
3.484 + while exc_tb:
3.485 + print>>self.__stderr, (
3.486 + ' File "%s", line %s, in %s' %
3.487 + (exc_tb.tb_frame.f_code.co_filename,
3.488 + exc_tb.tb_lineno,
3.489 + exc_tb.tb_frame.f_code.co_name))
3.490 + exc_tb = exc_tb.tb_next
3.491 + print>>self.__stderr, ("%s: %s" % (exc_type, exc_value))
3.492 + # Make sure that exc_tb gets deleted since it is a memory
3.493 + # hog; deleting everything else is just for thoroughness
3.494 + finally:
3.495 + del exc_type, exc_value, exc_tb
3.496 + else:
3.497 + if __debug__:
3.498 + self._note("%s.__bootstrap(): normal return", self)
3.499 + finally:
3.500 + _active_limbo_lock.acquire()
3.501 + try:
3.502 + self.__stop()
3.503 + try:
3.504 + # We don't call self.__delete() because it also
3.505 + # grabs _active_limbo_lock.
3.506 + del _active[_get_ident()]
3.507 + except:
3.508 + pass
3.509 + finally:
3.510 + _active_limbo_lock.release()
3.511 +
3.512 + def __stop(self):
3.513 + self.__block.acquire()
3.514 + self.__stopped = True
3.515 + self.__block.notifyAll()
3.516 + self.__block.release()
3.517 +
3.518 + def __delete(self):
3.519 + "Remove current thread from the dict of currently running threads."
3.520 +
3.521 + # Notes about running with dummy_thread:
3.522 + #
3.523 + # Must take care to not raise an exception if dummy_thread is being
3.524 + # used (and thus this module is being used as an instance of
3.525 + # dummy_threading). dummy_thread.get_ident() always returns -1 since
3.526 + # there is only one thread if dummy_thread is being used. Thus
3.527 + # len(_active) is always <= 1 here, and any Thread instance created
3.528 + # overwrites the (if any) thread currently registered in _active.
3.529 + #
3.530 + # An instance of _MainThread is always created by 'threading'. This
3.531 + # gets overwritten the instant an instance of Thread is created; both
3.532 + # threads return -1 from dummy_thread.get_ident() and thus have the
3.533 + # same key in the dict. So when the _MainThread instance created by
3.534 + # 'threading' tries to clean itself up when atexit calls this method
3.535 + # it gets a KeyError if another Thread instance was created.
3.536 + #
3.537 + # This all means that KeyError from trying to delete something from
3.538 + # _active if dummy_threading is being used is a red herring. But
3.539 + # since it isn't if dummy_threading is *not* being used then don't
3.540 + # hide the exception.
3.541 +
3.542 + _active_limbo_lock.acquire()
3.543 + try:
3.544 + try:
3.545 + del _active[_get_ident()]
3.546 + except KeyError:
3.547 + if 'dummy_threading' not in _sys.modules:
3.548 + raise
3.549 + finally:
3.550 + _active_limbo_lock.release()
3.551 +
3.552 + def join(self, timeout=None):
3.553 + if not self.__initialized:
3.554 + raise RuntimeError("Thread.__init__() not called")
3.555 + if not self.__started:
3.556 + raise RuntimeError("cannot join thread before it is started")
3.557 + if self is currentThread():
3.558 + raise RuntimeError("cannot join current thread")
3.559 +
3.560 + if __debug__:
3.561 + if not self.__stopped:
3.562 + self._note("%s.join(): waiting until thread stops", self)
3.563 + self.__block.acquire()
3.564 + try:
3.565 + if timeout is None:
3.566 + while not self.__stopped:
3.567 + self.__block.wait()
3.568 + if __debug__:
3.569 + self._note("%s.join(): thread stopped", self)
3.570 + else:
3.571 + deadline = _time() + timeout
3.572 + while not self.__stopped:
3.573 + delay = deadline - _time()
3.574 + if delay <= 0:
3.575 + if __debug__:
3.576 + self._note("%s.join(): timed out", self)
3.577 + break
3.578 + self.__block.wait(delay)
3.579 + else:
3.580 + if __debug__:
3.581 + self._note("%s.join(): thread stopped", self)
3.582 + finally:
3.583 + self.__block.release()
3.584 +
3.585 + def getName(self):
3.586 + assert self.__initialized, "Thread.__init__() not called"
3.587 + return self.__name
3.588 +
3.589 + def setName(self, name):
3.590 + assert self.__initialized, "Thread.__init__() not called"
3.591 + self.__name = str(name)
3.592 +
3.593 + def isAlive(self):
3.594 + assert self.__initialized, "Thread.__init__() not called"
3.595 + return self.__started and not self.__stopped
3.596 +
3.597 + def isDaemon(self):
3.598 + assert self.__initialized, "Thread.__init__() not called"
3.599 + return self.__daemonic
3.600 +
3.601 + def setDaemon(self, daemonic):
3.602 + if not self.__initialized:
3.603 + raise RuntimeError("Thread.__init__() not called")
3.604 + if self.__started:
3.605 + raise RuntimeError("cannot set daemon status of active thread");
3.606 + self.__daemonic = daemonic
3.607 +
3.608 +# The timer class was contributed by Itamar Shtull-Trauring
3.609 +
3.610 +def Timer(*args, **kwargs):
3.611 + return _Timer(*args, **kwargs)
3.612 +
3.613 +class _Timer(Thread):
3.614 + """Call a function after a specified number of seconds:
3.615 +
3.616 + t = Timer(30.0, f, args=[], kwargs={})
3.617 + t.start()
3.618 + t.cancel() # stop the timer's action if it's still waiting
3.619 + """
3.620 +
3.621 + def __init__(self, interval, function, args=[], kwargs={}):
3.622 + Thread.__init__(self)
3.623 + self.interval = interval
3.624 + self.function = function
3.625 + self.args = args
3.626 + self.kwargs = kwargs
3.627 + self.finished = Event()
3.628 +
3.629 + def cancel(self):
3.630 + """Stop the timer if it hasn't finished yet"""
3.631 + self.finished.set()
3.632 +
3.633 + def run(self):
3.634 + self.finished.wait(self.interval)
3.635 + if not self.finished.isSet():
3.636 + self.function(*self.args, **self.kwargs)
3.637 + self.finished.set()
3.638 +
3.639 +# Special thread class to represent the main thread
3.640 +# This is garbage collected through an exit handler
3.641 +
3.642 +class _MainThread(Thread):
3.643 +
3.644 + def __init__(self):
3.645 + Thread.__init__(self, name="MainThread")
3.646 + self._Thread__started = True
3.647 + _active_limbo_lock.acquire()
3.648 + _active[_get_ident()] = self
3.649 + _active_limbo_lock.release()
3.650 +
3.651 + def _set_daemon(self):
3.652 + return False
3.653 +
3.654 + def _exitfunc(self):
3.655 + self._Thread__stop()
3.656 + t = _pickSomeNonDaemonThread()
3.657 + if t:
3.658 + if __debug__:
3.659 + self._note("%s: waiting for other threads", self)
3.660 + while t:
3.661 + t.join()
3.662 + t = _pickSomeNonDaemonThread()
3.663 + if __debug__:
3.664 + self._note("%s: exiting", self)
3.665 + self._Thread__delete()
3.666 +
3.667 +def _pickSomeNonDaemonThread():
3.668 + for t in enumerate():
3.669 + if not t.isDaemon() and t.isAlive():
3.670 + return t
3.671 + return None
3.672 +
3.673 +
3.674 +# Dummy thread class to represent threads not started here.
3.675 +# These aren't garbage collected when they die, nor can they be waited for.
3.676 +# If they invoke anything in threading.py that calls currentThread(), they
3.677 +# leave an entry in the _active dict forever after.
3.678 +# Their purpose is to return *something* from currentThread().
3.679 +# They are marked as daemon threads so we won't wait for them
3.680 +# when we exit (conform previous semantics).
3.681 +
3.682 +class _DummyThread(Thread):
3.683 +
3.684 + def __init__(self):
3.685 + Thread.__init__(self, name=_newname("Dummy-%d"))
3.686 +
3.687 + # Thread.__block consumes an OS-level locking primitive, which
3.688 + # can never be used by a _DummyThread. Since a _DummyThread
3.689 + # instance is immortal, that's bad, so release this resource.
3.690 + del self._Thread__block
3.691 +
3.692 + self._Thread__started = True
3.693 + _active_limbo_lock.acquire()
3.694 + _active[_get_ident()] = self
3.695 + _active_limbo_lock.release()
3.696 +
3.697 + def _set_daemon(self):
3.698 + return True
3.699 +
3.700 + def join(self, timeout=None):
3.701 + assert False, "cannot join a dummy thread"
3.702 +
3.703 +
3.704 +# Global API functions
3.705 +
3.706 +def currentThread():
3.707 + try:
3.708 + return _active[_get_ident()]
3.709 + except KeyError:
3.710 + ##print "currentThread(): no current thread for", _get_ident()
3.711 + return _DummyThread()
3.712 +
3.713 +def activeCount():
3.714 + _active_limbo_lock.acquire()
3.715 + count = len(_active) + len(_limbo)
3.716 + _active_limbo_lock.release()
3.717 + return count
3.718 +
3.719 +def enumerate():
3.720 + _active_limbo_lock.acquire()
3.721 + active = _active.values() + _limbo.values()
3.722 + _active_limbo_lock.release()
3.723 + return active
3.724 +
3.725 +from thread import stack_size
3.726 +
3.727 +# Create the main thread object,
3.728 +# and make it available for the interpreter
3.729 +# (Py_Main) as threading._shutdown.
3.730 +
3.731 +_shutdown = _MainThread()._exitfunc
3.732 +
3.733 +# get thread-local implementation, either from the thread
3.734 +# module, or from the python fallback
3.735 +
3.736 +try:
3.737 + from thread import _local as local
3.738 +except ImportError:
3.739 + from _threading_local import local
3.740 +
3.741 +
3.742 +# Self-test code
3.743 +
3.744 +def _test():
3.745 +
3.746 + class BoundedQueue:
3.747 +
3.748 + def __init__(self, limit):
3.749 + self.mon = RLock()
3.750 + self.rc = Condition(self.mon)
3.751 + self.wc = Condition(self.mon)
3.752 + self.limit = limit
3.753 + self.queue = deque()
3.754 +
3.755 + def put(self, item):
3.756 + self.mon.acquire()
3.757 + while len(self.queue) >= self.limit:
3.758 + self._note("put(%s): queue full", item)
3.759 + self.wc.wait()
3.760 + self.queue.append(item)
3.761 + self._note("put(%s): appended, length now %d",
3.762 + item, len(self.queue))
3.763 + self.rc.notify()
3.764 + self.mon.release()
3.765 +
3.766 + def get(self):
3.767 + self.mon.acquire()
3.768 + while not self.queue:
3.769 + self._note("get(): queue empty")
3.770 + self.rc.wait()
3.771 + item = self.queue.popleft()
3.772 + self._note("get(): got %s, %d left", item, len(self.queue))
3.773 + self.wc.notify()
3.774 + self.mon.release()
3.775 + return item
3.776 +
3.777 + class ProducerThread(Thread):
3.778 +
3.779 + def __init__(self, queue, quota):
3.780 + Thread.__init__(self, name="Producer")
3.781 + self.queue = queue
3.782 + self.quota = quota
3.783 +
3.784 + def run(self):
3.785 + from random import random
3.786 + counter = 0
3.787 + while counter < self.quota:
3.788 + counter = counter + 1
3.789 + self.queue.put("%s.%d" % (self.getName(), counter))
3.790 + _sleep(random() * 0.00001)
3.791 +
3.792 +
3.793 + class ConsumerThread(Thread):
3.794 +
3.795 + def __init__(self, queue, count):
3.796 + Thread.__init__(self, name="Consumer")
3.797 + self.queue = queue
3.798 + self.count = count
3.799 +
3.800 + def run(self):
3.801 + while self.count > 0:
3.802 + item = self.queue.get()
3.803 + print item
3.804 + self.count = self.count - 1
3.805 +
3.806 + NP = 3
3.807 + QL = 4
3.808 + NI = 5
3.809 +
3.810 + Q = BoundedQueue(QL)
3.811 + P = []
3.812 + for i in range(NP):
3.813 + t = ProducerThread(Q, NI)
3.814 + t.setName("Producer-%d" % (i+1))
3.815 + P.append(t)
3.816 + C = ConsumerThread(Q, NI*NP)
3.817 + for t in P:
3.818 + t.start()
3.819 + _sleep(0.000001)
3.820 + C.start()
3.821 + for t in P:
3.822 + t.join()
3.823 + C.join()
3.824 +
3.825 +if __name__ == '__main__':
3.826 + _test()
3.827 +
3.828 +# vim: tabstop=4 expandtab shiftwidth=4