terminal: use an async thread to handle input
This commit is contained in:
parent
00493418a3
commit
0fbf35438a
@ -14,6 +14,7 @@
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
@ -30,6 +31,8 @@
|
||||
#include <toaru/graphics.h>
|
||||
#include <toaru/termemu.h>
|
||||
#include <toaru/mouse.h>
|
||||
#include <toaru/list.h>
|
||||
#include <toaru/spinlock.h>
|
||||
|
||||
#include "vga-palette.h"
|
||||
|
||||
@ -389,9 +392,63 @@ char * copy_selection(void) {
|
||||
return selection_text;
|
||||
}
|
||||
|
||||
void input_buffer_stuff(char * str) {
|
||||
size_t s = strlen(str) + 1;
|
||||
write(fd_master, str, s);
|
||||
static volatile int input_buffer_lock = 0;
|
||||
static int input_buffer_semaphore[2];
|
||||
static list_t * input_buffer_queue = NULL;
|
||||
struct input_data {
|
||||
size_t len;
|
||||
char data[];
|
||||
};
|
||||
|
||||
void * handle_input_writing(void * unused) {
|
||||
(void)unused;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Read one byte from semaphore; as long as semaphore has data,
|
||||
* there is another input blob to write to the TTY */
|
||||
char tmp[1];
|
||||
int c = read(input_buffer_semaphore[0],tmp,1);
|
||||
if (c > 0) {
|
||||
/* Retrieve blob */
|
||||
spin_lock(&input_buffer_lock);
|
||||
node_t * blob = list_dequeue(input_buffer_queue);
|
||||
spin_unlock(&input_buffer_lock);
|
||||
/* No blobs? This shouldn't happen, but just in case, just continue */
|
||||
if (!blob) {
|
||||
continue;
|
||||
}
|
||||
/* Write blob data to the tty */
|
||||
struct input_data * value = blob->value;
|
||||
write(fd_master, value->data, value->len);
|
||||
free(blob->value);
|
||||
free(blob);
|
||||
} else {
|
||||
/* The pipe has closed, terminal is exiting */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void write_input_buffer(char * data, size_t len) {
|
||||
struct input_data * d = malloc(sizeof(struct input_data) + len);
|
||||
d->len = len;
|
||||
memcpy(&d->data, data, len);
|
||||
spin_lock(&input_buffer_lock);
|
||||
list_insert(input_buffer_queue, d);
|
||||
spin_unlock(&input_buffer_lock);
|
||||
write(input_buffer_semaphore[1], d, 1);
|
||||
}
|
||||
|
||||
void handle_input(char c) {
|
||||
write_input_buffer(&c, 1);
|
||||
}
|
||||
|
||||
void handle_input_s(char * c) {
|
||||
size_t len = strlen(c);
|
||||
write_input_buffer(c, len);
|
||||
}
|
||||
|
||||
unsigned short * textmemptr = (unsigned short *)0xB8000;
|
||||
@ -705,25 +762,8 @@ void term_clear(int i) {
|
||||
}
|
||||
}
|
||||
|
||||
#define INPUT_SIZE 1024
|
||||
char input_buffer[INPUT_SIZE];
|
||||
int input_collected = 0;
|
||||
|
||||
void clear_input() {
|
||||
memset(input_buffer, 0x0, INPUT_SIZE);
|
||||
input_collected = 0;
|
||||
}
|
||||
|
||||
pid_t child_pid = 0;
|
||||
|
||||
void handle_input(char c) {
|
||||
write(fd_master, &c, 1);
|
||||
}
|
||||
|
||||
void handle_input_s(char * c) {
|
||||
write(fd_master, c, strlen(c));
|
||||
}
|
||||
|
||||
void key_event(int ret, key_event_t * event) {
|
||||
if (ret) {
|
||||
/* Special keys */
|
||||
@ -933,7 +973,7 @@ term_callbacks_t term_callbacks = {
|
||||
term_clear,
|
||||
term_scroll,
|
||||
term_redraw_cursor,
|
||||
input_buffer_stuff,
|
||||
handle_input_s,
|
||||
set_title,
|
||||
unsupported,
|
||||
unsupported_int,
|
||||
@ -984,6 +1024,7 @@ void check_for_exit(void) {
|
||||
/* Exit */
|
||||
char exit_message[] = "[Process terminated]\n";
|
||||
write(fd_slave, exit_message, sizeof(exit_message));
|
||||
close(input_buffer_semaphore[1]);
|
||||
}
|
||||
|
||||
static int mouse_x = 0;
|
||||
@ -1156,6 +1197,11 @@ int main(int argc, char ** argv) {
|
||||
|
||||
reinit();
|
||||
|
||||
pthread_t input_buffer_thread;
|
||||
pipe(input_buffer_semaphore);
|
||||
input_buffer_queue = list_create();
|
||||
pthread_create(&input_buffer_thread, NULL, handle_input_writing, NULL);
|
||||
|
||||
fflush(stdin);
|
||||
|
||||
system("cursor-off"); /* Might GPF */
|
||||
@ -1268,5 +1314,6 @@ int main(int argc, char ** argv) {
|
||||
|
||||
}
|
||||
|
||||
close(input_buffer_semaphore[1]);
|
||||
return 0;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <pty.h>
|
||||
#include <wchar.h>
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
@ -513,13 +514,64 @@ static char * copy_selection(void) {
|
||||
return selection_text;
|
||||
}
|
||||
|
||||
static volatile int input_buffer_lock = 0;
|
||||
static int input_buffer_semaphore[2];
|
||||
static list_t * input_buffer_queue = NULL;
|
||||
struct input_data {
|
||||
size_t len;
|
||||
char data[];
|
||||
};
|
||||
|
||||
void * handle_input_writing(void * unused) {
|
||||
(void)unused;
|
||||
|
||||
while (1) {
|
||||
|
||||
/* Read one byte from semaphore; as long as semaphore has data,
|
||||
* there is another input blob to write to the TTY */
|
||||
char tmp[1];
|
||||
int c = read(input_buffer_semaphore[0],tmp,1);
|
||||
if (c > 0) {
|
||||
/* Retrieve blob */
|
||||
spin_lock(&input_buffer_lock);
|
||||
node_t * blob = list_dequeue(input_buffer_queue);
|
||||
spin_unlock(&input_buffer_lock);
|
||||
/* No blobs? This shouldn't happen, but just in case, just continue */
|
||||
if (!blob) {
|
||||
continue;
|
||||
}
|
||||
/* Write blob data to the tty */
|
||||
struct input_data * value = blob->value;
|
||||
write(fd_master, value->data, value->len);
|
||||
free(blob->value);
|
||||
free(blob);
|
||||
} else {
|
||||
/* The pipe has closed, terminal is exiting */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void write_input_buffer(char * data, size_t len) {
|
||||
struct input_data * d = malloc(sizeof(struct input_data) + len);
|
||||
d->len = len;
|
||||
memcpy(&d->data, data, len);
|
||||
spin_lock(&input_buffer_lock);
|
||||
list_insert(input_buffer_queue, d);
|
||||
spin_unlock(&input_buffer_lock);
|
||||
write(input_buffer_semaphore[1], d, 1);
|
||||
}
|
||||
|
||||
/* Stuffs a string into the stdin of the terminal's child process
|
||||
* Useful for things like the ANSI DSR command. */
|
||||
static void input_buffer_stuff(char * str) {
|
||||
size_t s = strlen(str) + 1;
|
||||
write(fd_master, str, s);
|
||||
size_t len = strlen(str);
|
||||
write_input_buffer(str, len);
|
||||
}
|
||||
|
||||
|
||||
/* Redraw the decorations */
|
||||
static void render_decors(void) {
|
||||
/* Don't draw decorations or bother advertising the window if in "fullscreen mode" */
|
||||
@ -1432,9 +1484,8 @@ term_callbacks_t term_callbacks = {
|
||||
insert_delete_lines,
|
||||
};
|
||||
|
||||
/* Write data into the PTY */
|
||||
static void handle_input(char c) {
|
||||
write(fd_master, &c, 1);
|
||||
write_input_buffer(&c, 1);
|
||||
display_flip();
|
||||
if (scrollback_offset != 0) {
|
||||
scrollback_offset = 0;
|
||||
@ -1442,9 +1493,9 @@ static void handle_input(char c) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Write a string into the PTY */
|
||||
static void handle_input_s(char * c) {
|
||||
write(fd_master, c, strlen(c));
|
||||
size_t len = strlen(c);
|
||||
write_input_buffer(c, len);
|
||||
display_flip();
|
||||
if (scrollback_offset != 0) {
|
||||
scrollback_offset = 0;
|
||||
@ -1452,6 +1503,7 @@ static void handle_input_s(char * c) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Scroll the view up (scrollback) */
|
||||
static void scroll_up(int amount) {
|
||||
int i = 0;
|
||||
@ -1689,6 +1741,7 @@ static void check_for_exit(void) {
|
||||
/* Write [Process terminated] */
|
||||
char exit_message[] = "[Process terminated]\n";
|
||||
write(fd_slave, exit_message, sizeof(exit_message));
|
||||
close(input_buffer_semaphore[1]);
|
||||
}
|
||||
|
||||
static term_cell_t * copy_terminal(int old_width, int old_height, term_cell_t * term_buffer) {
|
||||
@ -2344,6 +2397,12 @@ int main(int argc, char ** argv) {
|
||||
/* Initialize the terminal buffer and ANSI library for the first time. */
|
||||
reinit();
|
||||
|
||||
/* Run thread to handle asynchronous writes to the tty */
|
||||
pthread_t input_buffer_thread;
|
||||
pipe(input_buffer_semaphore);
|
||||
input_buffer_queue = list_create();
|
||||
pthread_create(&input_buffer_thread, NULL, handle_input_writing, NULL);
|
||||
|
||||
/* Make sure we're not passing anything to stdin on the child */
|
||||
fflush(stdin);
|
||||
|
||||
@ -2412,6 +2471,8 @@ int main(int argc, char ** argv) {
|
||||
}
|
||||
}
|
||||
|
||||
close(input_buffer_semaphore[1]);
|
||||
|
||||
/* Windows will close automatically on exit. */
|
||||
return 0;
|
||||
}
|
||||
|
@ -42,8 +42,9 @@ int set_clipboard_from_file(char * file) {
|
||||
size_t size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
char * tmp = malloc(size);
|
||||
char * tmp = malloc(size+1);
|
||||
fread(tmp, 1, size, f);
|
||||
tmp[size] = '\0';
|
||||
|
||||
yutani_set_clipboard(yctx, tmp);
|
||||
|
||||
|
@ -74,11 +74,6 @@ void tty_output_process_slave(pty_t * pty, uint8_t c) {
|
||||
}
|
||||
|
||||
void tty_output_process(pty_t * pty, uint8_t c) {
|
||||
/* XXX hack to allow ^C to work when the tty is full */
|
||||
while (pty->write_out == pty_write_out && ring_buffer_available(pty->out) < 16) {
|
||||
unsigned char garbage[1];
|
||||
ring_buffer_read(pty->out, 1, garbage);
|
||||
}
|
||||
output_process_slave(pty, c);
|
||||
}
|
||||
|
||||
@ -655,8 +650,6 @@ pty_t * pty_new(struct winsize * size) {
|
||||
pty->in = ring_buffer_create(TTY_BUFFER_SIZE);
|
||||
pty->out = ring_buffer_create(TTY_BUFFER_SIZE);
|
||||
|
||||
pty->in->discard = 1;
|
||||
|
||||
/* Master endpoint - writes go to stdin, reads come from stdout */
|
||||
pty->master = pty_master_create(pty);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user