import threading

import synapse.glob as s_glob

class CmpSet:
    '''
    The CmpSet class facilitates atomic compare and set.
    '''
    def __init__(self, valu):
        self.valu = valu

    def set(self, valu):
        '''
        Atomically set the valu and return change status.

        Args:
            valu (obj): The new value

        Returns:
            (bool): True if the value changed.
        '''
        with s_glob.lock:
            retn = self.valu != valu
            self.valu = valu
            return retn

class Ready:
    '''
    Atomic inc/dec state with ready event above a threshold.
    '''
    def __init__(self, size, valu=0, lock=None):

        if lock is None:
            lock = s_glob.lock

        self.lock = lock
        self.valu = valu
        self.size = size
        self.evnt = threading.Event()

        self._maySetEvent()

    def _maySetEvent(self):

        if self.valu >= self.size and not self.evnt.is_set():
            self.evnt.set()
            return

        if self.evnt.is_set():
            self.evnt.clear()

    def wait(self, timeout=None):

        self.evnt.wait(timeout=timeout)
        return self.evnt.is_set()

    def inc(self, valu=1):

        with self.lock:
            self.valu += valu
            self._maySetEvent()

    def dec(self, valu=1):

        with self.lock:
            self.valu -= valu
            self._maySetEvent()

    def __enter__(self):
        self.inc()

    def __exit__(self, exc, cls, tb):
        self.dec()

class Serialize:
    '''
    Implements a todo queue which harnesses only 1 thread at a time.
    '''
    def __init__(self, dist):
        self.dist = dist
        self.todo = collections.deque()
        self.running = False

    def dist(self, mesg):

        with s_glob.lock:
            self.todo.append(mesg)
            want = self._wantCallDist()

        if want:
            self._callDistFunc()

    def _wantCallDist(self):
        if not self.running:
            self.running = True
            return True

    def puts(self, msgs):
        with s_glob.lock:
            self.todo.extend(msgs)
            want = self._wantCallFire()

        if want:
            self._callDistFunc()

    def _callDistFunc(self):

        while self.running:

            while self.todo:
                self.dist(self.todo.popleft())

            with s_glob.lock:
                if not self.todo:
                    self.running = False

#def serialize(f):
    #f._seri_todo = collections.deque()

class Counter:
    '''
    The Counter class facilitates atomic counter incrementing/decrementing.

    Args:
        valu (int): Value to start the counter at.
        lock (threading.Lock): The lock used to protect the counter value.

    Notes:
        This uses the default Synapse global thread lock by default.
    '''
    def __init__(self, valu=0, lock=None):
        if lock is None:
            lock = s_glob.lock
        self._lock = lock
        self._valu = valu

    def inc(self, valu=1):
        '''
        Atomically increment the counter and return the new value.

        Args:
            valu (int): Value too increment the counter by.

        Notes:
            The valu passed to inc may be an negative integer in order to decrement the counter value.

        Returns:
            int: The new value of the counter after the increment operation has been performed.
        '''
        with self._lock:
            self._valu += valu
            return self._valu

    def valu(self):
        '''
        Get the current counter valu

        Returns:
            int: The current counter value
        '''
        with self._lock:
            return self._valu

    def set(self, valu=0):
        '''
        Resets the counter to a value.

        Args:
            valu (int): Value to set the counter too.

        Returns:
            int: The current counter value after setting it.
        '''
        with self._lock:
            self._valu = valu
            return self._valu

class retnwait:
    '''
    Emulate synchronous callback waiting with a thread local event.

    Example:

    With retnwait() as retn:
        dothing(callback=retn)
        isset, valu = retn.wait(timeout=3)

    '''
    def __init__(self):

        thrd = threading.currentThread()

        self._retn_valu = None

        self._retn_evnt = getattr(thrd, '_retn_lock', None)
        if self._retn_evnt is None:
            self._retn_evnt = thrd._retn_lock = threading.Event()

        # ensure the event is clear
        self._retn_evnt.clear()

    def wait(self, timeout=None):
        '''
        Wait for an async callback to complete.

        Args:
            timeout (int/float): Timeout in seconds.
        '''
        evnt = self._retn_evnt
        if evnt is None:
            return True, self._retn_evnt

        evnt.wait(timeout=timeout)
        return self._retn_valu

    def retn(self, valu):
        '''
        An ease-of-use API for single value callbacks.
        '''
        with s_glob.lock:
            self._retn_valu = valu

    def retncall(self, *args, **kwargs):

        with s_glob.lock:
            self._retn_valu = (args, kwargs)
            if self._retn_evnt is not None:
                self._retn_evnt.set()

    def __enter__(self):
        return self

    def __exit__(self, exc, cls, tb):

        with s_glob.lock:
            self._retn_evnt.clear()
            self._retn_evnt = None


@@ -531,1995 +531,8 @@
 tn%0A%0A
-class Ready:%0A    '''%0A    Atomic inc/dec state with ready event above a threshold.%0A    '''%0A    def __init__(self, size, valu=0, lock=None):%0A%0A        if lock is None:%0A            lock = s_glob.lock%0A%0A        self.lock = lock%0A        self.valu = valu%0A        self.size = size%0A        self.evnt = threading.Event()%0A%0A        self._maySetEvent()%0A%0A    def _maySetEvent(self):%0A%0A        if self.valu %3E= self.size and not self.evnt.is_set():%0A            self.evnt.set()%0A            return%0A%0A        if self.evnt.is_set():%0A            self.evnt.clear()%0A%0A    def wait(self, timeout=None):%0A%0A        self.evnt.wait(timeout=timeout)%0A        return self.evnt.is_set()%0A%0A    def inc(self, valu=1):%0A%0A        with self.lock:%0A            self.valu += valu%0A            self._maySetEvent()%0A%0A    def dec(self, valu=1):%0A%0A        with self.lock:%0A            self.valu -= valu%0A            self._maySetEvent()%0A%0A    def __enter__(self):%0A        self.inc()%0A%0A    def __exit__(self, exc, cls, tb):%0A        self.dec()%0A%0Aclass Serialize:%0A    '''%0A    Implements a todo queue which harnesses only 1 thread at a time.%0A    '''%0A    def __init__(self, dist):%0A        self.dist = dist%0A        self.todo = collections.deque()%0A        self.running = False%0A%0A    def dist(self, mesg):%0A%0A        with s_glob.lock:%0A            self.todo.append(mesg)%0A            want = self._wantCallDist()%0A%0A        if want:%0A            self._callDistFunc()%0A%0A    def _wantCallDist(self):%0A        if not self.running:%0A            self.running = True%0A            return True%0A%0A    def puts(self, msgs):%0A        with s_glob.lock:%0A            self.todo.extend(msgs)%0A            want = self._wantCallFire()%0A%0A        if want:%0A            self._callDistFunc()%0A%0A    def _callDistFunc(self):%0A%0A        while self.running:%0A%0A            while self.todo:%0A                self.dist(self.todo.popleft())%0A%0A            with s_glob.lock:%0A                if not self.todo:%0A                    self.running = False%0A%0A#def serialize(f):%0A    #f._seri_todo = collections.deque()%0A%0A
 clas
@@ -2042,1440 +2042,4 @@
 alu%0A
-%0Aclass retnwait:%0A    '''%0A    Emulate synchronous callback waiting with a thread local event.%0A%0A    Example:%0A%0A    With retnwait() as retn:%0A        dothing(callback=retn)%0A        isset, valu = retn.wait(timeout=3)%0A%0A    '''%0A    def __init__(self):%0A%0A        thrd = threading.currentThread()%0A%0A        self._retn_valu = None%0A%0A        self._retn_evnt = getattr(thrd, '_retn_lock', None)%0A        if self._retn_evnt is None:%0A            self._retn_evnt = thrd._retn_lock = threading.Event()%0A%0A        # ensure the event is clear%0A        self._retn_evnt.clear()%0A%0A    def wait(self, timeout=None):%0A        '''%0A        Wait for an async callback to complete.%0A%0A        Args:%0A            timeout (int/float): Timeout in seconds.%0A        '''%0A        evnt = self._retn_evnt%0A        if evnt is None:%0A            return True, self._retn_evnt%0A%0A        evnt.wait(timeout=timeout)%0A        return self._retn_valu%0A%0A    def retn(self, valu):%0A        '''%0A        An ease-of-use API for single value callbacks.%0A        '''%0A        with s_glob.lock:%0A            self._retn_valu = valu%0A%0A    def retncall(self, *args, **kwargs):%0A%0A        with s_glob.lock:%0A            self._retn_valu = (args, kwargs)%0A            if self._retn_evnt is not None:%0A                self._retn_evnt.set()%0A%0A    def __enter__(self):%0A        return self%0A%0A    def __exit__(self, exc, cls, tb):%0A%0A        with s_glob.lock:%0A            self._retn_evnt.clear()%0A            self._retn_evnt = None%0A%0A

Revert changes to synapse.lib.atomic