예제 #1
0
 def setUp(self):
     self.game = ExampleGame(Builder(10, 10, 7, 6).create())
     self.game.addUnit(Unit(1), 1, (0, 0))
     self.bot1 = ExampleBot(1)
     self.bot1.gameState = self.game.copy()
     self.linker1 = ExampleBotControllerWrapper(self.bot1)
     self.game.addUnit(Unit(2), 1, (0, 0))
     self.bot2 = ExampleBot(2)
     self.bot2.gameState = self.game.copy()
     self.linker2 = ExampleBotControllerWrapper(self.bot2)
     self.game_info_pipe_parent1, self.game_info_pipe_child1 = Pipe(
     )  # type: Tuple[PipeConnection, PipeConnection]
     self.game_info_pipe_parent2, self.game_info_pipe_child2 = Pipe(
     )  # type: Tuple[PipeConnection, PipeConnection]
     self.move_pipe_parent1, self.move_pipe_child1 = Pipe(
     )  # type: Tuple[PipeConnection, PipeConnection]
     self.move_pipe_parent2, self.move_pipe_child2 = Pipe(
     )  # type: Tuple[PipeConnection, PipeConnection]
     self.linker1.setMainPipe(self.move_pipe_child1)
     self.linker1.setGameInfoPipe(self.game_info_pipe_child1)
     self.linker2.setMainPipe(self.move_pipe_child2)
     self.linker2.setGameInfoPipe(self.game_info_pipe_child2)
     self.collaboration_pipe_1, self.collaboration_pipe_2 = Pipe()
     self.linker1.addCollaborationPipe(2, self.collaboration_pipe_1)
     self.linker2.addCollaborationPipe(1, self.collaboration_pipe_2)
예제 #2
0
 def __init__(self):
     self._reader, self._writer = Pipe(duplex=False)
     self._rlock = Lock()
     self._poll = self._reader.poll
     if sys.platform == 'win32':
         self._wlock = None
     else:
         self._wlock = Lock()
     self._make_methods()
예제 #3
0
    def __init__(self, maxsize=0):
        if maxsize <= 0:
            maxsize = _multiprocessing.SemLock.SEM_VALUE_MAX
        self._maxsize = maxsize
        self._reader, self._writer = Pipe(duplex=False)
        self._rlock = Lock()
        self._opid = os.getpid()
        if sys.platform == 'win32':
            self._wlock = None
        else:
            self._wlock = Lock()
        self._sem = BoundedSemaphore(maxsize)
        # For use by concurrent.futures
        self._ignore_epipe = False

        self._after_fork()

        if sys.platform != 'win32':
            register_after_fork(self, Queue._after_fork)
예제 #4
0
    def _addControllerWrapper(self, wrapper: ControllerWrapper,
                              unit: Unit) -> None:
        """
        Adds the linker to the loop, creating the pipe connections

        Args:
            wrapper: The linker to add
            unit: The unit, linked by this linker
        """
        self.wrappers[wrapper] = unit
        parent_conn, child_conn = Pipe()
        parent_info_conn, child_info_conn = Pipe()
        self.wrappersConnection[wrapper] = parent_conn
        self.wrappersInfoConnection[wrapper] = parent_info_conn
        self._eventsToSend[wrapper] = []
        wrapper.setMainPipe(child_conn)
        wrapper.setGameInfoPipe(child_info_conn)
        if isinstance(wrapper, BotControllerWrapper):
            self._addCollaborationPipes(wrapper)
예제 #5
0
    def __init__(self, maxsize=0):
        if maxsize <= 0:
            maxsize = _multiprocessing.SemLock.SEM_VALUE_MAX
        self._maxsize = maxsize
        self._reader, self._writer = Pipe(duplex=False)
        self._rlock = Lock()
        self._opid = os.getpid()
        if sys.platform == 'win32':
            self._wlock = None
        else:
            self._wlock = Lock()
        self._sem = BoundedSemaphore(maxsize)
        # For use by concurrent.futures
        self._ignore_epipe = False

        self._after_fork()

        if sys.platform != 'win32':
            register_after_fork(self, Queue._after_fork)
예제 #6
0
    def _addCollaborationPipes(self, linker: BotControllerWrapper) -> None:
        """
        Adds the collaboration pipes between the given linker and its teammate's

        Args:
            linker: The linker to connect with its teammate
        """
        for teammate in self.game.teams[self.game.unitsTeam[
                self.wrappers[linker]]]:
            if teammate is not self.wrappers[linker]:
                teammate_linker = None  # type: BotControllerWrapper
                for other_linker in self.wrappers:
                    if self.wrappers[other_linker] is teammate:
                        teammate_linker = other_linker
                        break
                pipe1, pipe2 = Pipe()
                linker.addCollaborationPipe(
                    teammate_linker.controller.playerNumber, pipe1)
                teammate_linker.addCollaborationPipe(
                    linker.controller.playerNumber, pipe2)
예제 #7
0
def Pipe(duplex=True):
    '''
    Returns two connection object connected by a pipe
    '''
    from multiprocess.connection import Pipe
    return Pipe(duplex)
예제 #8
0
class TestBotControllerWrapper(unittest.TestCase):
    def setUp(self):
        self.game = ExampleGame(Builder(10, 10, 7, 6).create())
        self.game.addUnit(Unit(1), 1, (0, 0))
        self.bot1 = ExampleBot(1)
        self.bot1.gameState = self.game.copy()
        self.linker1 = ExampleBotControllerWrapper(self.bot1)
        self.game.addUnit(Unit(2), 1, (0, 0))
        self.bot2 = ExampleBot(2)
        self.bot2.gameState = self.game.copy()
        self.linker2 = ExampleBotControllerWrapper(self.bot2)
        self.game_info_pipe_parent1, self.game_info_pipe_child1 = Pipe(
        )  # type: Tuple[PipeConnection, PipeConnection]
        self.game_info_pipe_parent2, self.game_info_pipe_child2 = Pipe(
        )  # type: Tuple[PipeConnection, PipeConnection]
        self.move_pipe_parent1, self.move_pipe_child1 = Pipe(
        )  # type: Tuple[PipeConnection, PipeConnection]
        self.move_pipe_parent2, self.move_pipe_child2 = Pipe(
        )  # type: Tuple[PipeConnection, PipeConnection]
        self.linker1.setMainPipe(self.move_pipe_child1)
        self.linker1.setGameInfoPipe(self.game_info_pipe_child1)
        self.linker2.setMainPipe(self.move_pipe_child2)
        self.linker2.setGameInfoPipe(self.game_info_pipe_child2)
        self.collaboration_pipe_1, self.collaboration_pipe_2 = Pipe()
        self.linker1.addCollaborationPipe(2, self.collaboration_pipe_1)
        self.linker2.addCollaborationPipe(1, self.collaboration_pipe_2)

    def test_invalid_type_sent(self):
        """
        Tests that the linker raises an error when a message that is not a "BotEvent" is sent
        """
        self.move_pipe_parent1.send("")
        self.assertRaises(TypeError, self.linker1._routine,
                          self.game_info_pipe_child1, self.move_pipe_child1)

    def test_send_move(self):
        """
        Tests that moves are sent correctly, that they affect the GameState and that the AI responds well
        """
        move1_event = BotEvent(1, MOVE1)
        move2_event = BotEvent(1, MOVE2)
        self.move_pipe_parent1.send(move1_event)
        self.move_pipe_parent1.send(move1_event)
        self.move_pipe_parent1.send(move1_event)
        self.move_pipe_parent1.send(move2_event)
        self.linker1._routine()
        self.assertFalse(self.move_pipe_parent1.poll())
        self.linker1._routine()
        self.assertTrue(self.move_pipe_parent1.poll())
        self.assertEqual(self.move_pipe_parent1.recv(), "MOVE1-3/MOVE2-1")

    def test_send_message_to_teammate(self):
        """
        Tests that messages are sent well between two teammates
        """
        self.bot1.sendMessageToTeammate(2, MSG1)
        self.linker1._routine()  # Will send the message
        self.linker2._routine()  # Will receive the message
        self.assertTrue(self.move_pipe_parent2.poll())
        self.assertEqual(self.move_pipe_parent2.recv(), "MOVE1")

    def test_send_end_event(self):
        """
        Checks if the linker's logical loop ends correctly when it receives the end event
        """
        self.game_info_pipe_parent1.send(SpecialEvent(SpecialEvent.END))
        self.linker1.run()
        # Should run indefinitely if no flag was sent
        self.assertTrue(True)

    def test_unit_dead(self):
        """
        Checks if the linker blocks the incoming message of a dead unit, and starts to send again when resurrected
        """
        self.game_info_pipe_parent1.send(SpecialEvent(
            SpecialEvent.UNIT_KILLED))
        self.move_pipe_parent1.send(BotEvent(1, MOVE1))
        self.linker1._routine()
        self.assertFalse(self.move_pipe_parent1.poll())
        self.linker1._routine()  # Message blocked
        self.assertFalse(self.move_pipe_parent1.poll())
        self.game_info_pipe_parent1.send(
            SpecialEvent(SpecialEvent.RESURRECT_UNIT))
        self.move_pipe_parent1.send(BotEvent(1, MOVE2))
        self.linker1._routine()  # Message received
        self.linker1._routine()  # Message sent
        self.assertTrue(self.move_pipe_parent1.poll())
        # The message "MOVE1" was correctly received while the unit was dead => the game state is updated
        # while the unit is dead
        self.assertEqual(self.move_pipe_parent1.recv(), "MOVE1-1/MOVE2-1")
예제 #9
0
class Queue(object):

    def __init__(self, maxsize=0):
        if maxsize <= 0:
            maxsize = _multiprocessing.SemLock.SEM_VALUE_MAX
        self._maxsize = maxsize
        self._reader, self._writer = Pipe(duplex=False)
        self._rlock = Lock()
        self._opid = os.getpid()
        if sys.platform == 'win32':
            self._wlock = None
        else:
            self._wlock = Lock()
        self._sem = BoundedSemaphore(maxsize)
        # For use by concurrent.futures
        self._ignore_epipe = False

        self._after_fork()

        if sys.platform != 'win32':
            register_after_fork(self, Queue._after_fork)

    def __getstate__(self):
        assert_spawning(self)
        return (self._ignore_epipe, self._maxsize, self._reader, self._writer,
                self._rlock, self._wlock, self._sem, self._opid)

    def __setstate__(self, state):
        (self._ignore_epipe, self._maxsize, self._reader, self._writer,
         self._rlock, self._wlock, self._sem, self._opid) = state
        self._after_fork()

    def _after_fork(self):
        debug('Queue._after_fork()')
        self._notempty = threading.Condition(threading.Lock())
        self._buffer = collections.deque()
        self._thread = None
        self._jointhread = None
        self._joincancelled = False
        self._closed = False
        self._close = None
        self._send = self._writer.send
        self._recv = self._reader.recv
        self._poll = self._reader.poll

    def put(self, obj, block=True, timeout=None):
        assert not self._closed
        if not self._sem.acquire(block, timeout):
            raise Full

        self._notempty.acquire()
        try:
            if self._thread is None:
                self._start_thread()
            self._buffer.append(obj)
            self._notempty.notify()
        finally:
            self._notempty.release()

    def get(self, block=True, timeout=None):
        if block and timeout is None:
            self._rlock.acquire()
            try:
                res = self._recv()
                self._sem.release()
                return res
            finally:
                self._rlock.release()

        else:
            if block:
                deadline = time.time() + timeout
            if not self._rlock.acquire(block, timeout):
                raise Empty
            try:
                if block:
                    timeout = deadline - time.time()
                    if timeout < 0 or not self._poll(timeout):
                        raise Empty
                elif not self._poll():
                    raise Empty
                res = self._recv()
                self._sem.release()
                return res
            finally:
                self._rlock.release()

    def qsize(self):
        # Raises NotImplementedError on Mac OSX because of broken sem_getvalue()
        return self._maxsize - self._sem._semlock._get_value()

    def empty(self):
        return not self._poll()

    def full(self):
        return self._sem._semlock._is_zero()

    def get_nowait(self):
        return self.get(False)

    def put_nowait(self, obj):
        return self.put(obj, False)

    def close(self):
        self._closed = True
        self._reader.close()
        if self._close:
            self._close()

    def join_thread(self):
        debug('Queue.join_thread()')
        assert self._closed
        if self._jointhread:
            self._jointhread()

    def cancel_join_thread(self):
        debug('Queue.cancel_join_thread()')
        self._joincancelled = True
        try:
            self._jointhread.cancel()
        except AttributeError:
            pass

    def _start_thread(self):
        debug('Queue._start_thread()')

        # Start thread which transfers data from buffer to pipe
        self._buffer.clear()
        self._thread = threading.Thread(
            target=Queue._feed,
            args=(self._buffer, self._notempty, self._send,
                  self._wlock, self._writer.close, self._ignore_epipe),
            name='QueueFeederThread'
            )
        self._thread.daemon = True

        debug('doing self._thread.start()')
        self._thread.start()
        debug('... done self._thread.start()')

        # On process exit we will wait for data to be flushed to pipe.
        #
        # However, if this process created the queue then all
        # processes which use the queue will be descendants of this
        # process.  Therefore waiting for the queue to be flushed
        # is pointless once all the child processes have been joined.
        created_by_this_process = (self._opid == os.getpid())
        if not self._joincancelled and not created_by_this_process:
            self._jointhread = Finalize(
                self._thread, Queue._finalize_join,
                [weakref.ref(self._thread)],
                exitpriority=-5
                )

        # Send sentinel to the thread queue object when garbage collected
        self._close = Finalize(
            self, Queue._finalize_close,
            [self._buffer, self._notempty],
            exitpriority=10
            )

    @staticmethod
    def _finalize_join(twr):
        debug('joining queue thread')
        thread = twr()
        if thread is not None:
            thread.join()
            debug('... queue thread joined')
        else:
            debug('... queue thread already dead')

    @staticmethod
    def _finalize_close(buffer, notempty):
        debug('telling queue thread to quit')
        notempty.acquire()
        try:
            buffer.append(_sentinel)
            notempty.notify()
        finally:
            notempty.release()

    @staticmethod
    def _feed(buffer, notempty, send, writelock, close, ignore_epipe):
        debug('starting thread to feed data to pipe')
        from .util import is_exiting

        nacquire = notempty.acquire
        nrelease = notempty.release
        nwait = notempty.wait
        bpopleft = buffer.popleft
        sentinel = _sentinel
        if sys.platform != 'win32':
            wacquire = writelock.acquire
            wrelease = writelock.release
        else:
            wacquire = None

        try:
            while 1:
                nacquire()
                try:
                    if not buffer:
                        nwait()
                finally:
                    nrelease()
                try:
                    while 1:
                        obj = bpopleft()
                        if obj is sentinel:
                            debug('feeder thread got sentinel -- exiting')
                            close()
                            return

                        if wacquire is None:
                            send(obj)
                        else:
                            wacquire()
                            try:
                                send(obj)
                            finally:
                                wrelease()
                except IndexError:
                    pass
        except Exception as e:
            if ignore_epipe and getattr(e, 'errno', 0) == errno.EPIPE:
                return
            # Since this runs in a daemon thread the resources it uses
            # may be become unusable while the process is cleaning up.
            # We ignore errors which happen after the process has
            # started to cleanup.
            try:
                if is_exiting():
                    info('error in queue thread: %s', e)
                else:
                    import traceback
                    traceback.print_exc()
            except Exception:
                pass
예제 #10
0
class Queue(object):
    def __init__(self, maxsize=0):
        if maxsize <= 0:
            maxsize = _multiprocessing.SemLock.SEM_VALUE_MAX
        self._maxsize = maxsize
        self._reader, self._writer = Pipe(duplex=False)
        self._rlock = Lock()
        self._opid = os.getpid()
        if sys.platform == 'win32':
            self._wlock = None
        else:
            self._wlock = Lock()
        self._sem = BoundedSemaphore(maxsize)
        # For use by concurrent.futures
        self._ignore_epipe = False

        self._after_fork()

        if sys.platform != 'win32':
            register_after_fork(self, Queue._after_fork)

    def __getstate__(self):
        assert_spawning(self)
        return (self._ignore_epipe, self._maxsize, self._reader, self._writer,
                self._rlock, self._wlock, self._sem, self._opid)

    def __setstate__(self, state):
        (self._ignore_epipe, self._maxsize, self._reader, self._writer,
         self._rlock, self._wlock, self._sem, self._opid) = state
        self._after_fork()

    def _after_fork(self):
        debug('Queue._after_fork()')
        self._notempty = threading.Condition(threading.Lock())
        self._buffer = collections.deque()
        self._thread = None
        self._jointhread = None
        self._joincancelled = False
        self._closed = False
        self._close = None
        self._send = self._writer.send
        self._recv = self._reader.recv
        self._poll = self._reader.poll

    def put(self, obj, block=True, timeout=None):
        assert not self._closed
        if not self._sem.acquire(block, timeout):
            raise Full

        self._notempty.acquire()
        try:
            if self._thread is None:
                self._start_thread()
            self._buffer.append(obj)
            self._notempty.notify()
        finally:
            self._notempty.release()

    def get(self, block=True, timeout=None):
        if block and timeout is None:
            self._rlock.acquire()
            try:
                res = self._recv()
                self._sem.release()
                return res
            finally:
                self._rlock.release()

        else:
            if block:
                deadline = time.time() + timeout
            if not self._rlock.acquire(block, timeout):
                raise Empty
            try:
                if block:
                    timeout = deadline - time.time()
                    if timeout < 0 or not self._poll(timeout):
                        raise Empty
                elif not self._poll():
                    raise Empty
                res = self._recv()
                self._sem.release()
                return res
            finally:
                self._rlock.release()

    def qsize(self):
        # Raises NotImplementedError on Mac OSX because of broken sem_getvalue()
        return self._maxsize - self._sem._semlock._get_value()

    def empty(self):
        return not self._poll()

    def full(self):
        return self._sem._semlock._is_zero()

    def get_nowait(self):
        return self.get(False)

    def put_nowait(self, obj):
        return self.put(obj, False)

    def close(self):
        self._closed = True
        self._reader.close()
        if self._close:
            self._close()

    def join_thread(self):
        debug('Queue.join_thread()')
        assert self._closed
        if self._jointhread:
            self._jointhread()

    def cancel_join_thread(self):
        debug('Queue.cancel_join_thread()')
        self._joincancelled = True
        try:
            self._jointhread.cancel()
        except AttributeError:
            pass

    def _start_thread(self):
        debug('Queue._start_thread()')

        # Start thread which transfers data from buffer to pipe
        self._buffer.clear()
        self._thread = threading.Thread(
            target=Queue._feed,
            args=(self._buffer, self._notempty, self._send, self._wlock,
                  self._writer.close, self._ignore_epipe),
            name='QueueFeederThread')
        self._thread.daemon = True

        debug('doing self._thread.start()')
        self._thread.start()
        debug('... done self._thread.start()')

        # On process exit we will wait for data to be flushed to pipe.
        #
        # However, if this process created the queue then all
        # processes which use the queue will be descendants of this
        # process.  Therefore waiting for the queue to be flushed
        # is pointless once all the child processes have been joined.
        created_by_this_process = (self._opid == os.getpid())
        if not self._joincancelled and not created_by_this_process:
            self._jointhread = Finalize(self._thread,
                                        Queue._finalize_join,
                                        [weakref.ref(self._thread)],
                                        exitpriority=-5)

        # Send sentinel to the thread queue object when garbage collected
        self._close = Finalize(self,
                               Queue._finalize_close,
                               [self._buffer, self._notempty],
                               exitpriority=10)

    @staticmethod
    def _finalize_join(twr):
        debug('joining queue thread')
        thread = twr()
        if thread is not None:
            thread.join()
            debug('... queue thread joined')
        else:
            debug('... queue thread already dead')

    @staticmethod
    def _finalize_close(buffer, notempty):
        debug('telling queue thread to quit')
        notempty.acquire()
        try:
            buffer.append(_sentinel)
            notempty.notify()
        finally:
            notempty.release()

    @staticmethod
    def _feed(buffer, notempty, send, writelock, close, ignore_epipe):
        debug('starting thread to feed data to pipe')
        from .util import is_exiting

        nacquire = notempty.acquire
        nrelease = notempty.release
        nwait = notempty.wait
        bpopleft = buffer.popleft
        sentinel = _sentinel
        if sys.platform != 'win32':
            wacquire = writelock.acquire
            wrelease = writelock.release
        else:
            wacquire = None

        try:
            while 1:
                nacquire()
                try:
                    if not buffer:
                        nwait()
                finally:
                    nrelease()
                try:
                    while 1:
                        obj = bpopleft()
                        if obj is sentinel:
                            debug('feeder thread got sentinel -- exiting')
                            close()
                            return

                        if wacquire is None:
                            send(obj)
                        else:
                            wacquire()
                            try:
                                send(obj)
                            finally:
                                wrelease()
                except IndexError:
                    pass
        except Exception as e:
            if ignore_epipe and getattr(e, 'errno', 0) == errno.EPIPE:
                return
            # Since this runs in a daemon thread the resources it uses
            # may be become unusable while the process is cleaning up.
            # We ignore errors which happen after the process has
            # started to cleanup.
            try:
                if is_exiting():
                    info('error in queue thread: %s', e)
                else:
                    import traceback
                    traceback.print_exc()
            except Exception:
                pass