wdavis@x102c.harris-atd.com (davis william 26373) (01/05/91)
In article <1990Dec31.170612.7040@lta.com> with Subject: Frequently Asked Questions about X with Answers 3/3 [long monthly posting] xug@lta.com (X User's Group) writes: >Subject: 72) Why does XtAppAddInput not work as described? >I am using XtAppAddInput to read from a file, but the function is called even >when there isn't input pending. > > XtAppAddInput is actually working as it is supposed to. When used on >files, it is called whenever the file is READY to be read, not when there is >new data to be read. The file is almost always ready to be read, however, if >only because you can spin back to the beginning and read data you've read >before. This sounds like a rationalization of why the bug is now to be called a feature. Given this explanation, any open file descriptor can be considered "ready to be read". > The result is that your function will almost always be called every >time around XtMainLoop(). Right - and that is a bug - not a feature! > To get the type of interaction you are expecting, add this line to >the beginning of your function to test whether there is new data: > if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) return; > >[courtesy Dan Heller (argv@ora.com); 8/90] But this does not address the original problem because it is still calls the procedure even when there is nothing really ready to be read. I already have a check for when the read of the file descriptor returns a zero to ignore the call. Lots of overhead. But the bigger problem is that when there is a file descriptor that is always ready to read (because it is always open) then the Work Process never gets called. So, how do I get the brain damaged Xt logic to stop calling my input function long enough to execute a background work process? I do not want to close the file descriptor because I will not know what I have already read when I open it again. I do not want to remove the input because then I will have no way to know that the file has been appended to (or is there a way to know that?). And I cannot avoid using a background work process because that code is part of a purchased package. I will remove the input for X if there is a way to know when the file has something more added to the end of what has already been read. Any ideas on this? Lacking that is there any chance that the Xt logic will get fixed? How about an option (we could call it XT_GLITCH_INHIBIT) that will make the input stuff work rationally? Or is this really an underlying problem with the select call? My preference is for a work around that will get me past my short term problem without an Xt rewrite. I can tolerate the extra overhead if the Work Process will just get executed.
bjaspan@athena.mit.edu (Barr3y Jaspan) (01/05/91)
In article <5184@trantor.harris-atd.com>, wdavis@x102c.harris-atd.com (davis william 26373) writes: |> >I am using XtAppAddInput to read from a file, but the function is called even |> >when there isn't input pending. |> > |> > XtAppAddInput is actually working as it is supposed to. When used on |> >files, it is called whenever the file is READY to be read, not when there is |> >new data to be read. wdavis is incorrect; XtAddInput calls the procedure when there is DATA TO READ. All XtAddInput does, for functions registered with XtInputReadMask, is call select and then calls those procedures whose filedescriptor is set in the fdset returned from select. Perhaps he was thinking of the case of XtInputWriteMask, for which the associated procedure *IS* called constantly (since files/pipes/etc are almost always ready to be written to). (well, of course, XtAddInput doesn't so that, it causes XtMainLoop to.) I have only used XtAddInput for filedescriptors connected to pipes/sockets/etc, never for a file. I assure you that it does, in fact, work. At the end of the posting there is a sample program demonstrating its use. Perhaps your problem is the result of peculiar select() semantics. When EOF is reached on a filedescriptor, select() will return that *there is data waiting to be read on it* even though there isn't. Any subsequent read() from that descriptor will return 0 bytes, which indicates that it has been closed (and the program should deal accordingly; in this case, remove the input procedure). Howver, future calls to select() on the descriptor will CONTINUE to indicate that there is data waiting to be read. So, if your program is not checking that EOF has been reached, the input procedure will get called constantly once it has been. Sorry if this is poorly worded, I'm on a slow net connection and can't fix it. Barr3y Jaspan, bjaspan@mit.edu Watchmaker Computing --- snip snip --- #include <stdio.h> #include <X11/Intrinsic.h> #include <X11/StringDefs.h> #include <X11/Label.h> void input(); main(argc, argv) int argc; char **argv; { Widget top; top = XtInitialize("Hello", "World", NULL, 0, &argc, argv); (void) XtCreateManagedWidget("label", labelWidgetClass, top, NULL, 0); XtAddInput(0, XtInputReadMask, input, NULL); XtRealizeWidget(top); XtMainLoop(); } void input(client_data, source, input_id) caddr_t client_data; int *source; XtInputId *input_id; { char buf[BUFSIZ]; printf("Input received on fd %d.\n", *source); scanf("%s", buf); printf("\"%s\"\n", buf); }
mouse@lightning.mcrcim.mcgill.EDU (01/05/91)
>>> I am using XtAppAddInput to read from a file, but the function is >>> called even when there isn't input pending. >> XtAppAddInput is actually working as it is supposed to. When used >> on files, it is called whenever the file is READY to be read, not >> when there is new data to be read. > wdavis is incorrect; XtAddInput calls the procedure when there is > DATA TO READ. All XtAddInput does, for functions registered with > XtInputReadMask, is call select and then calls those procedures whose > filedescriptor is set in the fdset returned from select. This is not "when there is DATA TO READ". Even ignoring the question of select()'s semantics when applied to files, it sometimes returns when no data are available, such as a socket connection which has reached EOF (ie, all write ends shut down). > I have only used XtAddInput for filedescriptors connected to > pipes/sockets/etc, never for a file. Then why are you making pronouncements about what it - or rather, the presumably related XtAppAddInput - does when applied to files? > Perhaps your problem is the result of peculiar select() semantics. > When EOF is reached on a filedescriptor, select() will return that > *there is data waiting to be read on it* even though there isn't. > Any subsequent read() from that descriptor will return 0 bytes, which > indicates that it has been closed If it had been closed, the read would return -1 with errno set to EBADF (unless of course something else had been opened up since, and gotten the same descriptor). 0 means the descriptor is still open, but at EOF. The semantics select() is supposed to provide are not entirely clear. All the descriptions available to me simply say "ready for reading". I have seen this stated as "a read() will not block", which is what I observe from sockets. I, too, have not tried using select() on files, but if it truly does provide "read() will not block" indications, then select()ing a file for reading will always indicate readability. (Unless, presumably, the file is on a dead NFS server :-) der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
wdavis@x102c.harris-atd.com (davis william 26373) (01/08/91)
I quoted from Part 3 of Frequently Asked Questions: >>>> I am using XtAppAddInput to read from a file, but the function is >>>> called even when there isn't input pending. >>> XtAppAddInput is actually working as it is supposed to. When used >>> on files, it is called whenever the file is READY to be read, not >>> when there is new data to be read. In article <1991Jan4.221250.5174@athena.mit.edu>, bjaspan@athena.mit.edu (Barr3y Jaspan) writes: >> wdavis is incorrect; XtAddInput calls the procedure when there is >> DATA TO READ. Which is exactly what I expected from the documentation. When this didn't work, I posted my query. >> All XtAddInput does, for functions registered with >> XtInputReadMask, is call select and then calls those procedures whose >> filedescriptor is set in the fdset returned from select. Actually, I was asking about XtAppAddInput as my documentation on Xt Intrinsics claims that XtAddInput is obsolete and has been replaced by XtAppAddInput. The only difference in the documentation is that the obsolete one always uses the default application context and the one I was using requires you to specify it. I got the context from the ApplicationShell widget surrounding a list that was being kept updated from the bottom of a file. I assume the internals are similar for both routines. In article <9101051037.AA02347@lightning.McRCIM.McGill.EDU> mouse@lightning.mcrcim.mcgill.EDU writes: >This is not "when there is DATA TO READ". Even ignoring the question >of select()'s semantics when applied to files, it sometimes returns >when no data are available, such as a socket connection which has >reached EOF (ie, all write ends shut down). Having Xt Intrinsics claim to provide a function when it just uses underlying select semantics is misleading. If XtAppAddInput wants to claim it provides a particular function, then it should provide that function. If it just intends to be a wrapper for select then that is what it should claim. At least then it becomes a simple matter to test out select semantics and know what to expect for a particular release of Unix. >> I have only used XtAddInput for filedescriptors connected to >> pipes/sockets/etc, never for a file. > >Then why are you making pronouncements about what it - or rather, the >presumably related XtAppAddInput - does when applied to files? > >> Perhaps your problem is the result of peculiar select() semantics. >> When EOF is reached on a filedescriptor, select() will return that >> *there is data waiting to be read on it* even though there isn't. >> Any subsequent read() from that descriptor will return 0 bytes, which >> indicates that it has been closed > >If it had been closed, the read would return -1 with errno set to EBADF >(unless of course something else had been opened up since, and gotten >the same descriptor). 0 means the descriptor is still open, but at >EOF. > >The semantics select() is supposed to provide are not entirely clear. >All the descriptions available to me simply say "ready for reading". I >have seen this stated as "a read() will not block", which is what I >observe from sockets. I, too, have not tried using select() on files, >but if it truly does provide "read() will not block" indications, then >select()ing a file for reading will always indicate readability. >(Unless, presumably, the file is on a dead NFS server :-) > > der Mouse Well, based on this discussion, I wrote a simple program to test select semantics on files and pipes. For the version of Unix I am using (your mileage may vary), select will block when used on an open pipe with no data (as expected). It also blocks after a read of an end of file indication (end of files can be put into a stream and followed by more data without bothering select). Multiple end of file indications without intervening data cause the pipe to be closed. I did my pipe testing with a simple "cat" command and did not investigate how the Ctrl-D typed to cat actually translated to an EOF down the pipe. When select was applied to a file, the select returned "ready for reading" (from select(2) documentation here) when there was data to read or the current file position was at end of file. I did not try positioning the file position to weird places as this would not have helped my application (I need to track things as they are written to a file). So, the conclusion is that XtAppAddInput on files is only useful to read in a file one time. And it is clearly the hard way to go about it. I only see that as useful if the file read needs to proceed in parallel with user events (a big file or something that needs to allow a user cancel event during the read). Lacking any better suggestions (one suggestion here involved generating special X events to indicate it was time to look at the file), I decided to fork a process on a pipe. I forked a copy of "tail +0f filename" and use XtAppAddInput on the read side of the pipe. It seems to be working fine. Long term, it would be desirable to have X provide a lower overhead method of doing this, but I don't know a good way at the moment when select does not want to provide the functionality. What it sounds like is needed for this type of application (basically a fancy tail command under X) is to have a way to specify to Unix that select should not consider a file at end of file as readable. In this way, a program could read to the end of file, change (via fcntl) the select semantics and not be bothered until something became appended. Then , if desired, the select semantics could be toggled if it was important not to get tied up with a read of all available input in one call to the input function.
moss@brl.mil (Gary S. Moss (VLD/VMB) <moss>) (01/10/91)
In article <5184@trantor.harris-atd.com>, wdavis@x102c.harris-atd.com (davis william 26373) writes: |> |> I will remove the input for X if there is a way to know when the |> file has something more added to the end of what has already been |> read. Any ideas on this? The proper semantics of available data for input are clear when reading from a pipe or socket, but when reading from a file, it becomes something of a religious argument. I was fooled by the documentation also, so perhaps it should be tweaked. Anyway, I have combined the XtAppAddInput with code which checks for available input in the file. It is fairly simple so I have included it below; the application monitors a log file (like running a "tail -f" into an AsciiText widget. This doesn't solve the problem of your registered function being called in a tight loop so that your work proc doesn't get scheduled, but you could perhaps not use XtAppAddInput at all. Hope this helps, -Gary ... /* Register error log monitoring function. */ (void) XtAppAddInput( apcon, fileno(errorfp), XtInputReadMask, displayLogMsg, (XtPointer) errorfp ); /* Loop to handle events. */ XtAppMainLoop( apcon ); ... /* void displayLogMsg( XtPointer client_data, int *source, XtInputId *id ) Display the next line of the log file in the "errors" text widget. */ /*ARGSUSED*/ STATIC void displayLogMsg( client_data, source, id ) XtPointer client_data; int *source; XtInputId *id; { register int ct; long addr; /* save file offset of beginning of line */ FILE *fp = (FILE *) client_data; char buffer[MAXLOGLNLEN]; if( fp == NULL ) return; /* monitoring of log errors turned off */ addr = ftell( fp ); if( fgets( buffer, MAXLOGLNLEN, fp ) != NULL ) { register int len = strlen( buffer ); /* if( len <= 1 ) return; /* ignore blank lines */ if( buffer[len-1] != '\n' ) { /* A missing newline means that a write to the log is in progress, so we are done. */ (void) fseek( fp, addr, 0 ); /* beginning of line */ return; } sendToTextWidget( XtNameToWidget( toplevel, "main.errors" ), buffer ); } else clearerr( fp ); /* for 4.2 BSD or SUNs, need to clear EOF */ }