""" Threading logic.

The functionality here improves upon that in the standard L{threading} module.
"""
from __future__ import absolute_import
import threading, os.path, traceback

from srllib import util
from srllib.error import *

class ThreadError(SrlError):
    """ Encapsulation of an exception caught in a thread.
    @ivar name: Thread name.
    @ivar exc_type: Exception type.
    @ivar exc_value: Exception value.
    @ivar exc_traceback: Exception traceback.
    """
    def __init__(self, name, exc_info):
        SrlError.__init__(self, "An exception was caught in thread '%s':\n%s" %
                (name, " ".join(traceback.format_exception(*exc_info))))
        self.name = name
        self.exc_type, self.exc_value, self.exc_traceback = exc_info

class Cancellation(Exception):
    pass

class TimeoutError(Exception):
    pass

def _def_handler(thread_exc):
    print thread_exc
_prev_handler = _exc_handler = _def_handler

def register_exceptionhandler(handler):
    """ Register a handler for exceptions happening in background thread.

    The exception handler will receive a L{ThreadError}. """
    global _exc_handler, _prev_handler
    if _prev_handler != handler:
        _prev_handler = handler
    _exc_handler = handler

def restore_exceptionhandler():
    """ Restore global exception handler to previous one. """
    global _exc_handler, _prev_handler
    _exc_handler = _prev_handler

def synchronized(func):
    """ Decorator for making functions thread-safe. """
    def syncfunc(*args, **kwds):
        func._sync_lock.acquire()
        try: r = func(*args, **kwds)
        finally: func._sync_lock.release()
        return r
    
    func._sync_lock = threading.Lock()
    return syncfunc

_thread_specific = {}

class Lock(object):
    def __init__(self, *args, **kwds):
        self._lk = threading.Lock()
        self.__inError = None

    def acquire(self, *args, **kwds):
        ret = self._lk.acquire(*args, **kwds)
        if ret:
            global _thread_specific
            try:
                locks = _thread_specific[Thread.current_thread()]["locks"]
                locks.append(self)
            except KeyError:
                pass
        if self.__inError:
            raise self.__inError
        return ret

    def release(self, *args, **kwds):