Console input

This commit is contained in:
2025-08-20 21:23:12 -05:00
parent fbfcbe9578
commit 84f2735246
8 changed files with 125 additions and 48 deletions

View File

@@ -18,6 +18,6 @@ add_subdirectory(cmd)
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
target_compile_definitions(${DUSK_TARGET_NAME}
PRIVATE
DUSK_CONSOLE_TERMIOS=1
DUSK_CONSOLE_POSIX=1
)
endif()

View File

@@ -10,6 +10,5 @@
#include "engine/engine.h"
void cmdQuit(const consolecmdexec_t *exec) {
consolePrint("Quitting...");
ENGINE.running = false;
}

View File

@@ -27,15 +27,12 @@ void consoleInit() {
consolePrint(" = Dawn Console = ");
#if DUSK_CONSOLE_TERMIOS
// Create termios session.
struct termios newTermios;
tcgetattr(STDIN_FILENO, &CONSOLE.originalTermios);
#if DUSK_CONSOLE_POSIX
// Disable canonical mode & echo
newTermios.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newTermios);
fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);// Set stdin to non-blocking
threadInit(&CONSOLE.thread, consoleInputThread);
threadMutexInit(&CONSOLE.execMutex);
threadStartRequest(&CONSOLE.thread);
#endif
}
@@ -80,6 +77,8 @@ void consolePrint(const char_t *message, ...) {
}
void consoleExec(const char_t *line) {
threadMutexLock(&CONSOLE.execMutex);
assertNotNull(line, "line must not be NULL");
assertTrue(
CONSOLE.execBufferCount < CONSOLE_EXEC_BUFFER_MAX,
@@ -279,23 +278,22 @@ void consoleExec(const char_t *line) {
break;
}
}
threadMutexUnlock(&CONSOLE.execMutex);
}
// May move these later
void consoleUpdate() {
#if DUSK_CONSOLE_TERMIOS
char_t c;
for(;;) {
if(!read(STDIN_FILENO, &c, 1)) break;
putchar(c);
}
#if DUSK_CONSOLE_POSIX
#endif
threadMutexLock(&CONSOLE.execMutex);
for(uint32_t i = 0; i < CONSOLE.execBufferCount; i++) {
consolecmdexec_t *exec = &CONSOLE.execBuffer[i];
assertNotNull(exec->cmd, "Command execution has no command.");
exec->cmd->function(exec);
}
threadMutexUnlock(&CONSOLE.execMutex);
// #if DUSK_KEYBOARD_SUPPORT == 1
// uint8_t key;
@@ -337,8 +335,63 @@ void consoleUpdate() {
}
void consoleDispose(void) {
// Reset termios
#if DUSK_CONSOLE_TERMIOS
tcsetattr(STDIN_FILENO, TCSANOW, &CONSOLE.originalTermios);
#if DUSK_CONSOLE_POSIX
threadStop(&CONSOLE.thread);
threadMutexDispose(&CONSOLE.execMutex);
#endif
}
consolePrint(" = Console shutting down = ");
}
#if DUSK_CONSOLE_POSIX
void consoleInputThread(thread_t *thread) {
assertNotNull(thread, "Thread cannot be NULL.");
char_t line[CONSOLE_LINE_MAX];
size_t cap = 0;
struct pollfd pfd = {
.fd = STDIN_FILENO,
.events = POLLIN
};
while(!threadShouldStop(thread) && ENGINE.running) {
int32_t rc = poll(&pfd, 1, DUSK_CONSOLE_POSIX_POLL_RATE);
if(rc == 0) continue;
if(rc < 0) {
if(errno == EINTR) continue; // Interrupted by signal, retry
assertUnreachable("poll() failed with unexpected error.");
}
// Check for errors or input
if (pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) break;
if (!(pfd.revents & POLLIN)) {
pfd.revents = 0;
continue;
}
// Read a line from stdin
if(!fgets(line, CONSOLE_LINE_MAX, stdin)) {
if (feof(stdin)) break;
clearerr(stdin);
continue;
}
// Did we read a full line or did it get truncated?
size_t len = strlen(line);
int32_t fullLine = len > 0 && line[len - 1] == '\n';
// Strip trailing newline/CR
while(len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
line[--len] = '\0';
}
if(len > 0) consoleExec(line);
pfd.revents = 0;
}
}
#endif

View File

@@ -9,10 +9,12 @@
#include "consolevar.h"
#include "consolecmd.h"
#if DUSK_CONSOLE_TERMIOS
#include <termios.h>
#include <fcntl.h>
#if DUSK_CONSOLE_POSIX
#include "thread/thread.h"
#include <poll.h>
#include <unistd.h>
#define DUSK_CONSOLE_POSIX_POLL_RATE 75
#endif
typedef enum {
@@ -46,10 +48,10 @@ typedef struct {
bool_t visible;
#if DUSK_CONSOLE_TERMIOS
struct termios originalTermios;
#if DUSK_CONSOLE_POSIX
char_t inputBuffer[CONSOLE_LINE_MAX];
int32_t inputBufferLength;
thread_t thread;
threadmutex_t execMutex;
#endif
} console_t;
@@ -95,7 +97,8 @@ void consolePrint(
);
/**
* Executes a console command.
* Executes a console command. This method is thread safe and can be called from
* any thread.
*
* @param line The line to execute.
*/
@@ -109,4 +112,13 @@ void consoleUpdate();
/**
* Disposes of the console.
*/
void consoleDispose(void);
void consoleDispose(void);
#if DUSK_CONSOLE_POSIX
/**
* Input thread handler for posix input.
*
* @param thread The thread that is running.
*/
void consoleInputThread(thread_t *thread);
#endif

View File

@@ -27,4 +27,5 @@ void engineUpdate(void) {
}
void engineDispose(void) {
consoleDispose();
}

View File

@@ -7,22 +7,11 @@
#include "engine/engine.h"
#include "thread/thread.h"
thread_t thread;
threadmutex_t mutex;
void myCoolThread(thread_t *thread) {
printf("Hello from myCoolThread!\n");
}
int main(int argc, char **argv) {
threadInit(&thread, myCoolThread);
threadStart(&thread);
threadStop(&thread);
return 0;
engineInit();
for(;;) engineUpdate();
do {
engineUpdate();
} while(ENGINE.running);
engineDispose();
return 0;
}

View File

@@ -26,11 +26,9 @@ void threadInit(thread_t *thread, const threadcallback_t callback) {
void threadStartRequest(thread_t *thread) {
assertNotNull(thread, "Thread cannot be NULL.");
printf("Starting thread...\n");
threadMutexLock(&thread->stateMutex);
thread->state = THREAD_STATE_STARTING;
threadMutexUnlock(&thread->stateMutex);
printf("Thread marked starting.\n");
#if DUSK_THREAD_PTHREAD
assertTrue(thread->threadId == 0, "Thread id not 0.");
@@ -43,8 +41,6 @@ void threadStartRequest(thread_t *thread) {
);
pthread_detach(thread->threadId);
#endif
printf("Thread created.\n");
}
void threadStopRequest(thread_t *thread) {
@@ -70,7 +66,6 @@ void threadStart(thread_t *thread) {
void threadStop(thread_t *thread) {
assertNotNull(thread, "Thread cannot be NULL.");
threadStopRequest(thread);
threadMutexLock(&thread->stateMutex);
while(thread->state != THREAD_STATE_STOPPED) {
@@ -79,6 +74,25 @@ void threadStop(thread_t *thread) {
threadMutexUnlock(&thread->stateMutex);
}
bool_t threadShouldStop(thread_t *thread) {
bool_t state;
assertNotNull(thread, "Thread cannot be NULL.");
threadMutexLock(&thread->stateMutex);
switch(thread->state) {
case THREAD_STATE_STOPPED:
case THREAD_STATE_STOP_REQUESTED:
state = true;
break;
default:
state = false;
break;
}
threadMutexUnlock(&thread->stateMutex);
return state;
}
#if DUSK_THREAD_PTHREAD
void * threadHandler(thread_t *thread) {
assertNotNull(thread, "Thread cannot be NULL.");

View File

@@ -78,12 +78,21 @@ void threadStart(thread_t *thread);
/**
* Stops the thread, blocking until it has stopped. Does this as efficiently as
* possible depending on the threading implementation.
* possible depending on the threading implementation. Note that it is possible
* for the thread to fully COMPLETE well before this function returns.
*
* @param thread Pointer to the thread structure to stop.
*/
void threadStop(thread_t *thread);
/**
* Checks if the thread should stop, based on its state.
*
* @param thread Pointer to the thread structure to check.
* @return true if the thread should stop, false otherwise.
*/
bool_t threadShouldStop(thread_t *thread);
#if DUSK_THREAD_PTHREAD
/**
* Handles the thread's lifecycle for pthreads.