# Path: offset/sync/atomic.py
# class AtomicLong(object):
#     def __init__(self, initial_value):
#         self._storage = ffi.new('long *', initial_value)
# 
#     def __repr__(self):
#         return '<{0} at 0x{1:x}: {2!r}>'.format(
#             self.__class__.__name__, id(self), self.value)
# 
#     @property
#     def value(self):
#         return self._storage[0]
# 
#     @value.setter
#     def value(self, new):
#         lib.long_bool_compare_and_swap(self._storage, self.value, new)
# 
#     def add(self, delta):
#         """ atomically adds delta and returns the new value """
#         if delta >= 0:
#             lib.long_add_and_fetch(self._storage, delta)
#         else:
#             lib.long_sub_and_fetch(self._storage, abs(delta))
# 
#         return self._storage[0]
# 
# 
#     def __iadd__(self, inc):
#         lib.long_add_and_fetch(self._storage, inc)
#         return self
# 
#     def __isub__(self, dec):
#         lib.long_sub_and_fetch(self._storage, dec)
#         return self
# 
#     def __eq__(self, other):
#         if isinstance(other, AtomicLong):
#             return self.value == other.value
#         else:
#             return self.value == other
# 
#     def __ne__(self, other):
#         return not (self == other)
# 
#     def __lt__(self, other):
#         if isinstance(other, AtomicLong):
#             return self.value < other.value
#         else:
#             return self.value < other
# 
# Path: offset/core/context.py
# def park(self, g=None):
#     g = g or proc.current()
#     g.sleeping = True
#     try:
#         self.runq.remove(g)
#     except ValueError:
#         pass
#     self.schedule()
# 
# Path: offset/core/proc.py
# class ProcExit(Exception):
# class Proc(object):
# def current():
#     def __init__(self, m, func, args, kwargs):
#         def _run():
#     def switch(self):
#     def throw(self, *args):
#     def park(self):
#     def ready(self):
#     def is_alive(self):
#     def terminate(self):
#     def __eq__(self, other):
# def _create_main_proc():


from collections import deque
from .atomic import AtomicLong
from ..core.context import park
from ..core import proc
# -*- coding: utf-8 -
#
# This file is part of offset. See the NOTICE for more information.




class Semaphore(object):
    """ Semaphore implementation exposed to offset

    Intended use is provide a sleep and wakeup primitive that can be used in the
    contended case of other synchronization primitives.

    Thus it targets the same goal as Linux's futex, but it has much simpler
    semantics.

    That is, don't think of these as semaphores. Think of them as a way to
    implement sleep and wakeup such that every sleep is paired with a single
    wakeup, even if, due to races, the wakeup happens before the sleep.

    See Mullender and Cox, ``Semaphores in Plan 9,''
    http://swtch.com/semaphore.pdf

    Comment and code based on the Go code:
    http://golang.org/src/pkg/runtime/sema.goc
    """

    def __init__(self, value=0):
        self.sema = AtomicLong(value)

# Path: offset/sync/atomic.py
# class AtomicLong(object):
#     def __init__(self, initial_value):
#         self._storage = ffi.new('long *', initial_value)
# 
#     def __repr__(self):
#         return '<{0} at 0x{1:x}: {2!r}>'.format(
#             self.__class__.__name__, id(self), self.value)
# 
#     @property
#     def value(self):
#         return self._storage[0]
# 
#     @value.setter
#     def value(self, new):
#         lib.long_bool_compare_and_swap(self._storage, self.value, new)
# 
#     def add(self, delta):
#         """ atomically adds delta and returns the new value """
#         if delta >= 0:
#             lib.long_add_and_fetch(self._storage, delta)
#         else:
#             lib.long_sub_and_fetch(self._storage, abs(delta))
# 
#         return self._storage[0]
# 
# 
#     def __iadd__(self, inc):
#         lib.long_add_and_fetch(self._storage, inc)
#         return self
# 
#     def __isub__(self, dec):
#         lib.long_sub_and_fetch(self._storage, dec)
#         return self
# 
#     def __eq__(self, other):
#         if isinstance(other, AtomicLong):
#             return self.value == other.value
#         else:
#             return self.value == other
# 
#     def __ne__(self, other):
#         return not (self == other)
# 
#     def __lt__(self, other):
#         if isinstance(other, AtomicLong):
#             return self.value < other.value
#         else:
#             return self.value < other
# 
# Path: offset/core/context.py
# def park(self, g=None):
#     g = g or proc.current()
#     g.sleeping = True
#     try:
#         self.runq.remove(g)
#     except ValueError:
#         pass
#     self.schedule()
# 
# Path: offset/core/proc.py
# class ProcExit(Exception):
# class Proc(object):
# def current():
#     def __init__(self, m, func, args, kwargs):
#         def _run():
#     def switch(self):
#     def throw(self, *args):
#     def park(self):
#     def ready(self):
#     def is_alive(self):
#     def terminate(self):
#     def __eq__(self, other):
# def _create_main_proc():


# Path: offset/sync/sema.py
from collections import deque
from .atomic import AtomicLong
from ..core.context import park
from ..core import proc

# -*- coding: utf-8 -
#
# This file is part of offset. See the NOTICE for more information.




class Semaphore(object):
    """ Semaphore implementation exposed to offset

    Intended use is provide a sleep and wakeup primitive that can be used in the
    contended case of other synchronization primitives.

    Thus it targets the same goal as Linux's futex, but it has much simpler
    semantics.

    That is, don't think of these as semaphores. Think of them as a way to
    implement sleep and wakeup such that every sleep is paired with a single
    wakeup, even if, due to races, the wakeup happens before the sleep.

    See Mullender and Cox, ``Semaphores in Plan 9,''
    http://swtch.com/semaphore.pdf

    Comment and code based on the Go code:
    http://golang.org/src/pkg/runtime/sema.goc
    """

    def __init__(self, value=0):
        self.sema = AtomicLong(value)

        self.nwait = AtomicLong(1)