diff options
author | Haoran S. Diao (刁浩然) <0@hairydiode.xyz> | 2025-09-13 01:34:39 -0700 |
---|---|---|
committer | Haoran S. Diao (刁浩然) <0@hairydiode.xyz> | 2025-09-13 01:34:39 -0700 |
commit | dbc69eaff9a6bb80cfe324252f76dbb94781538b (patch) | |
tree | 40fbb75ca33bfa5f067c3cc11671e1ca56d626ab | |
parent | e0d4fadb292d51cbeb4724bcb1abf61887db36b3 (diff) |
Moved the pty->stdout routine and the im display routine to seperate threads
issue is that the im_display routine is overzealous
-rw-r--r-- | ptyim.c | 165 |
1 files changed, 100 insertions, 65 deletions
@@ -3,14 +3,18 @@ #define _DEFAULT_SOURCE #include <stdio.h> #include <stdlib.h> -#include <fcntl.h> -#include <errno.h> #include <unistd.h> +#include <errno.h> +#include <string.h> + +#include <fcntl.h> #include <sys/ioctl.h> #include <termios.h> -#include <string.h> + #include <signal.h> -#include <sys/prctl.h> +#include <pthread.h> +#include <semaphore.h> + #include "im.h" #include "escape.h" #define WRITE_BUFFER_LEN 128 @@ -41,7 +45,14 @@ void winchhook(int a) { } //child process pids pid_t shell_pid; -pid_t om_pid; +pthread_t om_thread; +pthread_t im_disp_thread; +//stdout semaphore +sem_t out_sem; +//tracks whether the screen has been updated by om +int om_updated = 1; + + //return 0 on success, -1 on error //sets the global vars pty_master and pty_slave int make_pty() { @@ -88,10 +99,51 @@ void condition_stdin() { void restore_stdin() { tcsetattr(STDIN_FILENO,TCSANOW,&stdin_termio_bk); } +void * om_routine( void *arg) { + //thread handling pty -> stdout + while (running) { + //output manager child process + //buffer for reading from pty_master and writing to stdout + char write_buffer[WRITE_BUFFER_LEN] = {0}; + //only read/write syscalls work well for this, printfs + //etcs do not work, this is blocking which is why its its own + //thread + // pty_master -> STDOUT + int wchars_read = read(pty_master,write_buffer, WRITE_BUFFER_LEN); + if (wchars_read >0) { + out_state = update_esc_state(write_buffer, wchars_read, out_state); + fprintf(stderr, "%c: %d\n", write_buffer[wchars_read-1], out_state); + sem_wait(&out_sem); + write(STDOUT_FILENO,write_buffer,wchars_read); + sem_post(&out_sem); + //sets update flag, im_disp_routine will set it to 0 + om_updated = 1; + } + } +} +void * im_disp_routine (void *args) { + while (running) { + // Every run of this loop, it checks to see if im_buffer has + // updated, if it has, and no escape sequences have been written + // so far, it will display the im + if (im_updated |om_updated) { + fprintf(stderr, "printing im statusline\n"); + if (safe_state(out_state)) { + sem_wait(&out_sem); + disp_im(STDIN_FILENO, trows, tcols); + sem_post(&out_sem); + im_updated = 0; + om_updated = 0; + } + } + } +} //main thread exit void exit_main() { //kill shell , can not be blocked kill(shell_pid, SIGKILL); + pthread_cancel(om_thread); + pthread_cancel(im_disp_thread); //exit, only the master process should reach this point close(pty_master); close(pty_slave); @@ -155,71 +207,54 @@ int main (int argc, char * argv[], char * envp[]) { //should automatically close any file descriptors _exit(0); } else { - //forks for read and write, master process handles im, child - //process just handles transfering pty output to stdout - om_pid = fork(); - if (om_pid == 0) { - //sets the name for cleaner ps output - prctl(PR_SET_NAME, "ptyim om thread"); - //output manager child process - //runs forever until SIGKILL'd - while (true) { - //output manager child process - //buffer for reading from pty_master and writing to stdout - char write_buffer[WRITE_BUFFER_LEN] = {0}; - //only read/write syscalls work well for this, printfs - //etcs do not work - // pty_master -> STDOUT - int wchars_read = read(pty_master,write_buffer, WRITE_BUFFER_LEN); - if (wchars_read >0) { - write(STDOUT_FILENO,write_buffer,wchars_read); - } - // stdin -> pty_master, im logic is also here - } - //child process exit - _exit(0); - } else { - //master process - //registers interrupts - signal(SIGCHLD, childhook); - signal(SIGWINCH, winchhook); - //display the im for the first time - disp_im(STDIN_FILENO, trows, tcols); + //creates stdout semaphire + if (sem_init(&out_sem, 0, 1)) { + fprintf(stderr, "errno: %d, Error creating output sempahore\n", errno); + exit_main(); + } + //creates a thread that just handles pty -> stdout transfers + if (pthread_create(&om_thread, NULL, &om_routine, NULL) ) { + fprintf(stderr, "errno: %d, Error creating om thread\n", errno); + exit_main(); + } + if (pthread_create(&im_disp_thread, NULL, &im_disp_routine, NULL) ) { + fprintf(stderr, "errno: %d, Error creating im display thread\n", errno); + exit_main(); + } + //master process + //registers interrupts + signal(SIGCHLD, childhook); + signal(SIGWINCH, winchhook); - //1 char buffer for reading from stdin and writing to pty_master - char read_buffer[1] = {0}; + //1 char buffer for reading from stdin and writing to pty_master + char read_buffer[1] = {0}; - //open - while (running) { - int rchars_read = read(STDIN_FILENO, read_buffer, 1); - if (rchars_read > 0) { - //feeds input char into the escape state - //machine - in_state = update_esc_state(read_buffer, 1, in_state); - //skips if the char was anything but - //normal - if (in_state == NORMAL || in_state ==DOUBLE_ESC) { - //feeds the input char into the im state machine - char input_buffer[IM_TABLE_ENTRY_LEN+1] = {0}; - int im_chars = update_im_state(read_buffer[0], - input_buffer); - //just in case it wasn't null terminated right - input_buffer[im_chars] = 0; - if (im_chars >0) { - //writes the input into pty_master if - //there was an output from the state - //machine - write(pty_master,input_buffer,im_chars); - } - } else { - write(pty_master,read_buffer,1); + //open + while (running) { + int rchars_read = read(STDIN_FILENO, read_buffer, 1); + if (rchars_read > 0) { + //feeds input char into the escape state + //machine + in_state = update_esc_state(read_buffer, 1, in_state); + //skips if the char was anything but + //normal + if (in_state == NORMAL || in_state ==DOUBLE_ESC) { + //feeds the input char into the im state machine + char input_buffer[IM_TABLE_ENTRY_LEN+1] = {0}; + int im_chars = update_im_state(read_buffer[0], + input_buffer); + //just in case it wasn't null terminated right + input_buffer[im_chars] = 0; + if (im_chars >0) { + //writes the input into pty_master if + //there was an output from the state + //machine + write(pty_master,input_buffer,im_chars); } - //any input update will lead to a disp_im update - disp_im(STDIN_FILENO, trows, tcols); + } else { + write(pty_master,read_buffer,1); } } - //at the end of the main process, kil lthe om process - kill(om_pid, SIGKILL); } } exit_main(); |