Asynchronous Serial I/O

Folks,

This is my first post here.

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.

Thanks.

Meng Fang

======================MY CODE===============================

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#include <signal.h>
#include <bits/siginfo.h>

#define BAUDRATE B57600
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* POSIX compliant source */
#define FALSE 0
#define TRUE 1
void signal_handler_IO (int status, siginfo_t *ioinfo, void *context );

volatile int STOP=FALSE;


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.
I read about POLL_IN and POLL_OUT for signal SIGIO here:

http://opengroup.org/onlinepubs/007908775/xsh/signal.h.html

The possible values for si_code is defined in the table located in the middle of the above page.

Based on the table, if an SIGIO signal is received, the value of si_code can be any of the following:


POLL_IN
POLL_OUT
POLL_MSG
POLL_ERR
POLL_PRI
POLL_HUP
SI_USER
SI_QUEUE
SI_TIMER
SI_ASYNCIO
SI_MESGQ


Does any body know the reason why I did not get the above values? How should I modify my code?
According to that webpage, those codes are for SIGPOLL, not SIGIO.
http://en.wikipedia.org/wiki/SIGPOLL

According to the above Wiki site, On Linux, SIGIO is a synonym for SIGPOLL.

This is proven in the signal.h file at Line 40

#define SIGPOLL SIGIO
Topic archived. No new replies allowed.