bitbake: Use a "fork" multiprocessing context

Python 3.14 changes the default multiprocessing context from "fork" to
"forkserver"; however bitbake heavily relies on "fork" to efficiently
pass data to the child processes. As such, make "fork" context in the bb
namespace and use it in place of the normal multiprocessing module.

Note that multiprocessing contexts were added in Python 3.4, so this
should be safe to use even before Python 3.14

[YOCTO #15858]

(Bitbake rev: 15d7448e04aa78c827d2cef9eb1a62bd6e0dd119)

Signed-off-by: Joshua Watt <JPEWhacker@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Martin Jansa <martin.jansa@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
Joshua Watt
2025-08-22 00:40:06 +02:00
committed by Steve Sakoman
parent 6400741e0c
commit f00c4968ff
7 changed files with 35 additions and 9 deletions

View File

@@ -37,6 +37,34 @@ class BBHandledException(Exception):
import os import os
import logging import logging
from collections import namedtuple from collections import namedtuple
import multiprocessing as mp
# Python 3.14 changes the default multiprocessing context from "fork" to
# "forkserver". However, bitbake heavily relies on "fork" behavior to
# efficiently pass data to the child processes. Places that need this should do:
# from bb import multiprocessing
# in place of
# import multiprocessing
class MultiprocessingContext(object):
"""
Multiprocessing proxy object that uses the "fork" context for a property if
available, otherwise goes to the main multiprocessing module. This allows
it to be a drop-in replacement for the multiprocessing module, but use the
fork context
"""
def __init__(self):
super().__setattr__("_ctx", mp.get_context("fork"))
def __getattr__(self, name):
if hasattr(self._ctx, name):
return getattr(self._ctx, name)
return getattr(mp, name)
def __setattr__(self, name, value):
raise AttributeError(f"Unable to set attribute {name}")
multiprocessing = MultiprocessingContext()
class NullHandler(logging.Handler): class NullHandler(logging.Handler):

View File

@@ -11,7 +11,7 @@ import os
import signal import signal
import socket import socket
import sys import sys
import multiprocessing from bb import multiprocessing
import logging import logging
from .connection import StreamConnection, WebsocketConnection from .connection import StreamConnection, WebsocketConnection
from .exceptions import ClientError, ServerError, ConnectionClosedError, InvokeError from .exceptions import ClientError, ServerError, ConnectionClosedError, InvokeError

View File

@@ -12,7 +12,7 @@
import sys, os, glob, os.path, re, time import sys, os, glob, os.path, re, time
import itertools import itertools
import logging import logging
import multiprocessing from bb import multiprocessing
import threading import threading
from io import StringIO, UnsupportedOperation from io import StringIO, UnsupportedOperation
from contextlib import closing from contextlib import closing

View File

@@ -13,7 +13,7 @@
import bb import bb
import bb.event import bb.event
import logging import logging
import multiprocessing from bb import multiprocessing
import threading import threading
import array import array
import os import os

View File

@@ -3,7 +3,7 @@
# #
import http.server import http.server
import multiprocessing from bb import multiprocessing
import os import os
import traceback import traceback
import signal import signal

View File

@@ -14,7 +14,7 @@ import logging
import bb import bb
import bb.msg import bb.msg
import locale import locale
import multiprocessing from bb import multiprocessing
import fcntl import fcntl
import importlib import importlib
import importlib.machinery import importlib.machinery
@@ -1174,8 +1174,6 @@ def process_profilelog(fn, pout = None):
# #
def multiprocessingpool(*args, **kwargs): def multiprocessingpool(*args, **kwargs):
import multiprocessing.pool
#import multiprocessing.util
#multiprocessing.util.log_to_stderr(10) #multiprocessing.util.log_to_stderr(10)
# Deal with a multiprocessing bug where signals to the processes would be delayed until the work # Deal with a multiprocessing bug where signals to the processes would be delayed until the work
# completes. Putting in a timeout means the signals (like SIGINT/SIGTERM) get processed. # completes. Putting in a timeout means the signals (like SIGINT/SIGTERM) get processed.

View File

@@ -11,7 +11,7 @@ from bb.asyncrpc import InvokeError
from .client import ClientPool from .client import ClientPool
import hashlib import hashlib
import logging import logging
import multiprocessing from bb import multiprocessing
import os import os
import sys import sys
import tempfile import tempfile