diff --git a/radicale/log.py b/radicale/log.py index e16b8cc..9503f5d 100644 --- a/radicale/log.py +++ b/radicale/log.py @@ -29,8 +29,11 @@ import logging import multiprocessing import os import sys +import tempfile import threading +from radicale import pathutils + try: import systemd.journal except ImportError: @@ -72,6 +75,27 @@ class IdentLogRecordFactory: return record +class RwLockWrapper(): + + def __init__(self): + self._file = tempfile.NamedTemporaryFile() + self._lock = pathutils.RwLock(self._file.name) + self._cm = None + + def acquire(self, blocking=True): + assert self._cm is None + if not blocking: + raise NotImplementedError + cm = self._lock.acquire("w") + cm.__enter__() + self._cm = cm + + def release(self): + assert self._cm is not None + self._cm.__exit__(None, None, None) + self._cm = None + + class ThreadStreamsHandler(logging.Handler): terminator = "\n" @@ -83,7 +107,11 @@ class ThreadStreamsHandler(logging.Handler): self.fallback_handler = fallback_handler def createLock(self): - self.lock = multiprocessing.Lock() + try: + self.lock = multiprocessing.Lock() + except Exception: + # HACK: Workaround for Android + self.lock = RwLockWrapper() def setFormatter(self, form): super().setFormatter(form) diff --git a/radicale/server.py b/radicale/server.py index 26a2d1d..3e458a8 100644 --- a/radicale/server.py +++ b/radicale/server.py @@ -30,6 +30,7 @@ import socket import socketserver import ssl import sys +import threading import wsgiref.simple_server from configparser import ConfigParser from urllib.parse import unquote @@ -42,7 +43,14 @@ try: except ImportError: systemd = None -if hasattr(os, "fork"): +USE_FORKING = hasattr(os, "fork") +try: + multiprocessing.BoundedSemaphore() +except Exception: + # HACK: Workaround for Android + USE_FORKING = False + +if USE_FORKING: ParallelizationMixIn = socketserver.ForkingMixIn else: ParallelizationMixIn = socketserver.ThreadingMixIn @@ -84,9 +92,12 @@ class ParallelHTTPServer(ParallelizationMixIn, def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + if USE_FORKING: + sema_class = multiprocessing.BoundedSemaphore + else: + sema_class = threading.BoundedSemaphore if self.max_connections: - self.connections_guard = multiprocessing.BoundedSemaphore( - self.max_connections) + self.connections_guard = sema_class(self.max_connections) else: # use dummy context manager self.connections_guard = contextlib.ExitStack()