Lowlevel

Lowlevel => OS-Design => Thema gestartet von: LittleFox am 30. June 2010, 13:39

Titel: [erledigt] IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 30. June 2010, 13:39
Moin,

bei mir geht es auch langsam in Richtung IPC.
Ich hab mir überlegt, dass Nachrichten über einen Syscall gesendet werden.
Zum empfangen muss sich jedes Programm einen Handler beim Kernel registrieren, der bei Nachrichten immer aufgerufen wird.
Momentan hänge ich beim Syscall fest, mit dem der Handler registriert werden soll. Am Ende soll etwas ähnliches rauskommen, wie in der WinAPI die WindowProcedure ;).

Hier ist mein Code aus dem Kernel:
if(r->int_no == 49)
{
     // RegisterEventHandler
     // eax = Funktionsnummer (momentan immer 0)
     // edx = Speicheradresse des Eventhandlers
     if(r->eax == 0)
     {
          currentEventHandler = (void*)r->edx;
     }
}

Die Variable CurrentEventHandler deklariere ich so:
void (*currentEventHandler)(int message, long params);
Und hier ist mein Testprogramm:
void eventHandler(int message, long params);

void _start(void)
{
asm("movl %0, %%edx;"::"r"(eventHandler));
asm("movl $0, %eax");
asm("int $49");
 
    while(1);
}

void eventHandler(int message, long params)
{
if(message == 0x00000001)
{
char temp[2] = "";
temp[0] = params;
temp[1] = 0;
asm("mov $0x07, %edx");
asm("movl %0, %%esi;"::"r"(temp));
asm("movl $0, %eax");
asm("movl $10, %ebx");
asm("movl $5, %ecx");
asm("int $48");
}
}

Die Nachricht 0x00000001 ist übrigens für Tastatureingaben.

So bekomme ich immer einen Bluescreen (Invalid Opcode), nachdem das Programm gestartet wurde.

Danke schonmal für die Hilfe.

LittleFox

EDIT: upps, im falschen Forum gelandet, müsste eigentlich nach OS-Design. Kann das bitte mal ein Mod verschieben? Danke  :-)
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 30. June 2010, 21:25
Scheinbar wird die variable currentEventHandler nicht mit dem neuen Wert belegt.
Es geht auch nicht, wenn ich das direkt im Kernel mache. Die Adresse von currentEventHander bleibt die ganze Zeit über NULL ...
Irgendwelche Ideen?
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: kevin am 30. June 2010, 21:42
Also als allererstes solltest du jeweils einen einzigen asm-Block nehmen (und die Instruktionen per ; oder \n trennen), nicht mehrere. Was bei dir passiert ist folgendes:

void _start(void)
{        
        // Registerzustand ist vom C-Compiler definiert
        asm("movl %0, %%edx;"::"r"(eventHandler)); // Kopiere eventHandler nach edx
        // Hier ist wieder C. Der Compiler kann mit den Registern anstellen was er will.
        asm("movl $0, %eax"); // Kopiere 0 nach edx, eax ist undefiniert
        // Hier ist wieder C. Der Compiler kann mit den Registern anstellen was er will.
        asm("int $49"); // Rufe int 49 auf. Der Registerinhalt sowohl von eax als auch edx ist undefiniert.

Wenn du besonders viel Glück hast, erkennt der Compiler sogar, dass dein Assembler-Block nichts sinnvolles beiträgt und "optimiert" ihn ganz raus. Am besten schaust du dir mal mit objdump an, was da tatsächlich produziert worden ist.
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 30. June 2010, 22:05
OK, ich hab das jetzt in einen asm block geschrieben.
Laut objdump wird nach edx $0x0 gelegt.

der neue asm block:
asm("movl %0, %%edx;"
"movl $0, %%eax;"
"int $49;"::"r"((void*)eventHandler));

Ausgabe von objdump:
main.o:     file format elf32-i386


Disassembly of section .text:

00000000 <puts>:
   0:   55                      push   %ebp
   1:   89 e5                   mov    %esp,%ebp
   3:   8b 45 08                mov    0x8(%ebp),%eax
   6:   89 c6                   mov    %eax,%esi
   8:   b8 02 00 00 00          mov    $0x2,%eax
   d:   cd 30                   int    $0x30
   f:   5d                      pop    %ebp
  10:   c3                      ret

00000011 <putc>:
  11:   55                      push   %ebp
  12:   89 e5                   mov    %esp,%ebp
  14:   83 ec 14                sub    $0x14,%esp
  17:   8b 45 08                mov    0x8(%ebp),%eax
  1a:   88 45 ec                mov    %al,-0x14(%ebp)
  1d:   8a 45 ec                mov    -0x14(%ebp),%al
  20:   88 45 fe                mov    %al,-0x2(%ebp)
  23:   c6 45 ff 00             movb   $0x0,-0x1(%ebp)
  27:   8d 45 fe                lea    -0x2(%ebp),%eax
  2a:   50                      push   %eax
  2b:   e8 fc ff ff ff          call   2c <putc+0x1b>
  30:   83 c4 04                add    $0x4,%esp
  33:   a1 00 00 00 00          mov    0x0,%eax
  38:   40                      inc    %eax
  39:   a3 00 00 00 00          mov    %eax,0x0
  3e:   c9                      leave
  3f:   c3                      ret

00000040 <putn>:
  40:   55                      push   %ebp
  41:   89 e5                   mov    %esp,%ebp
  43:   83 ec 50                sub    $0x50,%esp
  46:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)
  4d:   83 7d 0c 24             cmpl   $0x24,0xc(%ebp)
  51:   7f 65                   jg     b8 <putn+0x78>
  53:   8d 45 b7                lea    -0x49(%ebp),%eax
  56:   83 c0 40                add    $0x40,%eax
  59:   89 45 fc                mov    %eax,-0x4(%ebp)
  5c:   8b 45 fc                mov    -0x4(%ebp),%eax
  5f:   c6 00 00                movb   $0x0,(%eax)
  62:   ff 4d fc                decl   -0x4(%ebp)
  65:   8b 55 0c                mov    0xc(%ebp),%edx
  68:   8b 45 08                mov    0x8(%ebp),%eax
  6b:   89 d1                   mov    %edx,%ecx
  6d:   ba 00 00 00 00          mov    $0x0,%edx
  72:   f7 f1                   div    %ecx
  74:   89 d0                   mov    %edx,%eax
  76:   03 45 f8                add    -0x8(%ebp),%eax
  79:   8a 10                   mov    (%eax),%dl
  7b:   8b 45 fc                mov    -0x4(%ebp),%eax
  7e:   88 10                   mov    %dl,(%eax)
  80:   8b 55 0c                mov    0xc(%ebp),%edx
  83:   8b 45 08                mov    0x8(%ebp),%eax
  86:   89 d1                   mov    %edx,%ecx
  88:   ba 00 00 00 00          mov    $0x0,%edx
  8d:   f7 f1                   div    %ecx
  8f:   89 45 08                mov    %eax,0x8(%ebp)
  92:   83 7d 08 00             cmpl   $0x0,0x8(%ebp)
  96:   75 ca                   jne    62 <putn+0x22>
  98:   83 7d 0c 10             cmpl   $0x10,0xc(%ebp)
  9c:   75 0d                   jne    ab <putn+0x6b>
  9e:   68 25 00 00 00          push   $0x25
  a3:   e8 fc ff ff ff          call   a4 <putn+0x64>
  a8:   83 c4 04                add    $0x4,%esp
  ab:   ff 75 fc                pushl  -0x4(%ebp)
  ae:   e8 fc ff ff ff          call   af <putn+0x6f>
  b3:   83 c4 04                add    $0x4,%esp
  b6:   eb 01                   jmp    b9 <putn+0x79>
  b8:   90                      nop
  b9:   c9                      leave
  ba:   c3                      ret

000000bb <printf>:
  bb:   55                      push   %ebp
  bc:   89 e5                   mov    %esp,%ebp
  be:   83 ec 20                sub    $0x20,%esp
  c1:   8d 45 0c                lea    0xc(%ebp),%eax
  c4:   89 45 ec                mov    %eax,-0x14(%ebp)
  c7:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%ebp)
  ce:   e9 14 01 00 00          jmp    1e7 <printf+0x12c>
  d3:   8b 45 08                mov    0x8(%ebp),%eax
  d6:   8a 00                   mov    (%eax),%al
  d8:   3c 25                   cmp    $0x25,%al
  da:   0f 85 f3 00 00 00       jne    1d3 <printf+0x118>
  e0:   ff 45 08                incl   0x8(%ebp)
  e3:   8b 45 08                mov    0x8(%ebp),%eax
  e6:   8a 00                   mov    (%eax),%al
  e8:   0f be c0                movsbl %al,%eax
  eb:   83 f8 70                cmp    $0x70,%eax
  ee:   74 7d                   je     16d <printf+0xb2>
  f0:   83 f8 70                cmp    $0x70,%eax
  f3:   7f 2a                   jg     11f <printf+0x64>
  f5:   83 f8 63                cmp    $0x63,%eax
  f8:   0f 84 98 00 00 00       je     196 <printf+0xdb>
  fe:   83 f8 63                cmp    $0x63,%eax
 101:   7f 12                   jg     115 <printf+0x5a>
 103:   85 c0                   test   %eax,%eax
 105:   0f 84 eb 00 00 00       je     1f6 <printf+0x13b>
 10b:   83 f8 25                cmp    $0x25,%eax
 10e:   74 7a                   je     18a <printf+0xcf>
 110:   e9 a1 00 00 00          jmp    1b6 <printf+0xfb>
 115:   83 f8 64                cmp    $0x64,%eax
 118:   74 36                   je     150 <printf+0x95>
 11a:   e9 97 00 00 00          jmp    1b6 <printf+0xfb>
 11f:   83 f8 75                cmp    $0x75,%eax
 122:   74 2c                   je     150 <printf+0x95>
 124:   83 f8 78                cmp    $0x78,%eax
 127:   74 44                   je     16d <printf+0xb2>
 129:   83 f8 73                cmp    $0x73,%eax
 12c:   0f 85 84 00 00 00       jne    1b6 <printf+0xfb>
 132:   8b 45 ec                mov    -0x14(%ebp),%eax
 135:   8d 50 04                lea    0x4(%eax),%edx
 138:   89 55 ec                mov    %edx,-0x14(%ebp)
 13b:   8b 00                   mov    (%eax),%eax
 13d:   89 45 f0                mov    %eax,-0x10(%ebp)
 140:   ff 75 f0                pushl  -0x10(%ebp)
 143:   e8 fc ff ff ff          call   144 <printf+0x89>
 148:   83 c4 04                add    $0x4,%esp
 14b:   e9 94 00 00 00          jmp    1e4 <printf+0x129>
 150:   8b 45 ec                mov    -0x14(%ebp),%eax
 153:   8d 50 04                lea    0x4(%eax),%edx
 156:   89 55 ec                mov    %edx,-0x14(%ebp)
 159:   8b 00                   mov    (%eax),%eax
 15b:   89 45 f4                mov    %eax,-0xc(%ebp)
 15e:   6a 0a                   push   $0xa
 160:   ff 75 f4                pushl  -0xc(%ebp)
 163:   e8 fc ff ff ff          call   164 <printf+0xa9>
 168:   83 c4 08                add    $0x8,%esp
 16b:   eb 77                   jmp    1e4 <printf+0x129>
 16d:   8b 45 ec                mov    -0x14(%ebp),%eax
 170:   8d 50 04                lea    0x4(%eax),%edx
 173:   89 55 ec                mov    %edx,-0x14(%ebp)
 176:   8b 00                   mov    (%eax),%eax
 178:   89 45 f4                mov    %eax,-0xc(%ebp)
 17b:   6a 10                   push   $0x10
 17d:   ff 75 f4                pushl  -0xc(%ebp)
 180:   e8 fc ff ff ff          call   181 <printf+0xc6>
 185:   83 c4 08                add    $0x8,%esp
 188:   eb 5a                   jmp    1e4 <printf+0x129>
 18a:   6a 25                   push   $0x25
 18c:   e8 fc ff ff ff          call   18d <printf+0xd2>
 191:   83 c4 04                add    $0x4,%esp
 194:   eb 4e                   jmp    1e4 <printf+0x129>
 196:   8b 45 ec                mov    -0x14(%ebp),%eax
 199:   8d 50 04                lea    0x4(%eax),%edx
 19c:   89 55 ec                mov    %edx,-0x14(%ebp)
 19f:   8b 00                   mov    (%eax),%eax
 1a1:   89 45 fc                mov    %eax,-0x4(%ebp)
 1a4:   8b 45 fc                mov    -0x4(%ebp),%eax
 1a7:   0f be c0                movsbl %al,%eax
 1aa:   50                      push   %eax
 1ab:   e8 fc ff ff ff          call   1ac <printf+0xf1>
 1b0:   83 c4 04                add    $0x4,%esp
 1b3:   90                      nop
 1b4:   eb 2e                   jmp    1e4 <printf+0x129>
 1b6:   6a 25                   push   $0x25
 1b8:   e8 fc ff ff ff          call   1b9 <printf+0xfe>
 1bd:   83 c4 04                add    $0x4,%esp
 1c0:   8b 45 08                mov    0x8(%ebp),%eax
 1c3:   8a 00                   mov    (%eax),%al
 1c5:   0f be c0                movsbl %al,%eax
 1c8:   50                      push   %eax
 1c9:   e8 fc ff ff ff          call   1ca <printf+0x10f>
 1ce:   83 c4 04                add    $0x4,%esp
 1d1:   eb 11                   jmp    1e4 <printf+0x129>
 1d3:   8b 45 08                mov    0x8(%ebp),%eax
 1d6:   8a 00                   mov    (%eax),%al
 1d8:   0f be c0                movsbl %al,%eax
 1db:   50                      push   %eax
 1dc:   e8 fc ff ff ff          call   1dd <printf+0x122>
 1e1:   83 c4 04                add    $0x4,%esp
 1e4:   ff 45 08                incl   0x8(%ebp)
 1e7:   8b 45 08                mov    0x8(%ebp),%eax
 1ea:   8a 00                   mov    (%eax),%al
 1ec:   84 c0                   test   %al,%al
 1ee:   0f 85 df fe ff ff       jne    d3 <printf+0x18>
 1f4:   eb 01                   jmp    1f7 <printf+0x13c>
 1f6:   90                      nop
 1f7:   8b 45 f8                mov    -0x8(%ebp),%eax
 1fa:   c9                      leave
 1fb:   c3                      ret

000001fc <eventHandler>:
 1fc:   55                      push   %ebp
 1fd:   89 e5                   mov    %esp,%ebp
 1ff:   83 ec 10                sub    $0x10,%esp
 202:   83 7d 08 01             cmpl   $0x1,0x8(%ebp)
 206:   75 2f                   jne    237 <eventHandler+0x3b>
 208:   66 a1 28 00 00 00       mov    0x28,%ax
 20e:   66 89 45 fe             mov    %ax,-0x2(%ebp)
 212:   8b 45 0c                mov    0xc(%ebp),%eax
 215:   88 45 fe                mov    %al,-0x2(%ebp)
 218:   c6 45 ff 00             movb   $0x0,-0x1(%ebp)
 21c:   ba 07 00 00 00          mov    $0x7,%edx
 221:   8d 45 fe                lea    -0x2(%ebp),%eax
 224:   89 c6                   mov    %eax,%esi
 226:   b8 00 00 00 00          mov    $0x0,%eax
 22b:   bb 0a 00 00 00          mov    $0xa,%ebx
 230:   b9 05 00 00 00          mov    $0x5,%ecx
 235:   cd 30                   int    $0x30
 237:   c9                      leave
 238:   c3                      ret

00000239 <_start>:
 239:   55                      push   %ebp
 23a:   89 e5                   mov    %esp,%ebp
 23c:   b8 00 00 00 00          mov    $0x0,%eax
 241:   89 c2                   mov    %eax,%edx
 243:   b8 00 00 00 00          mov    $0x0,%eax
 248:   cd 31                   int    $0x31
 24a:   68 00 00 00 00          push   $0x0
 24f:   68 2c 00 00 00          push   $0x2c
 254:   e8 fc ff ff ff          call   255 <_start+0x1c>
 259:   83 c4 08                add    $0x8,%esp
 25c:   b8 00 00 00 00          mov    $0x0,%eax
 261:   c9                      leave
 262:   c3                      ret

Hab inzwischen noch eine printf funktion eingebaut, um die pointer zu vergleichen. Da hat komischerweise alles gestimmt ...

Danke für die Antwort
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 30. June 2010, 22:34
Ich hab jetzt in den Syscall, der für das Handler registrieren verantwortlich ist, noch 2 printf's eingebaut, um zu sehen,
ob die Speicheradresse aus dem Syscall richtig ankommt und ob die Variable currentEventHandler den neuen Wert bekommt.
Komischerweise stimmen alle 3 Werte überein  :? :? :?

Ich versteh nicht, warum der Handler nicht aufgerufen wird ...
Hier der Code aus der keyboard.c, der bei Tastatureingaben den aktuellen Handler aufruft:
if(currentEventHandler != NULL)
currentEventHandler(MESSAGE_KEYINPUT, kbdus[scancode]);
else
echoKeyboard(kbdus[scancode]);

MESSAGE_KEYINPUT ist mit 0x000001 definiert.
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: kevin am 30. June 2010, 23:13
Öhm, du willst den Handler aus dem Kernelcode heraus, also in Ring 0 aufrufen? Das scheint mir keine besonders schlaue Idee zu sein, schon allein aus Sicherheitsgründen. Und ist der Eventhandler überhaupt gemappt, wenn die Nachricht geschickt wird, während ein anderer Prozess aktiv ist?
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 30. June 2010, 23:19
bei mir läuft momentan alles noch im Ring 0, im Ring 3 ging das Multitasking irgendwie nicht ... da muss ich nochmal gucken.
Der Arbeitsspeicher ist bis jetzt auch an einem Stück, daran kann es also auch nicht liegen.
Mir ist jetzt noch eine andere Idee gekommen, nämlich in jedem Programm ein struct erstellen und die Adresse zu diesem Struct an den Kernel schicken.
Der Verändert dann die Werte. Das Programm läuft in einer Endlosschleife und überprüft immer, ob in dem struct was geändert wurde.
Wäre das vielleicht besser?
Wäre später auf jeden Fall kein Handler im Ring 0
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 01. July 2010, 18:23
Hallo,


Das Programm läuft in einer Endlosschleife und überprüft immer, ob in dem struct was geändert wurde.
Wäre das vielleicht besser?
Also Busy-Waiting, das würde ich als noch unsinniger als einen Event-Handler im Ring0 betrachten.

Das abschicken von Nachrichten ist für gewöhnlich kein Problem aber das Empfangen dagegen schon. Da gibt es im wesentlichen 2 Möglichkeiten: einmal aktives Abholen (z.B. getMyNextMessage() mit oder ohne Time-Out) und zum anderen das Empfänger-Programm unterbrechen (so wie klassische Unix-Signal-Handler). Beides hat einige Nachteile. Beim aktiven Abholen muss der Empfänger sich absichtlich für das Empfangen von Messages bereit machen, was natürlich nicht immer geht und daher Messages nicht gleich verarbeitet werden können. Dafür ist diese Lösung mMn jene die sich am leichtesten Implementieren lässt, wenn man die Daten 2 mal kopiert und im Kernel zwischenspeichert. Dazu benötigt man zwar im Kernel etwas (oder sehr viel) Speicher aber man bekommt ein relativ sicheres System. Das mit dem Unterbrechen scheint zwar auf den ersten Blick deutlich schneller zu arbeiten hat aber auch ne ganze Menge unangenehmer Nebenwirkungen (so eine Unterbrechung könnte z.B. in einem kritischen Moment passieren wo die libc gerade an der Heap-Verwaltung arbeitet), die tyndur-Leute können darüber viel trauriges erzählen.
Du kannst Dir also überlegen welches wohl das kleinere Übel ist oder versuchen einen besseren Weg zu finden. ;)

Eine andere Frage sollte auch noch bearbeitet werden: möchtest Du synchrone oder asynchrone Messages?
Bei den Synchronen wartet der Sender solange bis der Empfänger die passende Antwort zurückschickt und das OS kümmert sich darum das jede Antwort auch den richtigen Prozess erreicht, das macht das Handling in den Programmen um einiges einfacher aber der Sender blockiert eben auch so lange bis seine Anfrage bearbeitet ist. Bei den asynchronen Messages schickt einfach ein Programm einem anderen eine Nachricht und das wars, wenn da zwischen mehreren Nachrichten ein Zusammenhang hergestellt werden soll (als eine konkrete Antwort der zugehörigen Anfrage zugeordnet werden soll) ist dass das Problem der Programme, sowas lässt sich auch nur sehr schwer gegen absichtliche Manipulationen durch dritte Programme absichern (mMn für ein General-Purpose-OS ein absolutes KO-Kriterium). Die meiste Kommunikation in einem Micro-Kernel-OS ist klassisches RPC (http://de.wikipedia.org/wiki/Remote_Procedure_Call) (open/close/read/write und da will man immer einen zugehörigen Rückgabewert, also eine Antwort vom ausführenden Service, haben und wartet auch gerne darauf) und das geht am einfachsten/besten/sichersten mit synchronen Messages, sieh Dir dazu mal die Konzepte (und die dazugehörigen Gründe) an die im L4-Micro-Kernel umgesetzt wurden. Es gibt aber auch Situationen in denen asynchrone Messages kaum zu ersetzen sind, z.B. wenn der Kernel an einen Treiber-Prozess einen IRQ als asynchrone Message schickt, der Kernel wird ja wohl nicht warten wollen bis der Treiber mit seiner Hardware gequatscht hat.
Im Endeffekt wirst Du für ein ordentliches, stabiles und schnelles Micro-Kernel-OS beides benötigen, synchrone und asynchrone Messages.


Grüße
Erik

PS. falls Du kein Micro-Kernel-OS programmierst kannst Du meinen Beitrag ignorieren.
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: MNemo am 01. July 2010, 19:31
Hi,

ich hoffe ich habe jetzt nichts übersehen, hab die posts nur mal übelflogen.

1. bei mir würde dein asm-code so aussehen:

asm volatile ("int $49" :: "a" (0x00), "d" ((void*)eventHandler));das kann gcc besser optimieren,

2. das im objdump edx mit 0 belegt wird liegt wohl daran dass du das noch nicht durch den linker hast laufen lassen, der die Null durch die Adresse von eventHandler ersetzt.

3. es könnte nötig sein dein currentEventHandler als volatile zu deklarieren weil er durch einen Interrupt verändert wird, also für gcc an völlig unvorhersehbaren stellen. (mit volatile zwingst du den Compiler die variable immer direkt aus dem Speicher zu lesen und in ihn zu schreiben)
 
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 01. July 2010, 21:16
erstmal danke für die antworten.
@erik eigentlich soll es ja ein monolithischer Kernel werden, wobei Treiber als Modul geladen werden, aber im Ring 0 laufen.

@MNemo
1. ich probier das jetzt mal aus
2. upps, daran hab ich gar nicht gedacht

ich melde mich nochmal ob es geklappt hat.
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 01. July 2010, 21:31
wie deklariert man einen Funktionsprototypen als volatile?  :?
wenn ich void volatile (*currentEventHandler)(int message, long params) schreibe,
meckert er: warning: function return types not compatible due to 'volatile'

Edit: Ah, void (*volatile currentEventHandler)(blablabla), oder?
Wenn ja: geht trotzdem nicht
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: MNemo am 01. July 2010, 21:56
so müsste es lauten:
 volatile void (*currentEventHandler)(foo)


nee, dass ist doch richtig:
  void (* volatile currentEventHandler)(foo);
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 01. July 2010, 22:01
Hallo,


@erik eigentlich soll es ja ein monolithischer Kernel werden, wobei Treiber als Modul geladen werden, aber im Ring 0 laufen.
Warum machst Du Dir dann so einen Kopf wegen IPC (Inter-Process-Comunication)? Innerhalb eines Kernel kannst Du das Verbinden von Aufrufern mit ihrem Ziel dem (Runtime-)Linker überlassen.


Grüße
Erik
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 01. July 2010, 22:05
Der Kernel muss doch trotzdem mit normalen Programmen 'reden' können?
Oder hab ich da was falsch verstanden? Das soll gerade ein normales Programm werden, kein Treiber
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 01. July 2010, 22:14
Hallo,

Der Kernel muss doch trotzdem mit normalen Programmen 'reden' können?
Dazu gibt es die Syscalls. Man kann zwar über die Syscalls auch IPC zu Verfügung stellen aber ansonsten haben diese 2 Konzepte kaum was gemeinsam.
Und wenn der Kernel was von den Programmen will (was bei einem Monolithen eher selten ist) dann läuft das auf das selbe Problem wie mit dem Abholen von Messages raus (explizites Abholen vs. Unterbrechen vs. ganz-was-anderes).


Grüße
Erik
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 01. July 2010, 22:19
Momentan sollen die Nachrichten vom Kernel an's Programm über diesen Handler geschickt werden. Damit weiß das Programm bescheid, dass es Nachrichten hat und kann sie bearbeiten, wenn Zeit dafür ist.
Dadurch muss das Programm nicht dauernd fragen "hab ich Post?" und wird auch nicht unterbrochen.
Was das Programm mit den Nachrichten macht, kann es selber entscheiden. Es kann sagen, behandle ich jetzt sofort oder eben jetzt nicht, später.

Wenn ich irgendetwas komplett falsch verstanden habe, bitte bescheid sagen. :|
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: Svenska am 02. July 2010, 01:45
Naja, die Arbeit geht vom Programm aus, nie vom Kernel. Das heißt, dass das Programm immer eine Anfrage an den Kernel richtet (via Syscall) und ein Ergebnis zurückbekommt. Im einfachsten Falle ist dies blockierend, d.h. das Programm wartet, bis der Kernel die Antwort parat hat. Alternativ gibt es nicht-blockierende Syscalls, die dann später die Antworten zurückliefern.

Persönlich finde ich Callback-Funktionen ungünstig, da sie die Anwendungsentwicklung erschweren (asynchroner Programmfluss). Ein synchroner Ablauf sollte immer möglich sein.

Vergleiche mit den Syscalls einfach DOS: Anwendung setzt Register, ruft den Interrupt 21h auf, der tut irgendwas, setzt die Register und dann das Programm fort. Das Ergebnis des Syscalls kann direkt gelesen werden und die Aktion ist erfüllt - also eine blockierende Schnittstelle. Man kann es natürlich auch anders aufbauen, aber Interrupts sind eine Möglichkeit.

Wenn man nicht möchte, dass das Programm bis zum Abschluss des Syscalls steht, kann man einerseits die Syscalls auch nicht-blockierend bauen oder auf Multithreading setzen (ein Thread steht, die anderen laufen weiter). Beides ist aber aufwändiger.

Ein ereignisbasierendes System, wie du es gerade aufbaust, bringt an der Stelle nur wenig. In Unix-Systemen läuft die GUI etwa so ab, dass du ein Socket/Dateideskriptor nutzt und von diesem in einer Endlosschleife liest. Der Lesevorgang wartet, bis etwas geschieht (Maus bewegt, ...) und das wird dann behandelt. Die Verarbeitung läuft in einem anderen Thread ab; in Ereignisse konvertieren ist dann in der Anwendung möglich, wenn man das wünscht:

while(true)
{
  read(events, &buf);
  ping_worker_thread(&buf);
}

Gruß,
Svenska
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 02. July 2010, 09:44
also mach ich das jetzt ungefähr so:
int main()
{
// initialisierung des programs
bool is_running = true;
MESSAGE message;
while(is_running)
{
message = get_message();
do_something_with_the_message(message);
}
die funktionen sind in der SDK deklariert.

Ist es so in ordnung?
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 02. July 2010, 10:25
Hallo,


Momentan sollen die Nachrichten vom Kernel an's Programm über diesen Handler geschickt werden.
Also wird der aktuelle Programmfluss unterbrochen und der Handler im aktuellen Kontext wie eine Unterfunktion ausgeführt, im Prinzip das selbe wie bei einem IRQ. Das kann man machen, es vermittelt auch den subjektiven Eindruck einer hohen Geschwindigkeit und geringen Latenz weil die Message sofort bearbeitet wird und nicht erst dann wenn das Programm mal wieder aktiv nach neuen Messages fragt. Aber der Message-Handler hat auch die selben Probleme wie ein IRQ-Handler, alle Mechanismen die durch einen IRQ unterbrochen werden können kann der IRQ-Handler selber nicht benutzen, denn die könnten ja in einem kritischen/inkonsistenten Zustand sein wenn der IRQ kommt. Wenn Dein Message-Handler also malloc benutzen können soll dann muss innerhalb von malloc (und free usw.) das Handler-Aufrufen gesperrt werden (ähnlich dem sperren von IRQs). Das hat eine ganze Menge Nebenwirkungen. Eine davon ist das wenn der Kernel selber eine Message schicken können soll das dann der Kernel in der Lage sein muss seinen aktuellen Zustand zu sichern/unterbrechen und erstmal das Programm weiterlaufen zu lassen damit es eine solche verbotene Zone wieder verlassen kann (auf einem Multi-Core-System ginge es vielleicht das der Kernel einfach wartet aber toll ist das auch nicht). Wenn es im Kontext des Kernels nicht eigenständige unterbrechbare Threads gibt dürfte das nur mit sehr viel Aufwand umsetzbar sein. Für mein System hab ich mir daher ein Konzept ausgedacht wie es (fast) immer möglich ist einen solchen Handler aufzurufen ohne dass das Programm dadurch behindert wird.

Damit weiß das Programm bescheid, dass es Nachrichten hat und kann sie bearbeiten, wenn Zeit dafür ist.
Dieses "weiß bescheid" mus das Programm aber auch erst erfragen (z.B. auf ein Flag pollen) und damit ist das Konzept IMHO nicht viel besser als wenn das Programm gleich einen Syscall HabIchNeMessageDannGibMirDieGleichAnsonstenWarteNicht() aufruft.

und wird auch nicht unterbrochen.
Wenn der Kernel selbstständig im Kontext eines Programms einen Handler aufrufen soll dann wird das Programm dafür (kurz) unterbrochen.


Naja, die Arbeit geht vom Programm aus, nie vom Kernel.
Das trifft nicht immer zu, es gibt auch Dinge die immer vom Kernel ausgehen, könnten bei einem Monolithen eventuell sogar mehr sein als bei einem Micro-Kernel.

Alternativ gibt es nicht-blockierende Syscalls, die dann später die Antworten zurückliefern.
Das bedeutet dass das Programm mehrere Syscalls benötigt, einen um den Job beim Kernel zu starten und einen anderen um nach dem Ergebnis zu fragen. Der zweite Syscall könnte oft sogar mehrmals benötigt werden falls der Job eben noch nicht fertig ist.

Persönlich finde ich Callback-Funktionen ungünstig, da sie die Anwendungsentwicklung erschweren (asynchroner Programmfluss). Ein synchroner Ablauf sollte immer möglich sein.
Das stimmt zwar aber die meisten Ereignisse entstehen asynchron (Tastatur-Events, empfangene Netzwerk-Pakete usw.), wenn man maximale Performance (bei vertretbarer CPU-Last) möchte kommt man um eine asynchrone Ereignisbehandlung kaum herum.


Grüße
Erik
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 02. July 2010, 11:04
die idee mit dem handler hab ich wirklich von den IRQs übernommen ;)
man hätte man ja auch so machen können, dass eine variable wie bool has_message auf true gesetzt wird.

hab ich dich richtig verstanden, dass mein beispiel oben besser ist?
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 02. July 2010, 13:34
Hallo,


man hätte man ja auch so machen können, dass eine variable wie bool has_message auf true gesetzt wird.
Du meinst der Message-Handler setzt nur eine einzelne Variable und das Programm muss pollen? Wo ist da der Vorteil gegenüber einem Syscall "HabIchNeMessageDannGibMirDieGleichAnsonstenWarteNicht()"? Okay der Syscall benötigt etwas mehr CPU-Takte aber das Prinzip ist exakt das selbe.

hab ich dich richtig verstanden, dass mein beispiel oben besser ist?
Du meinst das von heute Früh 8:44? Das ist ungefähr die einfachste Lösung. Die kann man am schnellsten implementieren, bietet nur sehr wenig Fehlerpotential und ist für einen Monolithen erstmal recht brauchbar. Das Problem ist wie wartest Du auf mehrere verschiedene Events? Ein HTTP-Server mit sehr vielen gleichzeitig zu bearbeitenden Anfragen wird wohl kaum für jede TCP-Connection einen eigenen Thread starten (das geht zwar macht man aber nur bei Servern die nur wenig belastet sind). In der Win-API gibts dafür WaitForMultipleObject(), das stellt eine recht brauchbare Lösung für das Problem dar bis Du auf einer Multi-Core-Maschine auf die Idee kommst für jede CPU einen eigenen Thread starten zu wollen wo dann alle gleichzeitig WaitForMultipleObject() aufrufen wollen, auch das ist lösbar aber Du verstehst bestimmt was ich meine.

Für eine ordentliche Lösung muss man schon ziemlich tief in die Trickkiste greifen. Du solltest also erst mal überlegen was eigentlich Dein Ziel ist und dann prüfen welchen Aufwand Du bereit bist dafür zu investieren.


Grüße
Erik
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 02. July 2010, 14:12
momentan werd ich  wohl für alles die einfachste Lösung nehmen.
Was ich dann später mache, weiß ich noch nicht.

mit dem Handler hätte es einen winzigsten Geschwindigkeitsvorteil gebracht, weil das Programm nur Nachrichten abruft, wenn welche da sind.

Ich werde jetzt
int main()
{
// initialisierung des programs
bool is_running = true;
MESSAGE message;
while(is_running)
{
message = get_message();
do_something_with_the_message(message);
}
diese lösung nehmen.

Danke an alle für die Hilfe.
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: Svenska am 02. July 2010, 14:31
Hallo,

Naja, die Arbeit geht vom Programm aus, nie vom Kernel.
Das trifft nicht immer zu, es gibt auch Dinge die immer vom Kernel ausgehen, könnten bei einem Monolithen eventuell sogar mehr sein als bei einem Micro-Kernel.
Hier ging es aber um die Kommunikation zwischen Kernel und Userland. Sachen, die vom Kernel ausgehen, bleiben meist auch da drin. Bei einem Mikrokernel - wenn z.B. die Tastatur etwas raushaut und die Speicherverwaltung reagieren muss - ist das etwas anderes, aber dort bleibt es trotzdem "im" Kernel.

Ich sehe bei Callback-Funktionen immer das Problem des Programmabsturzes, wenn der Handler nicht mehr existiert aber noch registriert ist. Dann hast du nämlich ein Problem. (In einem Mikrokernel ist das relativ egal, wenn die Speicherverwaltung abstürzt, ist das System eh im Popöchen.)

Alternativ gibt es nicht-blockierende Syscalls, die dann später die Antworten zurückliefern.
Das bedeutet dass das Programm mehrere Syscalls benötigt, einen um den Job beim Kernel zu starten und einen anderen um nach dem Ergebnis zu fragen. Der zweite Syscall könnte oft sogar mehrmals benötigt werden falls der Job eben noch nicht fertig ist.
Ich sehe kein Problem darin.

read() muss ja nicht blocken und liefert dann -EAGAIN zurück. Blockierendes Verhalten wird immer dann schwierig, wenn man quasiparalleles, asynchrones Verhalten in nur einem Thread erzeugen möchte, aus welchen Gründen auch immer. Aber als Haupt-API würde ich nie ein Callback-Verhalten verwenden.

Persönlich finde ich Callback-Funktionen ungünstig, da sie die Anwendungsentwicklung erschweren (asynchroner Programmfluss). Ein synchroner Ablauf sollte immer möglich sein.
Das stimmt zwar aber die meisten Ereignisse entstehen asynchron (Tastatur-Events, empfangene Netzwerk-Pakete usw.), wenn man maximale Performance (bei vertretbarer CPU-Last) möchte kommt man um eine asynchrone Ereignisbehandlung kaum herum.
Und? Die kann man doch ganz einfach simulieren, man nehme einen Thread der nur poll() oder WaitForSomething() aufruft - ohne Ereignisse muss der ja nichtmal gestartet werden - und bei einem Ereignis eine Funktion in einem anderen Thread aufruft. Das ist die gleiche Last wie mit Callbackhandler, aber so wird die Asynchronität nicht erzwungen.

Grüßle
Titel: Re:IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 02. July 2010, 19:03
Hallo,


momentan werd ich wohl für alles die einfachste Lösung nehmen.
Was ich dann später mache, weiß ich noch nicht.
Falls Du Dir bis zu dem "später" nicht schon mit der existierenden Code-Basis andere Wege verbaut hast. Erst mal ein Provisorium zu entwickeln um dann später auf was besseres umzusteigen ist nicht nur doppelte Arbeit sondern oft auch nur sehr schwer umsetzbar. Du kennst http://www.scheissprojekt.de/hausbau.html (http://www.scheissprojekt.de/hausbau.html)? Ich hab schon mehrmals an Projekten in dieser Art mitmachen dürfen, da ist nie was gescheites bei raus gekommen (ich hab mich auch immer nach Kräften bemüht sowas schnellst möglich zu verlassen). Ich fange erst dann an mein OS zu coden wenn ich wenigstens einen guten Grobplan habe, klar laufe ich in die Gefahr das ich später bei den Details feststelle das mein Grobplan Mist ist und fange dann unter Umständen noch man ganz von vorne an, aber "No Risk - No Fun" und einen richtig tiefen Griff ins Klo hab ich persönlich noch nicht verursacht (bis jetzt zumindest).


Hier ging es aber um die Kommunikation zwischen Kernel und Userland.
Wenn der TCP-Socket (im monolithischen Kernel) einer wartenden Applikation die frisch eingetroffenen Daten überreichen will dann geht das IMHO schon vom Kernel ins Userland, der Tastatur-Treiber und viele andere mehr müssen einen ähnlichen Weg nutzen. Bei einem Micro-Kernel gehen nur die IRQs (und ein paar seltene Spezial-Sachen) vom Kernel ins Userland, alles andere ist User-2-User-Kommunikation.

Sachen, die vom Kernel ausgehen, bleiben meist auch da drin.
Dann würde der Computer "meist" nichts tun wenn irgend ein Ereignis anliegt. ;)

Ich sehe bei Callback-Funktionen immer das Problem des Programmabsturzes,
Das sehe ich ähnlich, da muss man schon recht gründlich vorgehen um da keine Stolperfallen zu bauen. Sowas meinte ich mit dem "deutlich" tieferen Griff in die Trickkiste.

.... Der zweite Syscall könnte oft sogar mehrmals benötigt werden falls der Job eben noch nicht fertig ist.
Ich sehe kein Problem darin.
Ich sehe da auch kein Problem, ich wollte diesen Umstand nur ansprechen, er kostet ein ganz klein wenig der kostbaren CPU-Zeit.

... wenn man quasiparalleles, asynchrones Verhalten in nur einem Thread erzeugen möchte
Das ist ja auch eine Kunst für sich, sowas sollte man immer vermeiden wenn es irgend möglich ist.

Aber als Haupt-API würde ich nie ein Callback-Verhalten verwenden.
Warum? Genau das habe ich in meinem OS vor.

.... wenn man maximale Performance (bei vertretbarer CPU-Last) möchte kommt man um eine asynchrone Ereignisbehandlung kaum herum.
Und? Die kann man doch ganz einfach simulieren ....
Mir ist klar das man mit asynchronen Dinge synchrone simulieren kann und auch umgedreht, aber damit kommt man nicht auf "maximale Performance (bei vertretbarer CPU-Last)". Wenn man ein annähernd optimales Ergebnis will dann muss man auch das passende Werkzeug benutzen, ansonsten kommt man zwar auch oft ins Ziel aber eben nicht mit dem Spitzenfeld sondern in der Nachzüglergruppe. Bitte nicht falsch verstehen, ich will hier keinen unnützen Effizienz-Wettbewerb starten. Aber man muss sich eben vorher überlegen was man eigentlich erwartet, ob man überhaupt ins Ziel will oder ob man auch einen der vorderen Plätze anstrebt.

und bei einem Ereignis eine Funktion in einem anderen Thread aufruft.
Wie ruft man denn Bitte eine Funktion in einem anderen Thread auf?


Grüße
Erik
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 02. July 2010, 19:57
 :| :| :|
inzwischen habe ich mich entschieden, nochmal komplett von vorne anzufangen, da mein Sourcecode etwas (sehr ;)) unübersichtlich ist. Bis jetzt hab ich alles programmiert, wie dieses Haus gebaut wurde. :oops:

Es ist nur Schade, weil ich schon Grafiktreiber, Maustreiber, GDT, IDT, Tastaturtreiber usw. fertig hatte.

Was empfehlt ihr mir den jetzt für die Nachrichten? Bis jetzt kamen ja immer nur Nachteile von beiden ;)
Kann man auch beides gleichzeitig verwenden?

Naja, ich werd mich dann jetzt erstmal wieder an die GDT setzen, trotzdem Danke für die Hilfe.

EDIT: was mir gerade aufgefallen ist, wird bei euch die IP-Adresse 127.0.0.1 gespeichert?!?
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 02. July 2010, 20:26
Hallo,


inzwischen habe ich mich entschieden, nochmal komplett von vorne anzufangen
Ich hoffe das ist nicht meine Schuld, ich möchte wirklich nicht das andere Leute ihre wertvolle Arbeit wegwerfen nur weil ich mal wieder etwas zu überspitzt geschrieben habe.

Bis jetzt hab ich alles programmiert, wie dieses Haus gebaut wurde.
Dann versuche wenigstens aus deinen Fehlern zu lernen. Ich habe am Anfang meiner Programmiererei auch etliche Fehler gemacht (auch heute bin ich längst nicht perfekt und werde das mit Sicherheit auch nie sein), so wie sicher jeder hier. ;)

Was empfehlt ihr mir den jetzt für die Nachrichten? Bis jetzt kamen ja immer nur Nachteile von beiden ;)
Kann man auch beides gleichzeitig verwenden?
Du kannst natürlich beide Services parallel anbieten. Die Frage ist ob Du sowas bei einem Monolithen wirklich dringend benötigst. Fürs erste sollte es reichen wenn Deine Syscalls überwiegend blockierend arbeiten (so wie DOS), damit kommen die meisten Programme ganz gut zurecht. Wenn Du dann später was besseres dazu haben möchtest kannst Du dann (wenn es so weit ist) immer noch die konkreten Anforderungen analysieren.

Mit ein bisschen Weitsicht und Bedacht sollte es gut möglich sein auch später noch grundsätzlich neue Features zu integrieren. Leider braucht man dafür auch einiges an Erfahrung und die bekommt man nur in der Praxis also musst Du erst mal irgendwie anfangen um wenigstens vom Fleck zu kommen. Ich programmiere jetzt seit fast 20 Jahren, da fällt es leicht über "Weitsicht und Bedacht" zu lamentieren, aber Du darfst Dir sicher sein mein Anfang war auch ziemlich hart.

Das entscheidende bei den ersten Schritten ist nicht ob Du auf der Nase landest oder wie weit Du kommst, sondern ob Du was lernst!

was mir gerade aufgefallen ist, wird bei euch die IP-Adresse 127.0.0.1 gespeichert?!?
Was genau meinst Du damit?


Grüße
Erik
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Svenska am 02. July 2010, 20:33
Wenn der TCP-Stack einer wartenden Applikation etwas mitteilen möchte, handelt es sich um eine Antwort auf eine von der Anwendung ausgehende Anfrage - sonst würde sie nicht warten.

Sachen, die vom Kernel ausgehen, bleiben da auch meistens drin - die Anwendung holt sich ihre Keystrokes etc. ja von dort ab. Im Extremfall (Callback) hat sie vorher halt Interesse angemeldet. Der Kernel schickt den Anwendungen niemals ungefragt etwas - davon stürzen die in der Regel ab.

Wenn ich eine Funktion in einem anderen Thread aufrufe, dann ist das quasi ein Callback. Zwischen Threads geht das mMn auch, weil die Anwendung ja zwangsweise darauf ausgelegt sein muss; als Haupt-API würde ich es wegen der komplzierten Verwendung nicht benutzen.

Oder, um es mit Fefe auszudrücken: Wenn eine API falsch zu bedienen leichter ist, als sie richtig zu bedienen, dann taugt sie nichts. Und Callback-Funktionen in jeder Lebenslage korrekt zu bedienen halte ich für schwierig.

Ein Thread, welcher in einer Endlosschleife Ereignisse abfragt und dann ein Callback aufruft ist nicht wesentlich langsamer, als ein Kernel, der diesen Callbackaufruf selbst tut. Zumal ein Threadwechsel keinen vollständigen Speicherkontext voraussetzt. Ein asynchrones Verhalten im Gegenzug synchronisieren halte ich für aufwändig, zumindest fällt mir kein schneller Weg dafür ein.

Gruß,
Svenska,
der jetzt wieder rausgeht und weitergrillt. :-P
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 02. July 2010, 20:45
Ich hoffe das ist nicht meine Schuld
Ne, ist es nicht, kannst dir meine main.h ja mal angucken: http://lf-os.googlecode.com/svn/trunk/main.h (http://lf-os.googlecode.com/svn/trunk/main.h)
Das ist wirklich das blanke Chaos (wer braucht schon mehrere Header Dateien  :-P)

Also das Endergebnis ist, dass der Kernel nie etwas an die programme schicken sollte, außer in Ausnahmefällen (Runterfahren ...)??

was mir gerade aufgefallen ist, wird bei euch die IP-Adresse 127.0.0.1 gespeichert?!?
Was genau meinst Du damit?
Hier im Forum wird doch die IP Adresse gespeichert, wenn man einen Beitrag erstellt (unter dem Beitrag rechts, man sieht nur die eigenen).
Bei mir wird da 127.0.0.1 gespeichert, was ja localhost wäre :D

Achja, GDT und IDT hab ich schon gemeistert ;)
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Svenska am 03. July 2010, 02:34
Bei mir wird auch nur 127.0.0.1 angezeigt - was gespeichert wird, mag vielleicht noch was anderes sein (bezweifel ich aber).

Ich würde das Endergebnis so umformulieren: Der Kernel schickt nie etwas an unvorbereitete(!) Programme. Also quasi ohne Anforderung von diesen. Signale sind da eine Ausnahme und werden zumindest unter Unix auch so behandelt. Mit der WinAPI kenne ich mich allerdings nicht aus, nur, dass sie stellenweise ähnlich (Sockets) und stellenweise völlig anders (ereignisbasierte Callback-GUI) funktioniert. :-)

Gruß,
Svenska
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Programm Noob am 03. July 2010, 02:56
littlefox kannst du mir deinen jetztigen code bitte als zip bei rapidshare hochladen oder mir eine andere downloadquelle nennen. Ich würde mir den nämlich gerne mal ansehen. Vor allem, wie d das mit den treibern gemacht hast.

Programm Noob
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 03. July 2010, 09:21
reicht dir als Downloadquelle SVN?
http://lf-os.googlecode.com/svn/trunk (http://lf-os.googlecode.com/svn/trunk)

Die Treiber sind bei mir aber in den Kernel mit rein kompiliert.

EDIT:
Bei mir wird auch nur 127.0.0.1 angezeigt - was gespeichert wird, mag vielleicht noch was anderes sein (bezweifel ich aber).
Vor dem Update gings ;)

Also sollen sich die Programme alles was Sie brauchen selber beim Kernel erfragen. Sehe ich das richtig?
Wie werden die Signale bei den UNIXoiden den umgesetzt?
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Programm Noob am 03. July 2010, 12:08
Klar reicht SVN.
Meine Treiber sind momentan auch im Kernel. aber mir geht es drum wie du die aufrufst und wie du deinen VGA Treiber programmierst. Vielen Dank

Programm Noob
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: LittleFox am 03. July 2010, 12:14
wobei ich zugeben muss, dass ich den VGA Treiber auch gefunden habe :oops:
die primitives.c ist aber selbst geschrieben ;)

gefunden hab ich den VGA treiber hier:
http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c (http://files.osdev.org/mirrors/geezer/osd/graphics/modes.c)
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 03. July 2010, 13:57
Hallo,


Ich würde das Endergebnis so umformulieren: Der Kernel schickt nie etwas an unvorbereitete(!) Programme. Also quasi ohne Anforderung von diesen.
Dem kann ich ohne Einschränkungen zustimmen!
Das könnte man sogar auf ein Micro-Kernel-OS erweitern "Prozesse senden sich gegenseitig nur das was der Empfänger auch explizit erwartet". Ein Service ist für alle offen aber nur für bestimmte Anfragen und ein Client erwartet natürlich nur die zugehörigen Antworten auf seine Anfragen und ein Treiber bekommt vom Kernel auch nur die IRQ-Messages für die er sich registriert hat.

Signale sind da eine Ausnahme ...
Da der Prozess ja erst mal einen Signal-Handler registrieren muss bevor er was empfangen kann würde ich sagen das auch (UNIX-)Signale keine Ausnahme sind. Es könnte gut sein das die libc bei einem typischen *NIX sowas schon per Default immer tut und dann bloß das weitergibt was der User-Code tatsächlich will (über eine libc-API).


So wie ich das sehe gibt es genau 3 Möglichkeiten Daten vom monolithischen Kernel in eine User-Space-Applikation zu bekommen:


Wenn ich eine Funktion in einem anderen Thread aufrufe, dann ist das quasi ein Callback.
Das habe ich immer noch nicht verstanden. Wie ruft man eine Funktion in einem anderen Thread auf? Der Kernel kann den Thread unterbrechen und dort einen Signal-Handler aufrufen (eben wie die CPU bei einem IRQ) so als würde der unterbrochene Thread einen CALL machen, aber zwischen zwei Threads in einem User-Mode-Prozess geht das IMHO nicht.

als Haupt-API würde ich es wegen der komplzierten Verwendung nicht benutzen.
Das kann man ja hinter der libc verbergen und für ein einfaches (open/read/write/close) wird man sicher keine Call-Backs benutzen, da sind blockierende Syscalls (beim Monolithen) oder synchrones RPC (beim Micro-Kernel) deutlich besser, Call-Backs sind nur dann interessant wenn man mit wirklich vielen parallel Jobs arbeitet oder für die Bereitstellung von Services in der Personality von einem Micro-Kernel-OS.


Grüße
Erik
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Svenska am 03. July 2010, 14:24
Okay, mit den Signalen stimmt auch wieder.

Du hast irgendwo in deiner Auflistung das normale asynchrone I/O vergessen, wo also read()/write()/... zwar blockieren, aber es einen speziellen Syscall gibt, der vorher nachfragt, ob diese Syscalls blocken würden. Das heißt, der Programmfluss ist trotzdem synchron, aber es wird nicht gewartet. Das programmiert sich leichter. Beispiele dafür sind select(), poll(), epoll (Linux) und kqueue (*BSD). Als Grund-API hast du dann also nur blockierende Syscalls, kannst damit aber trotzdem recht einfach asynchrones I/O starten.

Dann brauchst du nicht für jede Anfrage einen Thread, was nicht skaliert, hast aber die Freiheit, beliebig viele Worker-Threads zu verwenden. Ein Thread, der im Prinzip nur auf Ereignisse wartet und dann beliebig verteilt.

Was die Threads angeht, da diese ja in einem gemeinsamen Speicherkontext laufen, müsste man da eigentlich auch einfach hinspringen können - ich dachte da eher an ein Syscall in den Kernel (bzw. die libc), welche den anderen Thread beeinflusst.

Gruß,
Svenska
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: kevin am 03. July 2010, 14:58
select() usw. dürften Eriks Option 2 entsprechen.

Und asynchrones I/O ist das strenggenommen auch nicht: Du blockierst zwar nicht, wenn es nichts zu lesen gibt, aber wenn du dann mal das read() startest, läuft das eigentliche Lesen synchron ab. Dürfte bei Sockets natürlich in der Praxis nicht wirklich einen Unterschied machen, weil es wenig genug Daten sind, die außerdem nur im Speicher ein bisschen hin- und hergeschoben werden; und beim Zugriff auf normale Dateien ergibt select() nicht besonders viel Sinn.
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 03. July 2010, 18:36
Hallo,


... wo also read()/write()/... zwar blockieren, aber es einen speziellen Syscall gibt, der vorher nachfragt, ob diese Syscalls blocken würden.
Das ist asynchrones I/O, man initiiert einen Job und prüft dann ob schon Daten da sind damit man beim abholen eben nicht blockiert. Das ist ganz klar Option 2.

select() usw. dürften Eriks Option 2 entsprechen.
Sicher? Gibt es zu dem select() irgendwo eine verständliche Dokumentation? Ich hab leider nichts brauchbares gefunden.


Was die Threads angeht, da diese ja in einem gemeinsamen Speicherkontext laufen, müsste man da eigentlich auch einfach hinspringen können
Nur weil sich zwei Threads einen gemeinsamen Speicherkontext teilen ist der Gesamt-Kontext, dazu gehören die Register genauso wie der Stack, nicht gleich identisch. Man kann nicht mit einem CALL oder vergleichbares eine Funktion im Kontext eines anderen Threads aufrufen.

ich dachte da eher an ein Syscall in den Kernel (bzw. die libc), welche den anderen Thread beeinflusst.
So wie bei den (UNIX-)Signalen? Das würde ich meinen Worker-Threads nicht antun wollen, die sind mit ihrem letzten Job eventuell noch nicht fertig.


Grüße
Erik
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: kevin am 03. July 2010, 19:11
select() ist genau diese Funktion, die vorher prüft, ob read blockieren würde. select funktioniert so, dass du drei verschiedene fd_sets (also Mengen von Filedeskriptoren) angibst: Einmal für lesen, einmal für schreiben und einmal für Fehler. select() wirft dann diejenigen Deskriptoren raus, die nicht bereit sind zum lesen/schreiben bzw. die keinen Fehler haben. Wenn keiner der Filedeskriptoren bereit ist, blockiert select. Für das Blockieren gibt es nochmal einen Parameter, das einen Timeout angibt.

Und nein, es ist nicht asynchrones I/O, weil die Übertragung der Daten (also das eigentliche read/write) nicht im Hintergrund abläuft.
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 03. July 2010, 23:21
Hallo,


select() ist genau diese Funktion, die vorher prüft, ...
Ahja, jetzt bin ich wieder etwas schlauer, Danke. Warum können andere Dokus nicht auch erst mal mit so einem kompakten Dreizeiler anfangen anstatt gleich mit Details um sich zu werfen so das man keine Chance hat das grobe Ganze zu erkennen? (darüber wie ich das in einer libc umsetzen kann will ich jetzt lieber noch nicht nachdenken)

Und nein, es ist nicht asynchrones I/O, weil die Übertragung der Daten (also das eigentliche read/write) nicht im Hintergrund abläuft.
Ich würde schon sagen das es sich dabei um asynchrones I/O handelt, auch wenn es nicht ganz der Definition entspricht. Für TCP betrachtet übertragen read und write doch nur zwischen einem User-Puffer und einem Kernel-Puffer (simples memcpy bei einem Monolithen) die eigentliche Datenübertragung von/nach draußen passiert dann doch echt asynchron. Bei Dateien muss man natürlich trotzdem warten bis die HDD die Daten gelesen/geschrieben hat (wenn wir mal SW-Caches außer acht lassen) aber da macht select() auch nur extrem wenig Sinn. Der einzigst verbleibende Unterschied ist das bei richtigem asynchronem I/O auch das memcpy asynchron im Hintergrund abläuft, das kann natürlich ein paar Auswirkungen für das Programm haben.
Vielleicht können wir uns auf "fast asynchrones I/O" einigen? ;)
Das select() ist auf jeden Fall unendlich viel dichter an Option 2 als an Option 1. (da fällt mir auf es gibt hier keine nummerierten Aufzählungen, dafür ne Menge unnützer Firlefanz)


Grüße
Erik
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Svenska am 04. July 2010, 03:56
Wenn du Dateizugriffe multiplexen willst, kann es schon sinnvoll sein; beispielsweise liest du von einer modernen SSD mit ordentlich Datenrate und einer antiken Festplatte je ein GB. Für Schreiben gilt entsprechendes, für Sockets ebenfalls.

Während die alte Platte nicht hinterherkommt, blockt dein Programm - der Programmfluss ist synchron. Also lässt du besser immer nur ein paar Blöcke lesen (bzw. rufst ein readahead() auf, welches nicht blockiert) und wartest, bis die Daten gelesen sind, ehe du dann dein richtiges read() aufrufst. In dem Moment stört das nicht weiter, da dein readahead() garantiert, dass die Daten im Plattencache liegen und das read() nur zu einem memcpy() verkommt. Im Allgemeinen ist das nämlich nicht der Fall. Bei Sockets ist das noch schlimmer, weil die Geschwindigkeiten viel geringer sind.

Die Erweiterungen (select() und poll() sind umständlich zu handhaben und können allein von der API her nicht besser als linear skalieren) bezeichnet man als High-Performance AIO (asynchrones I/O), daher würde ich select()/poll() ebenfalls dem AIO zuordnen, obwohl der Programmfluss eines solchen Programms synchron ist. Übrigens skaliert unter Linux ein fork()-basierter Webserver besser als ein auf poll() basierender... vgl. Fefe :-)

Gruß,
Sebastian
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: kevin am 04. July 2010, 10:28
Hm, mit readahead habe ich noch nicht gemacht, aber bist du dir sicher? Die Manpage sagt nämlich:

Zitat von: Linux Programmer's Manual: readahead(2)
readahead() blocks until the specified data has been read.
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: erik.vikinger am 04. July 2010, 12:07
Hallo,


Wenn du Dateizugriffe multiplexen willst, kann es schon sinnvoll sein; beispielsweise liest du von einer modernen SSD mit ordentlich Datenrate und einer antiken Festplatte je ein GB. Für Schreiben gilt entsprechendes, für Sockets ebenfalls.
Das ist dann aber klassisches asynchrones I/O, man initiierst mehrere Jobs und schaut wie weit die jeweils sind um immer an der wichtigsten Stelle (non-blocking) zu arbeiten. Aber gerade dieses select() würde im Szenario mit den Dateien von unterschiedlich schnellen HDDs nichts helfen, wenn ich das richtig verstanden habe prüft select() nur ob noch Bytes da sind (was bei Dateien wo der aktuelle File-Pointer noch nicht am Ende der Datei ist ja immer stimmt), bei Sockets kommen von außen immer wieder mal neue Bytes dazu im Gegensatz zu Dateien die nicht einfach so von alleine wachsen.

Übrigens skaliert unter Linux ein fork()-basierter Webserver besser als ein auf poll() basierender
Bis zu wie vielen gleichzeitigen Anfragen? Ich denke mal spätestens beim 100000-ten fork() hast Du auch auf nem dicken Server Probleme. Klar ist fork() relativ kostengünstig (wobei ich hoffe auf meiner segmentierten Plattform das CreateThread() deutlich billiger zu bekommen) aber man braucht trotzdem einiges an Speicher (für die vielen Stacks und Verwaltungsstrukturen).


Grüße
Erik
Titel: Re:[erledigt] IPC - Callback Funktion registrieren
Beitrag von: Svenska am 05. July 2010, 18:40
Hm, mit readahead habe ich noch nicht gemacht, aber bist du dir sicher? Die Manpage sagt nämlich:

Zitat von: Linux Programmer's Manual: readahead(2)
readahead() blocks until the specified data has been read.
Akzeptiert, dann geht das in der Form nicht. Müsste man dann selbst implementieren. :-)

Aber gerade dieses select() würde im Szenario mit den Dateien von unterschiedlich schnellen HDDs nichts helfen, wenn ich das richtig verstanden habe prüft select() nur ob noch Bytes da sind (was bei Dateien wo der aktuelle File-Pointer noch nicht am Ende der Datei ist ja immer stimmt), bei Sockets kommen von außen immer wieder mal neue Bytes dazu im Gegensatz zu Dateien die nicht einfach so von alleine wachsen.
Korrekt, allerdings könnte man ja ein Flag dazu verwenden.
Grundgedanke ist halt, dafür einen Thread zu basteln, der im Hintergrund die benötigten Daten liefert.

Übrigens skaliert unter Linux ein fork()-basierter Webserver besser als ein auf poll() basierender
Bis zu wie vielen gleichzeitigen Anfragen? Ich denke mal spätestens beim 100000-ten fork() hast Du auch auf nem dicken Server Probleme. Klar ist fork() relativ kostengünstig (wobei ich hoffe auf meiner segmentierten Plattform das CreateThread() deutlich billiger zu bekommen) aber man braucht trotzdem einiges an Speicher (für die vielen Stacks und Verwaltungsstrukturen).
Ich beziehe mich auf diese PDF (http://bulk.fefe.de/scalable-networking.pdf), die ist allerdings von 2003. Der Kernel hat Threading noch nicht so lange, das wurde ewig in der glibc implementiert, von daher ist die Ansage nicht mehr ganz aktuell.

;-)

Gruß,
Svenska