Udostępnij przez


Błędy w środowisku wieloprocesorowym

W systemie operacyjnym opartym na NT sterowniki są wielowątkowe, mogą jednocześnie odbierać wiele żądań I/O z różnych wątków. Podczas projektowania sterownika należy założyć, że zostanie on uruchomiony w systemie SMP i podejmie odpowiednie środki w celu zapewnienia integralności danych.

W szczególności za każdym razem, gdy kierowca zmienia dane obiektu globalnego lub pliku, musi użyć blokady lub zablokowania sekwencji, aby zapobiec warunkom wyścigu.

Napotkanie warunku wyścigu podczas odwoływania się do danych globalnych lub plików specyficznych dla obiektu

W poniższym fragmencie kodu może wystąpić warunek wyścigu, gdy kierowca uzyskuje dostęp do danych globalnych na stronie Data.LpcInfo:

   PLPC_INFO pLpcInfo = &Data.LpcInfo; //Pointer to global data
   ...
   ...
   // This saved pointer may be overwritten by another thread.
   pLpcInfo->LpcPortName.Buffer = ExAllocatePool(
                                     PagedPool,
                                     arg->PortName.Length);

Wiele wątków wprowadzających ten kod w wyniku wywołania IOCTL może spowodować przeciek pamięci, ponieważ wskaźnik jest zastępowany. Aby uniknąć tego problemu, sterownik powinien używać procedur ExInterlockedXxx lub pewnego typu blokady podczas zmiany danych globalnych. Wymagania kierowcy określają dopuszczalne typy blokad. Aby uzyskać więcej informacji, zobacz Spin Locks, Kernel Dispatcher Objects i ExAcquireResourceSharedLite.

W poniższym przykładzie podjęto próbę ponownego przypisania buforu specyficznego dla pliku (Endpoint-LocalAddress>) w celu przechowywania adresu punktu końcowego:

   Endpoint = FileObject->FsContext;

    if ( Endpoint->LocalAddress != NULL &&
         Endpoint->LocalAddressLength <
                   ListenEndpoint->LocalAddressLength ) {

      FREE_POOL (Endpoint->LocalAddress,
                 LOCAL_ADDRESS_POOL_TAG
                 );
      Endpoint->LocalAddress  = NULL;
   }

    if ( Endpoint->LocalAddress == NULL ) {
       Endpoint->LocalAddress =
            ALLOCATE_POOL (NonPagedPool,
                           ListenEndpoint->LocalAddressLength,
                           LOCAL_ADDRESS_POOL_TAG);
   }

W tym przykładzie może wystąpić warunek wyścigu z dostępem do obiektu pliku. Ponieważ sterownik nie przechowuje żadnych blokad, dwa żądania dla tego samego obiektu pliku mogą wprowadzić tę funkcję. Wynikiem mogą być odwołania do zwolnionej pamięci, wiele prób zwolnienia tej samej pamięci lub przecieków pamięci. Aby uniknąć tych błędów, dwie instrukcje if powinny być ujęte w blokadę spin.