diff --git a/ChangeLog b/ChangeLog index 1d6131483..057a58858 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2024-12-08 Hugo Melder + * Source/NSThread.m: + Fix threadPriority and setThreadPriority: on Android. + 2024-08-08 Richard Frith-Macdonald * Tools/AGSHtml.m: diff --git a/Source/NSThread.m b/Source/NSThread.m index 9f174afbf..abbffd530 100644 --- a/Source/NSThread.m +++ b/Source/NSThread.m @@ -116,6 +116,11 @@ int pthread_spin_destroy(pthread_spinlock_t *lock) # include #endif +#if defined(__ANDROID__) +# include // For strerror +# include // For getpriority and setpriority +#endif + #if defined(HAVE_SYS_FCNTL_H) # include #elif defined(HAVE_FCNTL_H) @@ -1004,6 +1009,34 @@ + (BOOL) setThreadPriority: (double)pri return NO; } return YES; +#elif defined(__ANDROID__) +/* Android's pthread_setschedparam is currently broken, as it checks + * if the priority is in the range of the system's min and max + * priorities. The interval bounds are queried with `sched_get_priority_min`, + * and `sched_get_priority_max` which just return 0, regardless of the + * specified scheduling policy. + * + * The solution is to use `setpriority` to set the thread + * priority. This is possible because on Linux, it is not a per-process setting + * as specified by POSIX but a per-thread setting (See the `Bugs` section in `setpriority`). + * + * Android's internal implementation also relies on this behavior, so it + * is safe to use it here. + */ + + // Clamp pri into the required range. + if (pri > 1) { pri = 1; } + if (pri < 0) { pri = 0; } + + // Convert [0.0, 1.0] to [-20, 19] range where -20 is the highest + // and 19 the lowest priority. + int priority = (int)(-20 + (1-pri) * 39); + if (setpriority(PRIO_PROCESS, 0, priority) == -1) + { + NSLog(@"Failed to set thread priority %d: %s", priority, strerror(errno)); + return NO; + } + return YES; #elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0) int res; int policy; @@ -1097,6 +1130,18 @@ + (double) threadPriority NSLog(@"Unknown thread priority: %d", winPri); break; } +#elif defined(__ANDROID__) +/* See notes in setThreadPriority + */ + int priority = getpriority(PRIO_PROCESS, 0); + if (priority == -1) + { + NSLog(@"Failed to get thread priority: %s", strerror(errno)); + return pri; + } + + // Convert [-20, 19] to [0.0, 1.0] range + pri = 1 - (priority + 20) / 39.0; #elif defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING > 0) int res; int policy; @@ -1126,8 +1171,6 @@ + (double) threadPriority return pri; } - - /* * Thread instance methods. */