Skip to content

Commit 1d63740

Browse files
authored
fix: use confined arenas instead of auto arenas in FFM CLibrary (fixes #1872)
Replace Arena.ofAuto() with Arena.ofConfined() in try-with-resources blocks for deterministic native memory release, avoiding JVM Cleaner pressure under high-frequency polling. Also updates the winsize constructor argument order test to use a confined arena. Closes #1913
1 parent 1604643 commit 1d63740

2 files changed

Lines changed: 33 additions & 30 deletions

File tree

terminal-ffm/src/main/java/org/jline/terminal/impl/ffm/CLibrary.java

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,12 @@ static class winsize {
6060

6161
private final MemorySegment seg;
6262

63-
winsize() {
64-
seg = Arena.ofAuto().allocate(LAYOUT);
63+
winsize(Arena arena) {
64+
seg = arena.allocate(LAYOUT);
6565
}
6666

67-
winsize(short ws_col, short ws_row) {
68-
this();
67+
winsize(Arena arena, short ws_col, short ws_row) {
68+
this(arena);
6969
ws_col(ws_col);
7070
ws_row(ws_row);
7171
}
@@ -157,12 +157,12 @@ private static VarHandle adjust2LinuxHandle(VarHandle v) {
157157

158158
private final MemorySegment seg;
159159

160-
termios() {
161-
seg = Arena.ofAuto().allocate(LAYOUT);
160+
termios(Arena arena) {
161+
seg = arena.allocate(LAYOUT);
162162
}
163163

164-
termios(Attributes t) {
165-
this();
164+
termios(Arena arena, Attributes t) {
165+
this(arena);
166166
TermiosData data = TermiosMapping.forCurrentPlatform().toTermios(t);
167167
c_iflag(data.iflag());
168168
c_oflag(data.oflag());
@@ -374,8 +374,8 @@ private static String readFully(InputStream in) throws IOException {
374374
}
375375

376376
static Size getTerminalSize(int fd) {
377-
try {
378-
winsize ws = new winsize();
377+
try (Arena arena = Arena.ofConfined()) {
378+
winsize ws = new winsize(arena);
379379
int res = (int) ioctl.invoke(fd, (long) TIOCGWINSZ, ws.segment());
380380
return Size.of(ws.ws_col(), ws.ws_row());
381381
} catch (Throwable e) {
@@ -384,8 +384,8 @@ static Size getTerminalSize(int fd) {
384384
}
385385

386386
static void setTerminalSize(int fd, Sized size) {
387-
try {
388-
winsize ws = new winsize();
387+
try (Arena arena = Arena.ofConfined()) {
388+
winsize ws = new winsize(arena);
389389
ws.ws_row((short) size.getRows());
390390
ws.ws_col((short) size.getColumns());
391391
int res = (int) ioctl.invoke(fd, TIOCSWINSZ, ws.segment());
@@ -395,8 +395,8 @@ static void setTerminalSize(int fd, Sized size) {
395395
}
396396

397397
static Attributes getAttributes(int fd) {
398-
try {
399-
termios t = new termios();
398+
try (Arena arena = Arena.ofConfined()) {
399+
termios t = new termios(arena);
400400
int res = (int) tcgetattr.invoke(fd, t.segment());
401401
return t.asAttributes();
402402
} catch (Throwable e) {
@@ -405,8 +405,8 @@ static Attributes getAttributes(int fd) {
405405
}
406406

407407
static void setAttributes(int fd, Attributes attr) {
408-
try {
409-
termios t = new termios(attr);
408+
try (Arena arena = Arena.ofConfined()) {
409+
termios t = new termios(arena, attr);
410410
int res = (int) tcsetattr.invoke(fd, TermiosData.TCSANOW, t.segment());
411411
} catch (Throwable e) {
412412
throw new RuntimeException("Unable to call tcsetattr()", e);
@@ -422,8 +422,8 @@ static boolean isTty(int fd) {
422422
}
423423

424424
static String ttyName(int fd) {
425-
try {
426-
MemorySegment buf = Arena.ofAuto().allocate(64);
425+
try (Arena arena = Arena.ofConfined()) {
426+
MemorySegment buf = arena.allocate(64);
427427
int res = (int) ttyname_r.invoke(fd, buf, buf.byteSize());
428428
byte[] data = buf.toArray(ValueLayout.JAVA_BYTE);
429429
int len = 0;
@@ -440,17 +440,17 @@ static Pty openpty(TerminalProvider provider, Attributes attr, Size size) {
440440
if (openptyError != null) {
441441
throw openptyError;
442442
}
443-
try {
444-
MemorySegment buf = Arena.ofAuto().allocate(64);
445-
MemorySegment master = Arena.ofAuto().allocate(ValueLayout.JAVA_INT);
446-
MemorySegment slave = Arena.ofAuto().allocate(ValueLayout.JAVA_INT);
443+
try (Arena arena = Arena.ofConfined()) {
444+
MemorySegment buf = arena.allocate(64);
445+
MemorySegment master = arena.allocate(ValueLayout.JAVA_INT);
446+
MemorySegment slave = arena.allocate(ValueLayout.JAVA_INT);
447447
int res = (int) openptyHandle.invoke(
448448
master,
449449
slave,
450450
buf,
451-
attr != null ? new termios(attr).segment() : MemorySegment.NULL,
451+
attr != null ? new termios(arena, attr).segment() : MemorySegment.NULL,
452452
size != null
453-
? new winsize((short) size.getColumns(), (short) size.getRows()).segment()
453+
? new winsize(arena, (short) size.getColumns(), (short) size.getRows()).segment()
454454
: MemorySegment.NULL);
455455
if (res != 0) {
456456
throw new UncheckedIOException(new IOException("Unable to call openpty(): return code " + res));

terminal-ffm/src/test/java/org/jline/terminal/impl/ffm/FfmTest.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.io.ByteArrayInputStream;
1212
import java.io.ByteArrayOutputStream;
1313
import java.io.IOException;
14+
import java.lang.foreign.Arena;
1415
import java.nio.charset.Charset;
1516

1617
import org.jline.terminal.Attributes;
@@ -70,17 +71,19 @@ void testNewTerminalNoNull() throws IOException {
7071
@Test
7172
@DisabledOnOs(OS.WINDOWS)
7273
void testWinsizeConstructorArgumentOrder() {
73-
short cols = 120;
74-
short rows = 40;
75-
CLibrary.winsize ws = new CLibrary.winsize(cols, rows);
76-
assertEquals(cols, ws.ws_col());
77-
assertEquals(rows, ws.ws_row());
74+
try (Arena arena = Arena.ofConfined()) {
75+
short cols = 120;
76+
short rows = 40;
77+
CLibrary.winsize ws = new CLibrary.winsize(arena, cols, rows);
78+
assertEquals(cols, ws.ws_col());
79+
assertEquals(rows, ws.ws_row());
80+
}
7881
}
7982

8083
@Test
8184
@EnabledOnOs(OS.WINDOWS)
8285
void checkStructLayout() {
83-
try (java.lang.foreign.Arena arena = java.lang.foreign.Arena.ofConfined()) {
86+
try (Arena arena = Arena.ofConfined()) {
8487
assertNotNull(new Kernel32.KEY_EVENT_RECORD(arena));
8588
assertNotNull(new Kernel32.MOUSE_EVENT_RECORD(arena));
8689
assertNotNull(new Kernel32.WINDOW_BUFFER_SIZE_RECORD(arena));

0 commit comments

Comments
 (0)