4
\$\begingroup\$

I'm writing a C++ application for POSIX environment with terminal-based User Interface. I'd like to make my application's UI be consistent between Ctrl-Z and fg(i.e: SIGSTOP and SIGCONT).

Here is a minimal example (without using longjmp. this code uses C and POSIX headers only, but entire application will be C++):

#include <cstdio>
#include <cstdlib>
#include <csignal>
#include <unistd.h>
void PrintMessage() {
 printf("Press q to quit");
}
sig_atomic_t signalCheck;
void SigCONTHandler(int sig) {
 if(sig != SIGCONT) {
 return;
 } 
 printf("From Signal Handler\n");
 fflush(stdout);
 if(signalCheck != 0) {
 PrintMessage();
 } 
}
int main() {
 setbuf(stdout, NULL);
 signal(SIGCONT, SigCONTHandler);
 int ch = 0;
 while(true) {
 PrintMessage();
 signalCheck = 1;
 ch = getchar();
 signalCheck = 0;
 if(ch == 'q') {
 break;
 } 
 if(ch == EOF) {
 printf("I asked you to process q.\n");
 return EXIT_FAILURE;
 } 
 } 
 return EXIT_SUCCESS;
}

Usage(Ubuntu 16.04, g++ 5.4, TERM=linux):

$ ./app
Press q to quit
Press q to quit
Press q to quit
Press q to quit
Press q to quit^Z
[2]+ Stopped ./app
$ fg
./app
From Signal Handler
Press q to quit
Press q to quitq

This code works as intended, but I feel this code is Bad. signalCheck variable keep own state to check whether the application need to print PrintMessage() or not. However, if a application become complex, I don't think I can print whole thing to stdout in SigContHandler. Moreover, it won't work without setbuf(stdout, NULL), so I'm trying to make it with longjmp to restore state.

#include <cstdio>
#include <cstdlib>
#include <csignal>
#include <csetjmp>
#include <unistd.h>
sigjmp_buf jumpBuffer;
void PrintMessage() {
 printf("Press q to quit");
}
void SigCONTHandler(int sig) {
 if(sig != SIGCONT) {
 return;
 } 
 printf("From Signal Handler\n");
 siglongjmp(jumpBuffer, 1); 
}
int main() {
 // setbuf(stdout, NULL);
 signal(SIGCONT, SigCONTHandler);
 int ch = 0;
 while(true) {
 if(sigsetjmp(jumpBuffer, 1) == 0) {
 PrintMessage();
 ch = getchar();
 if(ch == 'q') {
 break;
 } 
 if(ch == EOF) {
 printf("I asked you to process q.\n");
 return EXIT_FAILURE;
 } 
 } 
 } 
 return EXIT_SUCCESS;
}

This code works, and I don't need to turn off stdout buffer, but this code also looks bad.

If I need to choose one of them, what I need to choose it? Is it portable from latest Linux to old Unix box?

asked Apr 13, 2017 at 4:19
\$\endgroup\$
3
  • 2
    \$\begingroup\$ I am not sure I understand what you are trying to achieve. In any case, calling printf from a signal handler is an undefined behavior. \$\endgroup\$ Commented Apr 13, 2017 at 4:44
  • \$\begingroup\$ @vnp I didn't know that. It is okay to change it to write(STDOUT_FILENO, ...)? Can I use printf after longjmp? \$\endgroup\$ Commented Apr 13, 2017 at 4:58
  • 1
    \$\begingroup\$ Since write translates directly to a system call, it it kind of safe. In doubt, consult man 7 signal-safety. \$\endgroup\$ Commented Apr 13, 2017 at 6:54

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.