Skip to content

Commit b9cf1b7

Browse files
committed
fix: narrow rumble re-entry guard, shrink input memcmp, clamp vibration intensity
- evshim.c: replace per-slot atomic g_keepalive_active with a thread-local t_keepalive_active. The atomic was reachable from any thread, so a legitimate cross-thread OnRumble during the keepalive's SDL_JoystickRumble window would be silently dropped. Only same-thread synchronous re-entry needs suppressing, which is exactly what TLS catches. - evshim.c: shrink vjoy_updater's memcmp to offsetof(gamepad_io, low_freq_rumble) so rumble writes at offset 32 no longer trip the input- changed branch and cause redundant SDL_JoystickSetVirtualAxis/Button/Hat replays each inotify wakeup. - evshim.c: drop the unreachable close(ino_fd)/return NULL tail after the for(;;) loop in vjoy_updater. The loop has no break; the early-return paths above run before ino_fd is opened. - evshim.c: remove now-unused <stdatomic.h> include; add <stddef.h> for offsetof. - XServerScreen.kt: clamp vibrationIntensity to 0..100 with coerceIn after toIntOrNull, so out-of-range container extras can't violate the WinHandler.setVibrationIntensity contract.
1 parent 8b1c6bc commit b9cf1b7

2 files changed

Lines changed: 14 additions & 14 deletions

File tree

app/src/main/cpp/extras/evshim.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77
#include <dlfcn.h>
88
#include <fcntl.h>
99
#include <errno.h>
10+
#include <stddef.h>
1011
#include <string.h>
1112
#include <stdlib.h>
1213
#include <stdio.h>
1314
#include <pthread.h>
1415
#include <unistd.h>
1516
#include <SDL2/SDL.h>
1617
#include <stdarg.h>
17-
#include <stdatomic.h>
1818
#include <sys/inotify.h>
1919
#include <poll.h>
2020
#include <time.h>
@@ -32,10 +32,12 @@ static int rumble_fd[MAX_GAMEPADS] = {-1};
3232
static void *handle = NULL;
3333
static pthread_mutex_t shm_mutex = PTHREAD_MUTEX_INITIALIZER;
3434

35-
/* Set to 1 on the player index being refreshed by the SDL keepalive so that
36-
* the resulting re-entrant OnRumble() call does not overwrite shared memory
37-
* (which may have been zeroed by a stop command that raced the keepalive). */
38-
static atomic_int g_keepalive_active[MAX_GAMEPADS];
35+
/* Set to 1 on the keepalive thread before calling SDL_JoystickRumble so the
36+
* resulting synchronous (same-thread) re-entrant OnRumble() call does not
37+
* overwrite shared memory (which may have been zeroed by a stop command that
38+
* raced the keepalive). Thread-local so legitimate OnRumble calls from other
39+
* threads are never suppressed. */
40+
static __thread int t_keepalive_active = 0;
3941

4042
struct gamepad_io {
4143
int16_t lx, ly, rx, ry, lt, rt;
@@ -89,7 +91,7 @@ static int OnRumble(void *userdata,
8991
* We must NOT update last_rumble or pwrite in that case: the game may
9092
* have already sent OnRumble(0,0) to stop vibration, and re-writing
9193
* the old non-zero values would restart rumble on the Android side. */
92-
if (atomic_load(&g_keepalive_active[idx])) {
94+
if (t_keepalive_active) {
9395
LOGD("Rumble P%d low=%u high=%u [keepalive noop]\n", idx,
9496
low_frequency_rumble, high_frequency_rumble);
9597
return 0;
@@ -179,7 +181,7 @@ static void *vjoy_updater(void *arg)
179181
ssize_t n = pread(fd, &cur, sizeof cur, 0);
180182
pthread_mutex_unlock(&shm_mutex);
181183

182-
if (n == sizeof cur && memcmp(&cur, &last_state, sizeof cur) != 0) {
184+
if (n == sizeof cur && memcmp(&cur, &last_state, offsetof(struct gamepad_io, low_freq_rumble)) != 0) {
183185

184186
p_SDL_JoystickSetVirtualAxis (js, 0, cur.lx);
185187
p_SDL_JoystickSetVirtualAxis (js, 1, cur.ly);
@@ -220,9 +222,9 @@ static void *vjoy_updater(void *arg)
220222
/* Flag this player's slot before calling SDL so that the
221223
* synchronous OnRumble() re-entry is recognised as a
222224
* keepalive and does not overwrite shared memory. */
223-
atomic_store(&g_keepalive_active[idx], 1);
225+
t_keepalive_active = 1;
224226
p_SDL_JoystickRumble(js, kl, kh, RUMBLE_KEEPALIVE_DUR_MS);
225-
atomic_store(&g_keepalive_active[idx], 0);
227+
t_keepalive_active = 0;
226228
LOGD("Rumble keepalive P%d low=%u high=%u\n", idx, kl, kh);
227229
}
228230
}
@@ -241,10 +243,6 @@ static void *vjoy_updater(void *arg)
241243
p_SDL_Delay(5);
242244
}
243245
}
244-
245-
/* Unreachable in normal operation; cleanup for early-return paths above. */
246-
if (ino_fd >= 0) close(ino_fd);
247-
return NULL;
248246
}
249247

250248
__attribute__((constructor))

app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1782,7 +1782,9 @@ fun XServerScreen(
17821782
container.getExtra("vibrationMode", "controller"),
17831783
),
17841784
)
1785-
handler.setVibrationIntensity(container.getExtra("vibrationIntensity", "100").toIntOrNull() ?: 100)
1785+
handler.setVibrationIntensity(
1786+
(container.getExtra("vibrationIntensity", "100").toIntOrNull() ?: 100).coerceIn(0, 100)
1787+
)
17861788
if (container.isDisableMouseInput()) {
17871789
PluviaApp.touchpadView?.setTouchscreenMouseDisabled(true)
17881790
} else if (container.isTouchscreenMode()) {

0 commit comments

Comments
 (0)