[comp.unix.questions] sending signal sends -1 to the receiving process

lin@CS.WMICH.EDU (Lite Lin) (03/14/91)

Hello,
  I have a question regarding signals.  This question occurs to me when 
I'm trying to write a curses based package.  I'd like certain area on 
the screen to blink, but SUN terminal does not support blinking (am I right?),
so I produce a child process and have the child process interrupt the parent
process, say, every 0.2 seconds, and then certain area on the screen changes
state accordingly (A related problem is, the visual effect produced in this way
is not really pleasing, is there any way to get around the problem?).  The
problem comes in when I notice that the parent process keeps receiving unwanted
characters.  This I did not know before; it looks like when a process sends a 
signal to another process, it puts something in the other process's input 
stream as well.  I tried to write a very much simplified program and then I
realized the problem has nothing to do with the cursor package.  I can get
around the problem because the unwanted character is always (char)(-1), so
I simply ignore that, but still I'm wondering what is the reason for this.
Anyone care to explain?  The programs are appended.
  BTW, if it is relevant, I'm using a SPARC IPC running SunOS 4.1 and
compiled the programs with /usr/5bin/cc and relevant libraries & includes,
where appropriate.
  Thanks in advance,
	Lite



========================================================================
#include <signal.h>

void blink();

main()
{
  int pid;
  char ch;

  if ((pid=fork()) == -1) {  /* forks off a process which would interrupt 
			        once in a while; help do blinking */
    perror("fork");
    exit(1);
  }
  else if (pid == 0) {
    execl("/sol3/cs1/lin/599/sysv-nopad/nap", "nap", "2000000", (char *)0);
    perror("execl");
  }
  else 
    signal(SIGALRM, blink); 
  while (ch=getchar()) {
    printf("%d\n", ch); /* this prints -1 */
    printf("%c", ch);
  }
}



void blink()
{
  signal(SIGALRM, blink);
}
========================================================================


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
#include <signal.h> /* the "nap" program */
#include <sys/types.h>
#include <stdio.h>

main(argc, argv, envp)
int argc;
char *argv[], *envp[];
{
  int usec = 0;
  char *ptr;
  int ppid;

  ppid = getppid();
  ptr = argv[1];
  while (*ptr) {
    usec = usec*10 + *ptr - '0';
    ptr++;
  }
  for (;;) {
    usleep(usec);
    kill(ppid, SIGALRM);
  }
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

paul@sequoia.cray.com (Paul Dow (CRI-UK)) (03/15/91)

In article <9103141128.AA12846@cs.wmich.edu>, lin@CS.WMICH.EDU (Lite Lin) writes:
|> 
|> Hello,
|>   I have a question regarding signals.  This question occurs to me when 
|> I'm trying to write a curses based package.  I'd like certain area on 
|> the screen to blink, but SUN terminal does not support blinking (am I right?),
|> so I produce a child process and have the child process interrupt the parent
|> process, say, every 0.2 seconds, and then certain area on the screen changes
|> state accordingly (A related problem is, the visual effect produced in this way
|> is not really pleasing, is there any way to get around the problem?).  The
|> problem comes in when I notice that the parent process keeps receiving unwanted
|> characters.  This I did not know before; it looks like when a process sends a 
|> signal to another process, it puts something in the other process's input 
|> stream as well.  I tried to write a very much simplified program and then I
|> realized the problem has nothing to do with the cursor package.  I can get
|> around the problem because the unwanted character is always (char)(-1), so
|> I simply ignore that, but still I'm wondering what is the reason for this.
|> Anyone care to explain?  The programs are appended.
|>   BTW, if it is relevant, I'm using a SPARC IPC running SunOS 4.1 and
|> compiled the programs with /usr/5bin/cc and relevant libraries & includes,
|> where appropriate.
|>   Thanks in advance,
|> 	Lite
|> 
|> 
|> 
|> ========================================================================
|> #include <signal.h>
|> 
|> void blink();
|> 
|> main()
|> {
|>   int pid;
|>   char ch;
|> 
|>   if ((pid=fork()) == -1) {  /* forks off a process which would interrupt 
|> 			        once in a while; help do blinking */
|>     perror("fork");
|>     exit(1);
|>   }
|>   else if (pid == 0) {
|>     execl("/sol3/cs1/lin/599/sysv-nopad/nap", "nap", "2000000", (char *)0);
|>     perror("execl");
|>   }
|>   else 
|>     signal(SIGALRM, blink); 
|>   while (ch=getchar()) {
|>     printf("%d\n", ch); /* this prints -1 */
|>     printf("%c", ch);
|>   }
|> }
|> 
|> 
|> 
|> void blink()
|> {
|>   signal(SIGALRM, blink);
|> }
|> ========================================================================
|> 
|> 
|> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|> #include <signal.h> /* the "nap" program */
|> #include <sys/types.h>
|> #include <stdio.h>
|> 
|> main(argc, argv, envp)
|> int argc;
|> char *argv[], *envp[];
|> {
|>   int usec = 0;
|>   char *ptr;
|>   int ppid;
|> 
|>   ppid = getppid();
|>   ptr = argv[1];
|>   while (*ptr) {
|>     usec = usec*10 + *ptr - '0';
|>     ptr++;
|>   }
|>   for (;;) {
|>     usleep(usec);
|>     kill(ppid, SIGALRM);
|>   }
|> }
|> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

Hi,

Time to enjoy the quirks of using signals....   Anyhow, firstly, a common
programmin error when using getchar() etc - it returns an int, so declare
ch to be of type int.  This then allows an ASCII character to be distinguished
from end of file.

Your real problem is the signal though.  If a read(2) is performed on a 'slow'
device - e.g. a terminal, then a signal will cause the read to return with
a -1, and errno will be set to EINTR (interrupted system call).  It is the
programmsers responsibility to check this & restart the call.  BSD (I think
in 4.1 automatically did this for you, then the feature was removed in 
later releases.  I beleive that udef SunOs (and possbily BSD), it is selectable
which behaviour you wish.  I'd stick with presuming that you have to restart the
call.

So, try something like (don't flame me since I am just brain dumping, and tend to use read(2) instead (for real time applications)

     int ch;

     while( (ch = getchar()) {
          if( ch == EOF ) {
              /* End of file or error ? */
              if( ferror( stdin ) && errno == EINTR ) {
                  continue;
              }
          }
     }

     The code may not be right, but it should point you in the right drirection.

In the type of applications that I work with, getchar() is a litle too fussy, so
we use read instead (we are handling characters individually by the software).
So our code tends to look like:


    char ch;
    int  status;

    while( (status = read( STDIN, &ch, sizeof ch )) ) {
        if( status == -1 ) {
            /* An error - ignore or handle ? */
            if( errno == EINTR ) {
                continue;    /* Retry read since interrupted */
            }

            /* Handle error */
        }
        else {
            /* Process character */
        }
    }

Yup - it's another brain dump, but I'm trying to show a principle.

You are liable to have problems with implemeting your blink via signals -
things like printf (in the signal routine) may not work - possibly causing
bus errors etc.  This is usually due to static data that printf references being
re-used in the signal routine.  Have you thought about using select().  This
is usually safer (though more complex) than singnal code.  You may only be able
to use it to  do the flashing if your processing "threads" are relatively short -
less than the 200mS blink interval.  Either way, you may find that it is
veryy stuttery due to the process sceduling on your machine.  It will probably
work great whilst the machine is lightly loaded.
 
That's thrown a few thoughts into the forum. I hope you find it useful.  Note
that several other system calls can alsl return with an EINTR error - so beware
when you use them!


Paul.