polling file descriptor

Hello,

for the embedded MIPS-based platform I'm implementing a small program to poll GPIO, i.e. I'm using chip vendor's user level GPIO library with basic functionality (open /dev/gpio, read, write pin etc.). The design is straightforward:

int gpio_fd; fd_set rfds;

gpio_fd = gpio_open(...);

while (1) { FD_ZERO(&rfds); FD_SET(gpio_fd, &rfds);

if (select(gpio_fd + 1, &rfds, NULL, NULL, NULL) > 0) { if (FD_ISSET(gpio_fd, &rfds)) { /* read pins and similar */ } } }

But I'm facing a secrious problem - this application when ran with '&' at the end, i.e. put it in background, consumes 99% CPU, this is obviously because of tight loop, but I observed the similar approach in many networking code and it worked fine.

Am I missing something, can it be a defect of the gpio library ?

Actually, just a single "while(1) ; " does the same effect. Can it be the "natural" behavior of the kernel?

Thanks.

--
Mark
Reply to
Mark
Loading thread data ...

It is in the nature of the handle you're polling: A network socket is not always ready, but a GPIO pin read is. The select() will yield when the polled handle is not ready. You have to insert some kind of delay in the loop to drop the CPU load to an acceptable level.

It is correct. See above.

--

Tauno Voipio
tauno voipio (at) iki fi
Reply to
Tauno Voipio

Sorry, not quite understand your idea. Could you please elaborate on that?

Just now I've checked the gpio driver's source code, and found that it doesn't seem to implement 'poll' method (the field in 'struct file_operations' ), may be that could be one of the reasons, i.e. select() in my program quickly returned and didn't do anything. So, does it make sense to try to add this functionality in the driver and see the results ?

--
Mark
Reply to
Mark

The 'handle' is the number of the I/O channel or socket.

A network interface has to wait for an arriving packet or for space in the send buffer. The driver blocks for this wait time, yielding control to other threads of execution in the system. The hardware mechanism for unblocking the driver is an interrupt connected to the driver and associated hardware.

There is nothing to wait for in the GPIO driver, so it is always immediately ready.

You would have a need for an appropriate interrupt with a suitable handler. Do you have the hardware documentation for the GPIO you have?

If you're going to do it, read the book

Linux Device Drivers

first. It is available as a PDF, google for it.

--

Tauno Voipio
tauno voipio (at) iki fi
Reply to
Tauno Voipio
[...]

Provided that it is possible block threads calling into the driver until they are woken up by some external event (such as an interrupt) signalling that 'something of interest has happened', my opinion would be that it makes sense technically: Even if no other application can make use of the CPU time freed in this way, it should still reduce power consumption and heat dissipation.

Reply to
Rainer Weikusat

You are 'select'ing the gpio fd for readability. Do you have any idea what this actually means semantically? If not, it is a programming error to do it.

For example, with a TCP connection, we know that 'readability' generally means that a read for a normal data would not block. So if we want to wait until a normal read would not block, we select for readability.

That is, our decision to call 'select' is based on the semantics of the a 'select' hit being what it is we want to wait for. Unless you know that the semantics of a 'select' hit being something you want to wait for, it is an error to call 'select'.

I suspect that you don't know that, and so your calling 'select' is an error.

DS

Reply to
David Schwartz

Could you please be more concrete?

As Tauno has already pointed out, select()'ing gpio file descriptor doesn't make much sense as it's always ready, unlike socket which may not be ready and thus application select()ing it would sleep.

--
Mark
Reply to
Mark

This depends on the driver and the configuration of the gpio.

Reply to
Rainer Weikusat

I'm not how I can be. You should call 'select' if, and only if, there is something you want to wait for or detect and 'select' is set up to wait for or detect that thing. It seems like in this case, the 'select' was thrown in as cargo cult programming. That is, it worked for someone else, so you did it, without any understanding of *why* the call was there.

So I'm trying to explain why the call was there and why that doesn't apply to you.

't

y

It doesn't make sense for two reasons. One is what it does, the other is what the application needs. Neither of them are the same as the usual case, so it's incorrect for both those reasons.

DS

Reply to
David Schwartz

As for the gpio driver I have, it operates on-chip registers (GPIO mask, enable/disable etc.), and exposes 'ioctl' to user space. So for this particular driver it seems there is no need for pollling.

Could you give some example when select() will be needed?

--
Mark
Reply to
Mark

Polling is the opposite of using select(), and seems to be exactly what you want. Polling means checking some status from time to time instead of waiting for it to change.

Perhaps a more detailed explanation of select() is in order.

What the system call select() does, is to take a set of file descriptors and wait until reading (or writing) can be done on one of the descriptors without blocking the process. Separate sets are provided to select() to wait for reading, writing, and exception conditions.

The most common use of the system call is in the situation where you have several file descriptors which provide incoming data att different rates, and you need to read each descriptor repeatedly to handle the data as it comes in. An example of this is a program that has many network connections open at the same time, and is receiving data from various sources more or less intermittently.

In that situation, if you simply make a read() call on one of the descriptors, the process will block indefinitely, until data arrives on that particular descriptor. This could take forever, and the process will be stuck in read() in the meantime. During that time, data may well arive on the other descriptors, but the program will not do anything about it since it is busy waiting for data on the first descriptor.

What you do instead, is you stick all the descriptors in a set, and call select(), giving that set as the "read set", to wait for reading becoming possible without blocking. Select() then blocks the process until data arrives on *any one* of the descriptors, at which time it returns to the process, indicating on which descriptor data arrived.

This way, you can have multiple sources of data and service them all in a timely manner. The other way to do that would be to poll all of the sources - that is, to loop and check each descriptor in turn to see if any data has arrived yet, repeating until no more data is to be read from any descriptor. The downside to this is that either you loop in a tight loop, using all the CPU time available, or you put a delay in between the checks, checking the descriptors at regular intervals, say once a second. This decreases CPU waste, but produces latencies in the reception of the data, since data could be available on one of the descriptors for a whole second before your process checks for it.

Does this make the use of select() clear?

Bjarni

--

                        INFORMATION WANTS TO BE FREE
Reply to
Bjarni Juliusson

I could construct a contrived example where select could be used on a file descriptor referring to a chardev (assumption) whose device driver provides access to GPIOs: In this case, events of interest wouldn't be GPIO states but GPIO state transitions and a read operation which blocks until the next GPIO state change has occurred, with this change being signalled by an interrupt. But I don't quite understand why this would be useful (the construction of the contrived example).

Generally 'select' (and similar routines) are only useful together with file descriptors referring to 'things' (devices, files, network connections etc) which provide read and write operation that might need to block.

Reply to
Rainer Weikusat

Then how will you know when to check the status?

Any time you need to wait for something to happen, such as waiting for a change in the GPIO state or for a particular GPIO input to have a particular value.

DS

Reply to
David Schwartz

I understand the difference, I was referring to 'polling' in the linux driver context (field 'poll' in the 'struct file_operations' ).

Thank you very much for your explanation, but how dos it prove that select() for this particular case (gpio) isn't needed ?

--
Mark
Reply to
Mark

Since you've noticed that select() on gpio file descriptor depends on the driver and the configuration of the gpio, I reasonably assumed that there should be an appropriate case of gpio driver, where select()ing would make perfect sense.

--
Mark
Reply to
Mark

Depends on how you define the semantics of select(). I would expect a basic gpio driver to return the state of the pins on read, and since 'current state' is always available there is no need for something like select() - it is a null op.

Having said that, when writing control software that has to deal with digital I/O pins I almost always end up with a process or thread that polls the I/O pins, and communicates status /changes/ to the rest of the app through some IPC mechanism. If the driver supported a select with semantics defined as 'only return if there was a state change since the last read on this file descriptor' it would make life much easier for the application programmer.

-j

Reply to
jack

True !

Unfortunately the more modern version of "select()" is called "epoll()" and of course does not do any polling.

No idea who invented this name :(.

-Michael

Reply to
Michael Schnell

You should not "check" the state but have your program block (e.g. in "select()"), until the state changes and continue with the new state.

-Michael

Reply to
Michael Schnell

Right, you need some way to know when to check the status.

DS

Reply to
David Schwartz

I'm not sure whether you mean the call to select in your code or the implementation of select in the driver.

For the call in your code: By the fact that your program uses 99% CPU. The select call is obviously not waiting for anything to change.

For the implementation of select functionality in the driver: Well, you're the one who knows what sort of response times and efficiency your application requires. If you need to respond quickly to events on the GPIO, and the GPIO hardware provides interrupts, then by all means add select support to the driver. If periodic polling will do, then just doing that would be easiest, and doesn't require any hardware support.

For each source of data, it is up to you to decide which of the two models to employ:

  1. The source can never be hung waiting for data to become available, and you have to decide how often you need to check it to determine the current state, handling multiplexing of multiple sources and frequency of polling by yourself.
  2. The source only occasionally has data available for reading, and in between, any attempt to read will block for some possibly variable amount of time. In this case, if your program needs to wait for data to become avilable before proceeding, use select on all the sources you need to receive data from (or just read if there is only one source).

If your program needs both to poll some sources periodically and handle arriving data on blocking file descriptors in a timely manner, use the timeout parameter to select, in which case select will provide you with the time base for the polling.

Does this answer your question, or am I barking up the wrong tree?

Bjarni

--

                        INFORMATION WANTS TO BE FREE
Reply to
Bjarni Juliusson

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.