Program too fast?

Program too fast?

Post by Rune Johanse » Sat, 04 May 1996 04:00:00



I have a problem with a program that is written for SCO 3.2V4.2, but I try to run
it on SCO OpenServer 5.

The problem is this: If I start the program, the output from the program is
garbeled. If I check the packets on the LAN, it shows that the packets contents are
equal to the packets I get on screen. Ok, not the terminal emulator that is the
problem. Then, I try on the console, same problem. But, if I run the program like
this:

program | cat

then it works OK !!! No garbles or anything. It's also OK if I pipe it to tee, and
logs to /dev/null, like this:

program | tee /dev/null

If I run it on 3.2V4.2, it's quite OK.

I thought that it maybe could be that the shell was too slow, but I get the same in
ksh, sh and csh. Also, tried to start 15 sh's first, but no good.

Question is: Who do I have to go to, and tell "your software is broken" ?

OS info: All patches and AHS applied, also Net100.

Rune

 
 
 

Program too fast?

Post by Bela Lubki » Sun, 05 May 1996 04:00:00



> I have a problem with a program that is written for SCO 3.2V4.2, but I try to run
> it on SCO OpenServer 5.

> The problem is this: If I start the program, the output from the program is
> garbeled. If I check the packets on the LAN, it shows that the packets contents are
> equal to the packets I get on screen. Ok, not the terminal emulator that is the
> problem. Then, I try on the console, same problem. But, if I run the program like
> this:

> program | cat

> then it works OK !!! No garbles or anything. It's also OK if I pipe it to tee, and
> logs to /dev/null, like this:

> program | tee /dev/null

> If I run it on 3.2V4.2, it's quite OK.

This is caused by a change in the O_NONBLOCK handling in OSR5.  POSIX
says that I/O to a file descriptor marked O_NONBLOCK cannot block,
period.  Under 3.2v4.2, O_NONBLOCK *usually* only applied to input on
tty fds.  Under OSR5, it also applies to output.  If you write a large
amount of data to a tty fd, you will eventually fill up a kernel buffer
and the driver will want to put the process to sleep (i.e. block on
output).  Because you have set O_NONBLOCK on your tty fd, this block is
not allowed.  write(S) instead returns with a short write.

In practice, very few programs actually want non-blocking *output*.  You
probably set it to get non-blocking *input*.  There are a number of
possible workarounds:

  o Use two fds.  Open the same device twice, once with O_NONBLOCK and
    once without.  (Note: dup(), dup2(), fcntl(F_DUPFD), all return a
    second fd which is identical to the first -- setting O_NONBLOCK on
    either fd sets it on both).  Use the O_NONBLOCK fd for input, the
    other for output.  Note -- if it's a tty device that your program
    started out with, you might need to do something like:

      if (isatty(0)) {
        close(1);
        ofd = open(ttyname(0), O_WRONLY);
        if (ofd < 0) {
          /* perror("reopen stdin"); exit(1); */
          /* instead, just let stdin/stdout alone, weird results may
             ensue -- but may not, so let the user decide */
        }
        else if (ofd != 1) dup2(ofd, 1); /* slam it onto stdout */
        imode = fcntl(0, F_GETFL);
        if (imode >= 0) fcntl(0, F_SETFL, imode | O_NONBLOCK);
      }

  o Use one fd.  Maintain it normally in the blocking state, but
    surround any input operations with fcntl() calls to turn O_NONBLOCK
    on and back off.  This may be easy to do if your program's input
    functions are well isolated.

  o Use one fd.  Maintain it normally in the non-blocking state, but
    surround any output operations with fcntl() calls to turn O_NONBLOCK
    off and back on.  This may be easy to do if your program's output
    functions are well isolated.

  o Use one fd.  Maintain it in the non-blocking state.  Perform all
    output through a function which checks the return from write(S) and
    re-writes any output which didn't get written.  Warning: do not do
    this blindly, or you will create a CPU spin loop.  The code should
    look something like:

      while ((obytes = write(outfd, buffer, bufsize)) != bufsize) {
        if (obytes == -1) {
          /* deal with error condition & exit loop */
        }
        else {
          /* account for bytes already written */
          buffer += obytes;
          bufsize -= obytes;
          /* use select(S) to wait for outfd to be writable */
          FD_ZERO(&tmpfds);
          FD_SET(outfd, &tmpfds);
          if (select(outfd + 1, NULL, tmpfds, NULL, NULL) < 0) {
            /* deal with error condition & exit loop */
          }
        }
      }

    This is the most "proper" solution, in that it is *always* possible
    you will get a short write, so all writes should be done this way.
    In practice, very few Unix programs anticipate short writes; watch
    the fireworks when a filesystem gets full.

    Running your program as `program | cat` works because cat implements
    such a loop.

- Show quoted text -

Quote:>Bela<


 
 
 

Program too fast?

Post by Mik » Tue, 07 May 1996 04:00:00



Quote:

>I have a problem with a program that is written for SCO 3.2V4.2, but I
try to run
>it on SCO OpenServer 5.

>The problem is this: If I start the program, the output from the
program is
>garbeled. If I check the packets on the LAN, it shows that the packets
contents are
>equal to the packets I get on screen. Ok, not the terminal emulator
that is the
>problem. Then, I try on the console, same problem. But, if I run the
program like
>this:

>program | cat

>then it works OK !!! No garbles or anything. It's also OK if I pipe it
to tee, and
>logs to /dev/null, like this:

>program | tee /dev/null

>If I run it on 3.2V4.2, it's quite OK.

>I thought that it maybe could be that the shell was too slow, but I get
the same in
>ksh, sh and csh. Also, tried to start 15 sh's first, but no good.

>Question is: Who do I have to go to, and tell "your software is broken"
?

>OS info: All patches and AHS applied, also Net100.

>Rune

I don't have exactly the same problem....  My problem is that my home-
grown app causes OS 5 to have a double kernel panic.  The app is an
rlogin client.  It does nothing but transfer characters to and from
the keyboard and the IPC socket.

Any thoughts?