Why scanf waits only when stdin is set to "/dev/pts/*" - c

int main()
{
int fd=open("/dev/pts/0",O_RDWR);
if(fd==-1){
printf("Error");
exit(1);
}
dup2(fd,0);
char c[20];
printf("reading from file\n");
scanf("%s",c);
}
In above code "/dev/pts/0" is set as stdin.scanf behaves normally.
But when I set to filename like "inp.txt" it doesn't wait directly reads whatever it finds.
Why is that like that?What to do if I want to make it wait?

When you read from a file, the data is already there, so why would scanf() wait? Or any other way of reading the file?
/dev/pts/<i>N</i> are Unix 98 pseudoterminals, which by their very nature are interactive. A blocking read from one waits for interactive input. A nonblocking read would just tell you that there is no data to read right now.
If you create a pipe between processes, associate the read end with an stdio FILE handle via fdopen(), you can use scanf() to scan data from the pipe. That, too, will wait for input, unless all write ends of the pipe are closed (then the scanf will fail with end-of-input). So, there is nothing special about the pseudoterminals in this respect.

Related

puts() doesn't flush the buffer in io redirection program

the code as follows:
int main(int argc, char **argv)
{
const char *file = "/tmp/out";
int fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
int stdout_tmp = dup(1);
close(1);
dup(fd);
puts("hello world!");
// fflush(stdout);
close(1);
close(fd);
dup(stdout_tmp);
puts("redirect completed!");
exit(0);
}
I compile the code succssfully without any warning using gcc10.2.0, Againest my expectation, the two line both are output to the stdout instead "hello world" in the /tmp/out file and "redirect completed!" in stdout. When uncomment the fflush(stdout), it works!
I guess that the puts() doesn't refresh the buffer in user space, after restoring the stdout and exit, the buffer is auto refreshed.
gets() output string with trailing '\n' and the stdout buffer will be auto refreshed when encounter '\n'. Why need to call fflush(stdout) manually?
The stdout file (where puts writes) is line-buffered (i.e. flushes the buffer on newline) only when connected to a terminal (basically when isatty(fileno(stdout)) is true).
When connected to another non-terminal output then it's fully buffered, which means you either need to fill the buffer completely, or call fflush explicitly to flush the buffer.
man 3 setvbuf says:
Normally all files are block buffered.
If a stream refers to a terminal (as stdout normally does), it is line buffered.
Since puts() uses stdout we should expect a flush
(because of the \n).
However, since in your example stdout has not been used before
the redirection, I guess that the buffering behaviour is not chosen
yet.
At your first write attempt to stdout, the underlying file descriptor
is not a terminal anymore but a regular file.
I guess the buffering behaviour is chosen at this moment.
If you add another call to puts() in your example before the
redirection, then the buffering behaviour is chosen for the terminal
and then does not change afterwards when the redirection is performed.
In this case, your example works as you expect (without the explicit
fflush()).
edit
Still in man 3 setvbuf:
When the first I/O operation occurs on a file, malloc(3) is called, and a buffer is obtained.
and further:
The setvbuf() function may only be used after opening a stream and before any other operations have been performed on it.
On linux, this is consistent with your example.
In the MSDN page for setvbuf:
stream must refer to an open file that has not undergone an I/O operation since it was opened.

c read() with pipe stays idle

I wrote this piece of code that is supposed to redirect something written on the STDOUT by a function to the STDIN so that it can be read by another function. I cannot access these functions, so this is the only way I can use them.
mpz_fput(stdout, c) is one of these function. It just prints on the STDOUT something contained in the c data structure.
Now everything worked fine while debugging as before the following code I had a printf(); followed by a fflush(stdout); (needed to print debugging messages).
Now that I removed these two lines I noticed (using gdb) that this code stays idle on the read() function (last line of this piece of code)
char buffer[BUFSIZ] = "";
int out_pipe[2];
int in_pipe[2];
int saved_stdout;
int saved_stdin;
int errno;
// REDIRECT STDIN
saved_stdin = dup(STDIN_FILENO); /* save stdin for later */
if(errno= pipe(in_pipe) != 0 ) { /* make a pipe */
printf("\n%s",strerror(errno));
exit(1);
}
close(STDIN_FILENO);
dup2(in_pipe[0], STDIN_FILENO); /* redirect pipe to stdin */
// REDIRECT STDOUT
saved_stdout = dup(STDOUT_FILENO); /* save stdout for display later */
if(errno= pipe(out_pipe) != 0 ) { /* make a pipe */
printf("\n%s",strerror(errno));
exit(1);
}
dup2(out_pipe[1], STDOUT_FILENO); /* redirect stdout to the pipe */
close(out_pipe[1]);
mpz_fput(stdout,c); // put c on stdout
read(out_pipe[0], buffer, BUFSIZ); // read c from stdout pipe into buffer
any idea why is that?
Seems you used the blocking type. In this case, out_pipe[0] is a blocking handle. So read() blocked, and waiting for anything out from out_pipe[0].
Besides, I think there's something to do with the fflush():
For output streams, fflush() forces a write of all user-space buffered data
for the given output or update stream via the stream's underlying write
function. For input streams, fflush() discards any buffered data that has
been fetched from the underlying file, but has not been by the application.
The open status of the stream is unaffected.
In your case, you redirected pipe to STDOUT, then called fflush() to make everything in STDOUT flushed and move them to read() buffer. Then you called read() to read them out. If you didn't call fflush(), and read() buffer would be empty. Since it's a blocking handle used by read(), you can't read anything from the buffer, so it will be blocked.
This is the brief theory, I suggest you to read Linux manpage for more details.

Whats wrong with this print order

have a look at this code:
#include<stdio.h>
#include <unistd.h>
int main()
{
int pipefd[2],n;
char buf[100];
if(pipe(pipefd)<0)
printf("Pipe error");
printf("\nRead fd:%d write fd:%d\n",pipefd[0],pipefd[1]);
if(write(pipefd[1],"Hello Dude!\n",12)!=12)
printf("Write error");
if((n=read(pipefd[0],buf,sizeof(buf)))<=0)
printf("Read error");
write(1,buf,n);
return 0;
}
I expect the printf to print Read fd and write fd before Hello Dude is read from the pipe. But thats not the case... see here. When i tried the same program in our college computer lab my output was
Read fd:3 write fd:4
Hello Dude!
also few of our friends observed that, changing the printf statement to contain more number of \n characters changed the output order... for example..printf("\nRead fd:%d\n write fd:%d\n",pipefd[0],pipefd[1]); meant that Read fd is printed then the message Hello Dude! then the write fd is printed. What is this behaviour??
Note: Out lab uses a linux server on which we run terminals, i don't remember the compiler version though.
It's because printf to the standard output stream is buffered but write to the standard output file descriptor is not.
That means the behaviour can change based on what sort of buffering you have. In C, standard output is line buffered if it can be determined to be connected to an interactive device. Otherwise it's fully buffered (see here for a treatise on why this is so).
Line buffered means it will flush to the file descriptor when it sees a newline. Fully buffered means it will only flush when the buffer fills (for example, 4K worth of data), or when the stream is closed (or when you fflush).
When you run it interactively, the flush happens before the write because printf encounters the \n and flushes automatically.
However, when you run it otherwise (such as by redirecting output to a file or in an online compiler/executor where it would probably do the very same thing to capture data for presentation), the flush happens after the write (because printf is not flushing after every line).
In fact, you don't need all that pipe stuff in there to see this in action, as per the following program:
#include <stdio.h>
#include <unistd.h>
int main (void) {
printf ("Hello\n");
write (1, "Goodbye\n", 8);
return 0;
}
When I execute myprog ; echo === ; myprog >myprog.out ; cat myprog.out, I get:
Hello
Goodbye
===
Goodbye
Hello
and you can see the difference that the different types of buffering makes.
If you want line buffering regardless of redirection, you can try:
setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
early on in your program - it's implementation defined whether an implementation supports this so it may have no effect but I've not seen many where it doesn't work.
You shouldn't mix calls to write and printf on single file descriptor. Change write to fwrite.
Functions which use FILE are buffered. Functions which use file descriptors are not. This is why you may get mixed order.
You can also try calling fflush before write.
When you write onto the same file, or pipe, or whatever by two means at once (direct IO and output stream) you can get this behaviour. The reason is that the output stream is buffered.
With fflush() you can control that behaviour.
What is happening is that printf writes to stdout in a buffered way -- the string is kept in a buffer before being output -- while the 'write' later on writes to stdout unbuffered. This can have the effect that the output from 'write' appears first if the buffer from the printf is only flushed later on.
You can explicitly flush using fflush() -- but even better would be not to mix buffered and non-buffered writes to the same output. Type man printf, man fflush, man fwrite etc. on your terminal to learn more about what these commands do exactly.

How to prevent stdin stream from reading data from associated file descriptor on program start?

I'm using select() call to detect input presence in the main cycle of my program. This makes me use raw file descriptor (0) instead of stdin.
While working in this mode I've noticed that my software occasionally loses a chunk of input at the beginning. I suspect that stdin consumes some of it on the program start. Is there a way to prevent this behavior of stdin or otherwise get the whole input data?
The effect described can be reproduced only with some data on standard input at the very moment of program start. My executable should be used as xinetd service in a way that it always has some input on the start.
Standard input is read in the following way:
Error processInput() {
struct timeval ktimeout;
int fd=fileno(stdin);
int maxFd=fd+1;
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
ktimeout.tv_sec = 0;
ktimeout.tv_usec = 1;
int selectRv=-1;
while ((selectRv=select(maxFd, &fdset, NULL, NULL, &ktimeout)) > 0) {
int left=MAX_BUFFER_SIZE-position-1;
assert(left>0);
int bytesCount=read(fd, buffer+position, left);
//Input processing goes here
}
}
Don't mix cooked and raw meat together. Try replacing the read() call with the equivalent fread() call.
It is very likely that fileno(stdin) is initializing the stdin object, causing it to read and buffer some input. Or perhaps you are already calling something that causes it to initialize (scanf(), getchar(), etc...).

How to buffer stdout in memory and write it from a dedicated thread

I have a C application with many worker threads. It is essential that these do not block so where the worker threads need to write to a file on disk, I have them write to a circular buffer in memory, and then have a dedicated thread for writing that buffer to disk.
The worker threads do not block any more. The dedicated thread can safely block while writing to disk without affecting the worker threads (it does not hold a lock while writing to disk). My memory buffer is tuned to be sufficiently large that the writer thread can keep up.
This all works great. My question is, how do I implement something similar for stdout?
I could macro printf() to write into a memory buffer, but I don't have control over all the code that might write to stdout (some of it is in third-party libraries).
Thoughts?
NickB
I like the idea of using freopen. You might also be able to redirect stdout to a pipe using dup and dup2, and then use read to grab data from the pipe.
Something like so:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define MAX_LEN 40
int main( int argc, char *argv[] ) {
char buffer[MAX_LEN+1] = {0};
int out_pipe[2];
int saved_stdout;
saved_stdout = dup(STDOUT_FILENO); /* save stdout for display later */
if( pipe(out_pipe) != 0 ) { /* make a pipe */
exit(1);
}
dup2(out_pipe[1], STDOUT_FILENO); /* redirect stdout to the pipe */
close(out_pipe[1]);
/* anything sent to printf should now go down the pipe */
printf("ceci n'est pas une pipe");
fflush(stdout);
read(out_pipe[0], buffer, MAX_LEN); /* read from pipe into buffer */
dup2(saved_stdout, STDOUT_FILENO); /* reconnect stdout for testing */
printf("read: %s\n", buffer);
return 0;
}
If you're working with the GNU libc, you might use memory streams string streams.
You can "redirect" stdout into file using freopen().
man freopen says:
The freopen() function opens the file
whose name is the string pointed to
by path and associates the stream
pointed to by stream with it. The
original stream (if it exists) is
closed. The mode argument is used
just as in the fopen() function.
The primary use of the freopen()
function is to change the file
associated with a standard text
stream (stderr, stdin, or stdout).
This file well could be a pipe - worker threads will write to that pipe and writer thread will listen.
Why don't you wrap your entire application in another? Basically, what you want is a smart cat that copies stdin to stdout, buffering as necessary. Then use standard stdin/stdout redirection. This can be done without modifying your current application at all.
~MSalters/# YourCurrentApp | bufcat
You can change how buffering works with setvbuf() or setbuf(). There's a description here: http://publications.gbdirect.co.uk/c_book/chapter9/input_and_output.html.
[Edit]
stdout really is a FILE*. If the existing code works with FILE*s, I don't see what prevents it from working with stdout.
One solution ( for both things your doing ) would be to use a gathering write via writev.
Each thread could for example sprintf into a iovec buffer and then pass the iovec pointers to the writer thread and have it simply call writev with stdout.
Here is an example of using writev from Advanced Unix Programming
Under Windows you would use WSAsend for similar functionality.
The method using the 4096 bigbuf will only sort of work. I've tried this code, and while it does successfully capture stdout into the buffer, it's unusable in a real world case. You have no way of knowing how long the captured output is, so no way of knowing when to terminate the string '\0'. If you try to use the buffer you get 4000 characters of garbage spit out if you had successfully captured 96 characters of stdout output.
In my application, I'm using a perl interpreter in the C program. I have no idea how much output is going to be spit out of what ever document is thrown at the C program, and hence the code above would never allow me to cleanly print that output out anywhere.

Resources