Compartir a través de


Objetos de semáforo

Cualquier controlador puede usar un objeto de semáforo para sincronizar las operaciones entre sus subprocesos creados por el controlador y otras rutinas de controlador. Por ejemplo, un subproceso dedicado al controlador podría colocarse en un estado de espera cuando no hay solicitudes de E/S pendientes para el controlador y las rutinas de distribución del controlador podrían establecer el semáforo en el estado Señalizado justo después de poner en cola un IRP.

Las rutinas de distribución de controladores de nivel superior, que se ejecutan en el contexto del subproceso que solicita una operación de E/S, pueden usar un semáforo para proteger un recurso compartido entre las rutinas de envío. Las rutinas de distribución de controladores de nivel inferior para las operaciones de E/S sincrónicas también pueden usar un semáforo para proteger un recurso compartido entre ese subconjunto de rutinas de envío o con un subproceso creado por el controlador.

Cualquier controlador que use un objeto de semáforo debe llamar a KeInitializeSemaphore antes de que espere o libere el semáforo. En la ilustración siguiente se muestra cómo un controlador con un subproceso puede usar un objeto de semáforo.

diagrama que ilustra la espera de un objeto de semáforo.

Como se muestra en la ilustración anterior, este controlador debe proporcionar el almacenamiento para el objeto de semáforo, que debe residir. El controlador puede usar la extensión de dispositivo de un objeto de dispositivo creado por el controlador, la extensión del controlador si usa un objeto de controlador de o un grupo no paginado asignado por el controlador.

Cuando el addDevice del controlador las llamadas rutinarias KeInitializeSemaphore, debe pasar un puntero al almacenamiento residente del controlador para el objeto de semáforo. Además, el autor de la llamada debe especificar un Count para el objeto de semáforo, como se muestra en la ilustración anterior, que determina su estado inicial (distinto de cero para Signaled).

El autor de la llamada también debe especificar un límite de para el semáforo, que puede ser cualquiera de los siguientes:

  • límite de = 1

    Cuando este semáforo se establece en el estado Signaled, un único subproceso que espera a que el semáforo se establezca en el estado Signaled es apto para su ejecución y puede acceder a cualquier recurso protegido por el semáforo.

    Este tipo de semáforo también se denomina semáforo binario porque un subproceso tiene o no tiene acceso exclusivo al recurso protegido por semáforos.

  • límite de > 1

    Cuando este semáforo se establece en el estado Signaled, algunos subprocesos que esperan que el objeto de semáforo se establezca en el estado Signaled se puede optar a la ejecución y puede acceder a cualquier recurso protegido por el semáforo.

    Este tipo de semáforo se denomina semáforo de recuento porque la rutina que establece el semáforo en el estado Signaled también especifica cuántos subprocesos en espera pueden cambiar de esperar a estar listos. El número de estos subprocesos en espera puede ser el límite de establecer cuando se inicializó el semáforo o un número menor que este valor preestablecido Limit.

Pocos controladores intermedios o de dispositivo tienen un único subproceso creado por el controlador; incluso menos tienen un conjunto de subprocesos que podrían esperar a que se adquiera o libere un semáforo. Algunos controladores proporcionados por el sistema usan objetos de semáforo y, de los que lo hacen, incluso menos usan un semáforo binario. Aunque un semáforo binario podría parecer similar en la funcionalidad de un objeto de exclusión mutua , un semáforo binario no proporciona la protección integrada contra interbloqueos que un objeto de exclusión mutua tiene para subprocesos del sistema que se ejecutan en máquinas SMP.

Después de cargar un controlador con un semáforo inicializado, puede sincronizar las operaciones en el semáforo que protege un recurso compartido. Por ejemplo, un controlador con un subproceso dedicado al dispositivo que administra la puesta en cola de IRP, como el controlador del controlador de disquete del sistema, puede sincronizar la puesta en cola de IRP en un semáforo, como se muestra en la ilustración anterior:

  1. El subproceso llama a KeWaitForSingleObject con un puntero al almacenamiento proporcionado por el controlador para el objeto de semáforo inicializado para colocarse en un estado de espera.

  2. Los IRP comienzan a entrar que requieren operaciones de E/S del dispositivo. Las rutinas de distribución del controlador insertan cada IRP en una cola interbloqueada bajo el control de bloqueo de número y llaman a KeReleaseSemaphore con un puntero al objeto semaphore, un aumento de prioridad determinado por el controlador para el subproceso (Incremento, como se muestra en la ilustración anterior), un Ajuste de 1 que se agrega al recuento del semáforo a medida que se pone en cola cada IRP, y un de espera de booleano establecido en FALSE. Un semáforo distinto de cero establece el objeto semaphore en el estado Signaled, cambiando así el estado del subproceso en espera para que esté listo.

  3. El kernel envía el subproceso para su ejecución en cuanto un procesador está disponible: es decir, ningún otro subproceso con una prioridad más alta está actualmente en estado listo y no hay rutinas en modo kernel que se ejecutarán en un IRQL superior.

    El subproceso quita un IRP de la cola interbloqueada bajo el control de bloqueo de número, lo pasa a otras rutinas de controlador para su posterior procesamiento y llama a KeWaitForSingleObject de nuevo. Si el semáforo todavía está establecido en el estado Signaled (es decir, su count sigue siendo distinto de cero, lo que indica que hay más IRP en la cola interbloqueada del controlador), el kernel cambia de nuevo el estado del subproceso de esperar a estar listo.

    Mediante el uso de un semáforo de recuento de esta manera, este tipo de subproceso de controlador "sabe" hay un IRP que se va a quitar de la cola interbloqueada cada vez que se ejecuta ese subproceso.

Para obtener información específica sobre cómo administrar IRQL al llamar a KeReleaseSemaphore, vea la sección Comentarios de KeReleaseSemaphore.

Cualquier rutina de controlador estándar que se ejecute en un IRQL mayor que PASSIVE_LEVEL no puede esperar un intervalo distinto de cero en cualquier objeto distribuidor sin bajar el sistema; consulte objetos de distribuidor de kernels para obtener más información. Sin embargo, esta rutina puede llamar a KeReleaseSemaphore mientras se ejecuta en un IRQL menor o igual que DISPATCH_LEVEL.

Para obtener un resumen de las IRQL en las que se ejecutan las rutinas de controlador estándar, consulte Administración de prioridades de hardware. Para conocer los requisitos de IRQL de una rutina de soporte técnico específica, consulte la página de referencia de la rutina.