Imported Upstream version 4.2.0.179

Former-commit-id: 0a113cb3a6feb7873f632839b1307cc6033cd595
This commit is contained in:
Xamarin Public Jenkins
2015-08-26 07:17:56 -04:00
committed by Jo Shields
parent 183bba2c9a
commit 6992685b86
7507 changed files with 90259 additions and 657307 deletions

View File

@ -10,10 +10,10 @@
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
@ -43,6 +43,13 @@
// find out whether the runtime performs the P/Invoke if the
// handle has been disposed already.
//
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
//
// Files:
// - mscorlib/system/runtime/interopservices/safehandle.cs
//
using System;
@ -54,183 +61,171 @@ using System.Threading;
namespace System.Runtime.InteropServices
{
[StructLayout (LayoutKind.Sequential)]
public abstract class SafeHandle : CriticalFinalizerObject, IDisposable {
//
// Warning: the offset of handle is mapped inside the runtime
// if you move this, you must updated the runtime definition of
// MonoSafeHandle
//
protected IntPtr handle;
int refcount;
bool owns_handle;
bool closed, disposed;
#if NET_2_1
protected SafeHandle ()
{
throw new NotImplementedException ();
}
#endif
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
protected SafeHandle (IntPtr invalidHandleValue, bool ownsHandle)
{
handle = invalidHandleValue;
public abstract partial class SafeHandle
{
const int RefCount_Mask = 0x7ffffffc;
const int RefCount_One = 0x4;
if (!ownsHandle) {
GC.SuppressFinalize (this);
} else {
owns_handle = true;
}
refcount = 1;
enum State {
Closed = 0x00000001,
Disposed = 0x00000002,
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public void Close ()
{
Dispose ();
}
//
// I do not know when we could not be able to increment the
// reference count and set success to false. It might just
// be a convention used for the following code pattern:
//
// bool release = false
// try { x.DangerousAddRef (ref release); ... }
// finally { if (release) x.DangerousRelease (); }
//
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
public void DangerousAddRef (ref bool success)
{
if (closed)
throw new ObjectDisposedException ("SafeHandle was closed");
bool registered = false;
int newcount, current;
do {
current = refcount;
newcount = current + 1;
if (current <= 0){
//
// In MS, calling sf.Close () followed by a call
// to P/Invoke with SafeHandles throws this, but
// am left wondering: when would "success" be
// set to false?
//
throw new ObjectDisposedException (GetType ().FullName);
}
// perform changes in finally to avoid async interruptions
RuntimeHelpers.PrepareConstrainedRegions ();
try {}
finally {
if (Interlocked.CompareExchange (ref refcount, newcount, current) == current)
registered = success = true;
}
} while (!registered);
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public IntPtr DangerousGetHandle ()
{
return handle;
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public void DangerousRelease ()
{
RunRelease ();
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public void Dispose ()
{
Dispose (true);
GC.SuppressFinalize (this);
}
//
// See documentation, this invalidates the handle without
// closing it.
//
/*
* This should only be called for cases when you know for a fact that
* your handle is invalid and you want to record that information.
* An example is calling a syscall and getting back ERROR_INVALID_HANDLE.
* This method will normally leak handles!
*/
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public void SetHandleAsInvalid ()
{
closed = true;
int old_state, new_state;
do {
old_state = _state;
new_state = old_state | (int) State.Closed;
} while (Interlocked.CompareExchange (ref _state, new_state, old_state) != old_state);
GC.SuppressFinalize (this);
}
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
protected virtual void Dispose (bool disposing)
/*
* Add a reason why this handle should not be relinquished (i.e. have
* ReleaseHandle called on it). This method has dangerous in the name since
* it must always be used carefully (e.g. called within a CER) to avoid
* leakage of the handle. It returns a boolean indicating whether the
* increment was actually performed to make it easy for program logic to
* back out in failure cases (i.e. is a call to DangerousRelease needed).
* It is passed back via a ref parameter rather than as a direct return so
* that callers need not worry about the atomicity of calling the routine
* and assigning the return value to a variable (the variable should be
* explicitly set to false prior to the call). The only failure cases are
* when the method is interrupted prior to processing by a thread abort or
* when the handle has already been (or is in the process of being)
* released.
*/
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.MayFail)]
public void DangerousAddRef (ref bool success)
{
if (disposing) {
if (disposed)
if (!_fullyInitialized)
throw new InvalidOperationException ();
int old_state, new_state;
do {
old_state = _state;
if ((old_state & (int) State.Closed) != 0)
throw new ObjectDisposedException ("handle");
new_state = old_state + RefCount_One;
} while (Interlocked.CompareExchange (ref _state, new_state, old_state) != old_state);
success = true;
}
/*
* Partner to DangerousAddRef. This should always be successful when used in
* a correct manner (i.e. matching a successful DangerousAddRef and called
* from a region such as a CER where a thread abort cannot interrupt
* processing). In the same way that unbalanced DangerousAddRef calls can
* cause resource leakage, unbalanced DangerousRelease calls may cause
* invalid handle states to become visible to other threads. This
* constitutes a potential security hole (via handle recycling) as well as a
* correctness problem -- so don't ever expose Dangerous* calls out to
* untrusted code.
*/
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
public void DangerousRelease ()
{
DangerousReleaseInternal (false);
}
void InternalDispose ()
{
if (!_fullyInitialized)
throw new InvalidOperationException ();
DisposeInternal ();
}
void InternalFinalize ()
{
if (_fullyInitialized)
DisposeInternal ();
}
void DisposeInternal ()
{
DangerousReleaseInternal (true);
GC.SuppressFinalize (this);
}
void DangerousReleaseInternal (bool dispose)
{
if (!_fullyInitialized)
throw new InvalidOperationException ();
int old_state, new_state;
/* See AddRef above for the design of the synchronization here. Basically we
* will try to decrement the current ref count and, if that would take us to
* zero refs, set the closed state on the handle as well. */
bool perform_release = false;
do {
old_state = _state;
/* If this is a Dispose operation we have additional requirements (to
* ensure that Dispose happens at most once as the comments in AddRef
* detail). We must check that the dispose bit is not set in the old
* state and, in the case of successful state update, leave the disposed
* bit set. Silently do nothing if Dispose has already been called
* (because we advertise that as a semantic of Dispose). */
if (dispose && (old_state & (int) State.Disposed) != 0)
return;
RunRelease ();
disposed = true;
} else {
if (owns_handle && !closed && !IsInvalid){
ReleaseHandle ();
}
}
}
void RunRelease ()
{
if (refcount == 0)
throw new ObjectDisposedException (GetType ().FullName);
int newcount = 0, current = 0;
bool registered = false;
RuntimeHelpers.PrepareConstrainedRegions ();
try {
do {
current = refcount;
newcount = current-1;
// perform changes in finally to avoid async interruptions
try {}
finally {
if (Interlocked.CompareExchange (ref refcount, newcount, current) == current)
registered = true;
}
} while (!registered);
} finally {
if (registered && newcount == 0) {
if (owns_handle && !closed && !IsInvalid)
ReleaseHandle ();
closed = true;
}
}
/* We should never see a ref count of zero (that would imply we have
* unbalanced AddRef and Releases). (We might see a closed state before
* hitting zero though -- that can happen if SetHandleAsInvalid is
* used). */
if ((old_state & RefCount_Mask) == 0)
throw new ObjectDisposedException ("handle");
perform_release =
(old_state & RefCount_Mask) == RefCount_One
&& (old_state & (int) State.Closed) == 0
&& _ownsHandle;
if (perform_release && IsInvalid)
perform_release = false;
/* Attempt the update to the new state, fail and retry if the initial
* state has been modified in the meantime. Decrement the ref count by
* substracting SH_RefCountOne from the state then OR in the bits for
* Dispose (if that's the reason for the Release) and closed (if the
* initial ref count was 1). */
new_state =
(old_state - RefCount_One)
| ((old_state & RefCount_Mask) == RefCount_One ? (int) State.Closed : 0)
| (dispose ? (int) State.Disposed : 0);
} while (Interlocked.CompareExchange (ref _state, new_state, old_state) != old_state);
if (perform_release)
ReleaseHandle ();
}
/*
* Implement this abstract method in your derived class to specify how to
* free the handle. Be careful not write any code that's subject to faults
* in this method (the runtime will prepare the infrastructure for you so
* that no jit allocations etc. will occur, but don't allocate memory unless
* you can deal with the failure and still free the handle).
* The boolean returned should be true for success and false if the runtime
* should fire a SafeHandleCriticalFailure MDA (CustomerDebugProbe) if that
* MDA is enabled.
*/
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
protected abstract bool ReleaseHandle ();
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
protected void SetHandle (IntPtr handle)
{
this.handle = handle;
}
public bool IsClosed {
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
get {
return closed;
}
}
public abstract bool IsInvalid {
[ReliabilityContract (Consistency.WillNotCorruptState, Cer.Success)]
get;
}
~SafeHandle ()
{
Dispose (false);
}
}
}