Autor Thema: [erledigt] IPC - Callback Funktion registrieren  (Gelesen 25117 mal)

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« 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  :-)
« Letzte Änderung: 02. July 2010, 14:13 von littlefox »

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #1 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?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #2 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #3 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

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #4 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.

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 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?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #6 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

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #7 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 (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.
« Letzte Änderung: 01. July 2010, 18:25 von erik.vikinger »
Reality is that which, when you stop believing in it, doesn't go away.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #8 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)
 
« Letzte Änderung: 01. July 2010, 19:33 von MNemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #9 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.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #10 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
« Letzte Änderung: 01. July 2010, 21:38 von littlefox »

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 01. July 2010, 21:56 »
so müsste es lauten:
 volatile void (*currentEventHandler)(foo)


nee, dass ist doch richtig:
  void (* volatile currentEventHandler)(foo);
« Letzte Änderung: 01. July 2010, 22:05 von MNemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #12 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
Reality is that which, when you stop believing in it, doesn't go away.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #13 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

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #14 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
Reality is that which, when you stop believing in it, doesn't go away.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #15 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. :|
« Letzte Änderung: 01. July 2010, 22:22 von littlefox »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #16 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

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #17 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?

erik.vikinger

  • Beiträge: 1 277
    • Profil anzeigen
Gespeichert
« Antwort #18 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
Reality is that which, when you stop believing in it, doesn't go away.

LittleFox

  • Beiträge: 306
    • Profil anzeigen
    • LF-Net.org
Gespeichert
« Antwort #19 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?

 

Einloggen