private bool TryEnterUpgradeableReadLockCore(int millisecondsTimeout) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } if (fDisposed) { throw new ObjectDisposedException(null); } int id = Thread.CurrentThread.ManagedThreadId; ReaderWriterCount lrwc; if (!fIsReentrant) { if (id == upgradeLockOwnerId) { //Check for AU->AU throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveUpgradeNotAllowed)); } else if (id == writeLockOwnerId) { //Check for AU->AW throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterWriteNotAllowed)); } EnterMyLock(); lrwc = GetThreadRWCount(id, true); //Can't acquire upgrade lock with reader lock held. if (lrwc != null && lrwc.readercount > 0) { ExitMyLock(); throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterReadNotAllowed)); } } else { EnterMyLock(); lrwc = GetThreadRWCount(id, false); if (id == upgradeLockOwnerId) { lrwc.rc.upgradecount++; ExitMyLock(); return(true); } else if (id == writeLockOwnerId) { //Write lock is already held, Just update the global state //to show presence of upgrader. Debug.Assert((owners & WRITER_HELD) > 0); owners++; upgradeLockOwnerId = id; lrwc.rc.upgradecount++; if (lrwc.readercount > 0) { fUpgradeThreadHoldingRead = true; } ExitMyLock(); return(true); } else if (lrwc.readercount > 0) { //Upgrade locks may not be acquired if only read locks have been //acquired. ExitMyLock(); throw new LockRecursionException(SR.GetString(SR.LockRecursionException_UpgradeAfterReadNotAllowed)); } } bool retVal = true; int spincount = 0; for (;;) { //Once an upgrade lock is taken, it's like having a reader lock held //until upgrade or downgrade operations are performed. if ((upgradeLockOwnerId == -1) && (owners < MAX_READER)) { owners++; upgradeLockOwnerId = id; break; } if (spincount < MaxSpinCount) { ExitMyLock(); if (millisecondsTimeout == 0) { return(false); } spincount++; SpinWait(spincount); EnterMyLock(); continue; } // Drat, we need to wait. Mark that we have waiters and wait. if (upgradeEvent == null) // Create the needed event { LazyCreateEvent(ref upgradeEvent, true); continue; // since we left the lock, start over. } //Only one thread with the upgrade lock held can proceed. retVal = WaitOnEvent(upgradeEvent, ref numUpgradeWaiters, millisecondsTimeout); if (!retVal) { return(false); } } if (fIsReentrant) { //The lock may have been dropped getting here, so make a quick check to see whether some other //thread did not grab the entry. if (IsRwHashEntryChanged(lrwc, id)) { lrwc = GetThreadRWCount(id, false); } lrwc.rc.upgradecount++; } ExitMyLock(); return(true); }
private bool TryEnterWriteLockCore(int millisecondsTimeout) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } if (fDisposed) { throw new ObjectDisposedException(null); } int id = Thread.CurrentThread.ManagedThreadId; ReaderWriterCount lrwc; bool upgradingToWrite = false; if (!fIsReentrant) { if (id == writeLockOwnerId) { //Check for AW->AW throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveWriteNotAllowed)); } else if (id == upgradeLockOwnerId) { //AU->AW case is allowed once. upgradingToWrite = true; } EnterMyLock(); lrwc = GetThreadRWCount(id, true); //Can't acquire write lock with reader lock held. if (lrwc != null && lrwc.readercount > 0) { ExitMyLock(); throw new LockRecursionException(SR.GetString(SR.LockRecursionException_WriteAfterReadNotAllowed)); } } else { EnterMyLock(); lrwc = GetThreadRWCount(id, false); if (id == writeLockOwnerId) { lrwc.rc.writercount++; ExitMyLock(); return(true); } else if (id == upgradeLockOwnerId) { upgradingToWrite = true; } else if (lrwc.readercount > 0) { //Write locks may not be acquired if only read locks have been //acquired. ExitMyLock(); throw new LockRecursionException(SR.GetString(SR.LockRecursionException_WriteAfterReadNotAllowed)); } } int spincount = 0; bool retVal = true; for (;;) { if (IsWriterAcquired()) { // Good case, there is no contention, we are basically done SetWriterAcquired(); break; } //Check if there is just one upgrader, and no readers. //Assumption: Only one thread can have the upgrade lock, so the //following check will fail for all other threads that may sneak in //when the upgrading thread is waiting. if (upgradingToWrite) { uint readercount = GetNumReaders(); if (readercount == 1) { //Good case again, there is just one upgrader, and no readers. SetWriterAcquired(); // indicate we have a writer. break; } else if (readercount == 2) { if (lrwc != null) { if (IsRwHashEntryChanged(lrwc, id)) { lrwc = GetThreadRWCount(id, false); } if (lrwc.readercount > 0) { //This check is needed for EU->ER->EW case, as the owner count will be two. Debug.Assert(fIsReentrant); Debug.Assert(fUpgradeThreadHoldingRead); //Good case again, there is just one upgrader, and no readers. SetWriterAcquired(); // indicate we have a writer. break; } } } } if (spincount < MaxSpinCount) { ExitMyLock(); if (millisecondsTimeout == 0) { return(false); } spincount++; SpinWait(spincount); EnterMyLock(); continue; } if (upgradingToWrite) { if (waitUpgradeEvent == null) // Create the needed event { LazyCreateEvent(ref waitUpgradeEvent, true); continue; // since we left the lock, start over. } Debug.Assert(numWriteUpgradeWaiters == 0, "There can be at most one thread with the upgrade lock held."); retVal = WaitOnEvent(waitUpgradeEvent, ref numWriteUpgradeWaiters, millisecondsTimeout); //The lock is not held in case of failure. if (!retVal) { return(false); } } else { // Drat, we need to wait. Mark that we have waiters and wait. if (writeEvent == null) // create the needed event. { LazyCreateEvent(ref writeEvent, true); continue; // since we left the lock, start over. } retVal = WaitOnEvent(writeEvent, ref numWriteWaiters, millisecondsTimeout); //The lock is not held in case of failure. if (!retVal) { return(false); } } } Debug.Assert((owners & WRITER_HELD) > 0); if (fIsReentrant) { if (IsRwHashEntryChanged(lrwc, id)) { lrwc = GetThreadRWCount(id, false); } lrwc.rc.writercount++; } ExitMyLock(); writeLockOwnerId = id; return(true); }
private static OpenExistingResult OpenExistingWorker( string name, #if !FEATURE_PAL && !FEATURE_NETCORE SemaphoreRights rights, #endif out Semaphore result) { if (name == null) { throw new ArgumentNullException("name"); } if (name.Length == 0) { throw new ArgumentException(SR.GetString(SR.InvalidNullEmptyArgument, "name"), "name"); } if (null != name && MAX_PATH < name.Length) { throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong)); } result = null; #if MOBILE throw new NotSupportedException(); #else #if MONO int errorCode; var myHandle = new SafeWaitHandle(OpenSemaphore_internal(name, rights, out errorCode), true); #else //Pass false to OpenSemaphore to prevent inheritedHandles #if FEATURE_PAL || FEATURE_NETCORE const int SYNCHRONIZE = 0x00100000; const int SEMAPHORE_MODIFY_STATE = 0x00000002; SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore(SEMAPHORE_MODIFY_STATE | SYNCHRONIZE, false, name); #else SafeWaitHandle myHandle = SafeNativeMethods.OpenSemaphore((int)rights, false, name); #endif #endif if (myHandle.IsInvalid) { #if !MONO int errorCode = Marshal.GetLastWin32Error(); #endif if (NativeMethods.ERROR_FILE_NOT_FOUND == errorCode || NativeMethods.ERROR_INVALID_NAME == errorCode) { return(OpenExistingResult.NameNotFound); } if (NativeMethods.ERROR_PATH_NOT_FOUND == errorCode) { return(OpenExistingResult.PathNotFound); } if (null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode) { return(OpenExistingResult.NameInvalid); } //this is for passed through NativeMethods Errors #if MONO InternalResources.WinIOError(errorCode, ""); #else InternalResources.WinIOError(); #endif } result = new Semaphore(myHandle); return(OpenExistingResult.Success); #endif }
private bool TryEnterReadLockCore(int millisecondsTimeout) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } if (fDisposed) { throw new ObjectDisposedException(null); } ReaderWriterCount lrwc = null; int id = Thread.CurrentThread.ManagedThreadId; if (!fIsReentrant) { if (id == writeLockOwnerId) { //Check for AW->AR throw new LockRecursionException(SR.GetString(SR.LockRecursionException_ReadAfterWriteNotAllowed)); } EnterMyLock(); lrwc = GetThreadRWCount(id, false); //Check if the reader lock is already acquired. Note, we could //check the presence of a reader by not allocating rwc (But that //would lead to two lookups in the common case. It's better to keep //a count in the struucture). if (lrwc.readercount > 0) { ExitMyLock(); throw new LockRecursionException(SR.GetString(SR.LockRecursionException_RecursiveReadNotAllowed)); } else if (id == upgradeLockOwnerId) { //The upgrade lock is already held. //Update the global read counts and exit. lrwc.readercount++; owners++; ExitMyLock(); return(true); } } else { EnterMyLock(); lrwc = GetThreadRWCount(id, false); if (lrwc.readercount > 0) { lrwc.readercount++; ExitMyLock(); return(true); } else if (id == upgradeLockOwnerId) { //The upgrade lock is already held. //Update the global read counts and exit. lrwc.readercount++; owners++; ExitMyLock(); fUpgradeThreadHoldingRead = true; return(true); } else if (id == writeLockOwnerId) { //The write lock is already held. //Update global read counts here, lrwc.readercount++; owners++; ExitMyLock(); return(true); } } bool retVal = true; int spincount = 0; for (;;) { // We can enter a read lock if there are only read-locks have been given out // and a writer is not trying to get in. if (owners < MAX_READER) { // Good case, there is no contention, we are basically done owners++; // Indicate we have another reader lrwc.readercount++; break; } if (spincount < MaxSpinCount) { ExitMyLock(); if (millisecondsTimeout == 0) { return(false); } spincount++; SpinWait(spincount); EnterMyLock(); //The per-thread structure may have been recycled as the lock is released, load again. if (IsRwHashEntryChanged(lrwc, id)) { lrwc = GetThreadRWCount(id, false); } continue; } // Drat, we need to wait. Mark that we have waiters and wait. if (readEvent == null) // Create the needed event { LazyCreateEvent(ref readEvent, false); if (IsRwHashEntryChanged(lrwc, id)) { lrwc = GetThreadRWCount(id, false); } continue; // since we left the lock, start over. } retVal = WaitOnEvent(readEvent, ref numReadWaiters, millisecondsTimeout); if (!retVal) { return(false); } if (IsRwHashEntryChanged(lrwc, id)) { lrwc = GetThreadRWCount(id, false); } } ExitMyLock(); return(retVal); }
public unsafe Semaphore(int initialCount, int maximumCount, string name, out bool createdNew, SemaphoreSecurity semaphoreSecurity) #endif { if (initialCount < 0) { throw new ArgumentOutOfRangeException("initialCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired)); } if (maximumCount < 1) { throw new ArgumentOutOfRangeException("maximumCount", SR.GetString(SR.ArgumentOutOfRange_NeedNonNegNumRequired)); } if (initialCount > maximumCount) { throw new ArgumentException(SR.GetString(SR.Argument_SemaphoreInitialMaximum)); } if (null != name && MAX_PATH < name.Length) { throw new ArgumentException(SR.GetString(SR.Argument_WaitHandleNameTooLong)); } SafeWaitHandle myHandle; #if MONO int errorCode; myHandle = new SafeWaitHandle(CreateSemaphore_internal(initialCount, maximumCount, name, out errorCode), true); #else #if !FEATURE_PAL && !FEATURE_NETCORE // For ACL's, get the security descriptor from the SemaphoreSecurity. if (semaphoreSecurity != null) { NativeMethods.SECURITY_ATTRIBUTES secAttrs = null; secAttrs = new NativeMethods.SECURITY_ATTRIBUTES(); secAttrs.nLength = (int)Marshal.SizeOf(secAttrs); byte[] sd = semaphoreSecurity.GetSecurityDescriptorBinaryForm(); fixed(byte *pSecDescriptor = sd) { secAttrs.lpSecurityDescriptor = new SafeLocalMemHandle((IntPtr)pSecDescriptor, false); myHandle = SafeNativeMethods.CreateSemaphore(secAttrs, initialCount, maximumCount, name); } } else { #endif myHandle = SafeNativeMethods.CreateSemaphore(null, initialCount, maximumCount, name); #if !FEATURE_PAL && !FEATURE_NETCORE } #endif int errorCode = Marshal.GetLastWin32Error(); #endif if (myHandle.IsInvalid) { if (null != name && 0 != name.Length && NativeMethods.ERROR_INVALID_HANDLE == errorCode) { throw new WaitHandleCannotBeOpenedException(SR.GetString(SR.WaitHandleCannotBeOpenedException_InvalidHandle, name)); } #if MONO InternalResources.WinIOError(errorCode, ""); #else InternalResources.WinIOError(); #endif } createdNew = errorCode != NativeMethods.ERROR_ALREADY_EXISTS; this.SafeWaitHandle = myHandle; }