News:

Simutrans Sites
Know our official sites. Find tools and resources for Simutrans.

Simutrans on Android builds as single threaded

Started by prissi, July 04, 2026, 02:20:43 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

prissi

Anyone having a look at that would be nice.

victor_18993

The Android build is single-threaded because
find_package(Threads) is currently placed inside a branch that Android never enters.
cmake/SimutransFindDependencies.cmake begins with:
if (NOT ANDROID)

and
find_package(Threads) is inside that branch. As a result, it is never called when configuring the Android build.
Nothing fails and no warning is emitted. The variable populated by
FindThreads,
CMAKE_USE_PTHREADS_INIT, is simply never set.
SimutransCompileOptions.cmake then checks that exact variable:
if (CMAKE_USE_PTHREADS_INIT)
    option(SIMUTRANS_MULTI_THREAD "Use multiple threads for drawing" ON)
else ()
    set(SIMUTRANS_MULTI_THREAD OFF)
endif ()

Android therefore always takes the second branch.
Since
SIMUTRANS_MULTI_THREAD is disabled,
MULTI_THREAD is never defined, and
environment.cc falls back to:
#ifdef MULTI_THREAD
    num_threads = min(MAX_THREADS, dr_get_max_threads());
#else
    num_threads = 1;
#endif

Android is not being built as single-threaded because the platform lacks thread support. It is being built that way because thread support is never detected.
Reproduced with the Android toolchain
I reproduced this using NDK r27c, targeting
arm64-v8a, configured directly from the current master branch.
These are the definitions passed to the compiler:
-DCOLOUR_DEPTH=0
-DMSG_LEVEL=3
-DNDEBUG=1
-Dsimutrans_EXPORTS

MULTI_THREAD is not present.
Fix
Move these two lines outside the
if (NOT ANDROID) branch so that they run on every platform:
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads)

That is the entire functional patch.
How thread detection works on Android
I initially expected Android to use the libc detection path in
FindThreads, since bionic provides the pthread implementation.
That is not what happens:
-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Failed
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread - not found
-- Check if compiler accepts -pthread - yes
-- Found Threads: TRUE

The libc probe fails because CMake's test program calls
pthread_cancel, which bionic does not provide:
error: call to undeclared function 'pthread_cancel'

Android also does not provide a separate
libpthread, so the library checks fail as expected.
Thread detection succeeds through the compiler's acceptance of the
-pthread flag. This results in the thread variables being initialized, including
CMAKE_USE_PTHREADS_INIT, which in turn enables
SIMUTRANS_MULTI_THREAD and defines
MULTI_THREAD.
Simutrans itself does not call
pthread_cancel, so the failed libc probe does not indicate a problem for the application.
Compatibility with older Android versions
I also checked the barrier implementation because
pthread_barrier_init is only available from Android API 24 onward.
The existing code already handles this correctly.
Bionic defines:
#define _POSIX_BARRIERS __BIONIC_POSIX_FEATURE_SINCE(24)

which evaluates according to the configured Android API level.
simthread.h checks:
#if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS > 0)

Below API 24, Simutrans uses its existing mutex-and-condition-variable barrier implementation, the same fallback used on macOS.
From API 24 onward, it uses the native pthread barrier functions.
No additional Android-specific thread code is required.
Verification
With the patch applied,
MULTI_THREAD reaches the compiler and all 28 translation units that use the threading code, including the multi-threaded drawing implementation, compile successfully for:
API 21, arm64-v8a     fallback barrier implementation
API 24, arm64-v8a     native pthread barriers
API 21, armeabi-v7a   32-bit build

I did not perform the final link step because that requires the prebuilt libraries included in the Gradle project, such as zlib, libpng, bzip2, zstd, FreeType and FluidSynth. None of those dependencies affects the thread detection or compilation result.
The Android CI build should now report
SIMUTRANS_MULTI_THREAD as enabled and include
MULTI_THREAD in the compiler definitions.
The desktop build is unaffected.
SIMUTRANS_MULTI_THREAD remains enabled and compiles as before.
Separate observation
The preceding line:
set(CMAKE_THREAD_PREFER_PTHREAD ON)

does not appear to have any effect.
FindThreads reads
THREADS_PREFER_PTHREAD_FLAG, not
CMAKE_THREAD_PREFER_PTHREAD.
I have deliberately left this unchanged rather than include an unrelated cleanup in the bug fix. It could be removed or corrected separately.
En la vida todo son vivencias y cada una de ellas nos hace mas grandes,¿Como de grande eres tu? :)

prissi

Thank you very much. This was very helpful.

victor_18993

You're welcome! I'm glad it helped.
I can also test the resulting Android build if needed.
En la vida todo son vivencias y cada una de ellas nos hace mas grandes,¿Como de grande eres tu? :)