Example #1
0
    def close(self):
        if self.closed:
            return

        self.closed = True

        # Pending takes get "channel closed"
        while True:
            try:
                taker = self.takes.pop()
            except IndexError:
                break
            if taker.is_active():
                callback = taker.commit()
                dispatch.run(lambda: callback(CLOSED))

        # Pending puts get "channel closed"
        while True:
            try:
                putter = self.puts.pop()
            except IndexError:
                break
            handler = putter.handler
            if handler.is_active():
                callback = handler.commit()
                dispatch.run(lambda: callback(False))
Example #2
0
    def put(self, value, handler):
        if value == CLOSED:
            raise Exception("Cannot put csp.CLOSED on a channel.")

        if self.closed or not handler.is_active():
            return Box(not self.closed)

        while True:
            try:
                taker = self.takes.pop()
            except IndexError:
                taker = None
            # There's a pending take...
            if taker is not None:
                # ... that is still interested
                if taker.is_active():
                    # Done, shake hand, here it is
                    callback, _ = taker.commit(), handler.commit()
                    # FIX
                    dispatch.run(lambda: callback(value))
                    return Box(True)
                else:
                    continue
            # No pending takes
            else:
                # Throw the value on the queue and be done with it
                if self.buf is not None and not self.buf.is_full():
                    handler.commit()
                    self.buf.add(value)
                    return Box(True)
                # No more room for waiting
                else:
                    # Periodically remove stale puts
                    if self.dirty_puts > MAX_DIRTY:
                        self.puts.cleanup(keep = lambda putter: putter.handler.is_active())
                        self.dirty_puts = 0
                    else:
                        self.dirty_puts += 1

                    # TODO: Do a last-chance "garbage collection" to
                    # be sure?
                    if len(self.puts) >= MAX_QUEUE_SIZE:
                        raise Exception("No more than %d pending puts are allowed on a single channel." % MAX_QUEUE_SIZE)

                    # Queue this put
                    self.puts.unbounded_unshift(PutBox(handler, value))
            break
Example #3
0
 def _done(self, value):
     if not self.finished:
         # print self, "finished"
         self.finished = True
         if self.finish_callback:
             dispatch.run(lambda: self.finish_callback(value))
Example #4
0
    def take(self, handler):
        if not handler.is_active():
            return

        # Waiting values go first
        if self.buf is not None and len(self.buf) > 0:
            handler.commit()
            # We need to check pending puts here, otherwise they won't
            # be able to proceed until their number reaches MAX_DIRTY
            value = self.buf.remove()
            while True:
                try:
                    putter = self.puts.pop()
                except IndexError:
                    break
                else:
                    put_handler = putter.handler
                    if put_handler.is_active():
                        callback = put_handler.commit()
                        dispatch.run(lambda: callback(True))
                        self.buf.add(putter.value)
                        break
                    else:
                        continue
            return Box(value)

        while True:
            try:
                putter = self.puts.pop()
            except IndexError:
                putter = None
            # There's a pending put...
            if putter is not None:
                put_handler = putter.handler
                # ... that is still interested
                if put_handler.is_active():
                    # Done, shake hand, take it
                    callback, _ = put_handler.commit(), handler.commit()
                    dispatch.run(lambda: callback(True))
                    return Box(putter.value)
                else:
                    continue
            # No pending puts
            else:
                if self.closed:
                    handler.commit()
                    return Box(CLOSED)
                else:
                    # Periodically remove stale takes
                    if self.dirty_takes > MAX_DIRTY:
                        self.takes.cleanup(keep = lambda handler: handler.is_active())
                        self.dirty_takes = 0
                    else:
                        self.dirty_takes += 1

                    # TODO: Do a last-chance "garbage collection" to
                    # be sure?
                    if len(self.takes) >= MAX_QUEUE_SIZE:
                        raise Exception("No more than %d pending takes are allowed on a single channel." % MAX_QUEUE_SIZE)

                    # Queue this take
                    self.takes.unbounded_unshift(handler)
            break
Example #5
0
 def _continue(self, response):
     # print self, "got", response
     # XXX: Is there be a better way to avoid infinite recursion?
     dispatch.run(lambda: self.run(response))