I am trying to configure a serial port under Ubuntu 10.04 to performer asynchronous serial I/O. The idea is to use the signal SIGIO to raise the flags for "data available to read" and "sand buffer is not in use". I would like to have my signal handler be able to tell whether the signal is caused by a "send" or a "receive", so I activated the SA_SIGINFO flag in the sa_flags field of the sigaction structure. Two additional arguments are passed to the signal-catching function. If the second argument is not equal to NULL, it points to a siginfo_t structure containing the reason why the signal was generated. the third argument points to a ucontext_t structure containing the receiving process's context when the signal was delivered.
I hook my linux machine to a windows machine via serial cable. However, my code is not working as I expected when I sent strings from my windows machine to the linux machine. The program succeeded in invoking the signal-catching function whenever new characters were received, and the received signal turns to be 29 (correspond to the signal SIGIO). But the member si_code in struct siginfo_t failed to be updated to reflect the reason of the signal. When characters are received, I expect the si_code to be up dated to POLL_IN (which is 1). But the actual value printed in the signal-catching program is 128, which does not make sense to me.
Can anybody take a look at my code and shine some light on it if at all possible? I cannot figure out what I missed.
int wait_flag=TRUE; /* TRUE while no signal received */
int main()
{
int fd, res;
struct termios oldtio,newtio;
struct sigaction saio; /* definition of signal action */
char buf[255];
/* open the device to be non-blocking (read will return immediatly) */
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
/* install the signal handler before making the device asynchronous */
//saio.sa_handler = signal_handler_IO;
sigemptyset(&saio.sa_mask);
saio.sa_flags = saio.sa_flags|SA_SIGINFO;
saio.sa_restorer = NULL;
saio.sa_sigaction = signal_handler_IO;
sigaction(SIGIO,&saio,NULL);
/* allow the process to receive SIGIO */
fcntl(fd, F_SETOWN, getpid());
/* Make the file descriptor asynchronous (the manual page says only
O_APPEND and O_NONBLOCK, will work with F_SETFL...) */
fcntl(fd, F_SETFL, FASYNC);
tcgetattr(fd,&oldtio); /* save current port settings */
/* set new port settings for canonical input processing */
newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | ICRNL;
newtio.c_oflag = 0;
newtio.c_lflag = 0;
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
/* loop while waiting for input. normally we would do something
useful here */
while (STOP==FALSE) {
printf(".");usleep(100000);
/* after receiving SIGIO, wait_flag = FALSE, input is available
and can be read */
if (wait_flag==FALSE) {
res = read(fd,buf,255);
buf[res]=0;
printf(":%s:%d\n", buf, res);
if (res==1) STOP=TRUE; /* stop loop if only a CR was input */
wait_flag = TRUE; /* wait for new input */
}
}
/* restore old port settings */
tcsetattr(fd,TCSANOW,&oldtio);
return 1;
}
/***************************************************************************
* signal handler. sets wait_flag to FALSE, to indicate above loop that *
* characters have been received. *
***************************************************************************/
void signal_handler_IO (int status, siginfo_t *ioinfo, void * context )
{
switch (ioinfo->si_code)
{
case POLL_IN:
printf("signal received for input chars.sig:%d -%d\n",status, ioinfo->si_code);
wait_flag = FALSE;
break;
case POLL_OUT:
default:
printf("signal received for something else.sig:%d -%d\n",status, ioinfo->si_code);
break;
}
According to the man page for sigaction, si_code has a small set of values it can be set to, and neither POLL_IN nor
POLL_OUT are in the set. The value you are seeing is SI_KERNEL, which is telling you that the kernel sent you the
signal.