From 3277301592ad5b8eeff2ec780233469012a7ddac Mon Sep 17 00:00:00 2001 From: jean Date: Wed, 31 Mar 1999 13:21:44 +0000 Subject: [PATCH] implement some functions svn path=/trunk/; revision=354 --- reactos/ntoskrnl/ex/resource.c | 350 +++++++++++++++++++++++++++++---- 1 file changed, 309 insertions(+), 41 deletions(-) diff --git a/reactos/ntoskrnl/ex/resource.c b/reactos/ntoskrnl/ex/resource.c index f05eb4e210c..04569aaa144 100644 --- a/reactos/ntoskrnl/ex/resource.c +++ b/reactos/ntoskrnl/ex/resource.c @@ -7,95 +7,291 @@ * UPDATE HISTORY: * Created 22/05/98 */ + + /* * Usage of ERESOURCE members is not documented. * From names of members and functionnalities, we can assume : + * + * OwnerTable = list of threads who have shared access(if more than one) * ActiveCount = number of threads who have access to the resource - * OwnerTable = list of threads who have shared access - * OwnerThreads[0]= thread who have exclusive access - * OwnerThreads[1]= thread who have shared access if only one thread - * else - * OwnerThread=0 - * and TableSize = number of entries in the owner table * Flag = bits : ResourceOwnedExclusive=0x80 * ResourceNeverExclusive=0x10 * ResourceReleaseByOtherThread=0x20 + * SharedWaiters = semaphore, used to manage wait list of shared waiters. + * ExclusiveWaiters = event, used to manage wait list of exclusive waiters. + * OwnerThreads[0]= thread who have exclusive access + * OwnerThreads[1]= if only one thread own the resource + * thread who have shared access + * else + * OwnerThread=0 + * and TableSize = number of entries in the owner table + * NumberOfExclusiveWaiters = number of threads waiting for exclusive access. + * NumberOfSharedWaiters = number of threads waiting for exclusive access. * */ #define ResourceOwnedExclusive 0x80 -/* INCLUDES *****************************************************************/ - - /* INCLUDES *****************************************************************/ #include -#include +#include #include +#define NDEBUG #include /* FUNCTIONS *****************************************************************/ BOOLEAN ExAcquireResourceExclusive(PERESOURCE Resource, BOOLEAN Wait) { - UNIMPLEMENTED; + return ExAcquireResourceExclusiveLite(Resource,Wait); } BOOLEAN ExAcquireResourceExclusiveLite(PERESOURCE Resource, BOOLEAN Wait) { - UNIMPLEMENTED; +// FIXME : protect essential tasks of this function from interrupts +// perhaps with KeRaiseIrql(SYNCH_LEVEL); + if(Resource->ActiveCount) // resource already locked + { + if((Resource->Flag & ResourceOwnedExclusive) + && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread()) + { // it's ok : same lock for same thread + Resource->OwnerThreads[0].a.OwnerCount++; + return TRUE; + } + if( ! Wait) return FALSE; + Resource->NumberOfExclusiveWaiters++; + if(KeWaitForSingleObject(Resource->ExclusiveWaiters,Executive,KernelMode,FALSE,NULL) + ==STATUS_TIMEOUT) + { + //FIXME : what to do if timeout ? + Resource->NumberOfExclusiveWaiters--; + return FALSE; + } + Resource->NumberOfExclusiveWaiters--; + } + Resource->OwnerThreads[0].a.OwnerCount=1; + Resource->Flag |= ResourceOwnedExclusive; + Resource->ActiveCount=1; + Resource->OwnerThreads[0].OwnerThread=ExGetCurrentResourceThread(); + return TRUE; } BOOLEAN ExAcquireResourceSharedLite(PERESOURCE Resource, BOOLEAN Wait) { - UNIMPLEMENTED; + POWNER_ENTRY freeEntry; + unsigned long i; +// FIXME : protect from interrupts + // first, resolve trivial cases + if(Resource->ActiveCount==0) // no owner, it's easy + { + Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread(); + Resource->OwnerThreads[1].a.OwnerCount=1; + Resource->ActiveCount=1; + return TRUE; + } + if((Resource->Flag & ResourceOwnedExclusive) + && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread()) + {// exclusive, but by same thread : it's ok + Resource->OwnerThreads[0].a.OwnerCount++; + return TRUE; + } + if((Resource->Flag & ResourceOwnedExclusive) + || Resource->NumberOfExclusiveWaiters) + { //exclusive by another thread , or thread waiting for exclusive + if(!Wait) return FALSE; + else + { + Resource->NumberOfSharedWaiters++; + // wait for the semaphore + if(KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0)==STATUS_TIMEOUT) + { + //FIXME : what to do ? + return FALSE; + } + } + } + //now, we must search if this thread has already acquired this resource + //then increase ownercount if found, else create new entry or reuse free entry + if(!Resource->OwnerThreads[1].a.TableSize) + { + // allocate ownertable,memset to 0, initialize first entry + Resource->OwnerTable=ExAllocatePool(NonPagedPool,sizeof(OWNER_ENTRY)*3); + memset(Resource->OwnerTable,sizeof(OWNER_ENTRY)*3,0); + Resource->OwnerTable[0].OwnerThread = Resource->OwnerThreads[1].OwnerThread; + Resource->OwnerTable[0].a.OwnerCount=Resource->OwnerThreads[1].a.OwnerCount; + Resource->OwnerThreads[1].OwnerThread=0;; + Resource->OwnerThreads[1].a.TableSize=3; + Resource->OwnerTable[1].OwnerThread=ExGetCurrentResourceThread(); + Resource->OwnerTable[1].a.OwnerCount=1; + return TRUE; + } + freeEntry=NULL; + for(i=0;iOwnerThreads[1].a.TableSize;i++) + { + if(Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread()) + {// old entry for this thread found + Resource->OwnerTable[i].a.OwnerCount++; + return TRUE; + } + if(Resource->OwnerTable[i].OwnerThread==0) + freeEntry = &Resource->OwnerTable[i]; + } + if(! freeEntry) + { + // reallocate ownertable with one more entry + freeEntry=ExAllocatePool(NonPagedPool + ,sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].a.TableSize+1)); + memcpy(freeEntry,Resource->OwnerTable + ,sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].a.TableSize)); + ExFreePool(Resource->OwnerTable); + Resource->OwnerTable=freeEntry; + freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].a.TableSize]; + Resource->OwnerThreads[1].a.TableSize ++; + } + freeEntry->OwnerThread=ExGetCurrentResourceThread(); + freeEntry->a.OwnerCount=1; + Resource->ActiveCount++; + return TRUE; } VOID ExConvertExclusiveToSharedLite(PERESOURCE Resource) { - UNIMPLEMENTED; + int oldWaiters=Resource->NumberOfSharedWaiters; + if(!Resource->Flag & ResourceOwnedExclusive) return; + //transfer infos from entry 0 to entry 1 and erase entry 0 + Resource->OwnerThreads[1].OwnerThread=Resource->OwnerThreads[0].OwnerThread; + Resource->OwnerThreads[1].a.OwnerCount=Resource->OwnerThreads[0].a.OwnerCount; + Resource->OwnerThreads[0].OwnerThread=0; + Resource->OwnerThreads[0].a.OwnerCount=0; + //erase exclusive flag + Resource->Flag &= (~ResourceOwnedExclusive); + //if no shared waiters, that's all : + if(!oldWaiters) return; + //else, awake the waiters : + Resource->ActiveCount += oldWaiters; + Resource->NumberOfSharedWaiters=0; + KeReleaseSemaphore(Resource->SharedWaiters,0,oldWaiters,0); } ULONG ExGetExclusiveWaiterCount(PERESOURCE Resource) { - UNIMPLEMENTED; + return Resource->NumberOfExclusiveWaiters; } BOOLEAN ExAcquireSharedStarveExclusive(PERESOURCE Resource, BOOLEAN Wait) { - UNIMPLEMENTED; + POWNER_ENTRY freeEntry; + unsigned long i; +// FIXME : protect from interrupts + // first, resolve trivial cases + if(Resource->ActiveCount==0) // no owner, it's easy + { + Resource->OwnerThreads[1].OwnerThread=ExGetCurrentResourceThread(); + Resource->OwnerThreads[1].a.OwnerCount=1; + Resource->ActiveCount=1; + return TRUE; + } + if((Resource->Flag & ResourceOwnedExclusive) + && Resource->OwnerThreads[0].OwnerThread==ExGetCurrentResourceThread()) + {// exclusive, but by same thread : it's ok + Resource->OwnerThreads[0].a.OwnerCount++; + return TRUE; + } + if(Resource->Flag & ResourceOwnedExclusive) + { //exclusive by another thread , or thread waiting for exclusive + if(!Wait) return FALSE; + else + { + Resource->NumberOfSharedWaiters++; + // wait for the semaphore + if(KeWaitForSingleObject(Resource->SharedWaiters,0,0,0,0)==STATUS_TIMEOUT) + { + //FIXME : what to do ? + return FALSE; + } + } + } + //now, we must search if this thread has already acquired this resource + //then increase ownercount if found, else create new entry or reuse free entry + if(!Resource->OwnerThreads[1].a.TableSize) + { + // allocate ownertable,memset to 0, initialize first entry + Resource->OwnerTable=ExAllocatePool(NonPagedPool,sizeof(OWNER_ENTRY)*3); + memset(Resource->OwnerTable,sizeof(OWNER_ENTRY)*3,0); + Resource->OwnerTable[0].OwnerThread = Resource->OwnerThreads[1].OwnerThread; + Resource->OwnerTable[0].a.OwnerCount=Resource->OwnerThreads[1].a.OwnerCount; + Resource->OwnerThreads[1].OwnerThread=0;; + Resource->OwnerThreads[1].a.TableSize=3; + Resource->OwnerTable[1].OwnerThread=ExGetCurrentResourceThread(); + Resource->OwnerTable[1].a.OwnerCount=1; + return TRUE; + } + freeEntry=NULL; + for(i=0;iOwnerThreads[1].a.TableSize;i++) + { + if(Resource->OwnerTable[i].OwnerThread==ExGetCurrentResourceThread()) + {// old entry for this thread found + Resource->OwnerTable[i].a.OwnerCount++; + return TRUE; + } + if(Resource->OwnerTable[i].OwnerThread==0) + freeEntry = &Resource->OwnerTable[i]; + } + if(! freeEntry) + { + // reallocate ownertable with one more entry + freeEntry=ExAllocatePool(NonPagedPool + ,sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].a.TableSize+1)); + memcpy(freeEntry,Resource->OwnerTable + ,sizeof(OWNER_ENTRY)*(Resource->OwnerThreads[1].a.TableSize)); + ExFreePool(Resource->OwnerTable); + Resource->OwnerTable=freeEntry; + freeEntry=&Resource->OwnerTable[Resource->OwnerThreads[1].a.TableSize]; + Resource->OwnerThreads[1].a.TableSize ++; + } + freeEntry->OwnerThread=ExGetCurrentResourceThread(); + freeEntry->a.OwnerCount=1; + Resource->ActiveCount++; + return TRUE; } BOOLEAN ExAcquireSharedWaitForExclusive(PERESOURCE Resource, BOOLEAN Wait) { - UNIMPLEMENTED; + return ExAcquireResourceSharedLite(Resource,Wait); } NTSTATUS ExDeleteResource(PERESOURCE Resource) { - UNIMPLEMENTED; + if(Resource->OwnerTable) ExFreePool(Resource->OwnerTable); + if(Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters); + if(Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters); + return 0; } NTSTATUS ExDeleteResourceLite(PERESOURCE Resource) { - UNIMPLEMENTED; + if(Resource->OwnerTable) ExFreePool(Resource->OwnerTable); + if(Resource->SharedWaiters) ExFreePool(Resource->SharedWaiters); + if(Resource->ExclusiveWaiters) ExFreePool(Resource->ExclusiveWaiters); + return 0; } ERESOURCE_THREAD ExGetCurrentResourceThread() { - UNIMPLEMENTED; + return ((ERESOURCE_THREAD)PsGetCurrentThread() ); } ULONG ExGetSharedWaiterCount(PERESOURCE Resource) { - UNIMPLEMENTED; + return Resource->NumberOfSharedWaiters; } NTSTATUS ExInitializeResource(PERESOURCE Resource) { - UNIMPLEMENTED; + return ExInitializeResourceLite(Resource); } NTSTATUS ExInitializeResourceLite(PERESOURCE Resource) @@ -105,15 +301,15 @@ NTSTATUS ExInitializeResourceLite(PERESOURCE Resource) // Resource->NumberOfExclusiveWaiters = 0; KeInitializeSpinLock(&Resource->SpinLock); // Resource->Flag=0; - Resource->ExclusiveWaiters = ExAllocatePool(NonPagedPool, - sizeof(KEVENT)); + // FIXME : I'm not sure it's a good idea to allocate and initialize + // immediately Waiters. + Resource->ExclusiveWaiters=ExAllocatePool(NonPagedPool , sizeof(KEVENT)); KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent, FALSE); - Resource->SharedWaiters = ExAllocatePool(NonPagedPool, - sizeof(KSEMAPHORE)); - KeInitializeSemaphore(Resource->SharedWaiters,5,0); + Resource->SharedWaiters=ExAllocatePool(NonPagedPool ,sizeof(KSEMAPHORE)); + KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff); // Resource->ActiveCount = 0; - return(STATUS_SUCCESS); + return 0; } BOOLEAN ExIsResourceAcquiredExclusiveLite(PERESOURCE Resource) @@ -145,37 +341,109 @@ ULONG ExIsResourceAcquiredSharedLite(PERESOURCE Resource) VOID ExReinitializeResourceLite(PERESOURCE Resource) { - UNIMPLEMENTED; + Resource->NumberOfSharedWaiters = 0; + Resource->NumberOfExclusiveWaiters = 0; + KeInitializeSpinLock(&Resource->SpinLock); + Resource->Flag=0; + KeInitializeEvent(Resource->ExclusiveWaiters,SynchronizationEvent, + FALSE); + KeInitializeSemaphore(Resource->SharedWaiters,0,0x7fffffff); + Resource->ActiveCount = 0; + if(Resource->OwnerTable) ExFreePool(Resource->OwnerTable); + Resource->OwnerThreads[0].OwnerThread=0; + Resource->OwnerThreads[0].a.OwnerCount=0; + Resource->OwnerThreads[1].OwnerThread=0; + Resource->OwnerThreads[1].a.OwnerCount=0; +} + +VOID ExReleaseResourceLite(PERESOURCE Resource) +{ + return ExReleaseResourceForThreadLite(Resource,ExGetCurrentResourceThread()); } VOID ExReleaseResource(PERESOURCE Resource) { - UNIMPLEMENTED; + return ExReleaseResourceForThreadLite(Resource,ExGetCurrentResourceThread()); } VOID ExReleaseResourceForThread(PERESOURCE Resource, ERESOURCE_THREAD ResourceThreadId) { - UNIMPLEMENTED; + return ExReleaseResourceForThreadLite(Resource,ResourceThreadId); } VOID ExReleaseResourceForThreadLite(PERESOURCE Resource, ERESOURCE_THREAD ResourceThreadId) { - UNIMPLEMENTED; + long i; + //FIXME : protect this function from interrupts + // perhaps with KeRaiseIrql(SYNCH_LEVEL); + if (Resource->Flag & ResourceOwnedExclusive) + { + if(--Resource->OwnerThreads[0].a.OwnerCount == 0) + {//release the resource + Resource->OwnerThreads[0].OwnerThread=0; + assert(--Resource->ActiveCount == 0); + if(Resource->NumberOfExclusiveWaiters) + {// get resource to first exclusive waiter + KeDispatcherObjectWake(&Resource->ExclusiveWaiters->Header); + return; + } + else + Resource->Flag &=(~ResourceOwnedExclusive); + if(Resource->NumberOfSharedWaiters) + {// get resource to waiters + Resource->ActiveCount=Resource->NumberOfSharedWaiters; + Resource->NumberOfSharedWaiters=0; + KeReleaseSemaphore(Resource->SharedWaiters,0,Resource->ActiveCount,0); + return; + } + } + return; + } + //search the entry for this thread + if(Resource->OwnerThreads[1].OwnerThread==ResourceThreadId) + { + if( --Resource->OwnerThreads[1].a.OwnerCount == 0) + { + Resource->OwnerThreads[1].OwnerThread=0; + if( --Resource->ActiveCount ==0) //normally always true + { + if(Resource->NumberOfExclusiveWaiters) + {// get resource to first exclusive waiter + KeDispatcherObjectWake(&Resource->ExclusiveWaiters->Header); + } + } + } + return; + } + if(Resource->OwnerThreads[1].OwnerThread) return ; + for(i=0;iOwnerThreads[1].a.TableSize;i++) + { + if(Resource->OwnerTable[i].OwnerThread==ResourceThreadId) + { + if( --Resource->OwnerTable[1].a.OwnerCount == 0) + { + Resource->OwnerTable[i].OwnerThread=0; + if( --Resource->ActiveCount ==0) + { + ExFreePool(Resource->OwnerTable); + Resource->OwnerTable=NULL; + Resource->OwnerThreads[1].a.TableSize=0; + if(Resource->NumberOfExclusiveWaiters) + {// get resource to first exclusive waiter + KeDispatcherObjectWake(&Resource->ExclusiveWaiters->Header); + } + } + } + return; + } + } } BOOLEAN ExTryToAcquireResourceExclusiveLite(PERESOURCE Resource) { - LARGE_INTEGER timeout; - - SET_LARGE_INTEGER_HIGH_PART(timeout, 0); - SET_LARGE_INTEGER_LOW_PART(timeout, 0); - return KeWaitForSingleObject(&Resource->ExclusiveWaiters, - Executive, - KernelMode, - FALSE, - &timeout) == STATUS_SUCCESS; + return ExAcquireResourceExclusiveLite(Resource,FALSE); }