Forum: Mikrocontroller und Digitale Elektronik Embedded Linux & C, system() liefert nicht den richtigen Rückgabewert?


von Problem0815 (Gast)


Lesenswert?

Hallo Forum,

in einem Programm das ich in C schreibe und das dann auf meinem Embedded 
Linux (Archlinux ARM Beaglebone Black) läuft, benutze ich system() um 
eine Checksumme zu überprüfen mittels
system("sha1sum -c  File.sha1");
Vorher wechsel ich in das entsprechende Verzeichnis usw.
Ich weiß, dass ich auch die libs nehmen kann aber das wird halt alles 
aufwändiger. Und zeitlich wird es dann eng..

In meinem man system() auf dem System steht:

RETURN VALUE
       The value returned is -1 on error (e.g., fork(2) failed), and the 
return status of the command otherwise.  This latter return  status  is 
in  the
       format  specified  in  wait(2).   Thus, the exit code of the 
command will be WEXITSTATUS(status).  In case /bin/sh could not be 
executed, the exit
       status will be that of a command that does exit(127).

       If the value of command is NULL, system() returns nonzero if the 
shell is available, and zero if not.

       system() does not affect the wait status of any other children.

Somit gehe ich davon aus das ich den Rückgabewert von sha1sum erhalte.

Wenn ich den Befehl direkt aus der Console ausführe und dann echo $? 
mache bekomme ich 1 angezeigt wenn die Überprüfung nicht passt.

In meinem C Programm bekomme ich in dem Fall 0 zurück.
Genau dasselbe Problem habe ich mit tar.

Wenn ich den Befehl mit system() aufrufe kommt immer 0 zurück. In der 
Console mein erwarteter Wert...

Woran liegt es? Denke an dem sh -c noch dazwischen. Nur wie komme ich 
denn nun am besten an den Rückgabewert des aufgerufenen Programms in 
meinem C Programm?

Würde es mit fork() und exec() funktionieren?

Oder gibt es eine andere elegantere Lösung?

Wie gesagt libs würde ich ungern verwenden müsste dann ja tar, sha1sum 
und eventuell auch nocht ncftp oder wenn ich auf sftp umschwenke 
unmengen an Code schreiben obwohl es die passenden Programme schon gibt.

von Quack (Gast)


Lesenswert?

Poste ein Minimalbeispiel, das dein Problem reproduziert.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Woran liegt es? Denke an dem sh -c noch dazwischen. Nur wie komme ich
> denn nun am besten an den Rückgabewert des aufgerufenen Programms in
> meinem C Programm?

Indem Du das Programm direkt aufrufst - ohne "sh -c" und ohne cd-Befehl 
dazwischen.

Wieso zeigst Du ein

    system("sha1sum -c  File.sha1");

und erzählst im Text, dass Du vorher noch das Verzeichnis wechselst und 
dann auch noch irgendwo ein "sh -c" reinwurschtelst?

Zeige bitte den system-Aufruf, den Du auch verwendest.

von Mark B. (markbrandis)


Lesenswert?

Problem0815 schrieb:
> Wie gesagt libs würde ich ungern verwenden müsste dann ja tar, sha1sum
> und eventuell auch nocht ncftp oder wenn ich auf sftp umschwenke
> unmengen an Code schreiben obwohl es die passenden Programme schon gibt.

Naja soooo kompliziert sieht das jetzt nicht aus:

ftp://ftp.gnupg.org/gcrypt/binary/sha1sum.c

Die main() Funktion hat grad mal 40 Zeichen. Das bisschen Dateien 
öffnen, Puffer bereitstellen, sha1_init(), sha1_write() und sha1_final() 
aufrufen - also daran sollte es jetzt nicht scheitern. "Unmengen an 
Code" sieht anders aus. ;-)

von mar IO (Gast)


Lesenswert?

Frank M. schrieb:
> Problem0815 schrieb:
>> Woran liegt es? Denke an dem sh -c noch dazwischen. Nur wie komme ich
>> denn nun am besten an den Rückgabewert des aufgerufenen Programms in
>> meinem C Programm?
>
> Indem Du das Programm direkt aufrufst - ohne "sh -c" und ohne cd-Befehl
> dazwischen.

"sh -c" ruft system() selber auf
1
...
2
system() executes a command specified in command by calling /bin/sh -c command, and returns after the command has been completed.
3
...
4
The value returned is -1 on error (e.g., fork(2) failed), and the return status of the command otherwise.
5
...
Quelle: http://linux.die.net/man/3/system

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

mar IO schrieb:
> "sh -c" ruft system() selber auf

Das weiß ich, das brauchst Du mir nicht zu erzählen. Es las sich nur 
anders, nämlich dass er im System-Call noch das Verzeichnis wechselt und 
auch noch ein "sh -c" reinpfriemelt.

Er soll mal folgendes probieren:

Datei x.sh:

#! /bin/sh
exit 2

Datei: x.c:

#include <stdio.h>

int
main ()
{
  int rtc = system ("./x.sh");

  printf ("%d\n", rtc >> 8);
  return 0;
}


Dann:

cc x.c -o x.out
chmod +x x.sh
./x.out

Dann sollte die Zahl 2 ausgegeben werden. Wenn nicht, ist sein system() 
kaputt.

P.S.
Ja, rtc muss um 8 Bit geshiftet werden.

von Problem0815 (Gast)


Lesenswert?

OK, hat sich erledigt...

hatte als Rückgabe Variable eine int_fast8_t genommen... Ist natürlich 
zu klein.

Mit int geht es.

von Kai S. (zigzeg)


Lesenswert?

Frank M. schrieb:

> Ja, rtc muss um 8 Bit geshiftet werden.

Besser (portabler) ist
1
#include <sys/wait.h>
2
3
...
4
5
printf ("%d\n", WEXITSTATUS(rtc));

ZigZeg

von Problem0815 (Gast)


Lesenswert?

sh -c benutze ich nicht. System aber. So war das gemeint.

Desweiteren wechsel ich vorher das Verzeichnis da sha1sum anscheinend 
nur im aktuellen prüft. Mit absoluten Pfadangaben kommt es nicht klar. 
Daher wechsel ich in das Verzeichnis wo meine beiden Files zum 
überprüfen liegen und anschließend wieder zurück.

Und unmengen an Code kommen jetzt nicht bei sha1sum aber wenn ich tar 
und gzip verwende bzw sftp/scp oder ncftpget / ncftpput.

Dann wird es mehr..

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> hatte als Rückgabe Variable eine int_fast8_t genommen... Ist natürlich
> zu klein.

Dachte mir sowas schon, deshalb habe ich es im P.S. nochmal explizit 
erwähnt. Merke Dir einfach, dass fast alle Standard-Lib-Funktionen unter 
Unix oder Linux ein int als Returnwert verwenden. Witzigerweise hattest 
Du die Manualseiten von system() noch zitiert, wo auch die Angabe über 
den Return-Wert drinsteht.

Lass solche "Optimierungen" wie Verwendung von "int_fast8_t" unter Unix 
oder Linux besser - jedenfalls dann, wenn Du Standard-Lib-Funktionen 
oder gar System-Calls verwendest. Solche "modernen" Typen gab es in den 
70er Jahren noch gar nicht.

: Bearbeitet durch Moderator
von Problem0815 (Gast)


Lesenswert?

Nur bei ping geht es trotzdem nicht...

Aber das hab ich mit popen und dann parsen gelöst..

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Kai S. schrieb:
> Besser (portabler) ist
> printf ("%d\n", WEXITSTATUS(rtc));

Stimmt, ich wollte ihn aber explizit darauf hinweisen, dass rtc groß 
genug sein muss, um mehr als ein Byte aufzunehmen. Ich glaube nicht, 
dass ein WEXITSTATUS() ihn in die richtige Ecke geschubst hätte.

Ausserdem:

Mit einem int_fast8_t als rtc funktioniert auch WEXITSTATUS(rtc) nicht 
;-)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Nur bei ping geht es trotzdem nicht...
>
> Aber das hab ich mit popen und dann parsen gelöst..

Geht auch mit ping. Warum sollte es da anders sein?

cat x.c:
1
#include <stdio.h>
2
#include <sys/wait.h>
3
4
int
5
main ()
6
{
7
  int rtc;
8
9
  rtc = system ("ping -c 1 192.168.1.1 >/dev/null 2>&1");  // den gibt es bei mir nicht
10
  printf ("rtc = %d\n", WEXITSTATUS(rtc));
11
12
  rtc = system ("ping -c 1 127.0.0.1 >/dev/null 2>&1");    // den gibt es immer ;-)
13
  printf ("rtc = %d\n", WEXITSTATUS(rtc));
14
  return 0;
15
}

# cc x.c -o x.out
# ./x.out
rtc = 1
rtc = 0

Und was hat ping mit popen() zu tun?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Desweiteren wechsel ich vorher das Verzeichnis da sha1sum anscheinend
> nur im aktuellen prüft. Mit absoluten Pfadangaben kommt es nicht klar.

Das glaube ich nicht:

# sha1sum /etc/passwd
03ee23731b71180ffc93169a82f8a47b11868321  /etc/passwd

Klappt einwandfrei. Keine Ahnung, welche Welt Du Dir da 
zurechtschusterst.

von Problem0815 (Gast)


Lesenswert?

Okay,...


manchmal zweifel ich an mir selber. Ping geht jetzt auch...

Hatte weil ich halt den Fehler hatte, ping mit popen aufgerufen und dann 
die pipe in einen Puffer eingelesen und dann geparsed nach 100% loss bzw 
not rechable usw..

von Problem0815 (Gast)


Lesenswert?

Nein ich habe eine Datei test.sha1 in einem Ordner und die zu 
überprüfende Datei auch in dem Ordner.

Und damit ich nicht in der .sha1 Datei den absoluten Pfadnamen drin 
haben muss (wird nämlich auf einem Windowsrechner erstellt) wechsel ich 
in den Ordner wo beide Dateien liegen.

von Problem0815 (Gast)


Lesenswert?

Also ich habe:

test.sha1
und
Latest.hex

(Beispieldateien...)

Und wenn ich jetzt in test.sha1 sowas drin habe:
03ee23731b71180ffc93169a82f8a47b11868321  Latest.hex

weil es auf einem Windows PC erstellt wurde geht es nicht unter Linux 
mit:

system("sha1sum -c /Downloads/Test/test.sha1");

Ich müsste daher entweder unter Windows den Pfad mit in die Datei 
schreiben.. (den ich eventuell nicht weiß) oder aber ich wechsel unter 
Linux in den Ordner wo beide Datein liegen und rufe dort dann:
system("sha1sum -c test.sha1"); auf..

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Nein ich habe eine Datei test.sha1 in einem Ordner und die zu
> überprüfende Datei auch in dem Ordner.
>
> Und damit ich nicht in der .sha1 Datei den absoluten Pfadnamen drin
> haben muss (wird nämlich auf einem Windowsrechner erstellt) wechsel ich
> in den Ordner wo beide Dateien liegen.

Sag das doch gleich, dass in der sha1-Datei die Pfade fehlen ;-)

Stünden die Pfade nämlich drin, klappt das einwandfrei:

# sha1sum  /etc/passwd >/tmp/a
# cat /tmp/a
03ee23731b71180ffc93169a82f8a47b11868321  /etc/passwd
chroot-eis-iv# sha1sum -c /tmp/a
/etc/passwd: OK
chroot-eis-iv# echo $?
0

von Problem0815 (Gast)


Lesenswert?

Mit Ordner wechseln meine ich das Arbeitsverzeichnis ändern...

Ich weiß nur nicht wie das sich mit Multi Threading verhält...

Wenn ich in einem Thread das Arbeitsverzeichnis ändere, ist das in den 
anderen auch geändert??

von Problem0815 (Gast)


Lesenswert?

Wenn ja muss ich mir da noch was überlegen..

Bzw. wohl critical sections oder so nutzen. Gibts doch bestimmt auch 
unter Linux..

von Peter II (Gast)


Lesenswert?

Problem0815 schrieb:
> Mit Ordner wechseln meine ich das Arbeitsverzeichnis ändern...
>
> Ich weiß nur nicht wie das sich mit Multi Threading verhält...
>
> Wenn ich in einem Thread das Arbeitsverzeichnis ändere, ist das in den
> anderen auch geändert??

naja anderen Systemen (MS) kann man bei erzeugen eine Prozesses das 
Arbeitsverzeichnis mitgeben. So etwas wird es doch wohl auch für Linux 
geben.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> weil es auf einem Windows PC erstellt wurde geht es nicht unter Linux
> mit:
>
> system("sha1sum -c /Downloads/Test/test.sha1");
>
> Ich müsste daher entweder unter Windows den Pfad mit in die Datei
> schreiben.. (den ich eventuell nicht weiß) oder aber ich wechsel unter
> Linux in den Ordner wo beide Datein liegen und rufe dort dann:
> system("sha1sum -c test.sha1"); auf..

Doch, ginge mit:

 system("cd /Downloads/Test && sha1sum -c /Downloads/Test/test.sha1");

Dann müsstest Du nicht in Deinem C-Programm hin- und herwechseln, weil 
nur Dein Kind den cd durchführt.

Wichtig ist die Trennung der beiden Befehle mit "&&" statt wie allgemein 
üblich mit ";". Nur so hast Du einen auswertbaren, d.h. 
vertrauenswürdigen rtc.

von Problem0815 (Gast)


Lesenswert?

Was man so alles dazu lernt :-)

Naja bin ja noch Frischling bei Linux Systemprogrammierung..
Bisher nur PICs.

Habe mir auch extra das Buch von Helmut Herold besorgt :)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Mit Ordner wechseln meine ich das Arbeitsverzeichnis ändern...
>
> Ich weiß nur nicht wie das sich mit Multi Threading verhält...
>
> Wenn ich in einem Thread das Arbeitsverzeichnis ändere, ist das in den
> anderen auch geändert??

Machs nicht so kompliziert. Du schaffst Dir so nur unnötige Komplexität. 
Unter Unix/Linuix sollte man das KISS-Prinzip ("Keep it small and 
simple") immer beachten.

Schreib den cd-Befehl einfach mit in den system-Aufruf, wie ich es ein 
Posting drüber angegeben habe. Dann bleibt Dein Programm im 
ursprünclichen Verzeichnis und Dein Kind springt hinüber.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Was man so alles dazu lernt :-)

Ich arbeite seit Mitte der Achtziger mit Unix-Systemen, habe sie auf der 
Uni kennengelernt. Damals war es noch Unix System-V auf VME-Bus-Systemen 
(Motorola 68020).

Ich bin also seit 30 Jahren mit Unix, dann später mit Linux altgeworden. 
Bei einem kannst Dir aber sicher sein: Auch dann lernt man immer noch 
dazu :-)

Unix-/Linux ist so mächtig durch das Bereitstellen vieler kleiner Tools, 
dass man selbst komplexe Aufgaben mit ein paar Shell-Befehlen lösen 
kann... wenn man weiß, wie man sie zu kombinieren hat ;-)

: Bearbeitet durch Moderator
von Peter II (Gast)


Lesenswert?

es muss doch auch etwas wie CreateProcess unter Linux geben. Also auch 
Programme unter anderen user-rechte starten usw.

Oder die stdin, stout, stderr als filehandle bekommen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> es muss doch auch etwas wie CreateProcess unter Linux geben.

Natürlich, in vielen Variationen.

> Also auch Programme unter anderen user-rechte starten usw.
> Oder die stdin, stout, stderr als filehandle bekommen.

Gibt es alles. Microsoft war auch unheimlich stolz auf ihren mächtigen 
CreateProcess(), als sie ihn mit Windows-NT einführten und damit auch 
endlich etwas ähnliches geschaffen haben, was es unter Unix schon seit 
über 20 Jahren gab.

Witzig, dass Du es so siehst, dass Unix (bzw. Linux) auch etwas haben 
muss, was Du bei Windows als selbstverständlich erachtest. Die Realität 
ist anders herum. Du ahnst gar nicht, was Microsoft so alles von Unix 
übernommen hat.

(*) Ja, ich war damals bei einer Präsentations-Show von Windows-NT 
selbst dabei. Die freuten sich damals wie die kleinen Kinder, dass sie 
endlich ein "echtes" OS geschaffen haben. Sie waren auch unheimlich 
stolz darauf, dass sie mit NT auch endlich POSIX-kompatibel waren und 
damit die Auflagen des US-Verteidigungsministeriums mit sicherem 
Gewissen erfüllen konnten. Nur für einen UNIX-Kenner waren das damals 
olle Kamellen.

(**) Was auch kaum jemand weiß: Microsoft hatte damals sogar ein eigenes 
Unix-System, nämlich Xenix. Wurde aber nicht weiter verfolgt.

: Bearbeitet durch Moderator
von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Natürlich, in vielen Variationen.

nenn doch mal eine?

Oder meinst du die Krücke, wo man eine fork machen, sich dann eine 
anderen Benutzer gibt. Die eigenen Handles umbiegt. Und dann den andere 
Prozess startet? und wie bekommt man dann die Handles in den alten 
Prozess zurück...

von Problem0815 (Gast)


Lesenswert?

Habs gerade umgebaut :-) und läuft.

Vielen Dank.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Frank M. schrieb:
>> Natürlich, in vielen Variationen.
>
> nenn doch mal eine?
>
> Oder meinst du die Krücke, wo man eine fork machen, sich dann eine
> anderen Benutzer gibt. Die eigenen Handles umbiegt. Und dann den andere
> Prozess startet? und wie bekommt man dann die Handles in den alten
> Prozess zurück...

Die Vielfalt liegt tatsächlich in der Kombination der Möglichkeiten. 
Dabei ist nicht unbedingt fork() nötig. popen() ist zum Beispiel genau 
das richtige, um ein Kind zu starten und sich mit den 
stdio-Filedescriptoren des Kindes zu verbinden. Dann ist einfache 
Kommunikation über stdio-Funktionen möglich... denn es ist genau 
dasselbe, als wenn Du in der Shell eine Pipe zwischen zwei Prozessen 
durch "|" erzeugst.

Das Beispiel mit der Krücke verstehe ich nicht. Wenn Dir das zu 
umständlich ist, schreibe alles nötige in eine eigene Funktion und nenne 
sie CreateProcess(). ;-)

> und wie bekommt man dann die Handles in den alten Prozess zurück...

Diese Frage verstehe ich nicht. Allein schon, dass Du die 
Windows-Sprache ("Handles") verwendest und nicht die richtige 
Bezeichnung ("File-Descriptor") dafür wählst, zeugt davon, dass Du nur 
rudimentäres Verständnis aufweist. Wie sollen wir uns beide dann über 
die Möglichkeiten von Unix/Linux "unterhalten"? ;-)

(Ja, ich weiß: Du willst einen Streit vom Zaun brechen. Ich muss Dich 
aber enttäuschen und werde nicht drauf eingehen.)

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:
> Habs gerade umgebaut :-) und läuft.

Freut mich! Und noch viel Spaß mit Linux! :-)

von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> denn es ist genau
> dasselbe, als wenn Du in der Shell eine Pipe zwischen zwei Prozessen
> durch "|" erzeugst.

und wie bekommst du damit stderr und stdout getrennt? (also nicht 
einfach in Dateien schreiben)

> > und wie bekommt man dann die Handles in den alten Prozess zurück...
> Diese Frage verstehe ich nicht.

wenn ich von dem Programm die stderr und stdout Daten brauche, dann 
brauche ich die handels oder File-Descriptoren.

man müsste halt 2 pipes verwenden, das wüsste ich nicht wie das gehen 
soll.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:
> Frank M. schrieb:
>> denn es ist genau
>> dasselbe, als wenn Du in der Shell eine Pipe zwischen zwei Prozessen
>> durch "|" erzeugst.
>
> und wie bekommst du damit stderr und stdout getrennt? (also nicht
> einfach in Dateien schreiben)

stdout und stderr sind unter Unix/Linux immer getrennt. Was soll ich da 
also noch trennen? ;-)

> man müsste halt 2 pipes verwenden, das wüsste ich nicht wie das gehen
> soll.

Wenn Du mehr als eine Pipe brauchst, dann musst Du tatsächlich den Weg 
über fork(), Verbinden der Kind-FDs mit eigenen FDs (das geht mit dup()) 
und anschließendem exec() gehen.(*) Ist aber auch nicht sooo 
kompliziert. Und ist auch keine Krücke. Das ist gewollt so.

Ich habe mal vor Jahren einen Text-Editor geschrieben, der mir einen 
beliebigen Prozess in einem Editor-Fenster öffnete. Das konnte make zum 
Compilieren sein, aber auch zum Beispiel eine Shell. Alles, was ich in 
das Editor-Fenster tippte, ging an die Shell und wurde 
ausgewertet/ausgeführt, alles was an Output (von der Shell oder deren 
Kindern) zurückkam, wurde ins Editor-Fenster zurückgeschrieben und war 
dort ganz normal editierbar wie Text. Wie gesagt: Geht alles. Auch dass 
stderr-Ausgaben im Editor-Fenster rot eingefärbt werden ;-)

Aufgaben löst man unter Unix/Linux, indem man viele kleine Tools 
miteinander sinnvoll kombiniert. Bei Windows macht man das eher anders: 
man ruft ein Monstrum auf, welches man über viele viele Parameter (z.B. 
in C: Unmengen von Structs, die zu füllen sind) steuert.

Man kann darüber streiten, was sinnvoller ist.

(*) Lies dazu auch:
  http://www.oser.org/~hp/labor5s/node54.html

: Bearbeitet durch Moderator
von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> Man kann darüber streiten, was sinnvoller ist.

bei Linux merkt man aber scheinbar, das es so nicht immer sinnvoll ist. 
Immerhin erfinden sie gerade soetwas wie den Dienstmanager unter Windows 
mit ihren SystemD neu.

von Peter II (Gast)


Lesenswert?

Frank M. schrieb:
> (*) Lies dazu auch:
>   http://www.oser.org/~hp/labor5s/node54.html

und das soll keine Krücke sein?

Klar kann ich auch mit ASM eine XML parsen, aber in der heutigen zeit 
erwartet man halt das so etwas schon fertig vorhanden ist.

KISS ist zwar schön, aber übertreiben muss man es nicht.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Achsoo, jetzt verstehe ich auch die Frage:

> und wie bekommt man dann die Handles in den alten Prozess zurück...

Du schließt die Filedescriptoren 0, 1, 2 (eigentlich fileno(stdin) usw.) 
einfach nicht vor dem exec(). Dann gehen sie auch nicht verloren.

Das mit dem Schließen der Standard-FDs macht man eigentlich nur, wenn 
man sie als Pipe und gleichzeitig als Standard-FDs verwenden will.

von Karl Käfer (Gast)


Lesenswert?

Hi,

Problem0815 schrieb:
> Was man so alles dazu lernt :-)
>
> Naja bin ja noch Frischling bei Linux Systemprogrammierung..
> Bisher nur PICs.
>
> Habe mir auch extra das Buch von Helmut Herold besorgt :)

Besorgen reicht nicht. Wer Erfolg haben will, muß es auch lesen. ;-)

SCNR,
Karl

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter II schrieb:

> und das soll keine Krücke sein?

Nein, das ist keine Krücke. Schreibe alle nötigen Aufrufe in eine 
Funktion und nenne sie meinetwegen MyUltimateFunctionOfCreateProcess().

> KISS ist zwar schön, aber übertreiben muss man es nicht.

Du hast leider nichts verstanden. Ich hatte es bereits befürchtet. Daher 
von meiner Seite EOD.

von Mark B. (markbrandis)


Lesenswert?

Frank M. schrieb:
> MyUltimateFunctionOfCreateProcess()

:-)

von Karl Käfer (Gast)


Lesenswert?

Hallo Peter,

Peter II schrieb:
> nenn doch mal eine?

fork(2)

> Oder meinst du die Krücke, wo man eine fork machen, sich dann eine
> anderen Benutzer gibt. Die eigenen Handles umbiegt. Und dann den andere
> Prozess startet? und wie bekommt man dann die Handles in den alten
> Prozess zurück...

Was sollte daran eine "Krücke" sein? Das ist eine sehr leistungsfähige 
und flexible Lösung. Daß Du sie offenbar nicht verstanden hast und sie 
darum als "Krücke" bezeichnest, spricht nicht gerade für Deine 
Fähigkeiten.

Liebe Grüße,
Karl

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Karl Käfer schrieb:
> Was sollte daran eine "Krücke" sein? Das ist eine sehr leistungsfähige
> und flexible Lösung. Daß Du sie offenbar nicht verstanden hast und sie
> darum als "Krücke" bezeichnest, spricht nicht gerade für Deine
> Fähigkeiten.

Lass Dich nicht auf einen Streit ein. Nur das will er. Er füllt halt 
lieber die Daten für

 LPCTSTR lpApplicationName,
 LPTSTR lpCommandLine,
 LPSECURITY_ATTRIBUTES lpProcessAttributes,
 LPSECURITY_ATTRIBUTES lpThreadAttributes,
 BOOL bInheritHandles,
 DWORD dwCreationFlags,
 LPVOID lpEnvironment,
 LPCTSTR lpCurrentDirectory,
 LPSTARTUPINFO lpStartupInfo

um dann endlich nach wilden Allokationen, Copy&Pastes aus irgendwelchen 
MSDN-Sites die ersehnte Funktion CreateProcess() aufrufen zu können, 
ohne dass sie einen Error wirft. ;-)

Und ehrlich gesagt: Ich weiß nicht, ob/wie man eine (oder gar mehrere) 
Pipes zu einem Kind-Prozess unter Windows per CreateProcess() aufbauen 
könnte. Das Boolean bInheritHandles wird einem da wohl nicht 
weiterhelfen.
Unter Unix/Linux weiß ich es aber sehr wohl, weil mir die Schritte dahin 
absolut plausibel und nachvollziehbar erscheinen.

Jedem das seine. Ich arbeite sowohl mit Unix, Linux als auch mit 
Windows. Alle Systeme haben ihre Daseinsberechtigung. Was man bei dem 
einen System gut bzw. schlecht findet, kann ein Anderer anders sehen.

von Problem0815 (Gast)


Lesenswert?

So vielleicht könnt Ihr mir nocheinmal helfen.

Ich rufe in meiner main() 4 Threads auf. Jeder Thread ist eine 
state-machine.
die für immer laufen soll.
Also beinhalten die Threads jeweils eine while(1){Sachen die gemacht 
werden.}

Nachdem die Threads erstellt und aufgerufen wurden geht meine main 
selber in eine while(1);

Läuft also bis der Beaglebone abschmiert...

Mein Problem ist das diese while(1); meine CPU Auslastung auf 100% jagt 
und dann irgendwann der watchdog auslöst.

(watchdog service ist auch ein thread).

Wie lege ich denn die main() am besten auf Eis? Mit einem sehr langen 
sleep(10000)? Oder gibt es einen extra Befehl für so etwas?

von Problem0815 (Gast)


Lesenswert?

Habe jetzt einen Thread weniger aufgemacht und die state-machine des 
Watchdogs in die main() geschoben. Jetzt hab ich nur noch 11% CPU mit 
allem.

Würde mcih aber trotzdem interessieren wie man sowas machen könnte?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Problem0815 schrieb:

> Nachdem die Threads erstellt und aufgerufen wurden geht meine main
> selber in eine while(1);

Sowas tut man nicht, wenn man den Processor nicht für sich allein hat 
;-)

> Wie lege ich denn die main() am besten auf Eis? Mit einem sehr langen
> sleep(10000)? Oder gibt es einen extra Befehl für so etwas?

Ja, zum Beispiel mit

  while (1) sleep (100000);

oder Du überwachst in der main-Funktion den Status der Threads 
(Watchdog) - was-weiss-ich.

Frage: Müssen es wirklich Threads sein? Interagieren die Threads 
irgendwie miteinander? Oder warum hast Du die Teilaufgaben nicht einfach 
als Sub-Prozesse gestartet, um dann als Mutter nach erfolgreichem 
Erzeugen der Kinder einfach in Frieden zu sterben?

: Bearbeitet durch Moderator
von Problem0815 (Gast)


Lesenswert?

Ja tun sie.

1.
Der eine wenn knopf gedrückt wurde andere Threads anhalten die auf die 
SD schreiben wollen und SD unmounten. Wenn dann wieder Knopf gedrückt SD 
mounten und Threads weiterlaufen lassen.
2.
Pin abfrage bzw. Interrupt mit epoll() wenn der Pin auf 0 geht dann 
Daten über SPI senden/empfangen auf SD schreiben.
3.
UMTS Verbindung aufbauen, Daten runterladen, überprüfen entpacken 
einlesen. Noch mehr Daten runterladen, überprüfen (wenn gültig Thread 4 
freigeben). Dann Daten packen (die Thread 2 geschriben hat) und 
hochladen. UMTS aus. Warten eine bestimmte Zeit.
4.
Daten waren gültig, Pin toggeln und über SPI rausschicken, Pin toggeln. 
Warten bis Thread 3 erneut freigibt.
5. bzw. die main()
Watchdog füttern.

Und da die Threads (zumindest 1,2,3,4) synchronisiert werden müssen hab 
ich es mit Threads gelöst.

Habe aber ein anderes Problem nun. Nummer 2 belastet das System ganz 
gewaltig. Weil ich Angst habe, das ich die Flanke verpasse Frage ich 
andauernd den Wert des Pins ab. Das scheint aber etwas zu viel des 
guten...
1
void *
2
state_get_Mess_Data (void * Give_Thread_Struct)
3
{
4
  Thread * Thread_Struct = (Thread *) Give_Thread_Struct;
5
  Config * Config_PTR = Thread_Struct->Config_PTR;
6
  SPI_Par * SPI_Param = Thread_Struct->SPI_Param;
7
  int_fast8_t ret;
8
  while (1)
9
    {
10
      ret = get_interrupt_gpio_fast ("/sys/class/gpio/gpio27/value", 10,
11
             EPOLLET);
12
      while (!((ret == 2)
13
    && (get_value_gpio_fast ("/sys/class/gpio/gpio27/value") == 0))
14
    || (ret == 0))
15
  {
16
    // printf ("Waiting for DSP ready!\n");
17
  }
18
      while (pthread_mutex_lock (&SPI_in_use_mutex))
19
  ;
20
      while (get_Mess_Data_SPI (SPI_Param, Config_PTR, &rx_to_ASCII_int) < 0)
21
  ;
22
      while (pthread_mutex_unlock (&SPI_in_use_mutex))
23
  ;
24
    }
25
  return (NULL);
26
}

Wie könnte man sowas verbessern?
Die Funktionen get_value_gpio und get_interrupt_gpio sehen so aus:
1
int_fast8_t
2
get_value_gpio_fast (char const * const Target2) //Alternativ get_interrupt_gpio() verwenden wenn auf Flanken getriggert werden kann und der Wert nicht interessiert! Wegen userspace langsam!! Wenn schneller benötigt muss ein Treiber geschrieben werden oder direkt von Adressen gelesen werden  mit mmap()!
3
{
4
  FILE* TMP2 = NULL;
5
  int_fast8_t ret = 0;
6
  int val = 0;
7
  TMP2 = fopen (Target2, "r");
8
  if (TMP2)
9
    {
10
      ret = fscanf (TMP2, "%i", &val);
11
      fclose (TMP2);
12
      if (!ret)
13
  {
14
    printf ("Cant read correct value!");
15
    TMP2 = NULL;
16
    return (-2);
17
  }
18
      TMP2 = NULL;
19
      return ((int_fast8_t) val);
20
    }
21
  printf ("Cant get value File doesnt exist!");
22
  return (-1);
23
}
1
int_fast8_t
2
get_interrupt_gpio_fast (char const * const Target2, int timeout,
3
       uint32_t trigger_event) //Achtung blocking!! Also extra thread oder process! //TODO Falls der Interrupt schneller bereit sein muss Pfad mit GPIO direkt übergeben also ohne allokieren usw..
4
{
5
  int_fast8_t ret = 0;
6
  int val = 0;
7
  int pin = open (Target2, O_RDWR | O_NONBLOCK);
8
  if (pin > 0)
9
    {
10
      int epollins = epoll_create1 (0);
11
      if (epollins >= 0)
12
  {
13
    struct epoll_event ev;
14
    struct epoll_event events;
15
    ev.events = trigger_event;
16
    ev.data.fd = pin;
17
    ret = epoll_ctl (epollins, EPOLL_CTL_ADD, pin, &ev);
18
    if (!ret)
19
      {
20
        ret = (int_fast8_t) read (pin, NULL, 1);
21
        ret = epoll_wait (epollins, &events, 1, timeout);
22
        if (ret > 0)
23
    {
24
      ret = (int_fast8_t) lseek (pin, 0, SEEK_SET);
25
      if (ret >= 0)
26
        {
27
          ret = (int_fast8_t) read (pin, &val, 1);
28
          if (ret)
29
      {
30
        close (pin);
31
        close (epollins);
32
        if (val == 49)
33
          return (1);
34
        else
35
          return (0);
36
      }
37
          printf ("Cant read correct value!\n");
38
          close (epollins);
39
          close (pin);
40
          return (-5);
41
        }
42
      printf ("Error @ lseek!\n");
43
      close (epollins);
44
      close (pin);
45
      return (-4);
46
    }
47
        else if (ret == 0)
48
    {
49
      printf ("Timeout!\n");
50
      close (epollins);
51
      close (pin);
52
      return (2);
53
    }
54
        printf ("Error @ epoll_wait! %i\n", errno);
55
        close (pin);
56
        close (epollins);
57
        return (-3);
58
      }
59
    printf ("Error @ epoll_ctl! %i\n", errno);
60
    close (epollins);
61
    close (pin);
62
    return (-2);
63
  }
64
      printf ("Error @ epoll_create! %i\n", errno);
65
      close (pin);
66
      return (-6);
67
    }
68
  printf ("No PIN for Interrupt!\n");
69
  return (-1);
70
}

von Problem0815 (Gast)


Lesenswert?

Hm,

ist wvdial nicht Thread sicher?

Wenn ich es in keinem extra Thread laufen lasse geht es.
Wenn ich es in einem extra Thread über vfork() und dann execl() starte 
ist irgendwann mein UMTS Modem also /dev/ttyUSB3 geblockt. Also wvdial 
kann es nicht mehr öffnen weil es busy sein soll. Ist es aber eigentlich 
nicht.

Und jetzt hängt es in einer Endlos schleife..


Ich starte halt wvdial warte dann 20 sekunden überprüfe dann mit einem 
ping ob google erreichbar ist. Wenn nicht wird system("killall wvdial") 
aufgerufen und dann nach 20 sekunden wieder erneut gestartet wie oben 
beschrieben.

Wenn ping erfolgreich macht er weiter.

von Problem0815 (Gast)


Lesenswert?

Also auch wenn es kein extra Thread ist mache ich die abfolge so (vfork 
usw. da mir ja wvdial sonst für immer alles blockt) und es Funktioniert.

Oder aber irgendwas wird mit den fd gemacht bei multiplen Threads. Aber 
ich hoffe mal das es so passt..

von Problem0815 (Gast)


Lesenswert?

Hm, da passt mehreres noch nicht. Alles einzeln geht.
Aber wenn in mehreren Threads gibts durcheinander.

Speziell mit den fd.

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.