A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #20727  by EP_X0FF
 Thu Sep 05, 2013 3:45 pm
Very detailed request as usual from you. No one will not write code for your just for nothing.

Why you need this, what have you done already and why this must be semaphores and not, for example, events. All particular kernel mode API described in MSDN (KeInitializeSemaphore, KeWaitForSingleObject, KeReleaseSemaphore).
 #20743  by Vrtule
 Sat Sep 07, 2013 11:49 pm
Hello,

the code below is a standard (theoretical) implementation of Producer-Consumer problem ported to Windows kernel. You can find a pseudo-code of the solution in many places, including the Operating Systems: Design and Implementation book.
Code: Select all
static KSEMAPHORE Full;
static KSEMAPHORE Empty;

VOID Initialize(ULONG StorageSize)
{
   KeInitializeSemaphore(&Full, 0, StorageSize);
   KeInitializeSemaphore(&Empty, StorageSize, StorageSize);

   return;
}

VOID ProducerThread(VOID)
{
   PVOID Item = NULL;

   while (TRUE) {
      Item = ProduceItem();
      (VOID) KeWaitForSingleObject(&Empty, Executive, KernelMode, FALSE, NULL);
      InsertItem(Item);
      KeReleaseSemaphore(&Full, IO_NO_INCREMENT, 1, FALSE);
   }

   return;
}

VOID ConsumerThread(VOID)
{
   PVOID item = NULL;

   while (TRUE) {
      (VOID) KeWaitForSingleObject(&Full, Executive, KernelMode, FALSE, NULL);
      Item = RemoveItem();
      KeReleaseSemaphore(&Empty, IO_NO_INCREMENT, 1, FALSE);
      DoSomethingWithItem(Item);
   }

   return;
}
StorageSize: size of the storage guarded by semaphores, in items.
Initialize: initializes the semaphores.
ProducerThread: a routine representing the producer.
ConsumerThread: a routine representing the consumer.
Full: a semaphore the counter of which matches the number of items placed in the storage.
Empty: a semaphore the counter of which matches the number of empty slots in the storage.
InsertItem: inserts an item into the storage (must provide its own synchronization to protect the storage against race conditions, the semaphores are not enough).
RemoveItem: Removes an item from the storage (must provide its own synchronization to protect the storage against race conditions, the semaphores are not enough).
ProduceItem: creates a new item that will be send to consumer.
DoSomethingWithItem: consumes an item.

However, I really doubt you find this example very useful. At least I hardly ever used such code (or nearly the same one) in my "kernel career". I usually use semaphores to count number of events waiting to be processed by a consumer which is usually an application. The producer is usually a kernel driver. However, the exact shape of the producer-consumer problem depends on many factors. For example, I do not remember ever using the Empty semaphore because my storage is (when solving producer-consumer problems) usually implemented as linked lists.

To sum up my post; you need to understand about what the producer-consumer problem is. When you get it, you do not need any sample implementations for various platforms (Windows kernel, Windows applications, Linux etc.) because these implementations only differs in a way how semaphore primitives are implemented/intended to be used on the target platform (and that can be read from documentation). The problem exists in some variants so it is better to learn the general concept and adapt it to current situation.