You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
8.8 KiB
412 lines
8.8 KiB
|
|
#pragma include_alias("clist.h", "..\newjob\clist.h")
|
|
|
|
#include "qmgrlib.h"
|
|
#include "locks.hxx"
|
|
#include "..\newjob\csd.h"
|
|
#include "..\newjob\tasksched.h"
|
|
|
|
//
|
|
// Following items are needed to link properly.
|
|
//
|
|
|
|
HINSTANCE g_hInstance;
|
|
SERVICE_STATUS_HANDLE ghServiceHandle;
|
|
unsigned long g_LastServiceControl;
|
|
|
|
bool IsServiceShuttingDown()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
long SetServiceStartup( bool ignore )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int InitializeBitsAllocator()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SidHandle
|
|
BITSAllocateAndInitializeSid(
|
|
BYTE nSubAuthorityCount, // count of subauthorities
|
|
DWORD dwSubAuthority0, // subauthority 0
|
|
DWORD dwSubAuthority1 ); // subauthority 1
|
|
|
|
|
|
//
|
|
// Preceding items are needed to link properly.
|
|
//
|
|
|
|
#define MAX_QUEUED_WORK_ITEMS 30
|
|
|
|
SidHandle g_NetworkUsersSid;
|
|
long g_ThreadCount;
|
|
long g_CancelCount;
|
|
HANDLE * g_hThreads;
|
|
HANDLE g_hWorkItemCreationThread;
|
|
|
|
TaskScheduler * g_Lock;
|
|
|
|
class TestWorkItem : public TaskSchedulerWorkItem
|
|
{
|
|
public:
|
|
|
|
TestWorkItem( long index )
|
|
{
|
|
m_index = index;
|
|
}
|
|
|
|
virtual SidHandle GetSid() {
|
|
return g_NetworkUsersSid;
|
|
}
|
|
virtual void OnDispatch();
|
|
|
|
long m_index;
|
|
};
|
|
|
|
bool TakeAndReleaseLock( bool fWrite, long Delay, bool fComplete );
|
|
|
|
struct
|
|
{
|
|
TestWorkItem * item;
|
|
long complete;
|
|
long cancelled;
|
|
}
|
|
g_PendingWorkItems[ MAX_QUEUED_WORK_ITEMS ];
|
|
|
|
//------------------------------------------------------------------------
|
|
|
|
void TestWorkItem::OnDispatch()
|
|
{
|
|
static int i;
|
|
|
|
bool fWrite;
|
|
|
|
if ((i % 7) == 0)
|
|
{
|
|
fWrite = true;
|
|
}
|
|
else
|
|
{
|
|
fWrite = false;
|
|
}
|
|
|
|
long Delay = -1;
|
|
long SleepChoice = (i % 10);
|
|
if (SleepChoice == 0)
|
|
{
|
|
// printf("Sleep 10\n");
|
|
Delay = 10;
|
|
}
|
|
else if (SleepChoice == 5)
|
|
{
|
|
// printf("Sleep 0\n");
|
|
Delay = 0;
|
|
}
|
|
|
|
bool fCancel;
|
|
if ((i % 3) == 1)
|
|
{
|
|
fCancel = true;
|
|
}
|
|
else
|
|
{
|
|
fCancel = false;
|
|
}
|
|
|
|
long PreLockSleep = (i % 5);
|
|
if (PreLockSleep < 3)
|
|
{
|
|
Sleep(10);
|
|
}
|
|
|
|
if (!TakeAndReleaseLock( fWrite, Delay, fCancel))
|
|
{
|
|
//
|
|
// The work-item was cancelled.
|
|
//
|
|
g_Lock->AcknowledgeWorkItemCancel();
|
|
InterlockedIncrement( &g_CancelCount );
|
|
}
|
|
else if (!fCancel)
|
|
{
|
|
g_Lock->CompleteWorkItem();
|
|
}
|
|
|
|
//
|
|
// Mark the item complete.
|
|
//
|
|
if (m_index >= 0)
|
|
{
|
|
if (g_PendingWorkItems[m_index].item != this)
|
|
{
|
|
printf("error: index mismatch\n");
|
|
exit(1);
|
|
}
|
|
|
|
// printf("completing item %p index %d\n", this, m_index);
|
|
g_PendingWorkItems[m_index].complete = 1;
|
|
}
|
|
|
|
//
|
|
|
|
// if ((i % 100000) == 0)
|
|
{
|
|
// printf("%d work items\n", i);
|
|
}
|
|
|
|
// if ((i % 1000) == 0)
|
|
{
|
|
// putchar('W');
|
|
}
|
|
|
|
++i;
|
|
}
|
|
|
|
bool TakeAndReleaseLock( bool fWrite, long Delay, bool fComplete )
|
|
{
|
|
if (fWrite)
|
|
{
|
|
// printf("lock writer\n");
|
|
if (g_Lock->LockWriter())
|
|
{
|
|
// cancelled
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// printf("lock reader\n");
|
|
if (g_Lock->LockReader())
|
|
{
|
|
// cancelled
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (Delay != -1)
|
|
{
|
|
Sleep(Delay);
|
|
}
|
|
|
|
if (fComplete)
|
|
{
|
|
g_Lock->CompleteWorkItem();
|
|
}
|
|
|
|
if (fWrite)
|
|
{
|
|
// printf("unlock writer\n");
|
|
g_Lock->UnlockWriter();
|
|
}
|
|
else
|
|
{
|
|
// printf("unlock reader\n");
|
|
g_Lock->UnlockReader();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
DWORD WINAPI ThreadProc( LPVOID arg )
|
|
{
|
|
long index = long(arg);
|
|
long i =0;
|
|
|
|
do
|
|
{
|
|
bool fWrite;
|
|
|
|
if ((i % 9) == index)
|
|
{
|
|
fWrite = true;
|
|
}
|
|
else
|
|
{
|
|
fWrite = false;
|
|
}
|
|
|
|
long Delay = -1;
|
|
long SleepChoice = (i % 10);
|
|
if (SleepChoice == 0)
|
|
{
|
|
// printf("Sleep 10\n");
|
|
Delay = 10;
|
|
}
|
|
else if (SleepChoice == 5)
|
|
{
|
|
// printf("Sleep 0\n");
|
|
Delay = 0;
|
|
}
|
|
|
|
if (!TakeAndReleaseLock( fWrite, Delay, false ))
|
|
{
|
|
printf("thread %d: cancel detected!", DWORD(arg));
|
|
exit(1);
|
|
}
|
|
|
|
if ((i % 100000) == 0)
|
|
{
|
|
printf("thread %d: %d iterations\n", DWORD(arg), i);
|
|
}
|
|
|
|
if ((i % 1000) == 0)
|
|
{
|
|
putchar('0'+DWORD(arg));
|
|
}
|
|
|
|
++i;
|
|
}
|
|
while ( 1 );
|
|
}
|
|
|
|
DWORD WINAPI WorkItemCreatorProc( LPVOID arg )
|
|
{
|
|
int i = 0;
|
|
|
|
for (;;)
|
|
{
|
|
int index;
|
|
|
|
if ((i % 1000) == 0)
|
|
{
|
|
putchar('w');
|
|
}
|
|
|
|
//
|
|
// Clean out completed work items
|
|
//
|
|
for (index = 0; index < RTL_NUMBER_OF( g_PendingWorkItems ); ++index)
|
|
{
|
|
if (g_PendingWorkItems[index].complete)
|
|
{
|
|
// printf("clearing index %d\n", index);
|
|
delete g_PendingWorkItems[index].item;
|
|
g_PendingWorkItems[index].item = 0;
|
|
g_PendingWorkItems[index].complete = 0;
|
|
g_PendingWorkItems[index].cancelled = 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fill up the queue.
|
|
//
|
|
do
|
|
{
|
|
// find a spot
|
|
|
|
for (index = 0; index < RTL_NUMBER_OF( g_PendingWorkItems ); ++index)
|
|
{
|
|
if (g_PendingWorkItems[index].item == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// A slot is available; create a new workitem for it.
|
|
//
|
|
if (index < RTL_NUMBER_OF( g_PendingWorkItems ))
|
|
{
|
|
TestWorkItem * item = new TestWorkItem( index );
|
|
|
|
g_PendingWorkItems[index].item = item;
|
|
|
|
g_Lock->InsertWorkItem( item, NULL );
|
|
}
|
|
}
|
|
while ( index < RTL_NUMBER_OF( g_PendingWorkItems ) );
|
|
|
|
//
|
|
// let them drain away
|
|
//
|
|
do
|
|
{
|
|
for (index = RTL_NUMBER_OF( g_PendingWorkItems )-1; index >=0; --index)
|
|
{
|
|
if (g_PendingWorkItems[index].item != 0 &&
|
|
g_PendingWorkItems[index].complete == 0 &&
|
|
g_PendingWorkItems[index].cancelled == 0)
|
|
{
|
|
g_Lock->CancelWorkItem( g_PendingWorkItems[index].item );
|
|
g_PendingWorkItems[index].cancelled = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Sleep(1);
|
|
}
|
|
while ( index >= 0 );
|
|
|
|
++i;
|
|
}
|
|
}
|
|
|
|
void __cdecl wmain (int argc, wchar_t *argv[])
|
|
{
|
|
if (argc < 2)
|
|
{
|
|
printf("arg1 should be a thread count\n");
|
|
return;
|
|
}
|
|
|
|
g_ThreadCount = _wtol( argv[1] );
|
|
g_hThreads = new HANDLE[ g_ThreadCount ];
|
|
|
|
if (!InitCompilerLibrary())
|
|
{
|
|
printf("init STL failed");
|
|
return;
|
|
}
|
|
|
|
if ( !DetectProductVersion() )
|
|
{
|
|
printf("version detect failed");
|
|
return;
|
|
}
|
|
|
|
if (0 != InitializeBitsAllocator())
|
|
{
|
|
printf("allocator init failed");
|
|
return;
|
|
}
|
|
|
|
Log_Init();
|
|
Log_StartLogger();
|
|
|
|
g_NetworkUsersSid = BITSAllocateAndInitializeSid( 1, SECURITY_NETWORK_RID, 0);
|
|
|
|
g_Lock = new TaskScheduler;
|
|
|
|
for (int index = 0; index < RTL_NUMBER_OF( g_PendingWorkItems ); ++index)
|
|
{
|
|
g_PendingWorkItems[index].item = 0;
|
|
g_PendingWorkItems[index].complete = 0;
|
|
g_PendingWorkItems[index].cancelled = 0;
|
|
}
|
|
|
|
DWORD id;
|
|
for (int i=0; i < g_ThreadCount; ++i)
|
|
{
|
|
g_hThreads[i] = CreateThread( NULL, 0, ThreadProc, LPVOID(i), 0, &id );
|
|
|
|
if (0 == g_hThreads[i])
|
|
{
|
|
printf("error %d creating thread\n", GetLastError());
|
|
}
|
|
}
|
|
|
|
g_hWorkItemCreationThread = CreateThread( NULL, 0, WorkItemCreatorProc, 0, 0, &id );
|
|
if (0 == g_hWorkItemCreationThread)
|
|
{
|
|
printf("error %d creating thread\n", GetLastError());
|
|
}
|
|
|
|
Sleep( 1000 * 1000 );
|
|
}
|
|
|
|
|