views:

229

answers:

4

I'm writing a linux daemon in C which gets values from an ADC by SPI interface (ioctl). The SPI (spidev - userland) seems to be a bit unstable and freezes the daemon at random times.

I need to have some better control of the calls to the functions getting the values, and I was thinking of making it as a thread which I could wait for to finish and get the return value and if it times out assume that it froze and kill it without this new thread taking down the daemon itself. Then I could apply measures like resetting the ADC before restarting. Is this possible?

Pseudo example of what I want to achieve:

(function int get_adc_value(int adc_channel, float *value) )

  1. pid = thread( get_adc_value(1,&value); //makes thread calling the function
  2. wait_until_finish(pid, timeout); //waits until function finishes/timesout
  3. if(timeout) kill pid, start over //if thread do not return in given time, kill it (it is frozen)
  4. else if return value sane, continue //if successful, handle return variable value and continue

Thanks for any input on the matter, examples highly appreciated!

+2  A: 

I would try looking at using the pthreads library. I have used it for some of my c projects with good success and it gives you pretty good control over what is running and when.

A pretty good tutorial can be found here: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html

ghills
Thanks for the quick answer. I think maybe the pthread_cond_timedwait condition can do the trick - needs to write some testcode to see how it works
Einar
A: 

I'd recommend a different approach.

Write a program that takes samples and writes them to standard output. It simply need have alarm(TIMEOUT); before every sample collection, and should it hang the program will exit automatically.

Write another program that runs that first program. If it exits, it runs it again. It looks something like this:

main(){for(;;){system("sampler");sleep(1);}}

Then in your other program, use FILE*fp=popen("supervise_sampler","r"); and read the samples from fp. Better still: Have the program simply read the samples from stdin and insist users start your program like this:

(while true;do sampler;sleep 1; done)|program

Splitting up the task like this makes it easier to develop and easier to test, for example, you can collect samples and save them to a file and then run your program on that file:

sampler > data
program < data

Then, as you make changes to program, you can simply run it again on the same data over and over again.

It's also trivial to enable data logging- so should you find a serious issue you can run all your data through your program again to find the bugs.

geocar
+1  A: 

In glib there is too a way to check the threads, using GCond (look for it in the glib help).

In resume you should periodically set a GCond in the child thread and check it in the main thread with a g_cond_timed_wait. It's the same with the glib or the pthread.

Here is an example with the pthread: http://koders.com/c/fidA03D565734AE2AD9F5B42AFC740B9C17D75A33E3.aspx?s=%22pthread_cond_timedwait%22#L46

Jon Ander Ortiz Durántez
A: 

Something very interesting happens to a thread when it executes an ioctl(), it goes into a very special kind of sleep known as disk sleep where it can not be interrupted or killed until the call returns. This is by design and prevents the kernel from rotting from the inside out.

If your daemon is getting stuck in ioctl(), its conceivable that it may stay that way forever (at least till the ADC is re-set).

I'd advise dropping something, like a file with a timestamp prior to calling ioctl() on a known buggy interface. If your thread does not unlink that file in xx amount of seconds, something else needs to re-start the ADC.

I also agree with the use of pthreads, if you need example code, just update your question.

Tim Post