C - pufferloses Datenschleusen

Herakles

Profifragensteller
Moin zusammen!

Ich möchte gern ohne Puffer Daten von einem Gerät lesen und unverändert auf ein anderes Gerät schreiben. Welches das jeweils ist, ist zunächst mal zweitrangig, es geht mir in erster Linie um das Prinzip. Ach ja - schnell darf das Ganze auch noch sein. Gerne auch richtig schnell. Implementieren möchte ich das aus Spaß gern in C. Insgesamt handelt es sich hierbei um einen Versuch, um mein Verstädnis der Materie zu erweitern :)

<Erläuterung>Das zu lesende Gerät könnte beispielsweise ein USB-Port oder auch eine WLAN-Karte sein, das schreibende Gerät die Netzwerkkarte oder die Soundkarte oder was auch immer - wie gesagt, zweitrangig. Ich möchte das mögliche Prinzip verstehen können... Mir sind dabei auch Protokollunterschiede bewusst (beim sinnvollen Schreiben auf ein Netzwerkgerät hätte ich sicher Spaß mit IP und derlei Dingen, etc.).</Erläuterung>

So, dieser Vorgang soll nun ohne einen Puffer auskommen können - so, als würde ich ein Kabel an das Lese-Gerät anklemmen und das andere Ende des Kabels an das Schreib-Gerät. Wie ein Datentunnel oder eine Pipe.

Wichtig ist mir dabei, dass kein Puffer zu nutzen ist, also auch kein Consumer-Producer Problem entsteht. Kann ich so etwas mit einem einfachen read(2) erledigen, indem ich einfach einen Filedescriptor als Pufferort angebe? Sicher nicht...

Lange Rede, kurzer Sinn: besteht die Möglichkeit, richtig schnell und ohne Puffer Daten per C-Programm von einem Systemgerät auf ein anderes durchzuschleusen?
 
Pufferlos und schnell schließt sich gegenseitig aus.

Um wirklich pufferlos zu übertragen dürftest du eigentlich nur Byte oder Wortweise schnipsel übetragen. Das heißt je nach Architektur max. 64Bit am Stück.
Auch eine einfache Pipe ist in der Regel gepuffert, da das ganze sonst viel zu lahm liefe.
 
RTFM open(2) bzw. fcntl(2) und suche nach O_SYNC. poll(2) hat auch entsprechende flags.

Und dann gibt es da noch den Unterschied zwischen character und block devices.

Wie bereits erwähnt, ist solches Byteschubsen geschwindigkeitsmässig völlig kontraproduktiv, es gibt gute Gründe, warum normalerweise kräftig gepuffert wird.
 
read(2) benutzt aber Puffer. Wo liest Du denn hin? Richtig, in einen Speicherbereich.

So etwas wie Du verlangst ist selten sinnvoll und ist, wenn überhaupt, auf Betriebssystemebene zu lösen.

Am besten ist immer zu sagen, was Du willst und nicht über abstrakte Mechanismen zu reden. Vielleicht gehst Du das Problem schon ganz grundlegend falsch an.
 
Angenommen es gäbe ein read(2), das als Ziel der Leseaktion einen Dateideskriptor akzeptiert, dann würde dafür kernelseitig trotzdem ein Puffer verwendet werden.

Schnelle Datentransfers werden hardwareseitig mittels eines DMA-Controllers erreicht. Dieser Controller hat die Möglichkeit unabhängig von der CPU Daten vom Speicher zu I/O-Geräten und umgekehrt zu kopieren.

Das was du möchtest wäre vom Prinzip her so etwas wie ein DMA-Controller, der direkt von einem Gerät die Daten zu einem anderen transferiert. Das wäre allerdings praktisch eher weniger von Nutzen, da ein Computer nun einmal ein Datenverarbeitungsgerät und kein Datenweiterleitungsgerät ist. Daher sind sämtliche Peripheriegeräte und Schnittstellen für solche Zwecke nicht ausgelegt.

Gruß
Björn
 
Zuletzt bearbeitet:
Vielen herzlichen Dank für die zahlreichen fundierten Antworten. Es ist einfach herrlich, in diesem Forum auf einen derart kompetenten Wissensfundus zurückgreifen zu können. Dickes Lob, vielen Dank Euch allen!

So, zurück zum Thema: offenbar ist das, was ich als "schnell" angedacht hatte - direktes Schieben der Daten von einer Schnittstelle auf die andere - gar nicht "schnell". Ich bleibe also auf meinem Puffer sitzen. Damit ändert sich die Ausgangslage ein wenig, denn nun ist mein Ziel ja nicht mehr meine Daten "pufferlos" zu bearbeiten, sondern "schnell" - und das bedeutet laut der Aussagen hier "mit Puffer".

Nun habe ich mich gefragt, wie so etwas schnell geschehen könnte. Fündig wurde ich bei Pronix, wo etwas über Memory Mapped zu finden ist - mmap(2).

Dort ist zu finden:

Der Hauptvorteil dieser Methode ist, dass hierbei weniger Kernel-Aktionen wie bei den Systemaufrufen gemacht werden müssen - es muss viel weniger vom User- in den Kernel-Level gewechselt werden. Und das wirkt sich (richtig eingesetzt) positiv auf die Performance aus.

Drei Fragen dazu:

1. Wie seht Ihr den Sachverhalt? Ist mmap eine effiziente Methode, um so schnell es eben geht Daten von Schnittstelle A nach Schnittstelle B zu schaufeln?

2. Der Autor Jürgen Wolf zeigt unter dem genannten Link ein Listing, das mit zwei Dateien arbeitet. Nun ist zwar in Unix jedes Gerät als Datei ansprechbar - ist damit ein solches Gerät auch mit mmap(2) ansprechbar bzw. verwendbar? Kann ich beispielsweise den Deskriptor einer geöffneten USB-Schnittstelle in mmap verwenden?

3. Ich habe versuchshalber ein kleines Programm geschrieben, dass einfach nur auf einer USB-Schnittstelle Daten liest und auf einer anderen USB-Schnittstelle Daten schreibt, etwa so:

Code:
read(fd1, buf, 1);
write(fd2, buf, 1);

Am Oszilloskop habe ich an der jeweiligen Schnittstelle die Daten hinsichtlich der Zeitlichen Abfolge gemessen und dabei herausgefunden, dass ein ASCII-Zeichen zwischen dem Erscheinen auf den Schnittstellen zwischen 2 und 7 Millisekunden benötigt, im Mittel etwa 4 Millisekunden.
Sind das übliche Werte? Sind diese Werte evtl. derart hoch, weil ich für beide Wege in diesem Test USB, also ein und denselben Bus verwendet habe - sprich hätte ich USB in Kombination mit beispielsweise Ethernet verwandt, wären die Werte dann geringer?

Viele Fragen, ich hoffe, ich konnte alles möglichst prägnant halten.

Herzliche Grüße und mein Dank im Voraus,
Herakles
 
Geht es dir um Schnell im Sinne von Echtzeit, oder im Sinne von Durchsatz.

Der read/write Ansatz wird reichen um eine USB-Schnittstelle beim Durchsatz auszulasten.

Vom Echtzeitgedanken ist das mit den bis zu 7ms aber nicht der Renner. Bei meiner Maus dauert es max 2 Milisekunden bis ein Signal bei der Anwendung ankommt. Das ist ein verdammt guter Wert. Das heißt stabile 4 ms sollten schon zu machen sein, wenn die Hardware entsprechend ausgelegt ist (1KHz Nachrichten-Takt). Die meisten USB-Geräte arbeiten aber nur mit einem Nachrichten-Takt von 125 Hz, damit können also bis zu 8ms vergehen bis auf deinen Leseversuch reagiert wird. Erst dann kannst du die Daten verarbeiten und weiterreichen.

Bei deinen Oszi-Messwerte n würde ich darauf schließen, dass deine Geräte immerhin ihre Nachrichten im Bereich 250Hz bis 500Hz verarbeiten. Zusammen mit der Verarbeitungszeit auf dem Rechner ließen sich so die Messwerte erklären.

Die einzige Möglichkeit da etwas zu verbessern wäre eigentlich bloß deine Anwendung als Kernel-Modul zu bauen.
 
USB hat verschiedene Modi (4 Stück glaube ich) in denen es betrieben wird. Wenn Du Dir die Spezifikation anschaust, dann siehst Du wie ein USB-Controller funktioniert.

Die Betriebsmodi können allerdings nur auf Kernel-Ebene gewählt werden, weil sie eigentlich für Treiber gedacht sind.

Eine Webcam zum Beispiel liefert konstanten Datendurchsatz. Sie muss ganz anders behandelt werden als eine Tastatur und diese auch ganz anders wie eine Festplatte, die mit Blockleseverfahren viel effizienter arbeitet.

Messwerte-Transfer ähnelt im Prinzip Echtzeit-Audiodatenübertragung.
 
Ich würd mal sagen, dass USB für ne Echtzeitschnitte überhaupt nicht geeignet ist. Wie soll man auf dem crap eine Reaktionszeit garantieren?
 
Nocheinmal aufgewärmt das Ganze: wie wäre es mit einem sendfile(2), das als source eine Netzwerkkarte hat und als destination Beispielsweise die Soundkarte.

Ein
Code:
offset = NULL;
sendfile( fd_socket, fd_sound, offset, blocksize_soundcard );

gibt mir ein "Invalid argument" zurück - egal ob ich die Soundkarte als source oder als destination verwende in dem sendfile-Befehl.

Sie ist - je nach source oder destination - write-only bzw. read-only geöffnet. Wenn ich von einer Datei lese, dann klappt das wunderbar, sobald ich von einem anderen Gerät lesen möchte (in diesem Fall eben eine Soundkarte), gibt es "invalid argument".

Hat jemand eine Idee, was ich falsch mache?

Danke, Herakles
 
Zurück
Oben