tui.c: a simple ncurses hello world tui app:
// gcc -o tui tui.c -lncurses
#include <ncurses.h>
int main() {
initscr(); // start curses mode
printw("Hello, World!"); // print Hello, World
refresh(); // print it on the real screen
getch(); // wait for user input
endwin(); // end curses mode
return 0;
}
test.c: a c program need to running on background (avoid blocking other terminal operations & tasks)
// gcc -o test test.c -lpthread
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
int countdown = 2;
void start_tui(){
system("./start.sh");
}
void sigusr1_handle(int signum){
system("uptime");
}
void sigtstp_handle(int signum){
_exit(0);
}
void* func2(void* callback){
signal(SIGUSR1, sigusr1_handle); // trap SIGUSR1
signal(SIGTSTP, sigtstp_handle); // trap SIGTSTP
printf("this is func2 running...");
sleep(3);
int status;
start_tui(); // just start the TUI app
void (*reset_timer)() = callback; // set callback
reset_timer(); // execute callback
return NULL;
}
void reset(){ // callback func definition
countdown = 2; // reset count down
}
void func1(){
while(1){
while(countdown > 0){ // timer 3s
printf("count down: %d\n", countdown);
sleep(1);
countdown--;
}
printf("count down: %d\n", countdown);
if(!countdown){ // segregate the process logic
pthread_t thread;
pthread_create(&thread, NULL, func2, reset); // exec func2
pthread_join(thread, NULL); // wait for thread end
printf("func2 has stopped.\n");
}
}
}
int main(){
func1();
return 0;
}
start.sh: called by above c program, to startup tui window.
#!/bin/sh
set -m # enable job control
./tui # invoke the ncurses tui app
expected behavior:
$ ./test & # this should be running in bg, so that no block on other user task on this tty
count down 2
count down 1
count down 0
hello world! # tui window output on foreground
<press any key to exit from ncurse tui window, interrupt the tui thread>
count down 2
count down 1
count down 0
actual behavior:
$ ./test & # this should be running in bg, so that no block on other user task on this tty
count down 2
count down 1
count down 0
hello world! # tui window output on foreground
<try press any key to exit from ncurse tui window, interrupt the tui thread>
<OOPs, the ssh terminal logged out. ssh session is down>
<login again, the tui hello world process is still running...
<the keystroke wont convey msg to inner thread of a background process>
the question:
0 if the test binary run on foreground:
$ test
then everything work's fine, but terminal block to neglect all userinput.
1 how can a background running task invoke a foreground tui app, let the terminal input active for the foreground app?
2 I'm trying to bring the foreground tui app background, but let it accept for stdin and output to stdout of current terminal.
For putting a job in backroung AND keep tty
useable for other foregroung jobs, you have to free STANDARDS descriptors (STD I/O and STDERR):
Here is a minimal shell sample (tested under busybox, dash and others):
Nota instead of your helloworld
program, I run uptime
which will output something too.
#!/bin/sh
bgTask() {
trap 'uptime >&4' USR1
trap 'break' TSTP
while :; do
read -r _
done
echo "SUB-Process $$ ended." >&4
}
exec 4>&1
bgTask </dev/null >/dev/null 2>&1 &
printf 'Task bgTask %d started!\nYou could trigg them by\n - kill -USR1 %d
Then you could stop them by\n - kill -TSTP %d\n' $! $! $!