I have a user defined shell project where I'm trying to implement the cat command but allow the user to click CTRL-/ to display the next x-lines. I'm new to signals so I think I have some syntax wrong somewhere...
in main...
while (fgets(buf, sizeof(buf), file) != NULL){ //CITE
//print out first four lines
if (j == 0){
for (i = 0; i < 4; i++){
printf("%s", buf);
fgets(buf, sizeof(buf), file);
}
j++;
}
signal(SIGQUIT, sig_int);
//now check for user input for the next x lines
if (keepRunning){
for (i = 0; i < 4; i++){
printf("%s", buf);
if (i < 3){
if (fgets(buf, sizeof(buf), file) == NULL){
fclose(file);
return 0;
}
}
}
keepRunning = 0;
}
Then I have the following sig_int function defined...
static volatile int keepRunning = 0;
void sig_int(int sig){
keepRunning = 1;
}
The main problem is that you don't slow down or stop anywhere when the signal is not received. You might use pause(), for example; it only returns when a signal is received. You'd then use that in place of the if (keepRunning) block (including the condition).
Alternatively, you might modify the terminal modes so that characters are sent as they're typed ('raw' mode), and attempt to read a character before continuing. However, if you do that, the onus is on you to ensure that the terminal mode is reset before the program exits under as many circumstances as possible. The good news is that there won't be any signals generated from the keyboard in raw mode, but you have to worry about signals from elsewhere.
You might want to let other signals wake the program and exit the loop, but if you don't set a signal handler for them, that'll happen automatically. That is, after pause() returns (it will always return with an error status and errno set to EINTR), you might check whether keepRunning is now 1 and exit the loop if not.
Related
This is a frontend to the tool dc; the idea is to type an infix expression (2 + 3), map it to the corresponding postfix notation (2 3 +) and send it to dc. It's what bc does.
I'm doing this with pipes, but the frontend hangs waiting for output.
This is the code; I will continue commenting it below. The "h" command in my dc is unimplemented, hence is what I'm looking for as an end of output from dc.
TL;DR: the process hangs because stdout in dc is not flushed or that's what I think to have found. How can I read it regardless or force a flush after every write?
What I've found is commented below.
#define DC_EOF_RCV "dc: 'h' (0150) unimplemented"
#define DC_EOF_SND "h\n"
static FILE *sndfp, *rcvfp;
int dcinvoke() {
int pfdout[2], pfdin[2];
pid_t pid;
pipe(pfdout);
pipe(pfdin);
switch (pid = fork()) {
case -1: exit(1);
case 0:
dup2(pfdout[0], STDIN_FILENO);
dup2(pfdin[1], STDOUT_FILENO);
close(pfdout[0]);
close(pfdout[1]);
close(pfdin[0]);
close(pfdin[1]);
execlp("dc", "dc", "-", NULL);
}
close(pfdout[0]);
close(pfdin[1]);
sndfp = fdopen(pfdout[1], "w");
rcvfp = fdopen(pfdin[0], "r");
return 1;
}
void dcsnd(const char *s) {
fputs(s, sndfp);
fflush(sndfp);
}
void dcrcv(char *buf, size_t max) {
fgets(buf, max, rcvfp); // <<<<< HANGS HERE
}
int turnaround() {
dcsnd(DC_EOF_SND); fflush(sndfp);
}
int rcvall() {
char buf[256];
turnaround();
for (;;) {
dcrcv(buf, sizeof(buf));
if (! strcmp(buf, DC_EOF_RCV)) {
break;
}
printf("%s", buf);
}
return 1;
}
int prompt(const char *msg, char *res, size_t resmax, int *eofp) {
char *p;
printf("\n%s ", msg);
if (!fgets(res, resmax, stdin)) {
*eofp = 1;
} else {
if (p = strrchr(res, '\n')) {
*p = 0;
}
*eofp = 0;
}
return 1;
}
int main() {
char buf[128], line[128];
int eof;
dcinvoke();
dcsnd("2 3 +\n");
dcsnd(DC_EOF_SND);
rcvall();
for (;;) {
prompt("Expression", buf, sizeof(buf), &eof);
if (eof) {
break;
}
snprintf(line, sizeof(line), "%s\n", buf);
dcsnd(line);
rcvall();
}
dcsnd("q\n");
return 0;
}
I have removed the error checks for simplicity of this question.
The frontend hangs at the line:
fgets(buf, max, rcvfp);
As I really had no idea how to find the problem, I wrote my own dc which does nothing but responds correctly to an "h" command and outputs everything it gets to a file (so I can debug it; I am not aware of any other way). I can add it here if it's useful.
I've found that a call to fflush(stdout) in (my) dc resumes the frontend, as a call to fgets finally returns.
I cannot change dc itself. How can it not hang on fgets?
Some ideas I had:
Use another thread to flush rcvfp (stdout of dc)
Write it using pseudoterminal
I'm looking for suggestions or a simple way to avoid both of them.
I tried to:
Use read() to fileno(rcvfp)
Read this and this similar posts
Use setlinebuf() (man)
dc sends error messages to stderr, not stdout, so you'll never see them -- they go straight to the terminal (or whatever stderr is connected to in your environment). To be able to read them in your program, you also need to redirect stderr. Add
dup2(pfdin[1], STDERR_FILENO);
in the child fork code.
To make your code actually work, I had to also add a newline to the end of the DC_EOF_RCV string (to match what dc sends), and remove the extra dcsnd(DC_EOF_SND); call from main, since you never do a receive that matches it anywhere. Even with this, you can still get race conditions within dc between writing to stdout and stderr, which can cause the output lines to get mixed, resulting in a response that does not match your DC_EOF_RCV string. You can probably avoid those by adding a small sleep to your turnaround function.
An alternate option is using poll in your main loop to read from stdin and dc simultaneously. With this, you don't need the weird "send h command to trigger an error" mechanism to figure out when dc is done -- you just loop. Your main loop ends up looking like:
struct pollfd polling[2] = { { STDIN_FILENO, POLLIN, 0 }, { fileno(rcvfp), POLLIN, 0 } };
printf("Expression ");
for(;;) {
if (poll(polling, 2, -1) < 0) {
perror("poll");
exit(1); }
if (polling[0].revents) {
/* stdin is ready */
if (!fgets(buf, sizeof(buf), stdin))
break;
dcsnd(buf); }
if (polling[1].revents) {
/* dc has something for us */
printf("\r \r"); /* erase the previsouly printed prompt */
dcrcv(buf, sizeof(buf));
printf("%s\n", buf); }
printf("Expression "); /* new prompt */
}
There's more detail you can do here with managing error conditions (the revents might be POLLERR or POLLHUP for an error or hangup rather than POLLIN for normal input -- all of these are non-zero values, so testing just for nonzero is reasonable).
With the dc command provided by macOS 10.14.6 Mojave, sending 2 3 + to the program works fine; it just doesn't say anything because you've not asked it to.
$ dc
2 3 +
p
5
q
$
The p (print) command triggers the response 5. The q command quits.
Sending h gets a mixed response:
$ dc
h
dc: 'h' (0150) unimplemented
q
$
The response is mixed because the dc: (and space) goes to standard error and the message to standard output:
$ dc >/dev/null
h
dc:
q
$
$ dc 2>/dev/null
h
'h' (0150) unimplemented
q
$
Consequently, I think your primary problem is that you are waiting for a response that dc is not going to provide. If you want to ensure that you get a printed value, then you need to add a p command. That can be on the same line or on a different line as the 2 3 + expression.
$ dc
2 3 + p
5
2
3
+
p
5
q
$
Working on an assignment for class and have been battling ncurses for a while now (it's new to me). Creating a program that is able to communicate with another instance of the same program across a network. Part of the program is to interactively get characters from keyboard and send them to the receiving side. (We have been advised to do this with single thread approach and using getch in ncurses, with nonblocking input from getch).
The issue I'm running into is that my getch is having behavior I cannot figure out. In different variations, it would either display every other character I type, and it won't display the most recently typed character until another character is typed after it. I've used nodelay() to get the live input, but .
Here is the setup for my ncurses display. (Note: I used noecho() as later I don't want to display every char that is enter).
/* initialize ncurses */
setlocale(LC_ALL,"");
initscr();
cbreak();
noecho();
nodelay(stdscr, TRUE);
nonl();
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
clear();
Here is the code I wrote that works with getch and sending/receiving the data over the socket.
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1); // direction to send data
}
for(i = 0; i <= maxfd; i++) {
if (FD_ISSET(i, &rfdset)) {
bzero(msgbuf, MSGSIZE);
idx = read(i, msgbuf, MSGSIZE);
if (i != STDIN)
printw("%s",msgbuf); // display received msg
}
}
}
When I run this and type data on any end of the application, I get results as follows:
Computer 1 keyboard input: testing123
Computer 1 screen display: tsig2
Computer 2 message recv'd: tsig2
Because of this, I feel certain that getch is causing most of my issues, and I must be missing or doing something incorrectly in my implementation. Any advice is appreciated.
Edit 1:
I managed to resolve the every other character issue by removing the for loop and just checking the sockets directly for input. I am baffled why this fixed it. Now my only remaining issue is why is a character not displayed until a character is entered after it. Here is my revised code in the while loop:
while(1) {
rfdset = master;
if (select(maxfd + 1, &rfdset, NULL, NULL, NULL) < 0) {
perror("select");
exit(EXIT_FAILURE);
}
ch = getch();
if (ch != ERR) {
printw("%c",ch);
write(direct, &ch, 1);
}
/* check for incoming data from left socket */
if (!NOLEFT && FD_ISSET(lcsad, &rfdset)) {
bzero(leftmsg, MSGSIZE);
idx = read(lcsad, leftmsg, MSGSIZE);
leftmsg[idx] = 0;
printw("%s", leftmsg);
lm = 1;
}
/* check for incoming data from right socket */
if (!NORIGHT && FD_ISSET(rsd, &rfdset)) {
bzero(rghtmsg, MSGSIZE);
idx = read(rsd, rghtmsg, MSGSIZE);
rghtmsg[idx] = 0;
printw("%s", rghtmsg);
rm = 1;
}
/* check and send left message onward */
if (lm && !NORIGHT) {
write(direct, leftmsg, MSGSIZE);
}
/* check and send right message onward */
if (rm && !NOLEFT) {
write(direct, rghtmsg, MSGSIZE);
}
lm, rm = 0;
}
The problem is that because your select call specifies no timeout (the last parameter is NULL), it blocks until there is some pending I/O (such as the next character which you type). At that point, the program continues into the getch call, which does a refresh (echoing the characters from your printw call).
Specifying a short timeout, e.g., 10 milliseconds, would improve things, e.g.,
struct timeval myTimeout;
myTimeout.tv_sec = 0;
myTimeout.tv_usec = 10000;
and pass the address of myTimeout in the call to select...
You can try if using wgetch() instead of getch() solves your problem.
I Work with couple of threads. all running as long as an exit_flag is set to false.
I Have specific thread that doesn't recognize the change in the flag, and therefor not ending and freeing up its resources, and i'm trying to understand why.
UPDATE: After debugging a bit with gdb, i can see that given 'enough time' the problematic thread does detects the flag change.
My conclusion from this is that not enough time passes for the thread to detect the change in normal run.
How can i 'delay' my main thread, long enough for all threads to detect the flag change, without having to JOIN them? (the use of exit_flag was in an intention NOT to join the threads, as i don't want to manage all threads id's for that - i'm just detaching each one of them, except the thread that handles input).
I've tried using sleep(5) in close_server() method, after the flag changing, with no luck
Notes:
Other threads that loop on the same flag does terminate succesfully
exit_flag declaration is: static volatile bool exit_flag
All threads are reading the flag, flag value is changed only in close_server() method i have (which does only that)
Data race that may occur when a thread reads the flag just before its changed, doesn't matter to me, as long as in the next iteration of the while loop it will read the correct value.
No error occurs in the thread itself (according to strerr & stdout which are 'clean' from error messages (for the errors i handle in the thread)
Ths situation also occurs even when commenting out the entire while((!exit_flag) && (remain_data > 0)) code block - so this is not a sendfile hanging issure
station_info_t struct:
typedef struct station_info {
int socket_fd;
int station_num;
} station_info_t;
Problematic thread code:
void * station_handler(void * arg_p)
{
status_type_t rs = SUCCESS;
station_info_t * info = (station_info_t *)arg_p;
int remain_data = 0;
int sent_bytes = 0;
int song_fd = 0;
off_t offset = 0;
FILE * fp = NULL;
struct stat file_stat;
/* validate station number for this handler */
if(info->station_num < 0) {
fprintf(stderr, "station_handler() station_num = %d, something's very wrong! exiting\n", info->station_num);
exit(EXIT_FAILURE);
}
/* Open the file to send, and get his stats */
fp = fopen(srv_params.songs_names[info->station_num], "r");
if(NULL == fp) {
close(info->socket_fd);
free(info);
error_and_exit("fopen() failed! errno = ", errno);
}
song_fd = fileno(fp);
if( fstat(song_fd, &file_stat) ) {
close(info->socket_fd);
fclose(fp);
free(info);
error_and_exit("fstat() failed! errno = ", errno);
}
/** Run as long as no exit procedure was initiated */
while( !exit_flag ) {
offset = 0;
remain_data = file_stat.st_size;
while( (!exit_flag) && (remain_data > 0) ) {
sent_bytes = sendfile(info->socket_fd, song_fd, &offset, SEND_BUF);
if(sent_bytes < 0 ) {
error_and_exit("sendfile() failed! errno = ", errno);
}
remain_data = remain_data - sent_bytes;
usleep(USLEEP_TIME);
}
}
printf("Station %d handle exited\n", info->station_num);
/* Free \ close all resources */
close(info->socket_fd);
fclose(fp);
free(info);
return NULL;
}
I'll be glad to get some help.
Thanks guys
Well, as stated by user362924 the main issue is that i don't join the threads in my main thread, therefore not allowing them enough time to exit.
A workaround to the matter, if for some reason one wouldn't want to join all threads and dynamically manage thread id's, is to use sleep command in the end of the main thread, for a couple of seconds.
of course this workaround is not good practice and not recommended (to anyone who gets here by google)
I am trying to read data from a socket. For some reason I cannot understand, it seems the read function goes into an infinite loop. The reason that's what I think happens is because while using eclipse to debug, the debugger does not get past the read function. Also, when I run the program with terminal, it runs forever. Help!!
Additional info: Running on Linux, and, not sure if has anything to do with this issue, but I create threads in the program.
Another something I think I should mention: The first time read() is called it works as expected and reads the whole message that's in the socket. The problem starts when read() is called again the second time (when there is nothing left to read). I expected that read would return 0 which would end the function, but instead, read goes into an infinite loop.
Here's where it's all happening:
read_write_res block_read_reply(int fd, void* buf, int max, int* read_size) {
int flag = 1;
if (read_size != NULL)
*read_size = 0;
int i;
while (1) {
i = read(fd, buf, max); /* HERE is where the debbuger gets stuck */
if (i == 0 && flag == 1) //nothing to read
continue;
if (i == 0 && flag == 0)
return READ_WRITE_SUCCESS;
if (i < 0){
return READ_WRITE_FAILURE;
if (i > 0 && read_size != NULL)
*read_size += i;
}
flag = 0;
max -= i;
buf = (char*) (buf) + i;
}
return READ_WRITE_SUCCESS;
}
If read returns 0, it means you have reached end-of-file status. For a socket or pipe, this means there will be nothing more to read. EVER. So performing continue; in this case is definitely not what you want to be doing.
I would like to stuff an 'A' character back into stdin using ungetc on receipt of SIGUSR1. Imagine that I have a good reason for doing this.
When calling foo(), the blocking read in stdin is not interrupted by the ungetc call on receipt of the signal. While I didn't expect this to work as is, I wonder if there is a way to achieve this - does anyone have suggestions?
void handler (int sig)
{
ungetc ('A', stdin);
}
void foo ()
{
signal (SIGUSR1, handler);
while ((key = fgetc (stdin)) != EOF)
{
...
}
}
Rather than try to get ungetc() to unblock a blocking fgetc() call via a signal, perhaps you could try not having fgetc() block to begin with and wait for activity on stdin using select().
By default, the line discipline for a terminal device may work in canonical mode. In this mode, the terminal driver doesn't present the buffer to userspace until the newline is seen (Enter key is pressed).
To accomplish what you want, you can set the terminal into raw (non-canonical) mode by using tcsetattr() to manipulate the termios structure. This should case the blocking call to fgetc() to immediately return the character inserted with ungetc().
void handler(int sig) {
/* I know I shouldn't do this in a signal handler,
* but this is modeled after the OP's code.
*/
ungetc('A', stdin);
}
void wait_for_stdin() {
fd_set fdset;
FD_ZERO(&fdset);
FD_SET(fileno(stdin),&fdset);
select(1, &fdset, NULL, NULL, NULL);
}
void foo () {
int key;
struct termios terminal_settings;
signal(SIGUSR1, handler);
/* set the terminal to raw mode */
tcgetattr(fileno(stdin), &terminal_settings);
terminal_settings.c_lflag &= ~(ECHO|ICANON);
terminal_settings.c_cc[VTIME] = 0;
terminal_settings.c_cc[VMIN] = 0;
tcsetattr(fileno(stdin), TCSANOW, &terminal_settings);
for (;;) {
wait_for_stdin();
key = fgetc(stdin);
/* terminate loop on Ctrl-D */
if (key == 0x04) {
break;
}
if (key != EOF) {
printf("%c\n", key);
}
}
}
NOTE: This code omits error checking for simplicity.
Clearing the ECHO and ICANON flags respectively disables echoing of characters as they are typed and causes read requests to be satisfied directly from the input queue. Setting the values of VTIME and VMIN to zero in the c_cc array causes the read request (fgetc()) to return immediately rather than block; effectively polling stdin. This causes key to get set to EOF so another method for terminating the loop is necessary. Unnecessary polling of stdin is reduced by waiting for activity on stdin using select().
Executing the program, sending a SIGUSR1 signal, and typing
t e s t results in the following output1:
A
t
e
s
t
1) tested on Linux
It is not entirely clear what your goal is, but is this what you are looking for?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
int handle = 0;
void handler (int sig) {
handle = 1;
}
void foo () {
int key;
signal (SIGUSR1, handler);
while ((key = fgetc (stdin)) != EOF) {
printf("%c\n",key);
if (handle) {
handle = 0;
ungetc('A',stdin);
}
}
}
int main(void) {
printf("PID: %d\n",getpid());
foo();
}
It produces this output:
PID: 8902
test (typed on stdin)
t
A
e
s
t
FILE*s are not async safe.
You cannot operate on a FILE* in a signal handler while someone else also uses that same FILE*. functions you can all in a signal handler is stated here:
http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html . (It might be
different on a windows machine, but still any FILE* are not safe there either.
This is essentially the same as #Jamie's answer, slightly changed to support your desire to process the A before the t, but it's too hard to type code into a comment box, so I've posted this answer separately.
int insert_an_A = 0;
void handler(int sig) { insert_an_A = 1; }
void process_char(char c) { ... }
int main(int argc, char **argv) {
int c;
/* skip signal setup */
while ((c = fgetc(stdin)) != EOF) {
if (insert_an_A) {
process_char('A');
insert_an_A = 0;
}
process_char(c);
}
}
If you want to process an handler received during the call to fgetc that returns EOF, you should also check insert_an_A after exiting the while loop.
Note also that in general the best practice for signal handlers is to set a global variable and return from the handler. Elsewhere in your program, look for that variable changing and react appropriately.