singrdk/base/Interfaces/Bartok/TryAll.csi

533 lines
21 KiB
Plaintext

// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
//This class provides the run-time support for "try_all { ... }" blocks
//(i.e. exception handlers with roll-back) and for "atomic { ... }"
//blocks implemented over STM.
//
//Overview
//--------
//
//Static methods on TryAllManager provide the entry points from compiled
//code. The per-thread TryAllManager objects that are passed in are
//instantiated the first time a thread invokes startTryAll.
//
//NB : for most entry points there are variants that take a
//TryAllManager and variants that look up the TryAllManager from the
//current thread. The former are used when
//StageControlOptions.TryAllOptimisePass is enabled (intended to be the
//default). The latter are there for performance comparisons.
//
//Names in this file reflect the try_all origin of the code. In
//practice a try_all is simply an atomic block that (a) doesn't enlist
//the objects that it works on and therefore can't fail with
//AtomicIsInvalidException and, (b) doesn't catch
//AtomicIsInvalidException and use that to prompt automatic
//re-execution.
//
//The external entry points are as follows:
//
//- startTryAll - start a new try_all / atomic
//
//- commit - attempt to commit the current try_all / atomic
//
//- abort - abort the current try_all / atomic
//
//- validate - validate the current atomic
//
//- Enlist[X]for[Y] where X is in {Addr, Indirect, Obj} and Y is in {Read, Update}
// - Add the specified item to the set for read-only access or
// read-write access in the current atomic block. "Obj"
// operations take an object reference. "Addr" operations take
// the address of a static field. "Indirect" operations take
// an arbitrary address and byte size.
//
//- Log* - Log the current contents of the specified data before it
// may be updated. Variants specify ref/val (whether the
// data being updated is a reference type or a value type)
// and heap/indirect (whether the data is identified by
// an object & offset (object == null for statics), or
// by a pointer).
//
//- RegisterForUndo - Register a call-back for execution during an
// abort. See Shinnar et al's paper for a discussion
// of the semantics: currently the heap is rolled back
// to the point of registration, then the call-back
// executes, then roll-back continues. If the
// call-back raises an exception then it itself is
// rolled back and the exception silently dropped.
//
//The caller must guarantee that:
//
//- commit / abort / validate / enlist* / log* are only invoked when there is
// an active try_all or atomic.
//
//- before a data item is read, an enlist-for-read or enlist-for-update
// has been issued that covers it (since the earliest active
// startTryAll on that manager).
//
//- before a data item is updated, an enlist-for-update has been issued
// that covers it (since the earliest active startTryAll on that
// manager) and a log call has been made for the item (since the most
// recent active startTryAllOnThatManager).
//
//- within an atomic block, a AtomicIsInvalidException will
// propagate to the edge of an atomic block and cause abort to be
// called.
//
//The roll-back code here is, of course, largely derived from the
//try_all implementation.
//
// Verbose runtime tracing
//#define ENABLE_LOG_TRACING
// Verbose tracing during GC
//#define ENABLE_GC_TRACING
// Trace to an in-memory buffer, not stdout
//#define BUFFER_LOG
// Profile operation counts
#define ENABLE_PROFILING
// Profile individual call sites (needs /StageControl.
//#define ENABLE_PER_CALL_SITE_PROFILING
// Occasionally pretend atomic blocks are invalid
//#define SHAKE
// Use hashing to attempt to filter duplicate udpate log entries
#define HASHING
// Test EnlistForRead calls as EnlistForUpdate
//#define ALWAYS_OPEN_FOR_UPDATE
using System.Runtime.CompilerServices;
namespace System
{
[RequiredByBartok]
public class AtomicException : Exception {}
//----------------------------------------------------------------------
//
// AtomicIsInvalidException is the sole way that invalidity is signalled:
// we assume that transactions generally execute and commit without conflict
// and so take a bigger hit on dealing with invalid exceptions in order to
// avoid testing against boolean results.
//
// Code must be prepared to deal with AtomicIsInvalidException being raised
// until the point where the status field is set to ChosenCommit.
//
// If building a non-blocking implementation we could throw
// AtomicIsInvalidException in asynchronously.
public sealed class AtomicIsInvalidException : AtomicException {}
// This Interface allows programs to define manual actions to be taken to
// recover during a tryall abort. See also TryAllManager.RegisterForUndo
public interface IUndo {
// Note that when Undo is called, accessible memory should be in the same
// state as it was when RegisterForUndo was called.
void Undo();
}
// A method marked as NoLoggingForUndo will not have logging code
// inserted even if called from a logging context
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
| AttributeTargets.Struct | AttributeTargets.Constructor
| AttributeTargets.Method,
Inherited = false)]
public sealed class NoLoggingForUndoAttribute: Attribute {}
// A method marked as NonTransactional may NOT be called from a
// transactional context. This is statically checked by
// convert\PropagateLogging.cs
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class
| AttributeTargets.Struct | AttributeTargets.Constructor
| AttributeTargets.Method,
Inherited = false)]
public sealed class NonTransactableAttribute: Attribute {}
//----------------------------------------------------------------------
//
// This is the main class that implements the runtime support for tryall
// clauses. Just about all functions called from outside the class are
// static, and they just call the current thread's local version of the
// function.
//----------------------------------------------------------------------
//
// This is the main class that implements the runtime support for tryall
// clauses. Just about all functions called from outside the class are
// static, and they just call the current thread's local version of the
// function.
[NoLoggingForUndo]
[CCtorIsRunDuringStartup]
[RequiredByBartok]
public sealed class TryAllManager {
//----------------------------------------------------------------------
//
// Start, validate, commit, abort, end
//
// These are expected to be called "start, validate*, commit"
// for transactions that attempt to commit, or "start, validate*,
// abort" for transactions that decide to abort. Validation is
// performed in commit, so explicit calls are needed only to detect
// if a transaction is looping. "end" is used internally in "commit"
// and "abort" so is not called explicitly.
public static void RegisterForUndo(IUndo ua);
[RequiredByBartok]
private static Object objForStaticEnlists;
[RequiredByBartok]
[NoLoggingForUndoAttribute]
internal static void StartTryAll(StackHeight stackHeight);
[RequiredByBartok]
[NoLoggingForUndoAttribute]
internal static void StartTryAll(StackHeight stackHeight,
TryAllManager m);
[RequiredByBartok]
[NoLoggingForUndoAttribute]
internal static void StartAtomic(StackHeight stackHeight);
[RequiredByBartok]
[NoLoggingForUndoAttribute]
internal static void StartAtomic(StackHeight stackHeight,
TryAllManager m);
[RequiredByBartok]
[NoLoggingForUndo]
internal static void CommitTryAll();
[RequiredByBartok]
[NoLoggingForUndo]
internal static void CommitTryAll(TryAllManager m);
[RequiredByBartok]
[NoLoggingForUndo]
internal static void CommitAtomic();
[RequiredByBartok]
[NoLoggingForUndo]
internal static void CommitAtomic(TryAllManager m);
[RequiredByBartok]
[NoLoggingForUndo]
internal static void AbortTryAll();
[RequiredByBartok]
[NoLoggingForUndo]
internal static void AbortTryAll(TryAllManager m);
[RequiredByBartok]
[NoLoggingForUndo]
internal static void AbortAtomic();
[RequiredByBartok]
[NoLoggingForUndo]
internal static void AbortAtomic(TryAllManager m);
[RequiredByBartok]
[NoLoggingForUndoAttribute]
internal static void ValidateEnlistments();
[RequiredByBartok]
[NoLoggingForUndoAttribute]
internal static void ValidateEnlistments(TryAllManager m);
[RequiredByBartok]
internal static void EnsureLogMemoryForUpdateLog(uint bytesNeeded);
[RequiredByBartok]
internal static void EnsureLogMemoryForUpdateLog(uint bytesNeeded,
TryAllManager m);
[RequiredByBartok]
internal static void EnsureLogMemoryForReadEnlistmentLog(uint bytesNeeded);
[RequiredByBartok]
internal static void EnsureLogMemoryForReadEnlistmentLog(uint bytesNeeded,
TryAllManager m);
[RequiredByBartok]
internal static void EnsureLogMemoryForUpdateEnlistmentLog(uint bytesNeeded);
[RequiredByBartok]
internal static void EnsureLogMemoryForUpdateEnlistmentLog(uint bytesNeeded,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistObjForRead(Object obj);
[RequiredByBartok]
internal static void EnlistObjForReadFast(Object obj);
[RequiredByBartok]
internal static void EnlistObjForRead(Object obj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistObjForReadFast(Object obj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistAddrForRead(UIntPtr pobj);
[RequiredByBartok]
internal static void EnlistAddrForReadFast(UIntPtr pobj);
[RequiredByBartok]
internal static void EnlistAddrForRead(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistAddrForReadFast(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistIndirectForRead(UIntPtr ptr,
UIntPtr byteSize);
[RequiredByBartok]
internal static void EnlistIndirectForReadFast(UIntPtr ptr,
UIntPtr byteSize);
[RequiredByBartok]
internal static void EnlistIndirectForRead(UIntPtr ptr,
UIntPtr byteSize,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistIndirectForReadFast(UIntPtr ptr,
UIntPtr byteSize,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistObjForUpdate(Object obj);
[RequiredByBartok]
internal static void EnlistObjForUpdateFast(Object obj);
[RequiredByBartok]
internal static void EnlistObjForUpdate(Object obj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistObjForUpdateFast(Object obj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistNewObjForUpdate(Object obj);
[RequiredByBartok]
internal static void EnlistNewObjForUpdateFast(Object obj);
[RequiredByBartok]
internal static void EnlistNewObjForUpdate(Object obj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistNewObjForUpdateFast(Object obj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistAddrForUpdate(UIntPtr pobj);
[RequiredByBartok]
internal static void EnlistAddrForUpdateFast(UIntPtr pobj);
[RequiredByBartok]
internal static void EnlistAddrForUpdate(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistAddrForUpdateFast(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistIndirectForUpdate(UIntPtr ptr,
UIntPtr byteSize);
[RequiredByBartok]
internal static void EnlistIndirectForUpdateFast(UIntPtr ptr,
UIntPtr byteSize);
[RequiredByBartok]
internal static void EnlistIndirectForUpdate(UIntPtr ptr,
UIntPtr byteSize,
TryAllManager m);
[RequiredByBartok]
internal static void EnlistIndirectForUpdateFast(UIntPtr ptr,
UIntPtr byteSize,
TryAllManager m);
[RequiredByBartok]
internal static void LogValHeapMultiple(Object obj,
UIntPtr off,
UIntPtr size);
[RequiredByBartok]
internal static void LogValHeapMultipleFast(Object obj,
UIntPtr off,
UIntPtr size);
[RequiredByBartok]
internal static void LogValHeapMultiple(Object obj,
UIntPtr off,
UIntPtr size,
TryAllManager m);
[RequiredByBartok]
internal static void LogValHeapMultipleFast(Object obj,
UIntPtr off,
UIntPtr size,
TryAllManager m);
[RequiredByBartok]
internal static void LogValHeap(Object obj,
UIntPtr off);
[RequiredByBartok]
internal static void LogValHeapFast(Object obj,
UIntPtr off);
[RequiredByBartok]
internal static void LogValHeap(Object obj,
UIntPtr off,
TryAllManager m);
[RequiredByBartok]
internal static void LogValHeapFast(Object obj,
UIntPtr off,
TryAllManager m);
[RequiredByBartok]
internal static void LogValStatic(UIntPtr addr);
[RequiredByBartok]
internal static void LogValStaticFast(UIntPtr addr);
[RequiredByBartok]
internal static void LogValStatic(UIntPtr addr,
TryAllManager m);
[RequiredByBartok]
internal static void LogValStaticFast(UIntPtr addr,
TryAllManager m);
[RequiredByBartok]
internal static void LogRefHeap(Object obj,
UIntPtr off);
[RequiredByBartok]
internal static void LogRefStatic(UIntPtr addr);
[RequiredByBartok]
internal static void LogRefHeapFast(Object obj,
UIntPtr off);
[RequiredByBartok]
internal static void LogRefStaticFast(UIntPtr addr);
[RequiredByBartok]
internal static void LogRefHeap(Object obj,
UIntPtr off,
TryAllManager m);
[RequiredByBartok]
internal static void LogRefStatic(UIntPtr addr,
TryAllManager m);
[RequiredByBartok]
internal static void LogRefHeapFast(Object obj,
UIntPtr off,
TryAllManager m);
[RequiredByBartok]
internal static void LogRefStaticFast(UIntPtr addr,
TryAllManager m);
[RequiredByBartok]
internal static void LogIndirectRef(UIntPtr pobj);
[RequiredByBartok]
internal static void LogIndirectRefFast(UIntPtr pobj);
[RequiredByBartok]
internal static void LogIndirectRef(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void LogIndirectRefFast(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void LogIndirectValMultiple(UIntPtr pobj,
UIntPtr size);
[RequiredByBartok]
internal static void LogIndirectValMultipleFast(UIntPtr pobj,
UIntPtr size);
[RequiredByBartok]
internal static void LogIndirectValMultiple(UIntPtr pobj,
UIntPtr size,
TryAllManager m);
[RequiredByBartok]
internal static void LogIndirectValMultipleFast(UIntPtr pobj,
UIntPtr size,
TryAllManager m);
[RequiredByBartok]
internal static void LogIndirectVal(UIntPtr pobj);
[RequiredByBartok]
internal static void LogIndirectValFast(UIntPtr pobj);
[RequiredByBartok]
internal static void LogIndirectVal(UIntPtr pobj,
TryAllManager m);
[RequiredByBartok]
internal static void LogIndirectValFast(UIntPtr pobj,
TryAllManager m);
//----------------------------------------------------------------------
public static bool InTryAll {
get;
}
//----------------------------------------------------------------------
//
// Per-call-site profiling.
//
// If /TryAllPerCallSiteProfiling is enabled then Bartok will generate calls
// to UnsafeSetCallSite just before each Enlist* or Log* instruction. This
// call supplies an integer value that uniquely identifies the call sit.
//
// The Enlist* and Log* operations are responsible for calling CountAsLogged
// if they write to the log.
//
// The counting is best effort because a single shared call site ID
// is kept at runtime and shared count arrays are used. This code is
// intended for single-threaded use when developing optimizations to
// reduce the calls made onto Enlist* and Log* functions.
[RequiredByBartok]
public static void UnsafeSetCallSite(int i);
}
}