#include <stdio.h>

#include <windows.h>

#include "Spin.h"

 

//#define TEST_QUEUED_SPINLOCKS

 

#ifndef TEST_QUEUED_SPINLOCKS

#define SPIN

#endif

 

#ifdef SPIN

#define ACQUIREQUEUEDSPINLOCK(x) AcquireSpinLock(x)

#define RELEASEQUEUEDSPINLOCK(x) ReleaseSpinLock(x)

#else

#define ACQUIREQUEUEDSPINLOCK(x) AcquireQueuedSpinLock(x)

#define RELEASEQUEUEDSPINLOCK(x) ReleaseQueuedSpinLock(x)

#endif

 

 

DECLSPEC_CACHEALIGN SPIN_LOCK SpinLock;

SPIN_LOCK_QUEUE SpinLockQueue, SpinLockQueue_Thread;

 

 

typedef struct _THREAD_PARAM

{

  UINT Cpu;

  SPIN_LOCK_QUEUE SpinLockQueue;

} THREAD_PARAM, *PTHREAD_PARAM;

 

 

#define MAX_CPU 8

PTHREAD_PARAM pThreadParamTable;

PHANDLE pThreads;

PUINT pHashTable;

 

 

HANDLE CloseEvent;

 

VOID

GetHashTable(PUINT Table, UINT Size);

 

DWORD WINAPI

ThreadStartAddress(LPVOID param)

{

    /* We will save ThreadParam on stack */

    THREAD_PARAM ThreadParam;

    PTHREAD_PARAM pThreadParam = (PTHREAD_PARAM) &ThreadParam;

    memcpy(pThreadParam, param, sizeof(THREAD_PARAM));

    pThreadParam->SpinLockQueue.Lock = &SpinLock;

    pThreadParam->SpinLockQueue.Next = NULL;

 

#ifdef SPIN

    printf("\t\t\tCPU[%d] - AcquireSpinLock\n", pThreadParam->Cpu);

    ACQUIREQUEUEDSPINLOCK(&SpinLock);

    printf("\t\t\tCPU[%d] - AcquireSpinLock -> Acquired.\n", pThreadParam->Cpu);

#else

    printf("\t\t\tCPU[%d] - AcquireQueuedSpinLock\n", pThreadParam->Cpu);

    ACQUIREQUEUEDSPINLOCK(&pThreadParam->SpinLockQueue);

    printf("\t\t\tCPU[%d] - AcquireQueueSpinLock -> Acquired.\n", pThreadParam->Cpu);

#endif

 

    printf("\t\t\tCPU[%d] - Waiting for CloseEvent\n", pThreadParam->Cpu);

    WaitForSingleObject(CloseEvent, INFINITE);

    printf("\t\t\tCPU[%d] - Received CloseEvent\n", pThreadParam->Cpu);

 

#ifdef SPIN

    printf("\t\t\tCPU[%d] - ReleaseSpinLock\n", pThreadParam->Cpu);

    RELEASEQUEUEDSPINLOCK(&SpinLock);

    printf("\t\t\tCPU[%d] - ReleaseSpinLock -> Released.\n\n", pThreadParam->Cpu);

#else

    printf("\t\t\tCPU[%d] - ReleaseQueuedSpinLock\n", pThreadParam->Cpu);

    RELEASEQUEUEDSPINLOCK(&pThreadParam->SpinLockQueue);

    printf("\t\t\tCPU[%d] - ReleaseQueuedSpinLock -> Released.\n\n", pThreadParam->Cpu);

#endif

 

    return 0;

}

 

int

main(int argc, char *argv[])

{

  int ch;

  UINT i=0;

  UINT CpuNo = MAX_CPU;

 

  SpinLockQueue.Next = NULL;

  SpinLockQueue.Lock = &SpinLock;

 

  if(argc > 1)

  {

    CpuNo = atoi(argv[1]);

    if(CpuNo == 0)

    {

      printf("atoi(%s) problems - using standard value.\n", argv[1]);

      CpuNo = MAX_CPU;

    }

  }

 

  printf("<==== Simulate %d CPUs =====>\n", CpuNo);

  pThreadParamTable = (PTHREAD_PARAM) malloc(CpuNo * sizeof(THREAD_PARAM));

  if(pThreadParamTable == NULL)

  {

    printf("malloc(pThreadParamTable) error\n");

    return 1;

  }

 

  pThreads = (PHANDLE) malloc(CpuNo * sizeof(HANDLE));

  if(pThreads == NULL)

  {

    printf("malloc(pThreads) error\n");

    free(pThreadParamTable);

    return 2;

  }

 

  pHashTable = (PUINT) malloc(CpuNo * sizeof(UINT));

  if(pHashTable == NULL)

  {

    printf("malloc(pHashTable) error\n");

    free(pThreadParamTable);

    free(pThreads);

    return 3;

  }

 

  GetHashTable(pHashTable, CpuNo);

  for(i=0; i<CpuNo; i++)

  {

    pThreads[i]=INVALID_HANDLE_VALUE;

  }

 

 

 

  CloseEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

 

 

  for(i=0; i<CpuNo; i++)

  {

     pThreadParamTable[i].Cpu = i;

     pThreads[i]= CreateThread(NULL, 0, ThreadStartAddress, &pThreadParamTable[i], CREATE_SUSPENDED, NULL);

 

     if(INVALID_HANDLE_VALUE == pThreads[i])

     {

       printf("CreateThread(%i) error: 0x%X\n", i, GetLastError());

     }

     else

     {

      if(!SetThreadPriority(pThreads[i], THREAD_PRIORITY_IDLE))

      {

        printf("SetThreadPriority(%d) error: 0x%X\n", i, GetLastError());

      }

     }

  }

 

#ifdef SPIN

  printf("AcquireSpinLock - Main\n");

      ACQUIREQUEUEDSPINLOCK(&SpinLock);

  printf("AcquireSpinLock - Main - Acquired\n");

#else

  printf("AcquireQueuedSpinLock - Main\n");

  ACQUIREQUEUEDSPINLOCK(&SpinLockQueue);

  printf("AcquireQueuedSpinLock - Main - Acquired\n");

#endif

 

 

  for(i=0; i<CpuNo; i++)

  {

    /* Random Threads resume */

    ResumeThread(pThreads[pHashTable[i]]);

    Sleep(200);

  }

 

  printf("\nx == exit \n");

  while( (ch=getchar()) != 'x')

  {

    ;

  }

 

  printf("\nGet x -> exit\n");

 

#ifdef SPIN

  printf("ReleaseSpinLock - Main\n");

  RELEASEQUEUEDSPINLOCK(&SpinLock);

  printf("ReleaseSpinLock - Main - Released\n");

#else

  printf("ReleaseQueuedSpinLock - Main\n");

  RELEASEQUEUEDSPINLOCK(&SpinLockQueue);

  printf("ReleaseQueuedSpinLock - Main - Released\n");

#endif

 

  SetEvent(CloseEvent);

  printf("Waiting for Threads\n");

  WaitForMultipleObjects(CpuNo, pThreads, TRUE, INFINITE);

 

  printf("END\n");

  CloseHandle(CloseEvent);

 

  if(pThreads)

    free(pThreads);

 

  if(pThreadParamTable)

    free(pThreadParamTable);

 

  if(pHashTable)

    free(pHashTable);

 

  getchar();

  getchar();

 

  return 0;

}