read function & timeout

Hi,

I want to read from serial port with timeout but readcond function don’t satisfy me because the timeout is specified only in 1/10 of a second. It’s not enaugh for me. So I was going to use read function which can be interrupted by a signal before it reads any data and a timer to send the signal when the timer expires.
It could look like this:

timer_t g_timer_id = -1;
struct itimerspec timer_settings;
timer_create(CLOCK_REALTIME, NULL, &g_timer_id);
timer_settings.it_value.tv_sec = 0;
///g_ansdelay * 10ms
timer_settings.it_value.tv_nsec = g_ansdelay*10000000;
timer_settings.it_interval.tv_sec = 0;
timer_settings.it_interval.tv_nsec = 0;
timer_settime(g_timer_id, 0, &timer_settings, NULL);
read(fd, (buffer + i), 1);
timer_delete(g_timer_id);

That code is not complete.

But how to send a signal to read function when the timer expires?

Thanks.

When I had to handle data/signals over serial ports (up to 48 per node) with very high time precision, I did it as follows:

  1. All ports are handled not by Dev.ser, but by specially written timer interrupt handler (TIH)

  2. TIH initializes all ports on the start and attaches the timer interrupt (0). From within the interrupt it monitors ports and if data is ready (DR on LSR) puts it into a buffer in the shared memory and then, from outside the interrupt, it kicks the application with SIGALRM.

  3. The application normally sleeps in pause (), until it is kicked by SIGALRM. Then it gets a byte from a buffer.

Could you give me a code example for that?
I would rather use devc-ser driver and open/read/write functions.
Thanks anyway.

These are just tiny extracts. I had to remove lots of code, so many definititions are lost and examples will not compile. And I had to remove all the comments as misleading and confusing.

To compile interrupt handler, you need to use additional options with cc:

-T 1 -zu -Wc,-s

Thanks a lot yurkir. I will try it. Do you know how to do that using read function and a timer as I asked at the beginning of this post?

You need to specify what resolution you require. You have simply stated that 1/10 of a second is insufficient.

Using select, you can specify in microseconds. Anything less than a microsecond is meaningless to a serial port.

Rennie

Hum, with select you can specify timeout in microseconds, but I think the granularity is still that of the tick size.

I need 1/100 of a second resolution. It seems select function will be useful.

However I am still curious to know how to interrupt read function using signals?

In documentation they say that “If read() is interrupted by a signal before it reads any data, it returns a value of -1 and sets errno to EINTR. However, if read() is interrupted by a signal after it has successfully read some data, it returns the number of bytes read.”

Does select() generate that signal? Or can I generate one of POSIX’s signals to interrupt read()?

With select you don’t need the signals. select will unblock when there is data on the serial port or if the timeout expired. Hence if select unblock because of data on the serial port, you just need to issue a read to obtain the data (and read in non block mode) and empty the buffer.

Now if you expect a LOT of data on these serial port and a constant flow of them, it might not be such a bad choise to poll all the serial port with a non blocking read().

If you’re using QNX6 you could always preceed your call to read() with a call to TimerTimeout(…,_NTO_TIMEOUT_REPLY,…) as well. If the read times out, it will return with ETIMEDOUT (or possibly EINTR…can’t remember). If you do go this route, make sure there are NO calls between the TimerTimeout() call and the read() call.

The tick size is tunable, and defaults to 1ms (1/1000 of a second, considerably higher res than 1/10).

No you cannot do this.

read() is a library call, not a kernel call. Only kernel calls are subject to timeout using TimerTimeout.

There maybe several kernel calls inside of read(), the rule you quote here “make sure there are NO calls between the TimerTimeout() and the read()” cannot be followed, since the caller has no idea how many kernel calls read() is making nor in what order.

Rennie

I’ve done it using select() and it’s works as I desired. I can place here my example code if anybody wants.

Thanks for help!!!

Regarding the use of TimerTimeout():
read() is simply a cover to MsgSend()…no additional kernel calls occur before MsgSend() is called.

There is no guarantee of this. Anyone who designs their code based on the underlying implementation of a API deserves what they get when they upgrade the O/S and their code stops working.

Advising people to do this is bad advise.

How do you know? Is that written in the specs?

  • Mario

RoverFan, unless its in written form then its like walking on thin ice.