no busyloop in otg msd

This commit is contained in:
Devaev Maxim 2020-03-01 03:58:08 +03:00
parent cae9ad9a21
commit ff6e284e64

View File

@ -103,8 +103,8 @@ class _VirtualDriveState:
class _State: class _State:
def __init__(self, changes_queue: asyncio.queues.Queue) -> None: def __init__(self, notifier: aiotools.AioNotifier) -> None:
self.__changes_queue = changes_queue self.__notifier = notifier
self.storage: Optional[_StorageState] = None self.storage: Optional[_StorageState] = None
self.vd: Optional[_VirtualDriveState] = None self.vd: Optional[_VirtualDriveState] = None
@ -116,13 +116,13 @@ class _State:
async def busy(self, check_online: bool=True) -> AsyncGenerator[None, None]: async def busy(self, check_online: bool=True) -> AsyncGenerator[None, None]:
with self._region: with self._region:
async with self._lock: async with self._lock:
await self.__changes_queue.put(None) await self.__notifier.notify()
if check_online: if check_online:
if self.vd is None: if self.vd is None:
raise MsdOfflineError() raise MsdOfflineError()
assert self.storage assert self.storage
yield yield
await self.__changes_queue.put(None) await self.__notifier.notify()
def is_busy(self) -> bool: def is_busy(self) -> bool:
return self._region.is_busy() return self._region.is_busy()
@ -154,9 +154,8 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
self.__new_file_written = 0 self.__new_file_written = 0
self.__new_file_tick = 0.0 self.__new_file_tick = 0.0
self.__changes_queue: asyncio.queues.Queue = asyncio.Queue() self.__state_notifier = aiotools.AioNotifier()
self.__state = _State(self.__state_notifier)
self.__state = _State(self.__changes_queue)
logger = get_logger(0) logger = get_logger(0)
logger.info("Using OTG gadget %r as MSD", gadget) logger.info("Using OTG gadget %r as MSD", gadget)
@ -215,15 +214,15 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
if inotify_task.done(): if inotify_task.done():
RuntimeError("Inotify task is dead") RuntimeError("Inotify task is dead")
try:
await asyncio.wait_for(self.__changes_queue.get(), timeout=0.1)
except asyncio.TimeoutError:
continue
state = await self.get_state() state = await self.get_state()
if state != prev_state: if state != prev_state:
yield state yield state
prev_state = state prev_state = state
await asyncio.wait([
inotify_task,
self.__state_notifier.wait(),
], return_when=asyncio.FIRST_COMPLETED)
finally: finally:
if not inotify_task.done(): if not inotify_task.done():
inotify_task.cancel() inotify_task.cancel()
@ -308,7 +307,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
with self.__state._region: # pylint: disable=protected-access with self.__state._region: # pylint: disable=protected-access
try: try:
async with self.__state._lock: # pylint: disable=protected-access async with self.__state._lock: # pylint: disable=protected-access
await self.__changes_queue.put(None) await self.__state_notifier.notify()
assert self.__state.storage assert self.__state.storage
assert self.__state.vd assert self.__state.vd
@ -324,7 +323,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
self.__new_file_written = 0 self.__new_file_written = 0
self.__new_file = await aiofiles.open(path, mode="w+b", buffering=0) self.__new_file = await aiofiles.open(path, mode="w+b", buffering=0)
await self.__changes_queue.put(None) await self.__state_notifier.notify()
yield yield
self.__set_image_complete(name, True) self.__set_image_complete(name, True)
@ -340,7 +339,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
# Между закрытием файла и эвентом айнотифи состояние может быть не обновлено, # Между закрытием файла и эвентом айнотифи состояние может быть не обновлено,
# так что форсим обновление вручную, чтобы получить актуальное состояние. # так что форсим обновление вручную, чтобы получить актуальное состояние.
await self.__reload_state() await self.__reload_state()
await self.__changes_queue.put(None) await self.__state_notifier.notify()
async def write_image_chunk(self, chunk: bytes) -> int: async def write_image_chunk(self, chunk: bytes) -> int:
assert self.__new_file assert self.__new_file
@ -350,7 +349,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
if self.__new_file_tick + 1 < now: if self.__new_file_tick + 1 < now:
# Это нужно для ручного оповещения о свободном пространстве на диске, см. get_state() # Это нужно для ручного оповещения о свободном пространстве на диске, см. get_state()
self.__new_file_tick = now self.__new_file_tick = now
await self.__changes_queue.put(None) await self.__state_notifier.notify()
return self.__new_file_written return self.__new_file_written
async def remove(self, name: str) -> None: async def remove(self, name: str) -> None:
@ -399,7 +398,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
while True: while True:
# Активно ждем, пока не будут на месте все каталоги. # Активно ждем, пока не будут на месте все каталоги.
await self.__reload_state() await self.__reload_state()
await self.__changes_queue.put(None) await self.__state_notifier.notify()
if self.__state.vd: if self.__state.vd:
break break
await asyncio.sleep(5) await asyncio.sleep(5)
@ -411,7 +410,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
# После установки вотчеров еще раз проверяем стейт, чтобы ничего не потерять # После установки вотчеров еще раз проверяем стейт, чтобы ничего не потерять
await self.__reload_state() await self.__reload_state()
await self.__changes_queue.put(None) await self.__state_notifier.notify()
while self.__state.vd: # Если живы после предыдущей проверки while self.__state.vd: # Если живы после предыдущей проверки
need_restart = False need_restart = False
@ -427,7 +426,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
break break
if need_reload_state: if need_reload_state:
await self.__reload_state() await self.__reload_state()
await self.__changes_queue.put(None) await self.__state_notifier.notify()
except asyncio.CancelledError: # pylint: disable=try-except-raise except asyncio.CancelledError: # pylint: disable=try-except-raise
raise raise
except Exception: except Exception: