Exemple #1
0
    def test_shared_memory_SharedMemoryManager_basics(self):
        smm1 = shared_memory.SharedMemoryManager()
        with self.assertRaises(ValueError):
            smm1.SharedMemory(
                size=9)  # Fails if SharedMemoryServer not started
        smm1.start()
        lol = [smm1.ShareableList(range(i)) for i in range(5, 10)]
        lom = [smm1.SharedMemory(size=j) for j in range(32, 128, 16)]
        doppleganger_list0 = shared_memory.ShareableList(name=lol[0].shm.name)
        self.assertEqual(len(doppleganger_list0), 5)
        doppleganger_shm0 = shared_memory.SharedMemory(name=lom[0].name)
        self.assertGreaterEqual(len(doppleganger_shm0.buf), 32)
        held_name = lom[0].name
        smm1.shutdown()
        if sys.platform != "win32":
            # Calls to unlink() have no effect on Windows platform; shared
            # memory will only be released once final process exits.
            with self.assertRaises(FileNotFoundError):
                # No longer there to be attached to again.
                absent_shm = shared_memory.SharedMemory(name=held_name)

        with shared_memory.SharedMemoryManager() as smm2:
            sl = smm2.ShareableList("howdy")
            shm = smm2.SharedMemory(size=128)
            held_name = sl.shm.name
        if sys.platform != "win32":
            with self.assertRaises(FileNotFoundError):
                # No longer there to be attached to again.
                absent_sl = shared_memory.ShareableList(name=held_name)
Exemple #2
0
    def __init__(self, shape, dtype=np.float64, name=None):
        """Creates a new SharedNDArray.

        If name is left blank, a new POSIX shared memory segment is created using a random name.

        Args:
            shape: Shape of the wrapped ndarray.
            dtype: Data type of the wrapped ndarray.
            name: Optional; the filesystem path of the underlying POSIX shared memory.

        Returns:
            A new SharedNDArray of the given shape and dtype and backed by the given optional name.

        Raises:
            SharedNDArrayError: if an error occurs.
        """
        size = MINIMUMSHMSIZE + int(np.prod(shape)) * np.dtype(dtype).itemsize
        if name:
            try:
                self._shm = shared_memory.SharedMemory(name, size=size)
            except shared_memory.ExistentialError as ee:
                raise ee.__class__(f"{ee.args[0]}; requested name: {name}")
        else:
            self._shm = shared_memory.SharedMemory(None,
                                                   flags=shared_memory.O_CREX,
                                                   size=size)
        self.array = np.ndarray(shape, dtype, self._shm.buf, order='C')
Exemple #3
0
 def _attach_existing_shmem_then_write(shmem_name_or_obj, binary_data):
     if isinstance(shmem_name_or_obj, str):
         local_sms = shared_memory.SharedMemory(shmem_name_or_obj)
     else:
         local_sms = shmem_name_or_obj
     local_sms.buf[:len(binary_data)] = binary_data
     local_sms.close()
Exemple #4
0
    def test_shared_memory_across_processes(self):
        # bpo-40135: don't define shared memory block's name in case of
        # the failure when we run multiprocessing tests in parallel.
        sms = shared_memory.SharedMemory(create=True, size=512)
        self.addCleanup(sms.unlink)

        # Verify remote attachment to existing block by name is working.
        p = multiprocessing.Process(
            target=self._attach_existing_shmem_then_write,
            args=(sms.name, b'howdy'))
        p.daemon = True
        p.start()
        p.join()
        self.assertEqual(bytes(sms.buf[:5]), b'howdy')

        # Verify pickling of SharedMemory instance also works.
        p = multiprocessing.Process(
            target=self._attach_existing_shmem_then_write,
            args=(sms, b'HELLO'))
        p.daemon = True
        p.start()
        p.join()
        self.assertEqual(bytes(sms.buf[:5]), b'HELLO')

        sms.close()
Exemple #5
0
    def test_shared_memory_cleaned_after_process_termination(self):
        cmd = '''if 1:
            import os, time, sys
            import shared_memory
            # Create a shared_memory segment, and send the segment name
            sm = shared_memory.SharedMemory(create=True, size=10)
            sys.stdout.write(sm.name + '\\n')
            sys.stdout.flush()
            time.sleep(100)
        '''
        with subprocess.Popen([sys.executable, '-E', '-c', cmd],
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE) as p:
            name = p.stdout.readline().strip().decode()

            # killing abruptly processes holding reference to a shared memory
            # segment should not leak the given memory segment.
            p.terminate()
            p.wait()

            deadline = time.monotonic() + 60
            t = 0.1
            while time.monotonic() < deadline:
                time.sleep(t)
                t = min(t * 2, 5)
                try:
                    smm = shared_memory.SharedMemory(name, create=False)
                except FileNotFoundError:
                    break
            else:
                raise AssertionError("A SharedMemory segment was leaked after"
                                     " a process was abruptly terminated.")

            if os.name == 'posix':
                # A warning was emitted by the subprocess' own
                # resource_tracker (on Windows, shared memory segments
                # are released automatically by the OS).
                err = p.stderr.read().decode()
                self.assertIn(
                    "resource_tracker: There appear to be 1 leaked "
                    "shared_memory objects to clean up at shutdown", err)
Exemple #6
0
    def test_shared_memory_basics(self):
        sms = shared_memory.SharedMemory('test01_tsmb', create=True, size=512)
        self.addCleanup(sms.unlink)

        # Verify attributes are readable.
        self.assertEqual(sms.name, 'test01_tsmb')
        self.assertGreaterEqual(sms.size, 512)
        self.assertGreaterEqual(len(sms.buf), sms.size)

        # Modify contents of shared memory segment through memoryview.
        sms.buf[0] = 42
        self.assertEqual(sms.buf[0], 42)

        # Attach to existing shared memory segment.
        also_sms = shared_memory.SharedMemory('test01_tsmb')
        self.assertEqual(also_sms.buf[0], 42)
        also_sms.close()

        # Attach to existing shared memory segment but specify a new size.
        same_sms = shared_memory.SharedMemory('test01_tsmb',
                                              size=20 * sms.size)
        self.assertLess(same_sms.size, 20 * sms.size)  # Size was ignored.
        same_sms.close()

        if _USE_POSIX:
            # Posix Shared Memory can only be unlinked once.  Here we
            # test an implementation detail that is not observed across
            # all supported platforms (since WindowsNamedSharedMemory
            # manages unlinking on its own and unlink() does nothing).
            # True release of shared memory segment does not necessarily
            # happen until process exits, depending on the OS platform.
            with self.assertRaises(FileNotFoundError):
                sms_uno = shared_memory.SharedMemory('test01_dblunlink',
                                                     create=True,
                                                     size=5000)

                try:
                    self.assertGreaterEqual(sms_uno.size, 5000)

                    sms_duo = shared_memory.SharedMemory('test01_dblunlink')
                    sms_duo.unlink()  # First shm_unlink() call.
                    sms_duo.close()
                    sms_uno.close()

                finally:
                    sms_uno.unlink()  # A second shm_unlink() call is bad.

        with self.assertRaises(FileExistsError):
            # Attempting to create a new shared memory segment with a
            # name that is already in use triggers an exception.
            there_can_only_be_one_sms = shared_memory.SharedMemory(
                'test01_tsmb', create=True, size=512)

        if _USE_POSIX:
            # Requesting creation of a shared memory segment with the option
            # to attach to an existing segment, if that name is currently in
            # use, should not trigger an exception.
            # Note:  Using a smaller size could possibly cause truncation of
            # the existing segment but is OS platform dependent.  In the
            # case of MacOS/darwin, requesting a smaller size is disallowed.
            class OptionalAttachSharedMemory(shared_memory.SharedMemory):
                _flags = os.O_CREAT | os.O_RDWR

            ok_if_exists_sms = OptionalAttachSharedMemory('test01_tsmb')
            self.assertEqual(ok_if_exists_sms.size, sms.size)
            ok_if_exists_sms.close()

        # Attempting to attach to an existing shared memory segment when
        # no segment exists with the supplied name triggers an exception.
        with self.assertRaises(FileNotFoundError):
            nonexisting_sms = shared_memory.SharedMemory('test01_notthere')
            nonexisting_sms.unlink()  # Error should occur on prior line.

        sms.close()

        # Test creating a shared memory segment with negative size
        with self.assertRaises(ValueError):
            sms_invalid = shared_memory.SharedMemory(create=True, size=-1)

        # Test creating a shared memory segment with size 0
        with self.assertRaises(ValueError):
            sms_invalid = shared_memory.SharedMemory(create=True, size=0)

        # Test creating a shared memory segment without size argument
        with self.assertRaises(ValueError):
            sms_invalid = shared_memory.SharedMemory(create=True)