Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions python/grass/pygrass/rpc/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import sys
from ctypes import CFUNCTYPE, c_void_p
from multiprocessing import Lock, Pipe, Process

import grass.lib.gis as libgis
from grass.exceptions import FatalError
Expand All @@ -22,7 +21,7 @@
from grass.pygrass.vector import VectorTopo
from grass.pygrass.vector.basic import Bbox

from .base import RPCServerBase
from .base import MP_CONTEXT, RPCServerBase

###############################################################################
###############################################################################
Expand Down Expand Up @@ -249,9 +248,9 @@ def __init__(self):

def start_server(self):
"""This function must be re-implemented in the subclasses"""
self.client_conn, self.server_conn = Pipe(True)
self.lock = Lock()
self.server = Process(
self.client_conn, self.server_conn = MP_CONTEXT.Pipe(True)
self.lock = MP_CONTEXT.Lock()
self.server = MP_CONTEXT.Process(
target=data_provider_server, args=(self.lock, self.server_conn)
)
self.server.daemon = True
Expand Down
21 changes: 17 additions & 4 deletions python/grass/pygrass/rpc/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import sys
import threading
import time
from multiprocessing import Lock, Pipe, Process
import multiprocessing as mp
from typing import TYPE_CHECKING, NoReturn

from grass.exceptions import FatalError
Expand All @@ -28,6 +28,17 @@

logger: logging.Logger = logging.getLogger(__name__)

# Python 3.14 changed the default multiprocessing start method from "fork" to
# "forkserver" on all platforms except macOS. The RPC worker process relies on
# "fork" semantics: subclasses run libgis via ctypes in the worker, which must
# inherit the initialized library state and the GRASS session environment from
# the parent. Pin "fork" where it used to be the default; macOS and Windows
# keep their default start method ("spawn").
if sys.platform != "darwin" and "fork" in mp.get_all_start_methods():
MP_CONTEXT = mp.get_context("fork")
else:
MP_CONTEXT = mp.get_context()


###############################################################################

Expand Down Expand Up @@ -142,9 +153,11 @@ def start_server(self):
"""This function must be re-implemented in the subclasses"""
logger.debug("Start the libgis server")

self.client_conn, self.server_conn = Pipe(True)
self.lock = Lock()
self.server = Process(target=dummy_server, args=(self.lock, self.server_conn))
self.client_conn, self.server_conn = MP_CONTEXT.Pipe(True)
self.lock = MP_CONTEXT.Lock()
self.server = MP_CONTEXT.Process(
target=dummy_server, args=(self.lock, self.server_conn)
)
self.server.daemon = True
self.server.start()

Expand Down
9 changes: 4 additions & 5 deletions python/grass/temporal/c_libraries_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
import sys
from ctypes import CFUNCTYPE, POINTER, byref, c_int, c_void_p, cast
from datetime import datetime
from multiprocessing import Lock, Pipe, Process
from typing import TYPE_CHECKING, Any, Literal

import grass.lib.date as libdate
Expand All @@ -27,7 +26,7 @@
import grass.lib.vector as libvector
from grass.exceptions import FatalError
from grass.pygrass.raster import RasterRow
from grass.pygrass.rpc.base import RPCServerBase
from grass.pygrass.rpc.base import MP_CONTEXT, RPCServerBase
from grass.pygrass.utils import decode
from grass.pygrass.vector import VectorTopo
from grass.script.utils import encode
Expand Down Expand Up @@ -1471,9 +1470,9 @@ def __init__(self) -> None:
RPCServerBase.__init__(self)

def start_server(self) -> None:
self.client_conn, self.server_conn = Pipe(True)
self.lock = Lock()
self.server = Process(
self.client_conn, self.server_conn = MP_CONTEXT.Pipe(True)
self.lock = MP_CONTEXT.Lock()
self.server = MP_CONTEXT.Process(
target=c_library_server, args=(self.lock, self.server_conn)
)
self.server.daemon = True
Expand Down
Loading