pipe ohne fork

xGhost

OpenBSD Freack
Hallo

Ich Arbeite gerade mit Pseudo Terminals.
Um nicht ein endlos loop zu verwenden, welche den CPU immer
auf 100% haltet, arbeite ich mit select.

Nun will ich ein Interface machen, welche Daten von Dritten benutzen
kann. Somit müsste ich auch das andere Interface im select berücksichtigen.
Nun ist es aber leider kein filedeskriptor und somit nicht select kompatible.

Meine Idee ist es nun, eine pipe dafür zu verwenden.
Da ich das ganze aber nicht forke sondern in threads ablauft lasse, weiss
ich nun nicht, ob das mit den Pipes gehen könnte. Ich kenne pipes nur
in Zusammenhang mit fork.

Nach meiner Theorie und Verständnis sollte es, aber ich will nicht am
ende das ganze Design ändern...

Ziel ist es auch nicht, dass jemand hier das nun nachbaut. Das kann ich
auch wenn ich wieder @home bin. Vl. weiss es aber gerade jemand :)

Greets
Ghost
 
Hm ich weiß ja nicht ob so eine Abhängigkeit für dich in Frage kommt, aber das Qt-Framework bietet die Möglichkeit von Signals & Slots [1] .
Damit lässt sich sehr genial zwischen unterschiedlichen Klassen kommunizieren, auch wenn die Objekte in unterschiedlichen Threads (und Eventloops) leben und Daten produzieren.
Der Link lässt es so aussehen, als sei das nur sinnvoll für GUI-Schnickschnack aber auch in reinen Konsolenanwendungen - besonders mit Threads - kann das sehr nüztlich sein.
Qt4 kannst du auch völlig ohne X11 als Abhängigkeit bauen.

[1] http://doc.trolltech.com/4.3/signalsandslots.html
 
Ich kann leider kein framework verwenden bzw. darf.
Im C++ standard hat es glaube ich auch sowas.

Aber das kleine demo demonstriert, dass es geht:
Code:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

int pipen[2];

void *PrintHello(void *threadid)
{
   char text[3];
   read(pipen[0], text, 3);
   printf("Und es kommt: %s\n", text);
   pthread_exit(NULL);
}

int main (int argc, char *argv[])
{
   pthread_t thread;

   pipe(pipen);
   pthread_create(&thread, NULL, PrintHello, NULL);

   write(pipen[1], "YES", 3);

   pthread_exit(NULL);
}
 
Meine Idee ist es nun, eine pipe dafür zu verwenden.
Da ich das ganze aber nicht forke sondern in threads ablauft lasse, weiss
ich nun nicht, ob das mit den Pipes gehen könnte. Ich kenne pipes nur
in Zusammenhang mit fork.

Pipes arbeiten mit Dateideskriptoren. Es ist egal, ob eine Pipe zwischen zwei Prozessen oder zwischen zwei Threads besteht, denn die Dateideskriptoren werden vom Kernel verwaltet. Das bedeutet auch, dass select(), write(), read(), etc. alles Systemaufrufe sind. Die sind, im Vergleich zur Inter-Thread-Kommunikation, sehr teuer. Da Du eh in Threads arbeitest, würde ich Dir empfehlen, die Pipe als kleine FIFO nachzubauen (oder eine fertige Implementierung zu verwenden). Ein Ringpuffer ist ideal, da schnell und einfach implementiert.
 
Abend

Pipes sind nicht fork(...) spezifisch, pipes sind umleitungen im sinne (pipeline) wo A nach B sendet. Das kann durchaus auch in der eigenen applikation stattfinden, bsp. umleitungen von dateien auf console.

Hier mal link, vieleicht hillft es: http://www.pronix.de/pronix-202.html

Gruss
bsdagent
 
Pipes arbeiten mit Dateideskriptoren. Es ist egal, ob eine Pipe zwischen zwei Prozessen oder zwischen zwei Threads besteht, denn die Dateideskriptoren werden vom Kernel verwaltet. Das bedeutet auch, dass select(), write(), read(), etc. alles Systemaufrufe sind. Die sind, im Vergleich zur Inter-Thread-Kommunikation, sehr teuer. Da Du eh in Threads arbeitest, würde ich Dir empfehlen, die Pipe als kleine FIFO nachzubauen (oder eine fertige Implementierung zu verwenden). Ein Ringpuffer ist ideal, da schnell und einfach implementiert.

Ich will den Prozess auf SELECT setzen. Mit einer Loop geht mir
zu viel CPU Leistung für nichts drauf.

Die Thread Implementation auf welche ich zugreifen darf,
hat sowas nicht... Bei glibmm könnte man Cound [1] nehmen.
Ich nehme an, dass es das ist was du meinst?

greets

[1] http://www.gtkmm.org/docs/glibmm-2.4/docs/reference/html/classGlib_1_1Cond.html
 
Ich will den Prozess auf SELECT setzen. Mit einer Loop geht mir zu viel CPU Leistung für nichts drauf.

Was meinst Du mit auf "SELECT" setzen? Dass der Prozess blockiert während er auf Daten wartet und automatisch aufgeweckt wird, sobald Daten da sind? Das geht auch mit read(2), aber im ersten Post liest sich das so, als ob Du select(2) verwenden wolltest. Wenn keine Daten auf keinem der Dateidescriptoren vorliegen, dann blockiert select(2). Meiner Meinung nach genau das was Du willst - und sollte auch mit einer Pipe funktionieren, da select(2) mit Dateideskriptoren arbeitet. Ein Dateideskriptor ist ja ein ganz abstraktes Objekt, nicht immer steht auch eine "echte" Datei hinter einem Deskriptor (z.B. bei Sockets). Wenn Du eine Pipe erstellst, dann erhältst Du ja zwei Dateideskriptoren - einen für jedes Ende. Die Enden können durchaus auch im selben Prozess liegen, ich sehe da kein Problem.

Allerdings glaube ich, dass Du Dir die Pipes sparen kannst. Da Du mit Threads arbeitest, hast Du nur einen Adressraum und kannst die Daten selbst, d.h. ohne den Kernel, hin- und herschicken. Eine Pipe wird vom Kernel erstellt und verwaltet, so ist eine einfache Interprozesskommunikation (IPC) möglich: Daten die am einen Ende geschrieben werden, können am andern Ende in der selben Reihenfolge wie sie eingeliefert wurden gelesen werden - das Prinzip nennt man FIFO, kurz für First-In, First-Out. Das Schöne an einer Pipe ist, dass sie über Prozessgrenzen hinweg funktioniert. Dazu müssen allerdings die Daten vom Kernel zwischen den beiden getrennten Adressräumen vermittelt werden, und der Weg Userland->Kernel->Userland ist verhältnismäßig teuer. Datenaustausch zwischen zwei Threads braucht den Kernel nicht und ist wesentlich billiger.

Eine FIFO Struktur kannst Du Dir auch einfach selbst nachbauen. Wie schon gesagt, mit einem Ringpuffer geht das schnell und einfach. Du brauchst auch kein Polling, sondern Du kannst Conditions verwenden. Conditions sind Teil der pthread-API und erlauben es, dass ein Thread blockiert, bis eine Condition aufgetreten ist. So würde z.B. der Reader-Thread einer FIFO auf die Condition "FifoNotEmpty" warten. Diese würde immer vom Writer-Thread signalisiert, wenn Daten in die FIFO geschrieben werden. Ein vollständiges Design einer FIFO findest Du in jedem Buch zur IPC - im Tanenbaum steht mit großer Sicherheit was drin.

Die Thread Implementation auf welche ich zugreifen darf,
hat sowas nicht... Bei glibmm könnte man Cound [1] nehmen.
Ich nehme an, dass es das ist was du meinst?

Das ganze sieht nach einem einfachen Wrapper um die pthread_cond_XXX API aus. Welche Thread-Bibliothek verwendest Du denn? Conditions sind essentiell, möglicherweise solltest Du über einen Wechsel nachdenken.
 
Ich hätte schon Cond. Das Problem ist, dass ich ein Teil des
Userlands in diesem Programm ersetze (nicht auf file ebene) um den keyloger*
effektive und unsichtbar zu machen.

Ich kann das hanling nicht total neu machen, und somit muss
ich auf diese Variante (pipes) zurückgreifen. Es darf nie etwas blockieren
oder verzögern. Den select() call habe ich schon im code.
Somit kann ich die pipes nur noch dort einpflanzen.
Einen Buffer brauche ich sowieso beim ein und Ausgang der Pipes, sonst blockiert das auslesen und einlesen von dritten den Normalen Ablauf
des Userlands.

*Das ganze wird dann ein Teil von Synergy2. Also kein Negativer Keyloger.
 
Ich versteh's nicht. Tut mir leid.

select(2) blockiert bzw. verzögert doch auch? Wenn keine Daten auf dem Deskriptor gelesen/geschrieben werden können, dann blockiert select(2) mindestens so lange wie der Timeout angibt. Wenn Du keinen Timeout angibst, dann sogar unendlich lange. Und selbst wenn Du einen Timeout von 0.0 sec angibst, dann bist Du effektiv beim Polling.

Mir scheint, als wolltest Du ein Event-basiertes Modell, kann das sein? Also dass ein Thread oder Prozess nur dann was tut, wenn ein Ereignis eingetreten ist das bearbeitet werden muss. Für sowas brauchst Du Signale.
 
Zurück
Oben