I am trying to implement a game using ncurses in C. I have to show the current time (the time must update each second) and my while loop looks like this
while(1)
{
clk = time(NULL);
cur_time = localtime(&clk);
mvprintw(0,1,"%d %d %d",cur_time->tm_hour,cur_time->tm_min,cur_time->tm_sec);
int key = getch()
//other stuff
}
My problem is that the time will refresh only when I press a key. Is it a way to make the time refresh without the need of pressing a key (and to implement this in the same while)?
There are a couple of functions you could use:
nodelay
timeout
int nodelay(WINDOW *win, bool bf);
Set bf true to make getch() non-blocking
void timeout(int delay);
Delay is in milliseconds, so if you set it to 1000, the getch will timeout after a second.
In both cases getch will return ERR if there is no input.
The solution here is EITHER to use non-blocking IO or to use threads. However, using threads will give you a new problem, which is that only one thread can use curses at any given time, so you will need to use locks or some such to prevent the other thread(s) from using curses at that point in time. Of course, one solution for that is to have one thread responsible for updating the screen content, and other threads simply send messages to that thread with "I want to put on the screen at X, Y"
This is a very ugly hack which supports just a single stdio function: fgetc(). Others could be added, btw. It works by setting a timer, an if the alarm goes off before a single character is read, a -2 value is returned instead (remember : -1 means EOF)
It won't work with any of the other curses's wgetXXX(), functions, which may call fgetc() (etc) directly. YMMV.
But, in the general case, I think you should investigate wgetch_events().
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
sigjmp_buf the_jump;
int my_fgetc(FILE *fp, unsigned timeout);
void sig_handler(int signr);
void sig_handler(int signr) {
switch (signr) {
case SIGALRM:
siglongjmp(the_jump,1);
break;
default:
break;
}
}
int my_fgetc(FILE *fp, unsigned timeout)
{
alarm( timeout);
switch (sigsetjmp(the_jump, -1)) {
case 0:
alarm(0);
return fgetc (fp);
case 1:
return -2;
default:
return -3;
}
}
int main()
{
int rc;
signal(SIGALRM, sig_handler);
rc = setvbuf(stdin, NULL, _IONBF, 0);
printf("setvbuf(_IONBF) = %d\n", rc);
while (1) {
rc = my_fgetc(stdin, 1);
printf("my_fgetc(NULL) = %d\n", rc);
}
return 0;
}
Related
I want to read everything that is on stdin after 10 seconds and then break. The code I've been able to write so far is:
#include <stdio.h>
#include <stdlib.h>
int main() {
sleep(10);
char c;
while (1) { // My goal is to modify this while statement to break after it has read everything.
c = getchar();
putchar(c);
}
printf("Everything has been read from stdin");
}
So when the letter "c" is entered before the 10 seconds have elapsed, it should print "c" (after sleep is done) and then "Everything has been read from stdin".
So far I have tried:
Checking if c is EOF -> getchar and similar functions never return EOF for stdin
Using a stat-type function on stdin -> stat-ing stdin always returns 0 for size (st_size).
Here's an offering that meets my interpretation of your requirements:
The program reads whatever data is typed (or otherwise entered) on standard input in a period of 10 seconds (stopping if you manage to enter 2047 characters — which would probably mean that the input is coming from a file or a pipe).
After 10 seconds, it prints whatever it has collected.
The alarm() call sets an alarm for an integral number of seconds hence, and the system generates a SIGALRM signal when the time is up. The alarm signal interrupts the read() system call, even if no data has been read.
The program stops without printing on receiving signals.
If the signal is one of SIGINT, SIGQUIT, SIGHUP, SIGPIPE, or SIGTERM, it stops without printing anything.
It fiddles with the terminal settings so that the input is unbuffered. This avoids it hanging around. It also ensures that system calls do not restart after a signal is received. That may not matter on Linux; using signal() on macOS Big Sur 11.7.1, the input continued after the alarm signal, which was not helpful — using sigaction() gives you better control.
It does its best to ensure that the terminal mode is restored on exit, but if you send an inappropriate signal (not one of those in the list above, or SIGALRM), you will have a terminal in non-canonical (raw) mode. That leads to confusion, in general.
It is easy to modify the program so that:
input is not echoed by the terminal driver;
characters are echoed by the program as they arrive (but beware of editing characters);
signals are not generated by the keyboard;
so it doesn't futz with standard input terminal attributes if it is not a terminal.
Code
/* SO 7450-7966 */
#include <ctype.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <unistd.h>
#undef sigemptyset /* MacOS has a stupid macro that triggers -Wunused-value */
static struct termios sane;
static void stty_sane(void)
{
tcsetattr(STDIN_FILENO, TCSANOW, &sane);
}
static void stty_raw(void)
{
tcgetattr(STDIN_FILENO, &sane);
struct termios copy = sane;
copy.c_lflag &= ~ICANON;
tcsetattr(STDIN_FILENO, TCSANOW, ©);
}
static volatile sig_atomic_t alarm_recvd = 0;
static void alarm_handler(int signum)
{
signal(signum, SIG_IGN);
alarm_recvd = 1;
}
static void other_handler(int signum)
{
signal(signum, SIG_IGN);
stty_sane();
exit(128 + signum);
}
static int getch(void)
{
char c;
if (read(STDIN_FILENO, &c, 1) == 1)
return (unsigned char)c;
return EOF;
}
static void set_handler(int signum, void (*handler)(int signum))
{
struct sigaction sa = { 0 };
sa.sa_handler = handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; /* No SA_RESTART! */
if (sigaction(signum, &sa, NULL) != 0)
{
perror("sigaction");
exit(EXIT_FAILURE);
}
}
static void dump_string(const char *tag, const char *buffer)
{
printf("\n%s [", tag);
int c;
while ((c = (unsigned char)*buffer++) != '\0')
{
if (isprint(c) || isspace(c))
putchar(c);
else
printf("\\x%.2X", c);
}
printf("]\n");
}
int main(void)
{
char buffer[2048];
stty_raw();
atexit(stty_sane);
set_handler(SIGALRM, alarm_handler);
set_handler(SIGHUP, other_handler);
set_handler(SIGINT, other_handler);
set_handler(SIGQUIT, other_handler);
set_handler(SIGPIPE, other_handler);
set_handler(SIGTERM, other_handler);
alarm(10);
size_t i = 0;
int c;
while (i < sizeof(buffer) - 1 && !alarm_recvd && (c = getch()) != EOF)
{
if (c == sane.c_cc[VEOF])
break;
if (c == sane.c_cc[VERASE])
{
if (i > 0)
i--;
}
else
buffer[i++] = c;
}
buffer[i] = '\0';
dump_string("Data", buffer);
return 0;
}
Compilation:
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common tensec53.c -o tensec53
No errors (or warnings, but warnings are converted to errors).
Analysis
The #undef line removes any macro definition of sigemptyset() leaving the compiler calling an actual function. The C standard requires this to work (§7.1.4 ¶1). On macOS, the macro is #define sigemptyset(set) (*(set) = 0, 0) and GCC complains, not unreasonably, about the "right-hand operand of comma expression has no effect". The alternative way of fixing that warning is to test the return value from sigemptyset(), but that's arguably sillier than the macro. (Yes, I'm disgruntled about this!)
The sane variable records the value of the terminal attributes when the program starts — it is set by calling tcgetattr() in stty_raw(). The code ensures that sane is set before activating any code that will call sttr_sane().
The stty_sane() function resets the terminal attributes to the sane state that was in effect when the program started. It is used by atexit() and also by the signal handlers.
The stty_raw() function gets the original terminal attributes, makes a copy of them, modifies the copy to turn off canonical processing (see Canonical vs non-canonical terminal input for more details), and sets the revised terminal attributes.
Standard C says you can't do much in a signal handler function than set a volatile sig_atomic_t variable, call signal() with the signal number, or call one of the exit functions. POSIX is a lot more gracious — see How to avoid using printf() in a signal handler? for more details.
There are two signal handlers, one for SIGALRM and one for the other signals that are trapped.
The alarm_handler() ignores further alarm signals and records that it was invoked.
The other_handler() ignores further signals of the same type, resets the terminal attributes to the sane state, and exits with a status used to report that a program was terminated by a signal (see POSIX shell Exit status for commands).
The getch() function reads a single character from standard input, mapping failures to EOF. The cast ensures that the return value is positive like getchar() does.
The set_handler() function uses sigaction() to set the signal handling. Using signal() in the signal handlers is a little lazy, but adequate. It ensures that the SA_RESTART bit is not set, so that when a signal interrupts a system call, it returns with an error rather than continuing.
The dump_string() function writes out a string with any non-printable characters other than space characters reported as a hex escape.
The main() function sets up the terminal, ensures that the terminal state is reset on exit (atexit() and the calls to set_handler() with the other_handler argument), and sets an alarm for 10 seconds hence.
The reading loop avoids buffer overflows and stops when the alarm is received or EOF (error) is detected.
Because canonical processing is turned off, there is no line editing. The body of the loop provides primitive line editing — it recognizes the erase (usually backspace '\b', sometimes delete '\177') character and the EOF character and handles them appropriately, otherwise adding the input to the buffer.
When the loop exits, usually because the alarm went off, it null terminates the string and then calls dump_string() to print what was entered.
If you wanted sub-second intervals, you would need to use the POSIX timer_create(), timer_delete(), timer_settime() (and maybe timer_gettime() and timer_getoverrun()) functions, which take struct timespec values for the time values. If they're not available, you might use the obsolescent setitimer() and getitimer() functions instead. The timer_create() step allows you to specify which signal will be sent when the timer expires — unlike alarm() and setitimer() which both send pre-determined signals.
POSIX functions and headers:
Functions
Functions
Headers
alarm()
sigaction()
<ctype.h>
atexit()
sigemptyset()
<signal.h>
exit()
signal()
<stdio.h>
getitimer()
tcgetattr()
<stdlib.h>
isprint()
tcsetattr()
<sys/time.h>
isspace()
timer_create()
<termios.h>
perror()
timer_delete()
<time.h>
printf()
timer_getoverrun()
<unistd.h>
putchar()
timer_gettime()
read()
timer_settime()
setitimer()
You can use the select function to wait to see if there is something to read on stdin with a timeout that starts at 10 seconds. When it detects something, you read a character and check for errors or EOF. If all is good, then you call select again, reducing the timeout by the elapsed time so far.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <time.h>
struct timeval tdiff(struct timeval t2, struct timeval t1)
{
struct timeval result;
result.tv_sec = t2.tv_sec - t1.tv_sec;
result.tv_usec = t2.tv_usec - t1.tv_usec;
while (result.tv_usec < 0) {
result.tv_usec += 1000000;
result.tv_sec--;
}
return result;
}
int cmptimestamp(struct timeval t1, struct timeval t2)
{
if (t1.tv_sec > t2.tv_sec) {
return 1;
} else if (t1.tv_sec < t2.tv_sec) {
return -1;
} else if (t1.tv_usec > t2.tv_usec) {
return 1;
} else if (t1.tv_usec < t2.tv_usec) {
return -1;
} else {
return 0;
}
}
int main()
{
struct timeval cur, end, delay;
int rval, len = 0;
fd_set fds;
gettimeofday(&cur, NULL);
end = cur;
end.tv_sec += 10;
FD_ZERO(&fds);
FD_SET(0, &fds);
if (fcntl(0, F_SETFL, O_NONBLOCK) == -1) {
perror("fcntl failed");
exit(1);
}
do {
delay = tdiff(end, cur);
rval = select(1, &fds, NULL, NULL, &delay);
if (rval == -1) {
perror("select failed");
} else if (rval) {
char c;
len = read(0, &c, 1);
if (len == -1) {
perror("read failed");
} else if (len > 0) {
printf("c=%c (%d)\n", c, c);
} else {
printf("EOF\n");
}
} else {
printf("timeout\n");
}
gettimeofday(&cur, NULL);
} while (rval > 0 && len > 0 && cmptimestamp(end,cur) > 0);
return 0;
}
Note that this doesn't detect the keys as you press them, only after you've either pressed RETURN or stdin is closed.
I am trying to allow an interrupt to cause a certain value to be returned by readline. Here is a minimal example:
#include <stdio.h>
#include <signal.h>
#include <readline/readline.h>
void handler (int status)
{
rl_replace_line("word",0);
rl_redisplay();
rl_done = 1;
}
int main (int argc, char** argv)
{
char* entry;
signal(SIGINT,handler);
entry = readline("");
printf("\nEntry was: %s\n", entry);
return 0;
}
If I run this code and press Control-C, after I hit ENTER, sure enough it prints "Entry was: word". But I would like it to do so without the user needing to press ENTER. I basically just want to set entry to "word" when the interrupt signal is received, ending the readline function. I have been unable to find any documentation for how to just end the readline loop and return a certain value (I'm sure it's out there, but I haven't found it).
One thing I tried was adding
(*rl_named_function("accept-line"))(1,0);
at the end of handler, but it didn't send the text to "entry" immediately.
I think I have what you want running here.
#include <stdio.h>
#include <signal.h>
#include <readline/readline.h>
int event(void) { }
void handler (int status)
{
rl_replace_line("word",0);
rl_redisplay();
rl_done = 1;
}
int main (int argc, char** argv)
{
char* entry;
rl_event_hook=event;
signal(SIGINT,handler);
entry = readline("");
printf("\nEntry was: %s\n", entry);
return 0;
}
The secret is the rl_done is only checked in the event loop. When you give it a null event hook function, it checks the rl_done and exits.
I don't believe there is any guarantee that you can call back into readline functions from an asynchronous signal handler. (The fact that it "seems to" work does not guarantee that it will not fail disastrously from time to time.) In general, you should do the absolute minimum in a signal handler, such as setting a flag to indicate that the signal has been received.
The readline library provides the variable rl_signal_event_hook, whose value is a function which will be called when a readline call is interrupted by a signal. It would probably be wise to put any code which modifies the readline state into such a function.
But it seems like the safest solution here would be to arrange for the Control-C character to be passed directly to readline without triggering a SIGINT. You could create a custom terminal setting based on the termios struct returned by tcgetattr which turns off the mapping of Ctrl-C to the INTR function, either by unsetting the ISIG flag (which will also turn off other interrupt characters, including Ctrl-Z) or by changing c_cc[VINTR] to _POSIX_VDISABLE (or to some other key).
If you are on Windows and you are not using Cygwin, which includes termios emulation, you can use native APIs to enable and disable Control-C handling.
Then you can use rl_bind_key to bind Ctrl-C (which is 3) to your own function. The function needs to match the rl_command_func_t typedef, which is int(*)(int, int). The function should return 0; in your simple case, you can probably ignore the arguments, but for the record the first one is a "count" (the numeric argument, entered by typing a number while holding down the Alt key), and the second one is the key itself.
You should probably make a copy of the termios structure before you modify it so that you can reset the terminal settings once you're done. Generally, you would want to install and restore the terminal settings around every call to readline (which is what readline itself does, as well).
CTRL+C should pass a SIGINT, or similar interrupt signal to your program. There should be ways to override the handling, see here for example.
You can achieve this by using the alternate interface, where your code is doing the event loop and calls libreadline functions each time a character needs to be read from the terminal. In the event loop you can handle all extra asynchronous events like signals (but not only that --- think a terminal chat application where messages arrive asynchronously from the network).
Here's how it could look like:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <readline/readline.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
static volatile sig_atomic_t my_signal_flag = 0;
static int done_loop = 0;
void my_signal_handler (int status)
{
my_signal_flag = 1; // set a volaatile sig-atomic_t var
// and exit, just as the standard says
}
void my_rlhandler(char* line) // all your app is in this function
// called each time a line is ready
{
if (line && strcmp(line, "quit"))
printf("Entry was: %s\n", line);
else
{
done_loop = 1;
rl_set_prompt("");
}
free(line);
}
void my_event_loop() // event loop
// handle all async events here
// signals, network, threads, whatever
{
rl_callback_handler_install("w00t>", my_rlhandler);
do
{
signal(SIGINT, my_signal_handler); // readline may override this
// better do it here each time
fd_set readfds; // prepare the select
FD_ZERO(&readfds);
FD_SET(0, &readfds);
if (select(1, &readfds, NULL, NULL, NULL) > 0)
{
rl_callback_read_char(); // character ready, let readline eat it
}
else if (my_signal_flag )
{
my_signal_flag = 0; // can get here only after a signal
rl_replace_line("word",0);
rl_done = 1;
rl_redisplay();
rl_pending_input = '\n'; // not sure why it's needed
rl_callback_read_char();
}
}
while (!done_loop);
rl_callback_handler_remove();
}
int main (int argc, char** argv)
{
char* entry;
signal(SIGINT, my_signal_handler);
my_event_loop();
return 0;
}
While this may seem more complicated that other methods, the callback interface is more appropriate for real-life programs that need to handle a variety of events.
Tried my best to figure this out on my own, but I really do not want to continue tampering with things that I do not fully understand. So for a programming assignment I have to do in C, I need to terminate a program upon the user entering CTRL+D key stroke via a terminal. I tried to isolate that functionality in a smaller test function, but now my CTRL+D behaves as my CTRL+C and CTRL+C does not have any effect, even outside of the program when it finishes executing. This is the program that caused this change:
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
printf("\n");
signal(SIGINT, SIG_DFL);
exit(0);
}
int main(){
signal(SIGINT, ctrlD);
while(1) {
printf("Hello\n");
sleep(5);
}
}
The line signal(SIGINT, SIG_DFL); was added afterward upon realizing my CTRL+C no longer worked. I thought it would return the keystrokes to their original functionalities, but to no avail. What do I do to get back the original functionalities while also making this program work with CTRL+D?
***EDIT: This question seems to have gone off the rails a bit. I get now that Ctrl+D is not a signal. Nonetheless, I no longer have the functionality of Ctrl+C anymore when attempting to use it in my MAC OS terminal, and instead Ctrl+D seems to have that exact functionality. HOW exactly can I return each to have the functionality that they had before I went on this haphazard journey?
If your intention is to restore signal's default behavior after executing handler then, pass SA_RESETHAND flag to sa_flags while registering signal action. For example.
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_RESETHAND;
act.sa_handler = some_handler;
sigaction(SIGINT, &act, NULL);
From sigaction() man
SA_RESETHAND
Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when
establishing a signal handler.
If you write a program to explore signals, it is much better to write it carefully, using proper POSIX interfaces (sigaction() instead of signal()), and avoiding undefined behaviour (using non-async-signal safe functions in a signal handler).
Consider, for example, the following program:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
static volatile sig_atomic_t sigint_count = 0;
static void catch_sigint(int signum)
{
if (signum == SIGINT)
sigint_count++;
}
static int install_sigint(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = catch_sigint;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) == -1)
return errno;
return 0;
}
static int install_default(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
struct timespec duration;
int result;
if (install_sigint()) {
fprintf(stderr, "Cannot install SIGINT handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
duration.tv_sec = 5;
duration.tv_nsec = 0; /* 1/1000000000ths of a second. Nine zeroes. */
printf("Sleeping for %d seconds.\n", (int)duration.tv_sec);
fflush(stdout);
while (1) {
result = nanosleep(&duration, &duration);
if (!result)
break;
if (errno != EINTR) {
fprintf(stderr, "nanosleep() failed: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* nanosleep was interrupted by a delivery of a signal. */
if (sigint_count >= 3) {
/* Ctrl+C pressed three or more times. */
if (install_default(SIGINT) == -1) {
fprintf(stderr, "Cannot revert SIGINT to the default handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("SIGINT has been reverted to the default handler.\n");
fflush(stderr);
}
}
if (sigint_count > 0)
printf("You pressed Ctrl+C %d time%s.\n", (int)sigint_count, (sigint_count > 1) ? "s" : "");
else
printf("You did not press Ctrl+C at all.\n");
return EXIT_SUCCESS;
}
The #define tells your C library (glibc in particular) that you want POSIX.1-2008 (and later) features from it.
The INT signal handler only increments a volatile sig_atomic_t counter. Note that this type may have a very small range it can represent; 0 to 127, inclusive, should be safe.
The main program waits using the POSIX nanosleep() function. On some systems, sleep() may be implemented via the SIGALRM function, so it is better avoided when using signals otherwise; nanosleep() does not interfere with signals like that at all. Plus, nanosleep() can return the amount of time remaining, if it is interrupted by a signal delivery.
In the main loop, nanosleep() will return 0, if it has slept the entire interval (but note that it may not update the remaining time to 0 in this case). If it is interrupted by the delivery of a signal, it will return -1 with errno == EINTR, and the remaining time updated. (The first pointer is to the duration of the sleep, and the second is to where the remaining time should be stored. You can use the same structure for both.)
Normally, the main loop does only one iteration. It can do more than one iteration, if it is interrupted by the delivery of a signal.
When the main loop detects that sigint_count is at least three, i.e. it has received at least three INT signals, it resets the signal handler back to default.
(Note that both the memset() and the sigemptyset() are important when clearing the struct sigaction structure. The memset() ensures that future code is backwards compatible with older code, by ensuring even padding fields are cleared. And sigemptyset() is the safe way to clear the signal mask (set of signals blocked while the handler runs).)
(In theory, memset() is not async-signal-safe, while both sigemptyset() and sigaction() are. This is why I reset the signal handler in the main program, and not in the signal handler.)
If you want to print from a signal handler, you need to use low-level I/O, because <stdio.h> functions are not async-signal safe. For example, you can use the following function to print strings to standard output:
static int wrerr(const char *p)
{
const int saved_errno = errno;
int retval = 0;
if (p) {
const char *q = p;
ssize_t n;
while (*q)
q++;
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
retval = EIO;
break;
} else
if (errno != EINTR) {
retval = errno;
break;
}
}
}
errno = saved_errno;
return retval;
}
The above wrerr() function is async-signal safe (because it only uses async-signal safe functions itself), and it even keeps errno unchanged. (Many guides forget to mention that it is quite important for a signal handler to keep errno unchanged. Otherwise, when a function is interrupted by a signal handler, and that signal handler modifies errno, the original function will return -1 to indicate an error, but then errno is no longer EINTR!)
You can just use wrerr("INT signal!\n") if you want. The return value from wrerr() is zero if the write was successful, and an errno error code otherwise. It ignores interrupts itself.
Do note that you should not mix stderr output via fprintf() or other <stdio.h> functions with the above (except perhaps for printing error messages when the program aborts). Mixing them is not undefined behaviour, it just may yield surprising results, like wrerr() output appearing in the midst of a fprintf(stderr,...) output.
Its because of exit(0) statement in the handler, when SIGINT is raised, handler strlD gets called and you might thinking why signal(SIGINT,SIG_DFL) didn't work ? Actually it works. But your main process a.out get terminated successfully there itself by calling exit(0). remove exit(0) if you want to restore the behavior of SIGINT.
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
//printf("CTRL+C pressed\n");/* just to observe I added one printf
statement, Ideally there shouldn't be any printf here */
signal(SIGINT, SIG_DFL);/*restoring back to original action */
}
int main(){
signal(SIGINT, ctrlD);/*1st time when CTRL+C pressed, handler ctrlD gets called */
while(1) {
printf("Hello\n");
sleep(5);
}
return 0;
}
Also its advisable to use sigaction() instead of signal() as told here What is the difference between sigaction and signal? . Read man 2 sigaction and man 2 exit to check what exit(0) means.
Also this How to avoid using printf in a signal handler?
Edit :
void ctrlD(int sig){
/* printf("CTRL+C pressed \n"); */
signal(SIGINT, SIG_DFL); /* only one time CTRL+C works
after that SIG_DFL will terminate whole process */
}
int main(){
signal(SIGINT, ctrlD); /* if you press CTRL+C then it will go to handler
and terminate */
int ch;
while( ((ch = getchar())!=EOF) ) { /* wait or read char until CTrl+D is not pressed */
printf("Hello : %d \n",ch);/* ASCII equivalent of char */
}
return 0;
}
Thank you everyone who contributed to this question. The resources provided/linked were tremendously helpful in learning more about signals (and that EOF isn't a signal), among the other wealth of information provided.
After some more research, I found out that somehow, either through some accidental bash command gone awry, or perhaps the program posted in my original question itself, I had altered the key mappings for my terminal's stty settings. If anyone finds themselves in this oddly specific situation in the future, I hope this can be of help, as it is what fixed my problem:
Enter the command $ stty -a to see all of your terminals settings, specifically the "cchars" section.
I then saw the reversal, and fixed it like so:
$ stty intr ^C
$ stty eof ^D
Then you can run $ stty -a once again to see that the changes have properly taken effect. Once again, thanks everyone.
How can I break out of this loop?
while(1){
//continuously blink an led
//stop when user hits CTRL+D
}
//do other stuff
I tried while(fgets(s, BUFSIZ, stdin) != NULL), but of course it will wait for user input before continuing. I want the code inside the loop to run continuously, and break only the user hits CTRL+D.
I've done this at a low level with interrupts, but no clue how to do it in a high level environment.
Platform is Raspbian (Kernel 3.10) on Raspberry Pi
Maybe this solution transforming Ctrl+D into Ctrl+C and Ctrl+C into Ctrl+D using term caps may help you : https://stackoverflow.com/a/1516414/1405208.
Ctrl+D will therefore send the SIGINT signal. You just have to catch it. You may have to use a global variable though.
volatile sig_atomic_t ctrld_pressed = 0;
void ctrld(int sig)
{
ctrld_pressed = 1;
}
int main()
{
signal(SIGINT, ctrld);
while (!ctrld_pressed)
{
}
}
As #unwind stated, you may use select.
#include <sys/select.h>
#include <unistd.h>
#include <string.h>
int main()
{
int run = 1, rc;
fd_set fd_list, readfd;
FD_ZERO(&fd_list);
FD_SET(STDIN_FILENO, &fd_list);
while (run)
{
readfd = fd_list;
rc = select(STDIN_FILENO + 1, &readfd, NULL, NULL, NULL);
if (rc == -1)
{
perror("Select error");
return 1;
}
if (FD_ISSET(STDIN_FILENO, &readfd) && read(STDIN_FILENO, &rc, sizeof(rc)) == 0 )
run = 0;
}
return 0;
}
We have told select to monitor for reading just one fd(STDIN_FILENO): the standard input one.
Once the user enters something, select will alert us of that event; we investigate to know whether that input comes from STDIN_FILENO and if so, we read from it. If read returns 0, that means an end-of-file was met.
You can try using select() if your platform supports it, otherwise you must make the input stream non-blocking ("raw") which again is highly platform-dependent code.
How can I exit or stop a thread immediately?
How can I make it stop immediately when the user enters an answer?
I want it to reset for every question.
Here's my code where threading is involved
int q1() {
int timer_start;
char ans[] = "lol";
char user_ans[50];
timer_start = pthread_create( &xtimer,NULL,(void*)timer_func,(void*)NULL);
printf("What is the capital city of Peru?\n");
while(limit){
scanf("%s",user_ans);
if(limit)
{
if(!strcmp(user_ans, ans))
{
// printf("YAY!\n");
score++;
// q2();
}
else
{
game_over();
}
}
}
}
You can simply call pthread_cancel on that thread to exit it. And you can send SIGSTOP/SIGCONT signal via pthread_kill to stop/restart it.
But if all you want is a timer, why must you thread?
Based on your code I can give a simple answer:
In this case do not use threads at all.
You do not need them. Store the start time, let the user answer, check the time again after user gives an answer.
{
time_t startTimeSec = time(NULL);
// answering
time_t endTimeSec = time(NULL);
time_t timeTakenSec = endTime-startTime;
if (timeTaken > 10) {
// do your thing
}
}
To answer your question:
You should use a mutex-protected or volatile variable to asynchronously communicate between threads. Set that variable from one thread and check it in another. Then reset its value and repeat. A simple snippet:
int stopIssued = 0;
pthread_mutex_t stopMutex;
int getStopIssued(void) {
int ret = 0;
pthread_mutex_lock(&stopMutex);
ret = stopIssued;
pthread_mutex_unlock(&stopMutex);
return ret;
}
void setStopIssued(int val) {
pthread_mutex_lock(&stopMutex);
stopIssued = val;
pthread_mutex_unlock(&stopMutex);
}
Using pthread_cancel() is an option, but I would not suggest doing it. You will have to check the threads state after this call returns, since pthread_cancel() does not wait for the actual thread stop. And, which to me is even more important, I consider using it ugly.
Using methods to stop a thread is a brute way.
You should rather politely ask the thread to stop by signalling.
Thereby the thread will have an option to tidy after itself e.g. if it has allocated memory, which it will not have any opportunity to do if the thread is cancelled.
The method is relatively simple and comprises no OS signalling:
define a thread state variable or structure outside the thread. Point to it at the pthread_create and dereference the state variable in the thread.
int thread_state = 0; // 0: normal, -1: stop thread, 1: do something
static void *thread_1 (void *arg)
{
int* pthread_state = arg;
... // initialize the thread locals
while(1)
{
switch( *pthread_state )
{
case 0: // normal thread loop
...
break;
case -1:
... // tidy or whatever is necessary
pthread_exit(0); // exit the thread signalling normal return
break;
case 1: //
... // do something special
break;
}
}
}
pthread_create (&t_1, NULL, thread_1, (void*)&thread_state);
...
thread_state = -1; // signal to the thread to stop
// maybe use pthread_exit(0) to exit main.
// this will leave the threads running until they have finished tidy etc.
It is even possible to communicate with the thread using a structure provided that it is simple 'atomic' variables or a simple handshake mechanism is established. Otherwise it may be necessary to use mutex.
Use pthread_join to wait for threads to terminate.
#Naruil's suggestion to call pthread_cancel() is pretty much the best solution i found, but it won't work if you didn't do the following things.
According to the man-page of pthread_cancel the pthread_cancelibility depend on two thing
thread_cancel_state.
thread_cancel_type.
thread_cancel_state is PTHREAD_CANCEL_ENABLE by default, so our main concern is about the thread_cancel_type, it's default value is type PTHREAD_CANCEL_DEFFERED but we need PTHREAD_CANCEL_ASYNCHRONOUS to set on that thread, which we wan't to cancel.
Following an example given::
#include <stdio.h>
#include <pthread.h>
void *thread_runner(void* arg)
{
//catch the pthread_object as argument
pthread_t obj = *((pthread_t*)arg);
//ENABLING THE CANCEL FUNCTIONALITY
int prevType;
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &prevType);
int i=0;
for( ; i < 11 ; i++)//1 - > 10
{
if(i == 5)
pthread_cancel(obj);
else
printf("count -- %d", i);
}
printf("done");
}
int main(int argc, char *argv[])
{
pthread_t obj;
pthread_create(&obj, NULL, thread_runner, (void*)&obj);
pthread_join(obj, NULL);
return 0;
}
run it using gcc filename.c -lpthread and output the following::
count -- 0
count -- 1
count -- 2
count -- 3
count -- 4
note that the done is never printed because the thread was canceled when the i became 5 & the running thread was canceled. Special thanks #Naruil for the "pthread_cancel" suggestion.