Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rethrow all errors from native #526

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions mosaic-terminal/src/c/mosaic-stdin-windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ platformError stdinReader_interrupt(stdinReader *reader) {
platformError stdinReader_free(stdinReader *reader) {
DWORD result = 0;
if (unlikely(CloseHandle(reader->waitHandles[1]) != 0)) {
result = GetLastError();
// TODO Sometimes this fails with error value 3 and I don't know why...
// result = GetLastError();
}
free(reader);
return result;
Expand Down Expand Up @@ -163,7 +164,8 @@ platformError stdinWriter_write(stdinWriter *writer, void *buffer, int count) {
platformError stdinWriter_free(stdinWriter *writer) {
DWORD result = 0;
if (unlikely(CloseHandle(writer->eventHandle) != 0)) {
result = GetLastError();
// TODO Sometimes this fails with error value 3 and I don't know why...
// result = GetLastError();
}
if (unlikely(CloseHandle(writer->writeHandle) != 0 && result == 0)) {
result = GetLastError();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,19 @@ class StdinReaderTest {
}

@Test fun readWithTimeoutReturnsZeroOnTimeout() {
// The timeouts passed are slightly higher than those validated thanks to Windows which
// can return _slightly_ early. Usually it's around .1ms, but we go 10ms to be sure.

val readA: Int
val tookA = measureTime {
readA = reader.readWithTimeout(ByteArray(10), 0, 10, 100)
readA = reader.readWithTimeout(ByteArray(10), 0, 10, 110)
}
assertThat(readA).isZero()
assertThat(tookA).isGreaterThan(100.milliseconds)

val readB: Int
val tookB = measureTime {
readB = reader.readWithTimeout(ByteArray(10), 0, 10, 100)
readB = reader.readWithTimeout(ByteArray(10), 0, 10, 110)
}
assertThat(readB).isZero()
assertThat(tookB).isGreaterThan(100.milliseconds)
Expand Down
28 changes: 20 additions & 8 deletions mosaic-terminal/src/jvmMain/jni/mosaic-jni.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ Java_com_jakewharton_mosaic_terminal_Tty_enterRawMode(JNIEnv *env, jclass type)
return 0;
}

JNIEXPORT jint JNICALL
JNIEXPORT void JNICALL
Java_com_jakewharton_mosaic_terminal_Tty_exitRawMode(JNIEnv *env, jclass type, jlong ptr) {
return exitRawMode((rawModeConfig *) ptr);
platformError error = exitRawMode((rawModeConfig *) ptr);
if (unlikely(error)) {
throwIse(env, error, "Unable to exit raw mode");
}
}

JNIEXPORT jlong JNICALL
Expand Down Expand Up @@ -113,14 +116,20 @@ Java_com_jakewharton_mosaic_terminal_Tty_stdinReaderReadWithTimeout(
return -1;
}

JNIEXPORT jint JNICALL
JNIEXPORT void JNICALL
Java_com_jakewharton_mosaic_terminal_Tty_stdinReaderInterrupt(JNIEnv *env, jclass type, jlong ptr) {
return stdinReader_interrupt((stdinReader *) ptr);
platformError error = stdinReader_interrupt((stdinReader *) ptr);
if (unlikely(error)) {
throwIse(env, error, "Unable to interrupt stdin reader");
}
}

JNIEXPORT jint JNICALL
JNIEXPORT void JNICALL
Java_com_jakewharton_mosaic_terminal_Tty_stdinReaderFree(JNIEnv *env, jclass type, jlong ptr) {
return stdinReader_free((stdinReader *) ptr);
platformError error = stdinReader_free((stdinReader *) ptr);
if (unlikely(error)) {
throwIse(env, error, "Unable to free stdin reader");
}
}

JNIEXPORT jlong JNICALL
Expand Down Expand Up @@ -161,7 +170,10 @@ Java_com_jakewharton_mosaic_terminal_Tty_stdinWriterGetReader(JNIEnv *env, jclas
return (jlong) stdinWriter_getReader((stdinWriter *) ptr);
}

JNIEXPORT jint JNICALL
JNIEXPORT void JNICALL
Java_com_jakewharton_mosaic_terminal_Tty_stdinWriterFree(JNIEnv *env, jclass type, jlong ptr) {
return stdinWriter_free((stdinWriter *) ptr);
platformError error = stdinWriter_free((stdinWriter *) ptr);
if (unlikely(error)) {
throwIse(env, error, "Unable to free stdin writer");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ public actual object Tty {
private val savedPtr: Long,
) : AutoCloseable {
override fun close() {
val error = exitRawMode(savedPtr)
check(error == 0) { "Unable to exit raw mode: $error" }
exitRawMode(savedPtr)
}
}

Expand All @@ -44,7 +43,7 @@ public actual object Tty {
private external fun enterRawMode(): Long

@JvmStatic
private external fun exitRawMode(savedConfig: Long): Int
private external fun exitRawMode(savedConfig: Long)

@JvmStatic
private external fun stdinReaderInit(): Long
Expand Down Expand Up @@ -73,12 +72,12 @@ public actual object Tty {
@JvmStatic
@JvmSynthetic // Hide from Java callers.
@JvmName("stdinReaderInterrupt") // Avoid internal name mangling.
internal external fun stdinReaderInterrupt(reader: Long): Int
internal external fun stdinReaderInterrupt(reader: Long)

@JvmStatic
@JvmSynthetic // Hide from Java callers.
@JvmName("stdinReaderFree") // Avoid internal name mangling.
internal external fun stdinReaderFree(reader: Long): Int
internal external fun stdinReaderFree(reader: Long)

@JvmStatic
private external fun stdinWriterInit(): Long
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public actual object Tty {
) : AutoCloseable {
override fun close() {
val error = exitRawMode(savedConfig)
check(error == 0U) { "Unable to exit raw mode: $error" }
if (error == 0U) return
throwError(error)
}
}

Expand All @@ -41,17 +42,21 @@ public actual object Tty {
val reader = stdinWriter_getReader(writer)!!
return StdinWriter(writer, reader)
}

internal fun throwError(error: UInt): Nothing {
throw RuntimeException(error.toString())
}
}

@OptIn(ExperimentalForeignApi::class)
public actual class StdinReader internal constructor(
private val ref: CPointer<stdinReader>,
private var ref: CPointer<stdinReader>?,
) : AutoCloseable {
public actual fun read(buffer: ByteArray, offset: Int, length: Int): Int {
buffer.usePinned {
stdinReader_read(ref, it.addressOf(offset), length).useContents {
if (error == 0U) return count
throw RuntimeException(error.toString())
Tty.throwError(error)
}
}
}
Expand All @@ -60,23 +65,31 @@ public actual class StdinReader internal constructor(
buffer.usePinned {
stdinReader_readWithTimeout(ref, it.addressOf(offset), length, timeoutMillis).useContents {
if (error == 0U) return count
throw RuntimeException(error.toString())
Tty.throwError(error)
}
}
}

public actual fun interrupt() {
stdinReader_interrupt(ref)
val error = stdinReader_interrupt(ref)
if (error == 0U) return
Tty.throwError(error)
}

public actual override fun close() {
stdinReader_free(ref)
ref?.let { ref ->
this.ref = null

val error = stdinReader_free(ref)
if (error == 0U) return
Tty.throwError(error)
}
}
}

@OptIn(ExperimentalForeignApi::class)
internal actual class StdinWriter internal constructor(
private val ref: CPointer<stdinWriter>,
private var ref: CPointer<stdinWriter>?,
readerRef: CPointer<stdinReader>,
) : AutoCloseable {
actual val reader: StdinReader = StdinReader(readerRef)
Expand All @@ -86,10 +99,19 @@ internal actual class StdinWriter internal constructor(
stdinWriter_write(ref, it.addressOf(0), buffer.size)
}
if (error == 0U) return
throw RuntimeException(error.toString())
Tty.throwError(error)
}

actual override fun close() {
stdinWriter_free(ref)
ref?.let { ref ->
this.ref = null

reader.close()

val error = stdinWriter_free(ref)

if (error == 0U) return
Tty.throwError(error)
}
}
}
Loading