C: fifo lesen
- schorsch_76
- Beiträge: 2543
- Registriert: 06.11.2007 16:00:42
- Lizenz eigener Beiträge: MIT Lizenz
Re: C: fifo lesen
Deshalb mach ich solche asyncronen Serverprogramme mit select/poll/epoll/kqueue. Der Signalhandler wird gesetzt und macht mit den Self Pipe Trick [1] das Signal für die select Schleife verfügbar ohne den Prozess abzubrechen. Die Daten die aus dem Request kommen werden in einen Puffer oder in einen Requestparser geschubst und dann verarbeitet. Der Request Parser gibt dann bsp. einen enum von "more_info_needed,done" zurück. In einer Membervariable des Requests ist dann der geparste Request zu finden. Da die Zeichen einzeln in den Parser geschubst werden oder per buffer, sizeofbuffer und der Rückgabewert die benutzen Bytes sind, funktioniert das. Falls weniger Bytes genutzt werden als reingegeben, behandle ich den request und gib dann die anderen Bytes wieder in den Parser.
Damit hat man dann ein sauberes Handling der Signale und Requests und einen sauberen Shutdown ohne SIGSEV
[1] https://lwn.net/Articles/177897/
Damit hat man dann ein sauberes Handling der Signale und Requests und einen sauberen Shutdown ohne SIGSEV
[1] https://lwn.net/Articles/177897/
Re: C: fifo lesen
Was meinst du mit ``FIFO aufraeumen''? Das Einzige was nicht gemacht wird, ist doch ``fclose(fp)'', was sich aber eruebrigt, wenn sich das Programm beendet, weil dann automatisch alle FDs geschlossen werden und aller Speicher freigegeben wird. Ich verstehe nicht was da nicht aufgeraeumt bleiben koennte.schorsch_76 hat geschrieben:21.08.2018 08:30:09fgets blockt im read System call. SIGINT, SIGTERM. Hier ist die Default Aktion "Terminate the process". Damit wird der Fifo nicht mehr aufgeräumt und der Handle des Rootwindow. Falls man auf select verzichten will, muss man Signal Handler setzen. Hier sind auch nur eine Hand voll System calls erlaubt (im Handler). Man müsste ein volatile oder atomic flag setzen welches in der Loop abgefragt wird und dann beenden.Meillo hat geschrieben:Gibt es Gruende, warum man das nicht so machen, sondern sich low-level mit select(2) und read(2) plagen sollte?
Beim X-Window-Handle fehlt mir das Fach-Know-How. Beibt da etwas ueber das Programmende hinaus noch reserviert?
Sicher?Lass den Sender in den Fifo mal mehr Daten als BUFSIZE reinschreiben. Dann hat der Buffer kein Ende Zeichen. Du setzt dann kein \0 mehr. strlen() geht über das ende des buffer hinaus und es ist gut möglich das es einen SIGSEV gibt. Falls nicht, gibt's du das dann trotzdem an XStoreName() weiter. XStoreName() weis nichts von deiner Buffergröße....
Du gehtst auch davon aus, dass die Daten atomar rein kommen. Durch verschiedene Faktoren kann der call aber auch die Daten nicht "in einem Rutsch" rüber geben und du hast kein Endezeichen in deinem String. Gleiches Problem wie oben beschrieben.
Es ist garantiert, dass der von fgets(3) gelesene String immer Null-terminiert ist.Manpage fgets(3) hat geschrieben: fgets() reads in at most one less than size characters
from stream and stores them into the buffer pointed to by
s. Reading stops after an EOF or a newline. If a new‐
line is read, it is stored into the buffer. A terminat‐
ing null byte ('\0') is stored after the last character
in the buffer.
Falls mehr reingeschrieben wird als fgets(3) auf einmal liest, dann verarbeitet es die Eingabe eben haeppchenweise. Das habe ich eben getestet.
Ich hab's genau so getestet. Mein Programm hat alle Zeilen in der FIFO gelesen, eine nach der anderen. Natuerlich werden die sofort nacheinander gelesen und so schnell angezeigt, dass man nur die letzte im Rootwindow-Title sieht. Aber das hat ja nichts mit dem Verarbeiten der FIFO selbst zu tun.Durch Scheduling kann es aber auch vorkommen, dass du länger schläfst als die Sender. Es stehen 2 Requests in dem Fifo. Du erkennst aber im Höchstfall nur einen Request. Zum testen, starte das Program, CTRL+Z. Sende mehrere Requests und dann in der Shell mit dem Suspend Programm... fg.
Vielleicht mal grundsaetzlich: Es waere schon sehr un-unixmaessig, wenn man FIFOs nicht wie regulaere Dateien lesen koennte. Darum geht's schliesslich in Unix immer: Everything's a file! Keine Sonderbehandlungen fuer spezielle Dateitypen. Das war ein Grunddesignziel von Unix.
FIFOs sind auch alt genug, dass diese Ziele noch umgesetzt sind. (Sockets sind die grosse Ausnahme. Das Warum wird klar, wenn man ihre Entstehung betrachtet: Sie wurden von Personen implementiert, die Unix nicht verstanden hatten. Dass man Sockets auch nach Unix-Art implementieren kann demonstriert Plan 9 ... da waren es dann auch wieder die Unix-Entwickler selbst, die sie implementiert haben.)
Und weiter: Wenn man FIFOs nicht wie regulaere Dateien lesen koennte, dann koennte auch sed(1) beispielsweise keine FIFOs lesen ... ausser es haette Sondercode zum Umgang mit ihnen ... oder man wuerde in sed(1) alles IO auf Systemcall-Ebene durchfuehren, was den ganzen Sinn von stdio zunichte machen wuerde. Wer wuerde denn stdio verwenden, wenn er damit nur regulaere Dateien lesen koennte? Und was ist eigentlich mit Terminals? Die sind schliesslich auch keine regulaeren Dateien sondern Devices. Devices kann man mit stdio problemlos lesen. Sind FIFOs eher wie Devices oder eher wie regulaere Dateien? ...
Das Lesen von FIFOs darf (in Unix!) letzlich gar nicht anders sein als das Lesen regulaerer Dateien. Und wenn das stimmt, wer arbeitet dann freiwillig auf Systemcall-Ebene wenn er stdio nutzen kann?
Use ed once in a while!
- schorsch_76
- Beiträge: 2543
- Registriert: 06.11.2007 16:00:42
- Lizenz eigener Beiträge: MIT Lizenz
Re: C: fifo lesen
fgets(3) liest bis zur Puffergroesse oder bis zum ersten Newline, was immer frueher kommt.schorsch_76 hat geschrieben:21.08.2018 10:33:08fgets kann aber nur die angegebene Puffergröße lesen.
Dann liest fgets(3) sooft es ganze BUFSIZ-Stuecke lesen kann und verarbeitet die. Wenn noch ein Stueck in der FIFO steckt, das weder ein Newline enthaelt noch BUFSIZ gross ist, bleibt das stehen bis irgendwann ein Newline in die FIFO geschrieben wird oder BUFSIZ voll wird. (Es ist folglich notwendig, dass ganze Textzeilen, also mit abschliessendem Newline in die FIFO geschrieben werden.)Was passiert wenn du BUFSIZE+x Bytes (ohne 0 oder \n) in den FIFO schreibst?
Probier's einfach aus! Mach ein printf(3) des Gelesenen in meine Schleife und verwende eine kleine Puffergroesse. Dann kannst du all die Faelle durchspielen.
fgets(3) terminiert seinen String immer!
Use ed once in a while!
- schorsch_76
- Beiträge: 2543
- Registriert: 06.11.2007 16:00:42
- Lizenz eigener Beiträge: MIT Lizenz
Re: C: fifo lesen
@meillo: Ich wird es heut abend mal ausprobieren
Zum x window Handle: Da würde ich schon schauen das ich das auf jeden Fall schließen. Die zugrunde liegende IPC zwischen dir und dem XServer hängt (so wie ich das verstehe) dazwischen. Da X eine riesige Codebase ist, würde ich mich als Programmierer schon möglichst daran halten alle Resourcen wieder zurück zu geben, da ich nicht 100% sagen kann was dort passiert (oder auch nicht passiert, falls ich es nicht mache).
Im Zweifel könnten dem xorg Prozess die File Descriptoren ausgehen.
https://www.x.org/archive/X11R7.5/doc/m ... lay.3.html
Zum x window Handle: Da würde ich schon schauen das ich das auf jeden Fall schließen. Die zugrunde liegende IPC zwischen dir und dem XServer hängt (so wie ich das verstehe) dazwischen. Da X eine riesige Codebase ist, würde ich mich als Programmierer schon möglichst daran halten alle Resourcen wieder zurück zu geben, da ich nicht 100% sagen kann was dort passiert (oder auch nicht passiert, falls ich es nicht mache).
Im Zweifel könnten dem xorg Prozess die File Descriptoren ausgehen.
https://www.x.org/archive/X11R7.5/doc/m ... lay.3.html
The XCloseDisplay function closes the connection to the X server for the display specified in the Display structure and destroys all windows, resource IDs (Window, Font, Pixmap, Colormap, Cursor, and GContext), or other resources that the client has created on this display, unless the close-down mode of the resource has been changed (see XSetCloseDownMode). Therefore, these windows, resource IDs, and other resources should never be referenced again or an error will be generated. Before exiting, you should call XCloseDisplay explicitly so that any pending errors are reported as XCloseDisplay performs a final XSync operation.
XCloseDisplay can generate a BadGC error.
- schorsch_76
- Beiträge: 2543
- Registriert: 06.11.2007 16:00:42
- Lizenz eigener Beiträge: MIT Lizenz
Re: C: fifo lesen
So, das erste was ich direkt nach dem compilieren bekomme....
fifo konnte nicht geöffnet werden, da er noch nicht existiert. Das sollte durch dieses Programm erledigt werden Auch wird nicht geprüft ob der fifo geöffnet wurde. Nachdem ich den Pfad angepasst und den Fifo erstellt habe, hab ich mal die Funktion getestet.
Mit einem Programm hab ich das dann mal für 3h durchgetestet und es hat keinen Crash gegeben (nur wenn der Fifo nicht da ist).
SendRnd (da nopaste kaputt ist gerade)
Code: Alles auswählen
georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ gcc set-title.c -lX11 -o set-title
georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ ./set-title
Speicherzugriffsfehler
georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ gcc set-title.c -O0 -g -lX11 -o set-title
georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ ./set-title
Speicherzugriffsfehler
georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ gdb ./set-title
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./set-title...done.
(gdb) start
Temporary breakpoint 1 at 0xb4b: file set-title.c, line 16.
Starting program: /home/georg/Dokumente/Entwicklung/misc/DfDeX11/set-title
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Temporary breakpoint 1, main () at set-title.c:16
16 char *display_name = NULL;
(gdb) c
Continuing.
Program received signal SIGSEGV, Segmentation fault.
_IO_fgets (buf=0x7fffffffbfa0 "", n=8192, fp=0x0) at iofgets.c:47
47 iofgets.c: Datei oder Verzeichnis nicht gefunden.
(gdb) bt
#0 _IO_fgets (buf=0x7fffffffbfa0 "", n=8192, fp=0x0) at iofgets.c:47
#1 0x0000555555554c92 in main () at set-title.c:29
(gdb) l
42 in iofgets.c
(gdb) ls
Undefined command: "ls". Try "help".
(gdb) bt
#0 _IO_fgets (buf=0x7fffffffbfa0 "", n=8192, fp=0x0) at iofgets.c:47
#1 0x0000555555554c92 in main () at set-title.c:29
(gdb) f 1
#1 0x0000555555554c92 in main () at set-title.c:29
29 while (fgets(name, BUFSIZ, fp)) {
Mit einem Programm hab ich das dann mal für 3h durchgetestet und es hat keinen Crash gegeben (nur wenn der Fifo nicht da ist).
SendRnd (da nopaste kaputt ist gerade)
Code: Alles auswählen
g++ --std=c++14 SendRnd.cpp -l boost_program_options -o sendrnd
./sendrnd --of /home/georg/fifo --alphabet=random --runs=1000000 --min_length=1000 --max_length=1280000
#include <array>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
enum class alphabet_t
{
alpha,
alnum,
print,
rnd
};
int run(std::ostream &os, const alphabet_t alphabet, const int min_length,
const int max_length, const int runs)
{
// clang-format off
// - 1 because 0 based array index
std::uniform_int_distribution<> dis_alpha (0, 2 * 26 - 1);
std::uniform_int_distribution<> dis_alnum (0, 2 * 26 + 10 - 1);
std::uniform_int_distribution<> dis_print (0, 95 - 1);
std::uniform_int_distribution<> dis_rnd (0, 256 - 1);
std::array<char, 95> int2char =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
'W', 'X', 'Y', 'Z', '0', '1', '2', '3',
'4', '5', '6', '7', '8', '9', '!', '"',
'#', '$', '%', '&', '(', ')', '*', '+',
',', '-', '.', '/', ':', ';', '<', '=',
'>', '?', '@', '[', '\\', ']', '^', '_',
'`', '{', '|', '}', '~', '\'', ' '
};
// clang-format on
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<> dis_length(min_length, max_length);
for (int i = 0; i < runs; ++i)
{
const int len = dis_length(gen);
std::string buffer;
buffer.reserve(len);
for (int l = 0; l < len; ++l)
{
switch (alphabet)
{
default:
case alphabet_t::alpha:
buffer += int2char[dis_alpha(gen)];
break;
case alphabet_t::alnum:
buffer += int2char[dis_alnum(gen)];
break;
case alphabet_t::print:
buffer += int2char[dis_print(gen)];
break;
case alphabet_t::rnd:
buffer += char(dis_rnd(gen));
break;
}
}
// write out buffer and the expected \n\0 ending
os.write(buffer.data(), buffer.size());
os.write("\n", 1);
}
return EXIT_SUCCESS;
}
int main(int argc, char *argv[])
{
try
{
po::options_description desc("SendRnd options");
// clang-format off
desc.add_options()
("help", "produce help message")
("alphabet", po::value< std::string >(), "alpha (default)|alnum|print|random (may contain additional newlines and zeros)")
("min_length", po::value< int >(), "minimum length between newline (Default 128k)")
("max_length", po::value< int >(), "maximum length between newline (Default 1024k)")
("runs", po::value< int >(), "number of runs")
("of", po::value< std::string >(), "output file (use - for stdout = default)")
;
// clang-format on
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help"))
{
std::cout << desc << "\n";
return EXIT_FAILURE;
}
// this values are now needed
alphabet_t alphabeth = alphabet_t::alpha;
if (vm.count("alphabet"))
{
std::string value = vm["alphabet"].as<std::string>();
if (value == "alpha" || value == "default")
{
alphabeth = alphabet_t::alpha;
}
else if (value == "alnum")
{
alphabeth = alphabet_t::alnum;
}
else if (value == "print")
{
alphabeth = alphabet_t::print;
}
else if (value == "random")
{
alphabeth = alphabet_t::rnd;
}
else
{
std::cerr << "Invalid alphabet mode" << std::endl;
return EXIT_FAILURE;
}
}
// length of the output
int min_length = 128 * 1024;
if (vm.count("min_length"))
{
min_length = vm["min_length"].as<int>();
if (min_length < 1)
{
std::cerr << "min_length must be >=1" << std::endl;
return EXIT_FAILURE;
}
}
int max_length = 1024 * 1024;
if (vm.count("max_length"))
{
max_length = vm["max_length"].as<int>();
if (max_length < 1)
{
std::cerr << "max_length must be >=1" << std::endl;
return EXIT_FAILURE;
}
}
if (max_length < min_length)
{
std::cerr << "min_length must be smaller or equal than max_length"
<< std::endl;
return EXIT_FAILURE;
}
if (min_length < 1)
{
std::cerr << "min_length must >= 1" << std::endl;
return EXIT_FAILURE;
}
if (max_length < 1)
{
std::cerr << "max_length must >= 1" << std::endl;
return EXIT_FAILURE;
}
// runs
int runs = -1;
if (!vm.count("runs"))
{
std::cout << desc << "\n";
return EXIT_FAILURE;
}
else
{
runs = vm["runs"].as<int>();
}
if (runs < 1)
{
std::cerr << "runs must be >= 1" << std::endl;
return EXIT_FAILURE;
}
// out
std::string fname = "-";
if (vm.count("of"))
{
fname = vm["of"].as<std::string>();
}
if (fname != "-")
{
std::ofstream ofs(fname.c_str(), std::ios_base::binary);
if (!ofs.is_open())
{
std::cerr << "Could not open output file: " << fname
<< std::endl;
return EXIT_FAILURE;
}
return run(ofs, alphabeth, min_length, max_length, runs);
}
else
{
return run(std::cout, alphabeth, min_length, max_length, runs);
}
}
catch (const std::exception &ex)
{
std::cerr << ex.what() << std::endl;
}
return EXIT_FAILURE;
}
Re: C: fifo lesen
Da hast du ganz recht. Da wurde schlampig gearbeitet ... schon im Originalprogramm ... ich hab's dann allerdings auch nicht besser gemacht ... war ganz auf Syscalls vs. Stdio fixiert ... hab ja noch nicht mal das ``BUFSIZ'' im fgets()-Aufruf durch ``sizeof(name)'' ersetzt, was man unbedingt tun sollte!schorsch_76 hat geschrieben:21.08.2018 20:45:32So, das erste was ich direkt nach dem compilieren bekomme....fifo konnte nicht geöffnet werden, da er noch nicht existiert. Das sollte durch dieses Programm erledigt werden Auch wird nicht geprüft ob der fifo geöffnet wurde. Nachdem ich den Pfad angepasst und den Fifo erstellt habe, hab ich mal die Funktion getestet.Code: Alles auswählen
georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ gcc set-title.c -lX11 -o set-title georg@M4700:~/Dokumente/Entwicklung/misc/DfDeX11$ ./set-title Speicherzugriffsfehler [...]
Lass uns diese Korrekturen und Verbesserungen in einem naechsten Schritt machen! Heute nicht mehr, aber ich liefere gerne noch eine Verbesserung meiner Version. Ihr koennt gerne solange schonmal damit anfangen.
Coole Sache ... deine Testreihe!Mit einem Programm hab ich das dann mal für 3h durchgetestet und es hat keinen Crash gegeben (nur wenn der Fifo nicht da ist).
Jetzt waere gut, wenn noch jemand mit Erfahrung und Wissen bestaetigen koennte, dass man FIFOs sehr wohl mit Stdio lesen und schreiben kann. Denn wenn Zufallseingaben kein Fehler erzeugen, heisst das ja noch nicht zwangslaeufig, dass der Code korrekt ist.
Bislang stehe ich noch alleine da, mit der Aussage, dass man auch FIFOs mit Stdio lesen und schreiben sollte -- kann und sollte! Ein paar mehr Wortmeldungen dazu wuerden gut tun.
Use ed once in a while!
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Ui, hier war ja heute richtig viel los!
Vielen Dank für euren input und eure Mühe. Ich verstehe noch nicht alles, aber versuche mal, auf ein paar Dinge einzugehen:
Der entscheidende Unterschied zwischen Deinem Code und meinem früheren Code, der nicht funktioniert, ist - wenn ich das richtig verstehe -, dass auch hier die fifo rw geöffnet wird, richtig?
Ich könnte das zum Einen mit dem aufrufenden Parent-Wrapper-Script lösen, welches im Moment so aussieht:
Wie ihr seht, prüfe ich meine fifos in diesem Wrapper-Script. Wenn die fifo für das hier diskutierte Programm, also /tmp/dwmblocks_fifo_intern (die fifo in $HOME ist nur zum Testen) nicht da ist, wird gar nichts gestartet. Dann braucht man ja auch keine Überprüfung am Anfang des Programmes, oder? Wobei, schaden kanns nicht... Was man tatsächlich prüfen müsste, ist, ob die fifo geöffnet wurde. Habe ich mal versucht - s. u.
Statt kill könnte ich hier einen spezifischen kill-string nutzen. Nachteil: Bei jedem Durchlauf muss der string, der von der fifo erhalten wurde, auf diesen spezifischen string überprüft werden. Nicht so elegant...
@schorch_76 hat jetzt dafür eine Lösung vorgestellt, aber ich verstehe leider nicht, wie das jetzt genau ablaufen soll. Könnte man nicht einfach eine Funktion implementieren, die ausgeführt wird, wenn das Programm ein bestimmtes Signal erhält?
Wobei: Was ist mit
Was auf jeden Fall ein Problem sein könnte, ist, dass die Verbindung zu X nicht richtig geschlossen wird. Deswegen könnte man dann vielleicht doch das Schließen des Programmes genau definieren, statt es einfach abzukillen?
BTW: Das mit "printf("EOF\\n");" habe ich aus @bluestars Link. Ich werde das nochmal nachschauen...
Mein Programm mit sizeof und open-check:
Vielen Dank für euren input und eure Mühe. Ich verstehe noch nicht alles, aber versuche mal, auf ein paar Dinge einzugehen:
Also ich tendierte zu low-level, weil ich mir dachte, dass das schneller ist und keine Nachteile hat. Mir schien das irgendwie mehr "Unix" und "suckless" zu sein, low-level zu bevorzugen. Aber Dein Code ist natürlich einfacher zu lesen.Meillo hat geschrieben:20.08.2018 23:55:15Gibt es Gruende, warum man das nicht so machen, sondern sich low-level mit select(2) und read(2) plagen sollte?
Der entscheidende Unterschied zwischen Deinem Code und meinem früheren Code, der nicht funktioniert, ist - wenn ich das richtig verstehe -, dass auch hier die fifo rw geöffnet wird, richtig?
Das stimmt, das ist doof.Meillo hat geschrieben:20.08.2018 23:55:15Auch in deiner Variante gibt es keinen erfolgreichen Exit. Jeder Exit im Code muss von einem Fehler verursacht sein.
Ich könnte das zum Einen mit dem aufrufenden Parent-Wrapper-Script lösen, welches im Moment so aussieht:
Code: Alles auswählen
#!/bin/sh
if [ -e /tmp/dwmblocks_fifo_intern ]; then
if [ ! -p /tmp/dwmblocks_fifo_intern ]; then
echo "Error: file /tmp/dwmblocks_fifo_intern exists, but is not my fifo. Please check!"
exit 1
fi
else
mkfifo /tmp/dwmblocks_fifo_intern
fi
/opt/scripts/bin/myxd &
myxd_pid=$!
while true; do
if [ -e /tmp/dwmblocks ]; then
if [ ! -p /tmp/dwmblocks ]; then
echo "Error: file /tmp/dwmblocks exists, but is not my fifo. Please check!"
exit 1
fi
else
mkfifo /tmp/dwmblocks
fi
/opt/scripts/barp.sh
done
kill $!
Statt kill könnte ich hier einen spezifischen kill-string nutzen. Nachteil: Bei jedem Durchlauf muss der string, der von der fifo erhalten wurde, auf diesen spezifischen string überprüft werden. Nicht so elegant...
@schorch_76 hat jetzt dafür eine Lösung vorgestellt, aber ich verstehe leider nicht, wie das jetzt genau ablaufen soll. Könnte man nicht einfach eine Funktion implementieren, die ausgeführt wird, wenn das Programm ein bestimmtes Signal erhält?
Wobei: Was ist mit
?Meillo hat geschrieben:21.08.2018 09:45:35Das Einzige was nicht gemacht wird, ist doch ``fclose(fp)'', was sich aber eruebrigt, wenn sich das Programm beendet, weil dann automatisch alle FDs geschlossen werden und aller Speicher freigegeben wird. Ich verstehe nicht was da nicht aufgeraeumt bleiben koennte.
Was auf jeden Fall ein Problem sein könnte, ist, dass die Verbindung zu X nicht richtig geschlossen wird. Deswegen könnte man dann vielleicht doch das Schließen des Programmes genau definieren, statt es einfach abzukillen?
Was genau meinst Du? Ich setze den Name des Root-Windows, dann bereite ich den nächsten Event vor. Es kann ja nicht sein, dass jedes Mal die Verbindung zu X geöffnet, geprüft und geschlossen werden muss. Das machen ja auch Window-Manager nicht...schorsch_76 hat geschrieben:21.08.2018 11:50:23Zum x window Handle: Da würde ich schon schauen das ich das auf jeden Fall schließen. Die zugrunde liegende IPC zwischen dir und dem XServer hängt (so wie ich das verstehe) dazwischen.
BTW: Das mit "printf("EOF\\n");" habe ich aus @bluestars Link. Ich werde das nochmal nachschauen...
Mein Programm mit sizeof und open-check:
Code: Alles auswählen
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
static const char program_name[] = "myxd";
static Display *dpy;
static int screen;
static Window root;
static XEvent ev;
int
main(void)
{
char *display_name = NULL;
char name[BUFSIZ+1];
int fd;
dpy = XOpenDisplay(display_name);
if (!dpy) {
fprintf(stderr, "%s: unable to open display '%s'\n",
program_name, XDisplayName (display_name));
exit(2);
}
root = RootWindow(dpy, screen);
/* fd = open("/tmp/dwmblocks_fifo_intern", O_RDWR | O_NONBLOCK); */
fd = open("/home/user/fifo", O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(1);
}
fd_set rfds;
int rc;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
for (;;) {
rc = select(fd + 1, &rfds, NULL, NULL, NULL);
if (rc > 0) {
memset (name, 0, sizeof(name));
ssize_t got = read(fd, name, sizeof(name));
if (got < 0) {
perror("read");
break;
} else if (got == 0) {
printf("EOF\\n");
break;
}
else {
/* remove trailing newline */
if (name[strlen(name)-1] == '\n')
name[strlen(name)-1] = '\0';
XStoreName(dpy, root, name);
while (XPending(dpy))
XNextEvent(dpy, &ev);
}
}
}
close(fd);
XCloseDisplay(dpy);
exit(1);
}
Re: C: fifo lesen
Erschreckend, was fuer ein verzerrtes Verstaendnis von Unix und Suckless da angekommen ist.RobertDebiannutzer hat geschrieben:21.08.2018 22:28:20Also ich tendierte zu low-level, weil ich mir dachte, dass das schneller ist und keine Nachteile hat. Mir schien das irgendwie mehr "Unix" und "suckless" zu sein, low-level zu bevorzugen. Aber Dein Code ist natürlich einfacher zu lesen.Meillo hat geschrieben:20.08.2018 23:55:15Gibt es Gruende, warum man das nicht so machen, sondern sich low-level mit select(2) und read(2) plagen sollte?
Gute Lesbarkeit von Code ist eines der wichtigen Ziele von Unix und Suckless (... halt unter Erwartung eines hohen Kenntnisstandes beim Code-Leser).
Low-Level-Code ist mehr Code, was klar dem Ziel von Suckless entgegen steht, die ja besonders explizit nach moeglichst wenig Code streben.
Low-Level-Code besteht zu grossem Teil aus Fehlerbehandlung, was der Lesbarkeit schadet.
Low-Level-Code ist fehleranfaelliger.
Im Zeitalter optimierender Compiler und optimierter Libraries ist es gar nicht unwahrscheinlich, dass eigener Low-Level-Code langsamer ist als wenn man Standardbibliotheken nutzt.
Das ganze Thema ist letztlich schon komplexer und hat viele Zusammenhaenge und Abwaegungen, aber als Faustregel kannst du nehmen: Wenn es weniger Code ist und einfacher zu lesen, dann ist es besser.
Wenn du mehr darueber lernen willst, wie man guten Code schreibt, dann lies ``The Practice of Programming'' von Kernighan und Pike.
Use ed once in a while!
- schorsch_76
- Beiträge: 2543
- Registriert: 06.11.2007 16:00:42
- Lizenz eigener Beiträge: MIT Lizenz
Re: C: fifo lesen
Dein XOpenDisplay baut eine Verbindung zum X window Manager auf. Hier wird eine Form von IPC verwendet. Da ich nicht weis wie im XServer bzw Client das gehandhabt wird wenn ein offenes Display nicht geschlossen wird, würde ich auf jeden Fall dafür sorgen das beim beenden des Programms ein XCloseDisplay erfolgt.RobertDebiannutzer hat geschrieben: Was genau meinst Du? Ich setze den Name des Root-Windows, dann bereite ich den nächsten Event vor. Es kann ja nicht sein, dass jedes Mal die Verbindung zu X geöffnet, geprüft und geschlossen werden muss. Das machen ja auch Window-Manager nicht...
Jeder Prozess hat ein per ulimit gesetztes Limit was offene File Descriptoren angeht. Das sind, Sockets, Fifos etc pp. Wird das überschritten, verweigert der Kernel dem Prozess neue FD.
Zu Low Level: Ich schreibe auf mehr auf Low Level Ebene Code und halte mich da eben an den POSIX Standard. Hierfür habe ich eben das Buch "The Linux Programming Interface" gekauft. Da hab ich mir je nach Bedarf das ein oder andere Kapitel reingezogen.
@RobertDebiannutzer: Die select schleife ist so exakt wie sie sein soll
Zuletzt geändert von schorsch_76 am 22.08.2018 08:52:53, insgesamt 1-mal geändert.
Re: C: fifo lesen
Achtung an der Stelle read(fd,name,sizeof(name)) hast du wieder das Problem, dass du bis zum Ende des Puffers liest und somit dein \0 End-Of-String Marker flöten geht... Also bitte sizeof(name) - 1 als Anzahl nehmen oder auf auf die funktions fgets(...) ausweichen, da erledigt die Funktion das \0 Handling für dich.RobertDebiannutzer hat geschrieben:21.08.2018 22:28:20Code: Alles auswählen
... char name[BUFSIZ+1]; ... for (;;) { ... memset (name, 0, sizeof(name)); ssize_t got = read(fd, name, sizeof(name)); --- }
Das ist übrigens ein typisches Beispiel für die höhrere Fehleranfälligkeit bei der Low-Level Code Programmierung, im Low Level Bereich musst du dich um solch lästigen Kleinkrams kümmern.
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
@bluestar: Mist, schon wieder übersehen. Ich wusste doch, dass da noch was war... Danke!
Ich hatte das immer so verstanden:
- Code soll elegant sein: lesbar, aber auch effizient
- im Zweifelsfall zugunsten der Geschwindigkeit die etwas weniger lesbare Variante nehmen
- je mehr "low-level" der Code ist, desto definierter ist er
- je definierter der Code ist, desto besser ist er
Aber vielleicht habe ich mir da Falsches gedacht, weil ich bisher auf praktischer Ebene haupstächlich mit Shell-Scripten und Perl gearbeitet habe.
Mal ein einfaches Beispiel für mein Verständnis:
- Lesen einer Datei in einem dash-Script (wo also nicht $(< datei) zu Verfügung steht):
statt
Ist einfach schneller, vor allem im Vergleich zu sed:
Die drei Scripte mit dash-Shebang und "echo $dbm" am Schluss in bash ausgeführt (in der obigen Reihenfolge):
"Low-level" ist hier quasi die builtin-Ebene. Die ist einfach immer schneller, auch wenn die Parameter Substitutions nicht so einfach lesbar sind.
Perl finde ich auch elegant (für meine aktuellen Verwendung, also Scripte von 100-300 Zeilen Länge). Hier ist zwar die Startzeit etwas mehr, aber die Ausführungszeit schön kurz, da die Scripte vom Perl-Interpreter kompiliert werden. So habe ich das jedenfalls verstanden und gemessen.
Außerdem kann man Perl sehr lesbar schreiben - z.B. so ähnlich wie C.
Die Überprüfung des read-Rückgabewertes ist richtig:RobertDebiannutzer hat geschrieben:21.08.2018 22:28:20BTW: Das mit "printf("EOF\\n");" habe ich aus @bluestars Link. Ich werde das nochmal nachschauen...
man 2 read hat geschrieben: On success, the number of bytes read is returned (zero indicates end of file), [...].
On error, -1 is returned [...].
Alles klar, ich überlege, wie ich das machen kann.schorsch_76 hat geschrieben:22.08.2018 07:57:07würde ich auf jeden Fall dafür sorgen das beim beenden des Programms ein XCloseDisplay erfolgt.
Meillo hat geschrieben:22.08.2018 06:57:36Erschreckend, was fuer ein verzerrtes Verstaendnis von Unix und Suckless da angekommen ist.
Ich hatte das immer so verstanden:
- Code soll elegant sein: lesbar, aber auch effizient
- im Zweifelsfall zugunsten der Geschwindigkeit die etwas weniger lesbare Variante nehmen
- je mehr "low-level" der Code ist, desto definierter ist er
- je definierter der Code ist, desto besser ist er
Aber vielleicht habe ich mir da Falsches gedacht, weil ich bisher auf praktischer Ebene haupstächlich mit Shell-Scripten und Perl gearbeitet habe.
Mal ein einfaches Beispiel für mein Verständnis:
- Lesen einer Datei in einem dash-Script (wo also nicht $(< datei) zu Verfügung steht):
statt
Code: Alles auswählen
tmp_var=$(cat /proc/net/wireless)
dbm1="${tmp_var%.*}"
dbm="${dbm1##*-}"
Code: Alles auswählen
while read -r line; do
case $line in
"wlp2s0"*)
dbm1="${line#*-}";;
esac
done < /proc/net/wireless
dbm="${dbm1%.*}"
Code: Alles auswählen
dbm=$(sed -n 's/^wlp2s0[^-]*\-//;s/\..*//p' /proc/net/wireless)
Code: Alles auswählen
/opt/scripts$ time ./test1.sh
69
real 0m0,005s
user 0m0,000s
sys 0m0,000s
/opt/scripts$ time ./test2.sh
69
real 0m0,003s
user 0m0,000s
sys 0m0,000s
/opt/scripts$ time ./test3.sh
69
real 0m0,006s
user 0m0,000s
sys 0m0,000s
Perl finde ich auch elegant (für meine aktuellen Verwendung, also Scripte von 100-300 Zeilen Länge). Hier ist zwar die Startzeit etwas mehr, aber die Ausführungszeit schön kurz, da die Scripte vom Perl-Interpreter kompiliert werden. So habe ich das jedenfalls verstanden und gemessen.
Außerdem kann man Perl sehr lesbar schreiben - z.B. so ähnlich wie C.
Re: C: fifo lesen
Ja.RobertDebiannutzer hat geschrieben:22.08.2018 11:53:13Meillo hat geschrieben:22.08.2018 06:57:36Erschreckend, was fuer ein verzerrtes Verstaendnis von Unix und Suckless da angekommen ist.
Ich hatte das immer so verstanden:
- Code soll elegant sein: lesbar, aber auch effizient
Genau anders rum!- im Zweifelsfall zugunsten der Geschwindigkeit die etwas weniger lesbare Variante nehmen
Bei vierzig Jahre altem Code ist eine gute Lesbarkeit noch immer vorteilhaft, waehrend die Geschwindigkeitsoptimierungen von damals heute voellig irrelevant sind und sehr wahrscheinlich seine Protabilitaet negativ beeinflusst haben ... weswegen es ihn vermutlich gar nicht mehr gibt. Wenn er unlesbar (wenn auch blitzschnell) gewesen waere, dann haette man sich die Pflege irgendwann auch gespart und ihn von Grund auf neu geschrieben. Fuer diese Anzeichen muss man normalerweise keine vierzig Jahre warten, es zeigt sich bereits nach wenigen Jahren ...
Unix wurde 1973 (IIRC) von hauptsaechlich Assembler auf hauptsaechlich C portiert. Manche waren der Meinung, dass das fuer ein Betriebssystem viel zu ineffizient sei. Rueckblickend war es einer der wertvollsten Schritte in der Unix-Geschichte.
MH (ein Mailclient der mehr der Unix Philosphie entspricht als jeder andere) wurde 1978 (IIRC) als Prototyp entwickelt, entgegen allen Befuerchtungen, dass das viel zu langsam und damit unbenutzbar sei. In den 80er Jahren war er die Basis fuer die erste MIME-Implementierung in einem MUA. Noch heute lebt sein Code!
Und ueberhaupt, der ganze Fokus auf die Shell in Unix ist fuer die Performance-Optimierer eine Katastrophe, aber aus Produktivitaetssicht ist die Unix-Toolchest (also Menge der ganzen Kommandozeilenprogramme: cat, tr, cut, sort, uniq, ...) so ziemlich das Grossartigste was es gibt. Sie lebt noch immer, obwohl sie ja so furchtbar ineffizient ist.
Am besten du vergisst alle Gedanken an Geschwindigkeitsoptimierungen und optimierst nur noch auf Lesbarkeit. So uebervereinfacht das auch ist, ich bin mir sicher, dass das zu besserer Software fuehrt. (Meist ist der am besten verstaendliche Code sowieso schon eine sehr schnelle Umsetzung ... und wenn er es heute noch nicht ist, dann naechstes Jahr.)
Ken Thompson hat geschrieben: One of my most productive days was throwing away 1,000 lines of code.
Kurz ist meist gut. Kurz ist (wenn man es nicht uebertreibt) oft besser verstaendlich.Doug McIlroy hat geschrieben: The real hero of programming is the one who writes negative code.
Auf dem Cover von ``The Practice of Programming'' von Kernighan und Pike stehen die Worte:
- Simplicity
- Clarity
- Generality
Man darf die als die Kernziele beim Programmieren betrachten (in dieser Reihenfolge).
... das alles nur als ein paar Schlaglichter. Wenn du wirklich verstehen willst, dann musst du die Buecher von diesen Unix-Typen lesen. (Oder dir meine Vortraege anschauen. )
Zum Schluss noch der Hinweis auf diese, sehr bekannten Hinweise zum Programmieren in C: https://www.lysator.liu.se/c/pikestyle.html
Use ed once in a while!
- schorsch_76
- Beiträge: 2543
- Registriert: 06.11.2007 16:00:42
- Lizenz eigener Beiträge: MIT Lizenz
Re: C: fifo lesen
Das mit dem C Fifo das passt schon so. Du hast auf die Posix API Programmiert. Das läuft auf praktisch jedem OS. Selbst VxWorks, Qnx und allen anderen.
Mach dir da keinen zu großen Kopf! Du lernst! Da kommt nicht immer 100%iger Code raus der 100 Jahre halten muss. Das muss nur deinen Ansprüchen genügen!
Mach dir da keinen zu großen Kopf! Du lernst! Da kommt nicht immer 100%iger Code raus der 100 Jahre halten muss. Das muss nur deinen Ansprüchen genügen!
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Vielen Dank für euren philosophischen Input!
Der Absatz über Comments in Deinem Link, @meillo, hat mich an etwas erinnert, was ich dazu mal von Linus Torvalds gelesen habe:
Quelle: https://lkml.org/lkml/2016/7/8/625
Dann habe ich auf Deine Anregung noch gefunden: http://marmaro.de/docs/studium/unix-phil/unix-phil.pdf
Das meintest Du doch, oder? Werde ich mal reinlesen. (Das Schöne an IT ist, dass man nebenbei auch seine Englisch-Kenntnisse verbessern kann.)
Der Absatz über Comments in Deinem Link, @meillo, hat mich an etwas erinnert, was ich dazu mal von Linus Torvalds gelesen habe:
I'm not even going to start talking about the people who prefer to
"box in" their comments, and line up both ends and have fancy boxes of
stars around the whole thing. I'm sure that looks really nice if you
are out of your mind on LSD, and have nothing better to do than to
worry about the right alignment of the asterisks.
Quelle: https://lkml.org/lkml/2016/7/8/625
Dann habe ich auf Deine Anregung noch gefunden: http://marmaro.de/docs/studium/unix-phil/unix-phil.pdf
Das meintest Du doch, oder? Werde ich mal reinlesen. (Das Schöne an IT ist, dass man nebenbei auch seine Englisch-Kenntnisse verbessern kann.)
Das ist der Grund, weshalb ich lerne... (Schließlich ist Programmieren aktuell (noch?) "nur" ein Hobby von mir.)
Re: C: fifo lesen
... und das: http://marmaro.de/docs/chaosseminar/RobertDebiannutzer hat geschrieben:22.08.2018 13:44:13Dann habe ich auf Deine Anregung noch gefunden: http://marmaro.de/docs/studium/unix-phil/unix-phil.pdf
Das meintest Du doch, oder?
Und textuell noch das: http://marmaro.de/docs/master/schnalke-mmh.pdf ... falls du dir das geben willst.
Use ed once in a while!
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Oh, da hast Du ja ganz schön viel zu dem Thema verfasst.
Übrigens, die Videos in dem Link http://ulm.ccc.de/ChaosSeminar/2010/03_UnixPhil gibt's nicht mehr...
BTW - nochmal zu meinen shell-builtins: Damit kein falscher Eindruck entsteht, wollte ich nochmal erwähnen, dass die nur in bestimmten Fällen Performance-Vorteile bringen. Die Datei /proc/net/wireless z.B. ist drei Zeilen lang. Wenn ich jetzt aber z.B. die Namen aller Dateien in /usr/share/applications/ möchte, die "NoDisplay=true" beinhalten, lande ich mit builtins von der Performance her auf der Nase und nehme grep. Insofern sind die Unix-Tools im Allgemeinen schon auch von der Performance her zu bevorzugen, denn wenn sie auch bei kleinen Datenmengen ein klein wenig langsamer sein mögen, so sieht es bei größeren Datenmengen um Gößenordnungen anders aus.
Übrigens, die Videos in dem Link http://ulm.ccc.de/ChaosSeminar/2010/03_UnixPhil gibt's nicht mehr...
BTW - nochmal zu meinen shell-builtins: Damit kein falscher Eindruck entsteht, wollte ich nochmal erwähnen, dass die nur in bestimmten Fällen Performance-Vorteile bringen. Die Datei /proc/net/wireless z.B. ist drei Zeilen lang. Wenn ich jetzt aber z.B. die Namen aller Dateien in /usr/share/applications/ möchte, die "NoDisplay=true" beinhalten, lande ich mit builtins von der Performance her auf der Nase und nehme grep. Insofern sind die Unix-Tools im Allgemeinen schon auch von der Performance her zu bevorzugen, denn wenn sie auch bei kleinen Datenmengen ein klein wenig langsamer sein mögen, so sieht es bei größeren Datenmengen um Gößenordnungen anders aus.
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Uff, signal handling geschafft...
Erst wollte ich einfach zusätzlich noch auf stdin lauschen - mit select geht das ja. Doch nachdem ich das implementiert hatte, habe ich gemerkt und ist mir wieder eingefallen, dass man nicht nach stdin eines im Terminal laufenden Processes mittels "echo /proc/pid/fd/0" pipen kann, weil diese fds immer zu denen des jeweiligen /dev/pts umgeleitet sind...
Aber eigentlich scheint es mir so jetzt auch eleganter. Ich nutze sigaction und etabliere vor dem loop eine Aktion, die beim Empfangen von SIGTERM (also "kill -15 pid") ausgeführt wird. Diese Aktion ist einfach das Umschalten einer toggle-Variable (ich mag toggle-Variablen ), auf deren Ursprungszustand der while-loop basiert. Wird sie also umgeschaltet, beendet sich der loop und dann werden die unter dem Loop stehenden Aufräumarbeiten ausgeführt. Man kann den Vorgang mit eingeschobenen printfs verifizieren.
(Das einzig Doofe ist, dass man die Variable signum benutzen muss, weil sich sonst gcc beklagt...)
Das kommt dann also bei "kill -15" heraus:
Der Code mit den Test-printfs:
Wie findet ihr das? Jetzt könnte ich doch das Programm mittels "kill -15 pid" aus dem Parent-Wrapper-Script heraus auf jeden Fall sauber beenden.
Erst wollte ich einfach zusätzlich noch auf stdin lauschen - mit select geht das ja. Doch nachdem ich das implementiert hatte, habe ich gemerkt und ist mir wieder eingefallen, dass man nicht nach stdin eines im Terminal laufenden Processes mittels "echo /proc/pid/fd/0" pipen kann, weil diese fds immer zu denen des jeweiligen /dev/pts umgeleitet sind...
Aber eigentlich scheint es mir so jetzt auch eleganter. Ich nutze sigaction und etabliere vor dem loop eine Aktion, die beim Empfangen von SIGTERM (also "kill -15 pid") ausgeführt wird. Diese Aktion ist einfach das Umschalten einer toggle-Variable (ich mag toggle-Variablen ), auf deren Ursprungszustand der while-loop basiert. Wird sie also umgeschaltet, beendet sich der loop und dann werden die unter dem Loop stehenden Aufräumarbeiten ausgeführt. Man kann den Vorgang mit eingeschobenen printfs verifizieren.
(Das einzig Doofe ist, dass man die Variable signum benutzen muss, weil sich sonst gcc beklagt...)
Das kommt dann also bei "kill -15" heraus:
Code: Alles auswählen
/opt/scripts/dev$ ./test2xd
Hello, I am the signal handler.
Hello, I am the end of the main function.
Code: Alles auswählen
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
static const char program_name[] = "test2xd";
static Display *dpy;
static int screen;
static Window root;
static XEvent ev;
static int finish;
static void
term_hdl (int signum)
{
/* we have to use signum */
switch (signum) {
case SIGTERM:
printf("Hello, I am the signal handler.\n");
finish = 1;
}
}
int
main(void)
{
char *display_name = NULL;
char name[BUFSIZ];
int fd;
struct sigaction term_act;
memset(&term_act, 0, sizeof(term_act));
dpy = XOpenDisplay(display_name);
if (dpy == '\0') {
fprintf(stderr, "%s: unable to open display '%s'\n",
program_name, XDisplayName (display_name));
exit(2);
}
root = RootWindow(dpy, screen);
/* fd = open("/tmp/dwmblocks_fifo_intern", O_RDWR | O_NONBLOCK); */
fd = open("/home/user/fifo", O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(1);
}
term_act.sa_handler = term_hdl;
if (sigaction(SIGTERM, &term_act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
fd_set rfds;
int rc;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
while (finish == 0) {
rc = select(fd + 1, &rfds, NULL, NULL, NULL);
if (rc > 0) {
memset(name, 0, sizeof(name)-1);
ssize_t got = read(fd, name, sizeof(name)-1);
if (got < 0) {
perror("read");
break;
} else if (got == 0) {
printf("EOF\\n");
break;
}
else {
/* remove trailing newline */
if (name[strlen(name)-1] == '\n')
name[strlen(name)-1] = '\0';
XStoreName(dpy, root, name);
while (XPending(dpy))
XNextEvent(dpy, &ev);
}
}
}
/* will never get here */
close(fd);
XCloseDisplay(dpy);
printf("Hello, I am the end of the main function.\n");
exit(EXIT_SUCCESS);
}
Re: C: fifo lesen
Ich muss wohl doch noch mal schimpfenRobertDebiannutzer hat geschrieben:22.08.2018 21:26:39Code: Alles auswählen
... memset(name, 0, sizeof(name)-1); ssize_t got = read(fd, name, sizeof(name)-1); ...
1) Wenn du read(...) nutzt dann
Code: Alles auswählen
memset(name, 0, sizeof(name)); // KEIN -1 bei der Länge
ssize_t got = read(fd, name, sizeof(name)-1); // EIN -1 bei der Länge wobei besser im Sinne von UTF-8 wäre: sizeof(name) - sizeof(char)
Code: Alles auswählen
memset(name, 0, sizeof(name)); // KEIN -1 bei der Länge
ssize_t got = fgets(name, sizeof(name),fp); // KEIN -1 bei der Länge
*WINKS*
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Ohje!
Vielen Dank für Deine Geduld, @bluestar! Manchmal muss ich einfach noch konzentrierter sein...
Ich habe es korrigiert (und dabei noch das sigaction an die richtige Stelle in main() gesetzt und den letzten comment entfernt, der nicht mehr gültig ist).
Was meint ihr übrigens zu dem neuen dpy-Test?
Also statt "if (!dpy)" "if (dpy == '\0')"? Ich habe noch auf der Suckless-Seite zusätzliche Links zu Coding-Style gesehen und in einem steht:
Schien mir irgendwie Sinn zu ergeben.
Vielen Dank für Deine Geduld, @bluestar! Manchmal muss ich einfach noch konzentrierter sein...
Ich habe es korrigiert (und dabei noch das sigaction an die richtige Stelle in main() gesetzt und den letzten comment entfernt, der nicht mehr gültig ist).
Code: Alles auswählen
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
static const char program_name[] = "test2xd";
static Display *dpy;
static int screen;
static Window root;
static XEvent ev;
static int finish;
static void
term_hdl (int signum)
{
/* we have to use signum */
switch (signum) {
case SIGTERM:
printf("Hello, I am the signal handler.\n");
finish = 1;
}
}
int
main(void)
{
char *display_name = NULL;
char name[BUFSIZ];
int fd;
struct sigaction term_act;
memset(&term_act, 0, sizeof(term_act));
term_act.sa_handler = term_hdl;
if (sigaction(SIGTERM, &term_act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
dpy = XOpenDisplay(display_name);
if (dpy == '\0') {
fprintf(stderr, "%s: unable to open display '%s'\n",
program_name, XDisplayName (display_name));
exit(2);
}
root = RootWindow(dpy, screen);
/* fd = open("/tmp/dwmblocks_fifo_intern", O_RDWR | O_NONBLOCK); */
fd = open("/home/user/fifo", O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("open");
exit(1);
}
fd_set rfds;
int rc;
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
while (finish == 0) {
rc = select(fd + 1, &rfds, NULL, NULL, NULL);
if (rc > 0) {
memset(name, 0, sizeof(name));
ssize_t got = read(fd, name, sizeof(name)-sizeof(char));
if (got < 0) {
perror("read");
break;
} else if (got == 0) {
printf("EOF\\n");
break;
}
else {
/* remove trailing newline */
if (name[strlen(name)-1] == '\n')
name[strlen(name)-1] = '\0';
XStoreName(dpy, root, name);
while (XPending(dpy))
XNextEvent(dpy, &ev);
}
}
}
close(fd);
XCloseDisplay(dpy);
printf("Hello, I am the end of the main function.\n");
exit(EXIT_SUCCESS);
}
Also statt "if (!dpy)" "if (dpy == '\0')"? Ich habe noch auf der Suckless-Seite zusätzliche Links zu Coding-Style gesehen und in einem steht:
Quelle: https://man.openbsd.org/styleDon't use ‘!’ for tests unless it's a boolean [...]
Schien mir irgendwie Sinn zu ergeben.
Re: C: fifo lesen
Das ist leider falscher.RobertDebiannutzer hat geschrieben:22.08.2018 22:15:32Was meint ihr übrigens zu dem neuen dpy-Test?
Also statt "if (!dpy)" "if (dpy == '\0')"?
XOpenDisplay(3) liefert einen Pointer zurueck und ...
Logisch korrekt ist also ``if (dpy == NULL)''. (Ich persoenlich finde ``if (!dpy)'' aber besser, weil mehr Signal und weniger Noise und damit direkter, treffender und lesbarer ... aber ich weiss, dass in dem Punkt viele da ``== NULL'' bevorzugen.)Manpage XOpenDisplay(3) hat geschrieben: If XOpenDisplay does not succeed, it returns NULL.
In der Praxis laeuft's auf's gleiche hinaus, trotzdem sollte man NULL, 0 und '\0' voneinander unterscheiden und stets das Passende verwenden.
Das hat durchaus seine Logik und einen Sinn. Ich selber verwende trotzdem `!' auch in anderen Situationen, immer wenn es mir so lesbarer erscheint. Bloss bei strcmp(3) verwende ich `!' nie und das aus starker Ueberzeugung: Es fuehrt einfach zu zu vielen Verstaendnisproblemen! Auch bei fork(2) halte ich `!' fuer nie sinnvoll. Insofern kann man schon sagen, dass man es nur fuer booleanartige Ausdruecke verwenden sollte. Es muss nicht nur 1 und 0 sein, es koennen schon auch viele verschiedene Werte zurueckgegeben werden (z.B. bei fopen(3)), aber wenn ich dort pruefe, ob der Aufruf fehlerhaft war, dann pruefe ich mit `!', weil ich etwas booleanartiges wissen will. Ich wuerde also sagen, dass man `!' nur verwenden sollte, wenn man eine booleanartige Pruefung macht (egal welcher Art die Daten sind).Ich habe noch auf der Suckless-Seite zusätzliche Links zu Coding-Style gesehen und in einem steht:Quelle: https://man.openbsd.org/styleDon't use ‘!’ for tests unless it's a boolean [...]
Schien mir irgendwie Sinn zu ergeben.
Bei strcmp(3) macht das `!' IMO keinen Sinn, weil was soll ``if not string-compare'' bitte bedeuten? (``if not fopen'' macht dagegen viel Sinn.)
Bei fork(2) macht die Pruefung mit `!' auch keinen Sinn, weil ``!fork()'' bedeutet, dass man das Kind ist.
Entscheidend ist die Sinnhaftigkeit und das Verstaendnis beim Codeleser. Solange du dir nicht sicher bist, dass du gute Gruende hast, es auf eine bestimmte Art zu machen -- als Anfaenger hast du die fast nie --, dann mach es so wie die (guten) Styleguides es empfehlen.
Use ed once in a while!
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Oh, alles klar, vielen Dank, @meillo! Mit dem Unterschied zwischen Null, 0 und '\0' sollte ich mich wohl mal beschäftigen...
Eigentlich sollte man ja alle Variablen in der entsprechenden Funktion deklarieren, wenn sie nicht funktionsübergreifend genutzt werden, richtig?
Und nach den breaks des loops bzw. nach einem gescheiterten open() wäre ja auch Aufräumen angesagt...
Habe das mal versucht:
Eigentlich sollte man ja alle Variablen in der entsprechenden Funktion deklarieren, wenn sie nicht funktionsübergreifend genutzt werden, richtig?
Und nach den breaks des loops bzw. nach einem gescheiterten open() wäre ja auch Aufräumen angesagt...
Habe das mal versucht:
Code: Alles auswählen
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <X11/Xlib.h>
/* BEGIN: user configuration */
static const char program_name[] = "test2xd";
/* static const char fifo[] = "/tmp/dwmblocks_fifo_intern"; */
static const char fifo[] = "/home/user/fifo";
/* END: user configuration */
static int finish;
static void
term_hdl (int signum)
{
/* if we do not use signum, gcc complains */
if (signum == SIGTERM)
finish = 1;
}
int
main(void)
{
char *display_name = NULL;
char name[BUFSIZ];
int fd;
int rc;
static int screen;
int state = EXIT_SUCCESS;
static Window root;
static Display *dpy;
struct sigaction term_act;
static XEvent ev;
fd_set rfds; /* fixed size buffer */
memset(&term_act, 0, sizeof(term_act));
term_act.sa_handler = term_hdl;
if (sigaction(SIGTERM, &term_act, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
dpy = XOpenDisplay(display_name);
if (dpy == NULL) {
fprintf(stderr, "%s: unable to open display '%s'\n",
program_name, XDisplayName(display_name));
exit(EXIT_FAILURE);
}
root = RootWindow(dpy, screen);
fd = open(fifo, O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("open");
XCloseDisplay(dpy);
exit(EXIT_FAILURE);
}
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
while (finish == 0) {
rc = select(fd + 1, &rfds, NULL, NULL, NULL);
if (rc > 0) {
memset(name, 0, sizeof(name));
ssize_t got = read(fd, name, sizeof(name)-sizeof(char));
if (got < 0) {
perror("read");
state = EXIT_FAILURE;
break;
} else if (got == 0) {
printf("EOF\\n");
break;
}
else {
/* remove trailing newline */
if (name[strlen(name)-1] == '\n')
name[strlen(name)-1] = '\0';
XStoreName(dpy, root, name);
while (XPending(dpy))
XNextEvent(dpy, &ev);
}
}
}
close(fd);
XCloseDisplay(dpy);
exit(state);
}
Re: C: fifo lesen
Die Binaerdarstellung all dieser Werte sind nur Nullen. (Auch wenn der Standard das nicht erfordert, so ist es in der Realitaet in allen Implementierungen so und es macht auch Sinn.)RobertDebiannutzer hat geschrieben:23.08.2018 12:55:20Mit dem Unterschied zwischen Null, 0 und '\0' sollte ich mich wohl mal beschäftigen...
Die Unterschiede liegen nur in den Datentypen. Finde heraus, welche Datentypen die drei Ausdruecke haben! 0 und '\0' sind einfach, NULL ist schwieriger.
Und ja, globale Variablen sollte man moeglichst vermeiden.
Use ed once in a while!
-
- Beiträge: 385
- Registriert: 16.06.2017 09:52:36
Re: C: fifo lesen
Alles klar, mache ich.
Was mir übrigens noch eingefallen ist (habe ich oben vergessen): Ich kann mir beim schließen des Prozesses das "-15" als Argument für kill sparen, denn das default-Signal von kill ist eh SIGTERM:
man 1 kill
Was mir übrigens noch eingefallen ist (habe ich oben vergessen): Ich kann mir beim schließen des Prozesses das "-15" als Argument für kill sparen, denn das default-Signal von kill ist eh SIGTERM:
man 1 kill
The default signal for kill is TERM.
Re: C: fifo lesen
Ich bin mir nicht sicher allerdings will ich es dennoch mal loswerden:
Der Code wird bei dir ja nur nach dem Empfang von Daten ausgeführt, mein Gefühl sagt mir das du hier auf kurz oder lang ein Problem bekommen wirst, wenn der EventPuffer von X voll läuft, während du "unendlich lange" auf Daten aus deinem Fifo wartest.
Ich würde die While Schleife (stark vereinfacht so gestalten):
Code: Alles auswählen
while (XPending(dpy))
XNextEvent(dpy, &ev);
Ich würde die While Schleife (stark vereinfacht so gestalten):
Code: Alles auswählen
while (finished==0) {
while (XPending(dpy)) {
XNextEvent(dpy, &ev);
}
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
rc = select (.....) // mit timeout von 1 sek oder 5 sek ...
if (rc > 0) {
...
}
}