Forum: Compiler & IDEs SIGALRM, setitimer(), sleep(), select()


von Ralph F. (feu)


Lesenswert?

Hallo Forum,
in meinem uClinux wird eine uart Schittstelle abgefragt. nun habe ich 
die Funktionen select(), setitimer() und sleep().  Alle
verwenden den systemcall SIGALRM (14), glaube ich. Nun wird ja bei 
select() nicht unbedingt gewartet bis der SIGALRM kommt (timout). nun 
geht das Programm weiter und es wird setitimer()  aufgerufen. ist der 
SIGALRM von select noch activ und kommt dem vom Timer zuvor gibts einen 
Konflikt. So zumindest meine erklärung warum select() in dieser 
Kombination nicht mehr sauber funktioniert.
Kann das sein, und wenn ja, hat jemand eine Idee wie man sleep(), 
select() und setitimer() entkoppeln kann ohne jedesmal zu warten bis der 
vorher initzierte SIGALRM gekommen ist?

Vielen Dank im Voraus

Feu

von Arbeiter (Gast)


Lesenswert?

Ralph Feuchter schrieb:
> Hallo Forum,
> in meinem uClinux wird eine uart Schittstelle abgefragt. nun habe ich
> die Funktionen select(), setitimer() und sleep().  Alle
> verwenden den systemcall SIGALRM (14), glaube ich.

select() hat nichts mit SIGALRM am Hut.

> Nun wird ja bei select() nicht unbedingt gewartet bis der SIGALRM kommt
> (timout). nun geht das Programm weiter und es wird setitimer()
> aufgerufen. ist der SIGALRM von select noch activ und kommt dem vom Timer
> zuvor gibts einen Konflikt.

Das kann eigentlich niht sein.

> So zumindest meine erklärung warum select() in dieser  Kombination nicht
> mehr sauber funktioniert.

Was heißt denn "nicht mehr sauber"? Was passiert? Sind noch andere 
Signale im Spiel? Bedenke, daß select() wie jeder system call generell 
durch Signale unterbrochen wird.

> Kann das sein, und wenn ja, hat jemand eine Idee wie man sleep(),
> select() und setitimer() entkoppeln kann ohne jedesmal zu warten bis der
> vorher initzierte SIGALRM gekommen ist?

Funktionen, die intern SIGALRM nutzen, werden nicht einfach einen Timer 
übrig lassen, der dann irgendwann auf einmal noch ein Signal generiert. 
Probleme mit sleep() und setitimer() dürften eigentlich nur auftreten, 
wenn du mit setitimer() einen Timer definierst, und bevor der abgelaufen 
ist, sleep() aufrufst.
Vielleicht kannst du nanosleep() verwenden. Das ist ein eigener system 
call und greift nicht auf SIGALRM zurück.

von Ralph F. (feu)


Lesenswert?

vielen Dank für die schnelle Antwort.
Arbeiter schrieb:
> Probleme mit sleep() und setitimer() dürften eigentlich nur auftreten,
> wenn du mit setitimer() einen Timer definierst, und bevor der abgelaufen
> ist, sleep() aufrufst.
das schein tatsächlich das Problem zu sei. mit setitimer setze ich einen 
Timer der eine while schleife abbricht falls read() nicht den 
gewünschten string empfangen hat. Kommt der string an ist der timer noch 
aktiv. den wollte ich mit

void timer_stop(void)
{
  struct itimerval it_val;
  it_val.it_value.tv_sec     = 0;
  it_val.it_value.tv_usec   = 0;
  it_val.it_interval.tv_sec   = 0;  //only once (no interval
  it_val.it_interval.tv_usec   = 0;

  setitimer(ITIMER_REAL, &it_val, NULL);

}

stoppen, aber scheinbar funktioniert das nicht so.



die Funktion die den Timer startet + Handler:

volatile int timer_status;

int timer_start(sec, usec, interv_sec, interv_usec)
{
  struct itimerval it_val;

  if (SIG_ERR == signal(SIGALRM, (void (*) (int)) timer_exp))
  {
    perror("Unable to catch SIGALRM");
//    exit(1);
  }
  timer_status = 1;

   it_val.it_value.tv_sec     = sec;
   it_val.it_value.tv_usec     = usec;
   it_val.it_interval.tv_sec   = interv_sec;  //only once (no interval
   it_val.it_interval.tv_usec   = interv_usec;

   setitimer(ITIMER_REAL, &it_val, NULL);

  return timer_status;
}


void timer_exp(void)          //interupt handler
{
  printf("--- timeout ---.\n");
  timer_status = 0;
}

Vielleicht liegt es auch daran, dass ich die structur in der 
Stop-funktion neu definiere. ich weiss aber nicht, wie ich es anders 
machen soll da der Timer von einer Funktion aus gestartet wird.





auf den konflikt mit select() bin ich gekommen, da der damit definierte 
select-timeout auch unkontrolliert getriggert wird.


Was vielleicht noch wichtig ist, ich sende mehrere Commandos 
nacheinander. wobei jedesmal select(), setitimer() und sleep() vorkommt. 
den tip mit nanosleep()werde ich einbaun. danke!

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ralph Feuchter schrieb:
> mit setitimer setze ich einen
> Timer der eine while schleife abbricht falls read() nicht den
> gewünschten string empfangen hat.

Einen Timer zu verwenden, um einen read() abzubrechen, ist suboptimal. 
Wenn Du select() verwendest, dann weisst Du auch, wann wieviel im Input 
zur Verfügung steht. Das kannst Du auf jeden Fall sicher abholen, ohne 
dass der read() hängenbleibt. Desweiteren gibt es gerade für UARTs unter 
UNIX/Linux die Möglichkeit, einen read() auf ein TTY komfortabel in 
einen Timeout laufen zu lassen, d.h. den read() vorzeitig zu beenden, 
wenn nix kommt.

Das Timeout kann in Zehntelsekunden (deciseconds) eingestellt werden.

Schau Dir die man page für termios(3) an, z.B.:

  http://linux.die.net/man/3/termios

Beachte insbesondere die Bemerkungen zu VMIN und VTIME.

von Ralph F. (feu)


Lesenswert?

Frank M. schrieb:
> Wenn Du select() verwendest, dann weisst Du auch, wann wieviel im Input
> zur Verfügung steht. Das kannst Du auf jeden Fall sicher abholen, ohne
> dass der read() hängenbleibt

Schon klar, aber die Schnittstelle ist ja langsamer als die ganze 
Ausleseprozedur. select() wird getriggert bei VMIN=0 mit dem ersten byte 
was ankommt, glaube ich. und um den ganzen Rest noch abzuholen der durch 
die Schnittstelle kommt, muss ich ja mehrere male read() auffordern um 
alles abzuholen. Wenn ich weiss wie gross der string ist kann ich das 
mit einem einzigsten read() und VTIME machen. Dazu brauche ich aber die 
buffergrösse. Also für lange Datensätze geht das nicht. Oder meinst du 
ich solle select() jedesmal vorm read() Aufruf bemühen. Jetzt mache ich 
es nur einmal um zu merken, wenn das modem anfängt zu antworten.

von Rolf Magnus (Gast)


Lesenswert?

Ralph Feuchter schrieb:
> auf den konflikt mit select() bin ich gekommen, da der damit definierte
> select-timeout auch unkontrolliert getriggert wird.
>
> Was vielleicht noch wichtig ist, ich sende mehrere Commandos
> nacheinander. wobei jedesmal select(), setitimer() und sleep() vorkommt.

Wie schon gesagt wurde: Jeder blockierende System Call, also auch 
select() wird durch Signale unterbrochen. Wenn du also noch von vorher 
irgendwo einen Timer hast, der gerade dann abläuft, wenn select() 
wartet, dann fliegst du der Funktion raus. Das hat dann aber nichts 
speziell mit SIGALRM zu tun, sondern würde bei jedem anderen Signal 
genauso passieren. Wenn der Aufruf mit -1 zurückkehrt und errno == EINTR 
ist, dann ist select() durch ein Signal unterbrochen worden, und du mußt 
es nochmal aufrufen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ralph Feuchter schrieb:
> Schon klar, aber die Schnittstelle ist ja langsamer als die ganze
> Ausleseprozedur.

Eben. Mach einen read() von jeweils einem Byte mit VMIN=0 und VTIME=x 
(>0) und alles ist gut.

Wenn Du befürchtest, dass dadurch die verbratene CPU-Zeit in die Höhe 
schnellt, kann ich Dich beruhigen: bei den niedrigen 
Übertragungsgeschwindigkeiten passiert da gar nichts.

von Ralph F. (feu)


Lesenswert?

vielen Dank für den tip mit EINTR ==1 und -1; werde es implementieren, 
aber nochmal zurück zur Frage (vielleicht ist sie auch zu basal), wie 
kann ich einen timer der einmal losgelaufen ist wieder stoppen ohne das 
er später im Programmablauf was anrichtet. Durch eine anderen Funktion 
alle it_value = 0 setzen hilft nicht so richtig, glaube ich.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Ralph Feuchter schrieb:
> wie
> kann ich einen timer der einmal losgelaufen ist wieder stoppen ohne das
> er später im Programmablauf was anrichtet. Durch eine anderen Funktion
> alle it_value = 0 setzen hilft nicht so richtig, glaube ich.

Das ist keine Frage des Glaubens.

Zitat aus man setitimer:

A timer which is set to zero (it_value is zero or the timer expires and 
it_interval is zero) stops.

von Ralph F. (feu)


Lesenswert?

klar, dann sollte es eigentlich gehen.
werde mal

Frank M. schrieb:
> read() von jeweils einem Byte mit VMIN=0 und VTIME=x
> (>0)

ausprobieren

und melde mich wieder

vielen Dank

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.