(file) Return to Strand.h CVS log (file) (dir) Up to [OMI] / omi / base

File: [OMI] / omi / base / Strand.h (download)
Revision: 1.1, Mon Apr 20 17:19:49 2015 UTC (9 years ago) by krisbash
Branch: MAIN
CVS Tags: OMI_1_0_8_2, OMI_1_0_8_1, HEAD
OMI 1.0.8-1

/*
**==============================================================================
**
** Open Management Infrastructure (OMI)
**
** Copyright (c) Microsoft Corporation
** 
** Licensed under the Apache License, Version 2.0 (the "License"); you may not 
** use this file except in compliance with the License. You may obtain a copy 
** of the License at 
**
**     http://www.apache.org/licenses/LICENSE-2.0 
**
** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 
** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 
** MERCHANTABLITY OR NON-INFRINGEMENT. 
**
** See the Apache 2 License for the specific language governing permissions 
** and limitations under the License.
**
**==============================================================================
*/

#ifndef _Strand_h
#define _Strand_h

#include <pal/thread.h>
#include <pal/atomic.h>
#include <pal/slist.h>
#include <pal/hashmap.h>
#include <base/interaction.h>
#include <sock/selector.h>
#include <pal/palcommon.h>

#if defined(CONFIG_OS_WINDOWS)
#include <windows.h> /* Required for Timer struct */
#endif

BEGIN_EXTERNC

//------------------------------------------------------------------------------------------------------------
// General Utility functions
//------------------------------------------------------------------------------------------------------------

MI_INLINE 
ptrdiff_t
ReadWithFence (
    _In_ volatile ptrdiff_t* source
    )
{
    return Atomic_CompareAndSwap( source, 0, 0 );
}

#if defined(_MSC_VER)

MI_INLINE 
unsigned long 
GetFirstSetLSB( ptrdiff_t x )
{
    unsigned long r = 0;

    if( _BitScanForward(&r, (unsigned long)x) )
        return r+1;
    else
        return 0;
}

#else

MI_INLINE 
unsigned long 
GetFirstSetLSB( ptrdiff_t x )
{
    if( x != 0 )
    {
#if defined(CONFIG_HAVE_BUILTIN_CTZ)
        return __builtin_ctz( (unsigned long) x ) + 1;
#else
        unsigned long count = 0; 
        unsigned long ulX = (unsigned long)x;
        while(ulX)
        {
            if((ulX & 1) != 0)
                break;
            count++;
            ulX = ulX >> 1;
        }        
        
        return count + 1;
#endif
    }
    else
        return 0;
}

#endif

#define FromOffset( type, memberName, memberPtr )   ( (type*) ( ((char*)(memberPtr)) - offsetof(type,memberName) ) )
#define FromOffsetConst( type, memberName, memberPtr )   ( (const type*) ( ((const char*)(memberPtr)) - offsetof(type,memberName) ) )

//------------------------------------------------------------------------------------------------------------

#if defined(CONFIG_ENABLE_DEBUG)
#define STRAND_ENABLE_DEBUG 1
#endif

//------------------------------------------------------------------------------------------------------------
// Strand Types
#define STRAND_TYPE_NOINTERACTION       0
#define STRAND_TYPE_LEFTMOST            1
#define STRAND_TYPE_RIGHTMOST           2
#define STRAND_TYPE_MIDDLE              3
#define STRAND_TYPE_PARENTLEFT          4
#define STRAND_TYPE_PARENTRIGHT         5
#define STRAND_TYPE_PARENTNOINTERACTION 6
#define STRAND_TYPE_ENTRY               7

#define STRAND_ISTYPE_EDGE( strand )    ( (strand)->strandType == STRAND_TYPE_LEFTMOST || (strand)->strandType == STRAND_TYPE_RIGHTMOST )
#define STRAND_ISTYPE_MIDDLE( strand )  ( (strand)->strandType == STRAND_TYPE_MIDDLE )
#define STRAND_ISTYPE_PARENT( strand )  ( (strand)->strandType == STRAND_TYPE_PARENTLEFT || (strand)->strandType == STRAND_TYPE_PARENTRIGHT || (strand)->strandType == STRAND_TYPE_PARENTNOINTERACTION )
#define STRAND_ISTYPE_ENTRY( strand )   ( (strand)->strandType == STRAND_TYPE_ENTRY )
#define STRAND_ISTYPE_MANY( strand )    ( STRAND_ISTYPE_ENTRY(strand) || STRAND_ISTYPE_PARENT(strand) )

typedef enum _TimerReason
{
    TimerReason_Expired         = 0,
    TimerReason_ManuallyFired   = 1,
    TimerReason_Canceled        = 2
}
TimerReason;

//------------------------------------------------------------------------------------------------------------
typedef MI_Boolean (*StrandMethod)( _In_ Strand* );

// Similar to the interaction one, but this called from the strand
typedef struct _StrandFT
{
    // - On a StrandBoth this can be NULL 
    //      and if the other side is opened message will always pass thru to the other side
    // - On a StrandMany(parent) this can be NULL
    //      and the message will be passed either a found entry or all entries (if findEntryProc is NULL)
    // - On a StrandEntry this can be NULL 
    //      and the message will be passed thru to the to the parent (once possible)
    void (*Post)( _In_ Strand* self, _In_ Message* msg);

    // - On a StrandBoth this can be NULL 
    //      and if the other side is opened message will always pass thru to the other side
    // - On a StrandMany(parent) this can be NULL 
    //      and the message will be passed either a found entry or all entries (if findEntryProc is NULL)
    // - On a StrandEntry this can be NULL 
    //      and the message will be passed to the to the parent (once possible)
    void (*PostControl)( _In_ Strand* self, _In_ Message* msg);

    // If this one is set to NULL (It should be NULL in a StrandMany(parent)):
    // - On normal Strand it will no do anything
    // - On StrandBoth it will pass thru to the other side if that side is Pending Ack (even if ackPassThru parameter is not set on Open/Post)
    // - On a StrandMany(parent) it will take care of keep sending messages from entries
    // - On a StrandEntry it will no do anything (NOTE that user is responsible to manage flow control if there are secondary messages)
    void (*Ack)( _In_ Strand* self);

    // If this one is set to NULL the strand will take care itself 
    // - On a Strand it will not do anything (only sending back to the left it is on the right)
    // - On a StrandBoth (even if it is not NULL) it always take care of passing thru cancel to the other side (if interaction is opened and not closed yet)
    // - On a StrandMany(parent) it cancels all entries
    // - On a StrandEntry it cancels the parent
    void (*Cancel)( _In_ Strand* self);     

    // If this one is set to NULL the strand will take care itself, 
    // including passing thru close to the other side (only in that case)
    // - On a StrandMany(parent) it closes all entries
    // - On a StrandEntry it does nothing (user should call StrandEntry_CloseParent if wants to close the parent)
    void (*Close)( _In_ Strand* self);      

    // Called when everything is finished (there are no ack pendings and everything is closed)
    // if NULL the strand will just delete itself
    void (*Finish)( _In_ Strand* self);

    // Called when either the timer expires or Strand_FireTimer is called
    // Should not be NULL if the timer is used
    void (*Timer)( _In_ Strand* self, TimerReason reason);
    
    // Auxiliary (optional) strand methods
    void (*Aux0)( _In_ Strand* self);
    void (*Aux1)( _In_ Strand* self);
    void (*Aux2)( _In_ Strand* self);
    void (*Aux3)( _In_ Strand* self);
    void (*Aux4)( _In_ Strand* self);
}
StrandFT;

typedef struct _StoredMsg
{
    Message *           msg;                // scheduled msg
    Message *           controlMsg;         // control msg (Note if we have more than one control message type we will need to add more of this)
} StoredMsg;

// information about one side interaction
typedef struct _InteractionInfo
{
    Interaction         interaction;        // interaction used
    StrandFT *          userFT;             // user methods
    MI_Boolean          opened;             // if the interaction have been opened (initial Ack is pending otherwise)
    MI_Boolean          thisClosedOther;    // if we closed the interaction with other component
    MI_Boolean          thisAckPending;     // if we posted to the other component and have an ack pending from it
    MI_Boolean          otherClosedThis;    // if the other component closed this interaction
    MI_Boolean          otherAckPending;    // if the other component posted to this component and have an ack pending from us
    MI_Boolean          ackPassthru;        // if the ack to last post/open should be relayed automatically to the other side (in a pass-thru fashion)
    StoredMsg           stored;             // stored scheduled msg(s)
    Message *           otherMsg;           // scheduled msg for other 
} InteractionInfo;

typedef struct _Timer Timer;

#if defined(STRAND_ENABLE_DEBUG)
typedef const char ** StrandDebugInfo;
#define STRAND_DEBUG( debugInfoName )   _Strand_DebugInfo_##debugInfoName,
#define STRAND_PASSDEBUG( debugInfo )   debugInfo,
#else
#define STRAND_DEBUG( debugInfoName )   
#define STRAND_PASSDEBUG( debugInfo )
#endif

//---------------------------------------------------------------------------------------------------------------------
// Used during creation (*_New/*_Init) to indicate that we are entering the strand
// that we just created (It SHOULD call Strand_Leave to leave it)
#define STRAND_FLAG_ENTERSTRAND         0x1

// Only used on Strand/StrandMany/StrandEntry (it doesnt make sense on StrandBoth)
#define STRAND_FLAG_NOINTERACTION       0x2     

// Can be issued by Strand_New/StrandBoth_New/StrandMany_New/StrandEntry_New 
// (does NOT zeroes all allocated fields)
// Note that Strand_Init/StrandBoth_Init only initialize strand fields 
// so since it doesnt have additional fields, that flag SHOULD NOT be used there 
// (it is used internally to indicate that fields have NOT been zeroed already)
#define STRAND_FLAG_NOZEROALLOCATED     0x4     

// When a Strand object is going to be deleted (just before calling Finish), 
// if it has a running timer then it is going to automatically fire/close it first 
// and only then (after timer callback) call Finish.
// If the implementer wants instead to wait until the timer expires before calling Finish 
// it can specify the following flag
// IMPORTANT: Please note that the Strand will not be deleted in that case until
// no timer is set (what can delay general shutdown).
#define STRAND_FLAG_FINISHWAITSFORTIMER 0x8

// Delays accepting the open/acking open until Strand_AcceptOpen() is called
#define STRAND_FLAG_DELAYACCEPTOPEN     0x10

typedef unsigned short StrandFlags;

//---------------------------------------------------------------------------------------------------------------------
// Strand with interactions in one side
struct _Strand
{
#if defined(STRAND_ENABLE_DEBUG)
    StrandDebugInfo     debug;
    ThreadID            threadId;               // threadId of the thread executing strand (if any)
    ThreadID            testThreadId;
#endif
    volatile ptrdiff_t  stateScheduled;         // methods marked for execution (by order bit)
    StrandMethod *      strandMethods;
    MI_Boolean          canceled;               // if we have been canceled (either way)
    MI_Boolean          delayFinish;            // if the object wants to delay its finalization (false by default)
    ptrdiff_t           currentMethodBit;
    MI_Boolean *        strandStealedFlag;      // used to notify bailing out when an opening is completed while running a strand method
    unsigned char       strandType;             // see STRAND_TYPE_* above
    StrandFlags         flags;
    Timer*              timer;
    InteractionInfo     info;                   // Interaction info (for the left on StrandBoth) 
};

// Strand with interactions in both directions
typedef struct _StrandBoth
{
    Strand              base;
    InteractionInfo     infoRight;          // Interaction info used for the right interaction
    MI_Boolean          leftCanceled;       // If we have passed the cancelation to the left side
    //Flag to track an async open on right interaction initiated but not yet completed. 
    //This is introduced to have a simple solution to prevent WSManCD leaks on 
    //different failure paths that did not have the right interaction opened yet
    //Note that only WSManCD currently does an async open on the right interaction.
    //TODO: This needs to be integrated into base strand or we need a better alternative
    MI_Boolean          asyncOpenInProgress;      // False initially, True upon an async open, False upon open completion
} StrandBoth;

typedef struct _StrandMany StrandMany;
typedef struct _StrandEntry StrandEntry;

typedef StrandEntry* (*FindEntryProc)(_In_ const StrandMany* parent, _In_ const Message* msg);

// Used on StrandMany between parent and entries
typedef struct _StrandManyInternalFT
{
    // Called on the parent when StrandEntry_ScheduleNew is called
    // Can be NULL if StrandEntry_ScheduleNew is never used
    // note that if it is used and it is NULL failure on creation 
    // may go unnoticed.
    // *failed can be MI_TRUE if the entry failed to be added, 
    // or the user function can also set it to MI_TRUE if it has 
    // a problem (like starting the interaction);
    // The entry will be automatically deleted in either case.
    void (*NewEntry)( _In_ StrandMany* self, _In_ StrandEntry* newEntry, _In_opt_ Message* msg, _Inout_ MI_Boolean* failed );

    // Called when (after) a entry is deleted (by the Entry itself, not by the parent)
    // If NULL does nothing
    void (*EntryDeleted)( _In_ StrandMany* self );
    
    // If NULL message is just posted thru the interaction (when possible)
    // If NOT NULL, it is only called once ACK is not pending
    void (*EntryPost)( _In_ StrandMany* self, _In_ Message* msg);

    // If NULL message is just posted thru the interaction
    void (*EntryPostControl)( _In_ StrandMany* self, _In_ Message* msg);

    // If NULL interaction is closed (if not already)
    // If NOT NULL, it is only called if the interaction is not closed already
    void (*EntryClose)( _In_ StrandMany* self);      

    // Called once the parent has added us
    // If NULL nothing is done
    void (*AddedToParent)( _In_ StrandEntry* self, _In_opt_ Message* msg);

    // If NULL message is just posted thru the interaction
    void (*ParentPost)( _In_ StrandEntry* self, _In_ Message* msg);

    // If NULL message is just posted thru the interaction
    void (*ParentPostControl)( _In_ StrandEntry* self, _In_ Message* msg);

    // If NULL ack is just passed thru (if passthru version was used)
    void (*ParentAck)( _In_ StrandEntry* self);
    
    // If NULL interaction is closed
    void (*ParentClose)( _In_ StrandEntry* self);      
}
StrandManyInternalFT;

// Strand with interactions on to many 
struct _StrandMany
{
    SListHead               pending;        // pending operations on main strand
    HashMap                 many;           // collection with interactions on the MANY direction (a StrandEntry)
    HashMapIterator         iter;           // to interato thru "many"
    size_t                  numEntries;     // number of entries on "many"
    FindEntryProc           findEntryProc;
    Strand                  strand;         // includes interaction for the Parent
    StrandManyInternalFT*   userInternalFT;
    StrandEntry*            currentEntry;   // current entry whose operation is being executed
    MI_Boolean              pendingRetry;   // if there are items in the pending list for retry
};

typedef unsigned short EntryOperationMaskType;

// A Strand with interaction belonging to the MANY part of StrandMany
struct _StrandEntry
{
    SListEntry              entry;              // to be used on parent "pending" list
    HashBucket              bucket;             // to be used on parent "many" list
    Strand                  strand;             // Includes Interaction info for the entry
    StrandMany *            parent;
    EntryOperationMaskType  operationScheduled; // entry operation scheduled on parent
    EntryOperationMaskType  operationsPending;  // entry operations pending to be scheduled on parent
    MI_Boolean              ackPassthru;        // if the ack for the post parent operation should go pass thru to interaction
    StoredMsg               toParent;           // stored scheduled msg(s) to/for parent
    StoredMsg               fromParent;         // stored scheduled msg(s) from parent
};

// If interaction is NULL then is assumed that is going to open an interaction to the right
// (and thisAckPending is going to be set to true)
Strand* Strand_New(
#if defined(STRAND_ENABLE_DEBUG)
    _In_        StrandDebugInfo         debug,
#endif
    _In_        StrandFT *              userFT,
                size_t                  structSize,
                StrandFlags             flags,
    _In_opt_    InteractionOpenParams*  interactionOpenParams );

// If interaction is NULL then is assumed that is going to open an interaction to the right
// (and thisAckPending is going to be set to true)
void Strand_Init(
#if defined(STRAND_ENABLE_DEBUG)
    _In_        StrandDebugInfo         debug,
#endif
    _Out_       Strand*                 self,
    _In_        StrandFT*               userFT,
                StrandFlags             flags,
    _In_opt_    InteractionOpenParams*  interactionOpenParams );
// interaction indicates the interaction opening from the left
// It is always assumed that is going to open an interaction to the right
StrandBoth* StrandBoth_New(
#if defined(STRAND_ENABLE_DEBUG)
    _In_        StrandDebugInfo         debug,
#endif
    _In_        StrandFT*               userLeftFT,
    _In_        StrandFT*               userRightFT,
                size_t                  structSize,
                StrandFlags             flags,
    _In_opt_    InteractionOpenParams*  interactionOpenParams );

// interaction indicates the interaction opening from the left
// It is always assumed that is going to open an interaction to the right
void StrandBoth_Init(
#if defined(STRAND_ENABLE_DEBUG)
    _In_        StrandDebugInfo         debug,
#endif
    _Out_       StrandBoth*             self,
    _In_        StrandFT*               userLeftFT,
    _In_        StrandFT*               userRightFT,
                StrandFlags             flags,
    _In_opt_    InteractionOpenParams*  interactionOpenParams );

// interaction indicates the interaction opening from the left
// otherwise if parentHasInteraction is MI_TRUE it is then assumed that is going to open an interaction to the right
// (and infoRight.thisAckPending is going to be set to true)
StrandMany* StrandMany_New(
#if defined(STRAND_ENABLE_DEBUG)
    _In_        StrandDebugInfo         debug,
#endif
    _In_        StrandFT*               userParentFT,
    _In_opt_    StrandManyInternalFT*   userInternalFT,
                size_t                  structSize,
                StrandFlags             flags,
    _In_opt_    InteractionOpenParams*  interactionOpenParams,  // if STRAND_FLAG_NOINTERACTION is not used and interactionOpenParams is NULL it is assumed it will open an interaction on the right
                size_t                  numLists,               // numlist for the underlying Hash table, use 1 if it is not going to be searched
    _In_opt_    HashMapHashProc         hash,                   // hashing func for the underlying Hash table, if NULL will use the StrandEntry pointer
    _In_opt_    HashMapEqualProc        equal,                  // equal func for the underlying Hash table, can be NULL if it is not going to be searched or entry ptr comparison is ok
    _In_opt_    FindEntryProc           findEntryProc );        // finds a entry based on a message, can be NULL if msg should not be automatically redirected to entries

// This can be called from outside (StrandMany) parent strand
// IMPORTANT: The entry is not completely created/added until StrandEntry_ScheduleAdd/StrandMany_AddEntry is called
StrandEntry* StrandEntry_New(
#if defined(STRAND_ENABLE_DEBUG)
    _In_        StrandDebugInfo         debug,
#endif
    _In_        StrandMany*             parent,
    _In_        StrandFT*               userEntryFT,
                size_t                  structSize,
                StrandFlags             flags,
    _In_opt_    InteractionOpenParams*  interactionOpenParams );

// Completes adding a entry created by StrandEntry_New
// if the entry cannot be added it will be automatically deleted
void StrandEntry_ScheduleAdd( 
    _In_        StrandEntry*            self,
    _In_opt_    Message *               msg );          // optional initial message
    
// Completes adding a entry created by StrandEntry_New, but
// this should ONLY be called from parent (StrandMany) strand
// if the entry cannot be added it will be automatically deleted
MI_Result StrandMany_AddEntry(
    _In_        StrandEntry*            self );
    
// Can be used with any type of strand (this should be called in the object strand)
void Strand_Delete( _In_ Strand* self );

// It should delete all entries first (this should be called in the Parent object strand)
void StrandMany_Delete( _In_ StrandMany* self );

// Deletes a StrandEntry FROM the parent (StrandMany) strand
void StrandMany_DeleteEntry( _In_ StrandEntry* entry );

// Deletes a StrandEntry (this should be called in the Entry object strand)
void StrandEntry_Delete( _In_ StrandEntry* self );

// Deletes a StrandEntry that was NOT ADDED yet to the StrandMany 
// (not StrandEntry_ScheduleAdd or StrandMany_AddEntry called)
MI_INLINE void StrandEntry_DeleteNoAdded( _In_ StrandEntry* self )
{
    SList_Free( self );
}

// Called inside a strand method (or when creating strand with STRAND_FLAG_ENTERSTRAND)
// to explictly leave the strand (prematurely on the case of the strand method)
// Note that additional strand methods can be called if they are already 
// scheduled when Strand_Leave is called
void Strand_Leave( _In_ Strand* self );

//------------------------------------------------------------------------------------------------------------

// For testing purposes only
#if defined(STRAND_ENABLE_DEBUG)

#define STRAND_SETTESTSTRANDTHREAD( strand )    ((strand)->testThreadId = Thread_ID())

// internal use
MI_INLINE void _Strand_SetCurrentStrandThread( _In_ Strand* strand )
{
    strand->threadId = Thread_ID();
}

// internal use
MI_INLINE void _Strand_ExitCurrentStrandThread( _In_ Strand* strand )
{
    strand->threadId = Thread_ID_Null();
}

#else

#define STRAND_SETTESTSTRANDTHREAD( strand )
#define _Strand_SetCurrentStrandThread( strand )
#define _Strand_ExitCurrentStrandThread( strand )

#endif

// internal use
MI_INLINE void _Strand_Finish( 
    _In_ Strand* self)
{
    if( NULL != self->info.userFT->Finish )
    {
        (*self->info.userFT->Finish)(self);
    }
    else
    {
        Strand_Delete( self );
    }
}

// internal use
MI_INLINE
void _Strand_Post_CommonImp(
    _In_ InteractionInfo*   info,
    _In_ Message *          msg)
{
    DEBUG_ASSERT( !info->thisClosedOther );
    DEBUG_ASSERT( !info->thisAckPending );

    info->thisAckPending = MI_TRUE;
}

// internal use
MI_INLINE
void _Strand_Post_Imp(
    _In_ InteractionInfo*   info,
    _In_ Message *          msg)
{
    DEBUG_ASSERT( !info->ackPassthru );

    _Strand_Post_CommonImp( info, msg );
    info->interaction.other->ft->Post( info->interaction.other, msg );
}

// internal use
MI_INLINE
void _Strand_PostPassthru_Imp(
    _In_ InteractionInfo*   info,
    _In_ Message *          msg)
{
    DEBUG_ASSERT( !info->ackPassthru );
    info->ackPassthru = MI_TRUE;
    
    _Strand_Post_CommonImp( info, msg );
    info->interaction.other->ft->Post( info->interaction.other, msg );
}

// internal use
MI_INLINE
void _Strand_PostAndLeaveStrand_Imp(
    _In_ Strand*            strand,
    _In_ InteractionInfo*   info,
    _In_ Message *          msg)
{
    Interaction* other = info->interaction.other;
    DEBUG_ASSERT( !info->ackPassthru );

    _Strand_Post_CommonImp( info, msg );
    Strand_Leave(strand);
    other->ft->Post( other, msg );
}

// internal use
MI_INLINE
void _Strand_PostControl_Imp(
    _In_ InteractionInfo*   info,
    _In_ Message *          msg)
{
    DEBUG_ASSERT( !info->thisClosedOther );
    
    info->interaction.other->ft->PostControl( info->interaction.other, msg );
}

// internal use
MI_INLINE
void _Strand_Ack_Imp(
    _In_ InteractionInfo*   info)
{
    DEBUG_ASSERT( info->otherAckPending );
    
    info->otherAckPending = MI_FALSE;
    info->opened = MI_TRUE; // as soon as it send an Ack it means the interaction has been opened
    info->interaction.other->ft->Ack( info->interaction.other );
}

// internal use
MI_INLINE
void _Strand_Close_Imp(
    _In_ InteractionInfo*   info)
{
    DEBUG_ASSERT( !info->thisClosedOther );

    info->thisClosedOther = MI_TRUE;
    if( NULL != info->interaction.other )
    {
        info->interaction.other->ft->Close( info->interaction.other );
    }
    // otherwise implies a strand without interaction
}

//------------------------------------------------------------------------------------------------------------
#define BitExecuting            0x1

#define FirstMethodBit          1
#define FirstRealMethodBit      1

// For all Strands
#define BitCompleteOpenAsync    0x2
#define BitTimer                0x4

// For Strands with just one interaction
#define BitCancel               0x8
#define BitCancelSelf           0x10
#define BitPostControl          0x20    // Note if we have more than one control message type we will need to add more of this
#define BitPost                 0x40
#define BitPostOther            0x80
#define BitAck                  0x100
#define BitAckOther             0x200
#define BitClose                0x400
#define BitCloseOther           0x800
#define BitAux0                 0x1000
#define BitAux1                 0x2000
#define BitAux2                 0x4000
#define BitAux3                 0x8000
#define BitAux4                 0x10000

#define Strand_NumBaseMethods   11
#define Strand_NumAuxMethods    5
#define Strand_NumMethods       (Strand_NumBaseMethods+Strand_NumAuxMethods)

// For Strands with both interactions
#define BitCancel_Left          0x8
#define BitCancel_Right         0x10
#define BitCancelSelf_Both      0x20
#define BitPostControl_Left     0x40    // Note if we have more than one control message type we will need to add more of this
#define BitPostControl_Right    0x80    // (and same here)
#define BitPost_Left            0x100
#define BitPost_Right           0x200
#define BitPostOther_Left       0x400
#define BitPostOther_Right      0x800
#define BitAck_Left             0x1000
#define BitAck_Right            0x2000
#define BitAckOther_Left        0x4000
#define BitAckOther_Right       0x8000
#define BitClose_Left           0x10000
#define BitClose_Right          0x20000
#define BitCloseOther_Left      0x40000
#define BitCloseOther_Right     0x80000
#define BitAux0_Left            0x100000
#define BitAux1_Left            0x200000
#define BitAux2_Left            0x400000
#define BitAux3_Left            0x800000
#define BitAux4_Left            0x1000000
#define BitAux0_Right           0x2000000
#define BitAux1_Right           0x4000000
#define BitAux2_Right           0x8000000
#define BitAux3_Right           0x10000000
#define BitAux4_Right           0x20000000

#define StrandBoth_NumBaseMethods   19
#define StrandBoth_NumAuxMethods    10
#define StrandBoth_NumMethods       (StrandBoth_NumBaseMethods+StrandBoth_NumAuxMethods)

// for StrandMany/StrandEntry
#define BitCancel_Many          0x8
#define BitCancelSelf_Many      0x10
#define BitCancelInternal       0x20
#define BitPostControl_Many     0x40    // Note if we have more than one control message type we will need to add more of this
#define BitPostControlInternal  0x80    // Note if we have more than one control message type we will need to add more of this
#define BitPost_Many            0x100
#define BitPostOther_Many       0x200
#define BitPostInternal         0x400
#define BitAck_Many             0x800
#define BitAckOther_Many        0x1000
#define BitAckInternal          0x2000
#define BitEntryOperation       0x4000   // Entry operation (for scheduling operations on parent from entries)
#define BitClose_Many           0x8000
#define BitCloseOther_Many      0x10000
#define BitCloseInternal        0x20000
#define BitAux0_Many            0x40000
#define BitAux1_Many            0x80000
#define BitAux2_Many            0x100000
#define BitAux3_Many            0x200000
#define BitAux4_Many            0x400000

#define StrandMany_NumBaseMethods   17
#define StrandMany_NumAuxMethods    5
#define StrandMany_NumMethods       (StrandMany_NumBaseMethods+StrandMany_NumAuxMethods)

// for StrandMany/StrandEntry, bits of EntryOperations scheduled on one particular entry
#define BitEntryAdd             0x1
#define BitEntryCancel          0x2
#define BitEntryPostControl     0x4
#define BitEntryPost            0x8
#define BitEntryClose           0x10
#define BitEntryAux0            0x20
#define BitEntryAux1            0x40
#define BitEntryAux2            0x80
#define BitEntryAux3            0x100
#define BitEntryAux4            0x200
#define BitEntryDeleted         0x400

#define StrandMany_FirstBitEntryOperationAux    6
#define StrandMany_LastBitEntryOperationAux     10
#define StrandMany_NumEntryOperations           11

// internal use
#if defined(STRAND_ENABLE_DEBUG)
extern void _Strand_ScheduleImp( 
    _In_        Strand*                 self, 
                unsigned int            methodBit, 
                MI_Boolean              allowMultiSchedule, 
    _In_opt_    Strand*                 fromStrand,  
                EntryOperationMaskType  entryOperationBit );
                
#define _Strand_Schedule( self, methodBit ) \
    ( _Strand_ScheduleImp( (self), (methodBit), MI_FALSE, NULL, 0 ) )
    
#define _Strand_ScheduleEntryOperation( self, allowMultiSchedule, fromStrand, entryOperationBit ) \
    ( _Strand_ScheduleImp( (self), BitEntryOperation, (allowMultiSchedule), (fromStrand), (entryOperationBit) ) )

#define _Strand_ScheduleTimer( self ) \
    ( _Strand_ScheduleImp( (self), BitTimer, MI_TRUE, NULL, 0 ) )
    
#else

extern void _Strand_ScheduleImp( 
    _In_        Strand*                 self, 
                unsigned int            methodBit );
                
#define _Strand_Schedule( self, methodBit ) \
    ( _Strand_ScheduleImp( (self), (methodBit) ) )
    
#define _Strand_ScheduleEntryOperation( self, allowMultiSchedule, fromStrand, entryOperationBit ) \
    ( _Strand_ScheduleImp( (self), BitEntryOperation ) )
    
#define _Strand_ScheduleTimer( self ) \
    ( _Strand_ScheduleImp( (self), BitTimer ) )
    
#endif

//------------------------------------------------------------------------------------------------------------
// Debugging aid
//------------------------------------------------------------------------------------------------------------

#if defined(STRAND_ENABLE_DEBUG)
typedef struct _StrandBaseDebugInfo
{
    const char *    name;
    char            letter;
} StrandBaseDebugInfo;

extern StrandBaseDebugInfo _Strand_BaseNameDebugInfo[Strand_NumMethods+5];
extern StrandBaseDebugInfo _StrandBoth_BaseNameDebugInfo[StrandBoth_NumMethods+5];
extern StrandBaseDebugInfo _StrandMany_BaseNameDebugInfo[StrandMany_NumMethods+5];
extern char * _StrandMany_BaseEntryOperationDebugInfo[StrandMany_NumEntryOperations+3];
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME( strandName )   const char * _Strand_DebugInfo_##strandName [1] = { #strandName }
#else
#define STRAND_DEBUGNAME( strandName )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME1( strandName, auxName0 )   const char * _Strand_DebugInfo_##strandName [Strand_NumAuxMethods+1] = { #strandName, #auxName0 }
#else
#define STRAND_DEBUGNAME1( strandName, auxName0 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME2( strandName, auxName0, auxName1 )   const char * _Strand_DebugInfo_##strandName [Strand_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1 }
#else
#define STRAND_DEBUGNAME2( strandName, auxName0, auxName1 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME3( strandName, auxName0, auxName1, auxName2 )   const char * _Strand_DebugInfo_##strandName [Strand_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2 }
#else
#define STRAND_DEBUGNAME3( strandName, auxName0, auxName1, auxName2 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME4( strandName, auxName0, auxName1, auxName2, auxName3 )   const char * _Strand_DebugInfo_##strandName [Strand_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3 }
#else
#define STRAND_DEBUGNAME4( strandName, auxName0, auxName1, auxName2, auxName3 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME5( strandName, auxName0, auxName1, auxName2, auxName3, auxName4 )   const char * _Strand_DebugInfo_##strandName [Strand_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3, #auxName4 }
#else
#define STRAND_DEBUGNAME5( strandName, auxName0, auxName1, auxName2, auxName3, auxName4 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME6( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5 )   const char * _Strand_DebugInfo_##strandName [StrandBoth_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3, #auxName4, #auxName5 }
#else
#define STRAND_DEBUGNAME6( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME7( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6 )   const char * _Strand_DebugInfo_##strandName [StrandBoth_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3, #auxName4, #auxName5, #auxName6 }
#else
#define STRAND_DEBUGNAME7( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME8( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6, auxName7 )   const char * _Strand_DebugInfo_##strandName [StrandBoth_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3, #auxName4, #auxName5, #auxName6, #auxName7 }
#else
#define STRAND_DEBUGNAME8( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6, auxName7 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME9( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6, auxName7, auxName8 )   const char * _Strand_DebugInfo_##strandName [StrandBoth_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3, #auxName4, #auxName5, #auxName6, #auxName7, #auxName8 }
#else
#define STRAND_DEBUGNAME9( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6, auxName7, auxName8 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUGNAME10( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6, auxName7, auxName8, auxName9 )   const char * _Strand_DebugInfo_##strandName [StrandBoth_NumAuxMethods+1] = { #strandName, #auxName0, #auxName1, #auxName2, #auxName3, #auxName4, #auxName5, #auxName6, #auxName7, #auxName8, #auxName9 }
#else
#define STRAND_DEBUGNAME10( strandName, auxName0, auxName1, auxName2, auxName3, auxName4, auxName5, auxName6, auxName7, auxName8, auxName9 )   
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUG_GETBASEINFO( strand )  ( STRAND_TYPE_MIDDLE == (strand)->strandType ?  _StrandBoth_BaseNameDebugInfo : ( STRAND_ISTYPE_EDGE(strand) ? _Strand_BaseNameDebugInfo : _StrandMany_BaseNameDebugInfo ) )
#define STRAND_DEBUG_GETINFOSIZE( strand )  ( STRAND_TYPE_MIDDLE == (strand)->strandType ?  StrandBoth_NumMethods : ( STRAND_ISTYPE_EDGE(strand) ? Strand_NumMethods : StrandMany_NumMethods ) )
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUG_GETNAME( strand )   ( NULL != (strand)->debug ? (strand)->debug[0] : STRAND_DEBUG_GETBASEINFO(strand)[0].name )
#else
#define STRAND_DEBUG_GETNAME( strand )   ""
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define _STRAND_DEBUG_GETMETHOD( strand, bitIndex0 ) \
    ( (bitIndex0) >= Strand_NumBaseMethods && NULL != (strand)->debug && NULL != (strand)->debug[(bitIndex0)-Strand_NumBaseMethods+1] ? \
        (strand)->debug[(bitIndex0)-Strand_NumBaseMethods+1] : \
        _Strand_BaseNameDebugInfo[(bitIndex0)+2].name )
#define _STRANDBOTH_DEBUG_GETMETHOD( strand, bitIndex0 ) \
    ( (bitIndex0) >= StrandBoth_NumBaseMethods && NULL != (strand)->debug && NULL != (strand)->debug[(bitIndex0)-StrandBoth_NumBaseMethods+1] ? \
        (strand)->debug[(bitIndex0)-StrandBoth_NumBaseMethods+1] : \
        _StrandBoth_BaseNameDebugInfo[(bitIndex0)+2].name )
#define _STRANDMANY_DEBUG_GETMETHOD( strand, bitIndex0 )  \
    ( (bitIndex0) >= StrandMany_NumBaseMethods && NULL != (strand)->debug && NULL != (strand)->debug[(bitIndex0)-StrandMany_NumBaseMethods+1] ? \
        (strand)->debug[(bitIndex0)-StrandMany_NumBaseMethods+1] : \
        _StrandMany_BaseNameDebugInfo[(bitIndex0)+2].name )
#endif 

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUG_GETMETHODINDEX( strand, bitIndex ) \
    ( STRAND_TYPE_MIDDLE == (strand)->strandType ?  \
        _STRANDBOTH_DEBUG_GETMETHOD( strand, (bitIndex)-FirstMethodBit-1 ) : \
            ( STRAND_ISTYPE_EDGE(strand) ? \
                _STRAND_DEBUG_GETMETHOD( strand, (bitIndex)-FirstMethodBit-1 ) : \
                _STRANDMANY_DEBUG_GETMETHOD( strand, (bitIndex)-FirstMethodBit-1 ) ) )
#else
#define STRAND_DEBUG_GETMETHODINDEX( strand, bitIndex ) ""
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUG_GETMETHOD( strand, methodBit ) ( (methodBit == 0) ? "EnterStrand" : STRAND_DEBUG_GETMETHODINDEX( strand, GetFirstSetLSB(methodBit) ) )
#else
#define STRAND_DEBUG_GETMETHOD( strand, methodBit ) ""
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUG_GETOPERATIONINDEX( strand, bitIndex ) \
    ( (bitIndex) >= StrandMany_FirstBitEntryOperationAux && (bitIndex) <= StrandMany_LastBitEntryOperationAux \
    && NULL != (strand)->debug && NULL != (strand)->debug[(bitIndex)-StrandMany_FirstBitEntryOperationAux+1] ? \
        (strand)->debug[(bitIndex)-StrandMany_FirstBitEntryOperationAux+1] : _StrandMany_BaseEntryOperationDebugInfo[(bitIndex)-1] )
#else
#define STRAND_DEBUG_GETOPERATIONINDEX( strand, bitIndex ) ""
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_DEBUG_GETOPERATION( strand, operationMethodBit ) STRAND_DEBUG_GETOPERATIONINDEX( strand, GetFirstSetLSB(operationMethodBit) )
#else
#define STRAND_DEBUG_GETOPERATION( strand, operationMethodBit ) ""
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_ASSERTEXECUTING( strand )    DEBUG_ASSERT( ( ReadWithFence(&(strand)->stateScheduled) & BitExecuting ) != 0 )
#else
#define STRAND_ASSERTEXECUTING( strand )
#endif

#if defined(STRAND_ENABLE_DEBUG)    
void _Strand_AssertOnStrand( _In_ Strand* strand );
#define STRAND_ASSERTONSTRAND( strand )     _Strand_AssertOnStrand( strand )
#else
#define STRAND_ASSERTONSTRAND( strand )
#endif

#if defined(STRAND_ENABLE_DEBUG)
extern void _StrandLogWithName( _In_ Strand* self, _In_ const char * operation );
#define STRAND_LOGWITHNAME( strand, operation ) \
    _StrandLogWithName( strand, operation )
#else
#define STRAND_LOGWITHNAME( strand, operation )
#endif

/*
#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_VERIFYPROPERLYOPENED( strand ) \
DEBUG_ASSERT( (strand)->info.opened || \
    ( STRAND_ISTYPE_EDGE( strand ) && (strand)->currentMethodBit == BitAck ) || \
    ( STRAND_ISTYPE_MANY( strand ) && (strand)->currentMethodBit == BitAck_Many ) )
#else
#define STRAND_VERIFYPROPERLYOPENED( strand )
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand ) \
DEBUG_ASSERT( (strand)->base.info.opened || (strand)->base.currentMethodBit == BitAck_Left )
#else
#define STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand )
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand ) \
DEBUG_ASSERT( (strand)->infoRight.opened || (strand)->base.currentMethodBit == BitAck_Right )
#else
#define STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand )
#endif
*/

#if defined(STRAND_ENABLE_DEBUG)
#define STRAND_VERIFYPROPERLYOPENED( strand ) DEBUG_ASSERT( (strand)->info.opened )
#else
#define STRAND_VERIFYPROPERLYOPENED( strand )
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand ) DEBUG_ASSERT( (strand)->base.info.opened )
#else
#define STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand )
#endif

#if defined(STRAND_ENABLE_DEBUG)
#define STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand ) DEBUG_ASSERT( (strand)->infoRight.opened )
#else
#define STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand )
#endif

//------------------------------------------------------------------------------------------------------------

// initiates a Post in the other interaction (should be running on the strand)
// Can also be used on StrandMany and StrandEntry (but not with StrandBoth)
MI_INLINE
void Strand_Post(
    _In_ Strand *   strand,
    _In_ Message *  msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( strand ) || STRAND_ISTYPE_MANY( strand ) );
    STRAND_ASSERTONSTRAND( strand );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRAND_VERIFYPROPERLYOPENED( strand );
    
    STRAND_LOGWITHNAME( strand, "Post" );
    _Strand_Post_Imp( &strand->info, msg );
    STRAND_LOGWITHNAME( strand, "Returning from Post" );
}

// initiates a Post in the other left interaction (should be running on the strand)
MI_INLINE
void StrandBoth_PostLeft(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand );
    
    STRAND_LOGWITHNAME( &strand->base, "PostLeft" );
    _Strand_Post_Imp( &strand->base.info, msg );
    STRAND_LOGWITHNAME( &strand->base, "Returning from PostLeft" );
}

// initiates a Post in the other right interaction (should be running on the strand)
MI_INLINE
void StrandBoth_PostRight(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand );

    STRAND_LOGWITHNAME( &strand->base, "PostRight" );
    _Strand_Post_Imp( &strand->infoRight, msg );
    STRAND_LOGWITHNAME( &strand->base, "Returning from PostRight" );
}

// initiates a Post in the other interaction (should be running on the strand)
// In this version the ack is relayed automatically to the other side (in a pass-thru fashion)
// ( no user Ack will be called )
MI_INLINE
void Strand_PostPassthru(
    _In_ Strand *   strand,
    _In_ Message *  msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( strand ) || STRAND_ISTYPE_MANY( strand ) );
    STRAND_ASSERTONSTRAND( strand );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRAND_VERIFYPROPERLYOPENED( strand );

    STRAND_LOGWITHNAME( strand, "PostPassthru" );
    _Strand_PostPassthru_Imp( &strand->info, msg );
    STRAND_LOGWITHNAME( strand, "Returning from PostPassthru" );
}

// initiates a Post in the other left interaction (should be running on the strand)
// In this version the ack is relayed automatically to the other side (in a pass-thru fashion)
// ( no user Ack will be called )
MI_INLINE
void StrandBoth_PostPassthruLeft(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand );

    STRAND_LOGWITHNAME( &strand->base, "PostPassthruLeft" );
    _Strand_PostPassthru_Imp( &strand->base.info, msg );
    STRAND_LOGWITHNAME( &strand->base, "Returning from PostPassthruLeft" );
}

// initiates a Post in the other right interaction (should be running on the strand)
// In this version the ack is relayed automatically to the other side (in a pass-thru fashion)
// ( no user Ack will be called )
MI_INLINE
void StrandBoth_PostPassthruRight(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand );

    STRAND_LOGWITHNAME( &strand->base, "PostPassthruRight" );
    _Strand_PostPassthru_Imp( &strand->infoRight, msg );
    STRAND_LOGWITHNAME( &strand->base, "Returning from PostPassthruRight" );
}

// initiates a Post in the other interaction (should be running on the strand)
// and leaves the strand before returning
// Can also be used on StrandMany and StrandEntry (but not with StrandBoth)
MI_INLINE
void Strand_PostAndLeaveStrand(
    _In_ Strand *   strand,
    _In_ Message *  msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( strand ) || STRAND_ISTYPE_MANY( strand ) );
    STRAND_ASSERTONSTRAND( strand );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRAND_VERIFYPROPERLYOPENED( strand );
    
    STRAND_LOGWITHNAME( strand, "PostAndLeaveStrand" );
    _Strand_PostAndLeaveStrand_Imp( strand, &strand->info, msg );
}

// initiates a Post in the other left interaction (should be running on the strand)
// and leaves the strand before returning
MI_INLINE
void StrandBoth_PostLeftAndLeaveStrand(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand );
    
    STRAND_LOGWITHNAME( &strand->base, "PostLeftAndLeaveStrand" );
    _Strand_PostAndLeaveStrand_Imp( &strand->base, &strand->base.info, msg );
}

// initiates a Post in the other right interaction (should be running on the strand)
// and leaves the strand before returning
MI_INLINE
void StrandBoth_PostRightAndLeaveStrand(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand );

    STRAND_LOGWITHNAME( &strand->base, "PostRightAndLeaveStrand" );
    _Strand_PostAndLeaveStrand_Imp( &strand->base, &strand->infoRight, msg );
}

// initiates a PostControl in the other interaction (should be running on the strand)
// Can also be used on StrandMany and StrandEntry (but not with StrandBoth)
MI_INLINE
void Strand_PostControl(
    _In_ Strand *   strand,
    _In_ Message *  msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( strand ) || STRAND_ISTYPE_MANY( strand ) );
    STRAND_ASSERTONSTRAND( strand );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRAND_VERIFYPROPERLYOPENED( strand );

    STRAND_LOGWITHNAME( strand, "PostControl" );
    _Strand_PostControl_Imp( &strand->info, msg );
    STRAND_LOGWITHNAME( strand, "Returning from PostControl" );
}

// initiates a PostControl in the other left interaction (should be running on the strand)
MI_INLINE
void StrandBoth_PostControlLeft(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand );

    STRAND_LOGWITHNAME( &strand->base, "PostControlLeft" );
    _Strand_PostControl_Imp( &strand->base.info, msg );
    STRAND_LOGWITHNAME( &strand->base, "Returning from PostControlLeft" );
}

// initiates a PostControl in the other right interaction (should be running on the strand)
MI_INLINE
void StrandBoth_PostControlRight(
    _In_ StrandBoth *   strand,
    _In_ Message *      msg)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand );

    STRAND_LOGWITHNAME( &strand->base, "PostControlRight" );
    _Strand_PostControl_Imp( &strand->infoRight, msg );
    STRAND_LOGWITHNAME( &strand->base, "Returning from PostControlRight" );
}

// initiates an Ack in the other interaction (should be running on the strand)
// Can also be used on StrandMany and StrandEntry (but not with StrandBoth)
MI_INLINE
void Strand_Ack(
    _In_ Strand *   strand)
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( strand ) || STRAND_ISTYPE_MANY( strand ) );
    STRAND_ASSERTONSTRAND( strand );

    STRAND_LOGWITHNAME( strand, "Ack" );
    _Strand_Ack_Imp( &strand->info );
    STRAND_LOGWITHNAME( strand, "Returning from Ack" );
}

// initiates an Ack in the other left interaction (should be running on the strand)
MI_INLINE
void StrandBoth_AckLeft(
    _In_ StrandBoth *   strand)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );

    STRAND_LOGWITHNAME( &strand->base, "AckLeft" );
    _Strand_Ack_Imp( &strand->base.info );
    STRAND_LOGWITHNAME( &strand->base, "Returning from AckLeft" );
}

// initiates an Ack in the other right interaction (should be running on the strand)
MI_INLINE
void StrandBoth_AckRight(
    _In_ StrandBoth *   strand)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );

    STRAND_LOGWITHNAME( &strand->base, "AckRight" );
    _Strand_Ack_Imp( &strand->infoRight );
    STRAND_LOGWITHNAME( &strand->base, "Returning from AckRight" );
}

// initiates a cancel wherever necessary
// ( can be used with any type of strand)
void Strand_Cancel(
    _In_ Strand *   self);

// initiates a Close in the other interaction (should be running on the strand)
// Can also be used on StrandMany and StrandEntry (but not with StrandBoth)
MI_INLINE
void Strand_Close(
    _In_ Strand *   strand)
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( strand ) || STRAND_ISTYPE_MANY( strand ) );
    STRAND_ASSERTONSTRAND( strand );
    // During ack the opened state is not set until it returns back from user method, so the user can Post while opened is not set yet
    STRAND_VERIFYPROPERLYOPENED( strand );

    STRAND_LOGWITHNAME( strand, "Close" );
    _Strand_Close_Imp( &strand->info );
    STRAND_LOGWITHNAME( strand, "Returning from Close" );
}

// initiates a Close in the other left interaction (should be running on the strand)
MI_INLINE
void StrandBoth_CloseLeft(
    _In_ StrandBoth *   strand)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Close while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_LEFT( strand );

    STRAND_LOGWITHNAME( &strand->base, "CloseLeft" );
    _Strand_Close_Imp( &strand->base.info );
    STRAND_LOGWITHNAME( &strand->base, "Returning from CloseLeft" );
}

// initiates a Close in the other right interaction (should be running on the strand)
MI_INLINE
void StrandBoth_CloseRight(
    _In_ StrandBoth *   strand)
{
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &strand->base ) );
    STRAND_ASSERTONSTRAND( &strand->base );
    // During ack the opened state is not set until it returns back from user method, so the user can Close while opened is not set yet
    STRANDBOTH_VERIFYPROPERLYOPENED_RIGHT( strand );

    STRAND_LOGWITHNAME( &strand->base, "CloseRight" );
    _Strand_Close_Imp( &strand->infoRight );
    STRAND_LOGWITHNAME( &strand->base, "Returning from CloseRight" );
}

MI_INLINE
void Strand_SetDelayFinish(
    _In_ Strand* self )
{
    STRAND_ASSERTONSTRAND( self );
    self->delayFinish = MI_TRUE;
}

MI_INLINE
void Strand_ResetDelayFinish(
    _In_ Strand* self )
{
    STRAND_ASSERTONSTRAND( self );
    self->delayFinish = MI_FALSE;
}

//------------------------------------------------------------------------------------------------------------
// Internal use
MI_INLINE
void _Strand_StartOpenImp( 
    _In_        InteractionInfo*    info,
                MI_Boolean          initialAckPending )
{    
    DEBUG_ASSERT( !info->otherAckPending );
    DEBUG_ASSERT( !info->thisAckPending );
    
    info->thisClosedOther = MI_FALSE;
    info->otherClosedThis = MI_FALSE;
    info->thisAckPending = initialAckPending;
    info->otherAckPending = MI_FALSE;
    info->opened = MI_TRUE;
}

// Internal use
MI_INLINE
void _Strand_StartOpenCancelImp( 
    _In_        InteractionInfo*    info )
{    
    DEBUG_ASSERT( info->opened );
    
    info->thisAckPending = MI_FALSE;
    info->opened = MI_FALSE;
}

// Internal use
MI_INLINE
void _Strand_OpenPrepareImp( 
    _In_        Strand *                self, 
    _In_        InteractionInfo*        info, 
    _Out_       InteractionOpenParams*  interactionParams, 
    _In_opt_    void*                   callbackData,   // Optional callbackData (usually the object being called back)
    _In_opt_    Message*                msg,            // Optional initial message, if not NULL receiver should call Message_Release once interaction is opened/done with the message 
                MI_Boolean              leaveStrand )   // If true it will leave the strand once opened
{    
    STRAND_ASSERTONSTRAND(self);

    _Strand_StartOpenImp( info, NULL != msg );

    interactionParams->callbackData = callbackData;
    interactionParams->interaction = &info->interaction;
    interactionParams->msg = msg;
    interactionParams->origin = leaveStrand ? self : NULL;
}

// Internal use
MI_INLINE
void _Strand_OpenImp( 
    _In_        Strand *            self, 
    _In_        InteractionInfo*    info, 
    _In_        OpenCallback        callback, 
    _In_opt_    void*               callbackData,   // Optional callbackData (usually the object being called back)
    _In_opt_    Message*            msg,            // Optional initial message, if not NULL receiver should call Message_Release once interaction is opened/done with the message 
                MI_Boolean          leaveStrand )   // If true it will leave the strand once opened
{    
    InteractionOpenParams params;

    _Strand_OpenPrepareImp(self, info, &params, callbackData, msg, leaveStrand );
    
    (*callback)( &params );
}

// Used on Strand/StrandMany/StrandEntry (but not StrandBoth, see below)
MI_INLINE
void Strand_Open( 
    _In_        Strand *        self, 
    _In_        OpenCallback    callback, 
    _In_opt_    void*           callbackData,   // Optional callbackData (usually the object being called back)
    _In_opt_    Message*        msg,            // Optional initial message, if not NULL receiver should call Message_Release once interaction is opened/done with the message 
                MI_Boolean      leaveStrand )   // If true it will leave the strand once opened
{    
    DEBUG_ASSERT( !self->info.ackPassthru );
    DEBUG_ASSERT( !STRAND_ISTYPE_MIDDLE( self ) );
    _Strand_OpenImp( self, &self->info, callback, callbackData, msg, leaveStrand );
}

// Make sure of call Strand_OpenCancel if the open doesnt actually occurs
// Used on Strand/StrandMany/StrandEntry (but not StrandBoth, see below)
MI_INLINE
void Strand_OpenPrepare( 
    _In_        Strand *                self, 
    _Out_       InteractionOpenParams*  interactionParams, 
    _In_opt_    void*                   callbackData,   // Optional callbackData (usually the object being called back)
    _In_opt_    Message*                msg,            // Optional initial message, if not NULL receiver should call Message_Release once interaction is opened/done with the message 
                MI_Boolean              leaveStrand )   // If true it will leave the strand once opened
{    
    DEBUG_ASSERT( !self->info.ackPassthru );
    DEBUG_ASSERT( !STRAND_ISTYPE_MIDDLE( self ) );
    _Strand_OpenPrepareImp( self, &self->info, interactionParams, callbackData, msg, leaveStrand );
}

// If after call Strand_OpenPrepare the opend didnt happen
// Used on Strand/StrandMany/StrandEntry (but not StrandBoth, see below)
MI_INLINE
void Strand_OpenCancel( 
    _In_        Strand *                self )
{
    STRAND_ASSERTONSTRAND(self);
    _Strand_StartOpenCancelImp( &self->info );
}

// Always open to the right
// ackPassthru indicates if the initial Ack from open is just going to be passed thru
// or delivered to the Ack user method instead (it will always be passthru if the ack
// user method is NULL)
MI_INLINE
void StrandBoth_Open( 
    _In_        StrandBoth *    self, 
    _In_        OpenCallback    callback, 
    _In_opt_    void*           callbackData,   // Optional callbackData (usually the object being called back)
    _In_opt_    Message*        msg,            // Optional initial message, if not NULL receiver should call Message_Release once interaction is opened/done with the message 
                MI_Boolean      leaveStrand,    // If true it will leave the strand once opened
                MI_Boolean      ackPassthru )
{    
    DEBUG_ASSERT( !self->infoRight.ackPassthru );
    DEBUG_ASSERT( !ackPassthru || NULL != msg );    // No sense on indicating passthru if there is no message
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &self->base ) );
    self->infoRight.ackPassthru = ackPassthru;
    _Strand_OpenImp( &self->base, &self->infoRight, callback, callbackData, msg, leaveStrand );
}

// Make sure of call Strand_OpenCancel if the open doesnt actually occurs
// Always open to the right
// ackPassthru indicates if the initial Ack from open is just going to be passed thru
// or delivered to the Ack user method instead (it will always be passthru if the ack
// user method is NULL)
MI_INLINE
void StrandBoth_OpenPrepare( 
    _In_        StrandBoth *            self, 
    _Out_       InteractionOpenParams*  interactionParams, 
    _In_opt_    void*                   callbackData,   // Optional callbackData (usually the object being called back)
    _In_opt_    Message*                msg,            // Optional initial message, if not NULL receiver should call Message_Release once interaction is opened/done with the message 
                MI_Boolean              leaveStrand,    // If true it will leave the strand once opened
                MI_Boolean              ackPassthru )
{    
    DEBUG_ASSERT( !self->infoRight.ackPassthru );
    DEBUG_ASSERT( !ackPassthru || NULL != msg );    // No sense on indicating passthru if there is no message
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &self->base ) );
    self->infoRight.ackPassthru = ackPassthru;
    _Strand_OpenPrepareImp( &self->base, &self->infoRight, interactionParams, callbackData, msg, leaveStrand );
}

// If after call Strand_OpenPrepare the opend didnt happen
// Used on Strand/StrandMany/StrandEntry (but not StrandBoth, see below)
MI_INLINE
void StrandBoth_OpenCancel( 
    _In_        StrandBoth *            self )
{
    STRAND_ASSERTONSTRAND(&self->base);
    _Strand_StartOpenCancelImp( &self->infoRight );
}

// Used on Strand/StrandMany/StrandEntry (but not StrandBoth, see below)
MI_INLINE
void Strand_StartOpenAsync( 
    _In_        Strand *        self )
{    
    STRAND_ASSERTONSTRAND(self);
    DEBUG_ASSERT( !self->info.ackPassthru );
    DEBUG_ASSERT( !STRAND_ISTYPE_MIDDLE( self ) );

    _Strand_StartOpenImp( &self->info, MI_FALSE );
    // this is different in this case
    // not opened until Strand_CompleteOpenAsync
    self->info.opened = MI_FALSE; 
}

// Always open to the right
MI_INLINE
void StrandBoth_StartOpenAsync( 
    _In_        StrandBoth *    self )
{    
    STRAND_ASSERTONSTRAND(&self->base);
    DEBUG_ASSERT( !self->infoRight.ackPassthru );
    DEBUG_ASSERT( STRAND_ISTYPE_MIDDLE( &self->base ) );

    _Strand_StartOpenImp( &self->infoRight, MI_FALSE );
    // this is different in this case
    // not opened until StrandBoth_CompleteOpenAsync
    self->infoRight.opened = MI_FALSE; 
}

// Used on Strand/StrandMany/StrandEntry AND StrandBoth (which always accepts on the left)
void Strand_AcceptOpen( 
    _In_        Strand*                 self, 
    _In_        InteractionOpenParams*  params );

// Used on Strand/StrandMany/StrandEntry AND StrandBoth (which always accepts on the left)
// However this should only be used if the 'otherStrand' is a Strand/StrandMany/StrandEntry 
// (use Strand_AcceptOpenAsyncFromStrandBoth if it is StrandBoth)
void Strand_AcceptOpenAsync( 
    _In_        Strand*                 self, 
    _In_        Strand*                 otherStrand );

// Used on Strand/StrandMany/StrandEntry AND StrandBoth (which always accepts on the left)
// However this should only be used if the 'otherStrand' is a StrandBoth
void Strand_AcceptOpenAsyncFromStrandBoth( 
    _In_        Strand*                 self, 
    _In_        StrandBoth*             otherStrand );

// Also used on all kind of strands
void Strand_FailOpenWithMsg( 
    _In_        InteractionOpenParams*  params,
    _In_opt_    Message*                msg );  // Optional failed response message (it will be canceled otherwise). Note that it is NOT released inside 

// Also used on all kind of strands
MI_INLINE
void Strand_FailOpen( 
    _In_        InteractionOpenParams*  params )
{    
    Strand_FailOpenWithMsg( params, NULL );
}

typedef PostResultMsg* (*MakeResultMessageCallback)(
    _In_ Message* req,
    _In_opt_ const MI_Instance* err,
    _In_opt_z_ const MI_Char* errmsg,
    _In_z_ const MI_Char *errorType,
    _In_ MI_Uint32 r);

// Also used on all kind of strands
void Strand_FailOpenWithResult(
    _In_ InteractionOpenParams*  params,
    MI_Result result,
    _In_ MakeResultMessageCallback callback);
   
//------------------------------------------------------------------------------------------------------------
// Needed in a StrandBoth if we are opening one side but the other side is in error
// and therefore we need to force it closed
MI_INLINE
void Strand_ForceClose(
    _In_ InteractionInfo *  info )
{
    DEBUG_ASSERT( !info->otherAckPending );
    
    info->thisClosedOther = MI_TRUE;
    info->otherClosedThis = MI_TRUE;
    info->thisAckPending = MI_FALSE;
}

#ifdef _PREFAST_
#pragma prefast (push)
#pragma prefast (disable: 26001) // bogus "we know the interaction points to the middle of the Strand struct"
#endif /* _PREFAST_ */

MI_INLINE
Strand* 
Strand_FromInteraction(
    _In_ Interaction* interaction )
{
    return FromOffset(Strand,info,interaction);
}

MI_INLINE
StrandBoth* 
Strand_FromInteractionRight(
    _In_ Interaction* interaction )
{
    return FromOffset(StrandBoth,infoRight,interaction);
}

// For use on StrandMany user methods
MI_INLINE
StrandMany* StrandMany_FromStrand( _In_ Strand * strand )
{
    return FromOffset(StrandMany,strand,strand);
}

// For use on StrandMany user methods
MI_INLINE
StrandEntry* StrandEntry_FromStrand( _In_ Strand * strand )
{
    return FromOffset(StrandEntry,strand,strand);
}

// For use on HashMapHashProc and HashMapEqualProc
MI_INLINE
StrandEntry* StrandEntry_FromBucket( _In_ HashBucket * bucket )
{
    return FromOffset(StrandEntry,bucket,bucket);
}
MI_INLINE
const StrandEntry* StrandEntry_FromBucketConst( _In_ const HashBucket * bucket )
{
    return FromOffsetConst(StrandEntry,bucket,bucket);
}

//------------------------------------------------------------------------------------------------------------
// note that an internal "iter" variable is used, so this can only be used inside the strand
MI_INLINE
void StrandMany_BeginIteration( _In_ StrandMany* self )
{
    STRAND_ASSERTONSTRAND( &self->strand );
    HashMap_BeginIteration( &self->many, &self->iter);
}

MI_INLINE
StrandEntry * StrandMany_Iterate( _In_ StrandMany* self )
{
    HashBucket* bucket;

    STRAND_ASSERTONSTRAND( &self->strand );

    bucket = (HashBucket*)HashMap_Iterate(&self->many, &self->iter);
    
    if( NULL == bucket )
        return NULL;
    else
        return StrandEntry_FromBucket( bucket );
}

#ifdef _PREFAST_
#pragma prefast (pop)
#endif /* _PREFAST_ */

//------------------------------------------------------------------------------------------------------------

MI_INLINE
void _Strand_SchedulePostCommon( _In_ InteractionInfo* info, _In_ Message * msg ) 
{
    DEBUG_ASSERT( NULL == info->otherMsg );
    Message_AddRef( msg );  // since the actual message use can be delayed
    info->otherMsg = msg;
}

// Dont use with a StrandBoth (use StrandBoth_SchedulePostLeft or StrandBoth_SchedulePostRight instead)
// (neither with a StrandMany/StrandEntry, see below instead)
MI_INLINE
void Strand_SchedulePost( _In_ Strand* self, _In_ Message * msg ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( self ) );
    _Strand_SchedulePostCommon( &self->info,  msg );
    _Strand_Schedule( self, BitPostOther );
}

MI_INLINE
void StrandBoth_SchedulePostLeft( _In_ StrandBoth* self, _In_ Message * msg ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_SchedulePostCommon( &self->base.info,  msg );
    _Strand_Schedule( &self->base, BitPostOther_Left );
}

MI_INLINE
void StrandBoth_SchedulePostRight( _In_ StrandBoth* self, _In_ Message * msg ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_SchedulePostCommon( &self->infoRight,  msg );
    _Strand_Schedule( &self->base, BitPostOther_Right );
}

MI_INLINE
void StrandMany_SchedulePost( _In_ StrandMany* self, _In_ Message * msg  ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_PARENT(&self->strand) );
    _Strand_SchedulePostCommon( &self->strand.info,  msg );
    _Strand_Schedule( &self->strand, BitPostOther_Many );
}

MI_INLINE
void StrandEntry_SchedulePost( _In_ StrandEntry* self, _In_ Message * msg  ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_ENTRY(&self->strand) );
    _Strand_SchedulePostCommon( &self->strand.info,  msg );
    _Strand_Schedule( &self->strand, BitPostOther_Many );
}

// Dont use with a StrandBoth (use StrandBoth_ScheduleAckLeft or StrandBoth_ScheduleAckRight instead)
// (neither with a StrandMany/StrandEntry, see below instead)
MI_INLINE
void Strand_ScheduleAck( _In_ Strand* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( self ) );
    _Strand_Schedule( self, BitAckOther );
}

MI_INLINE
void StrandBoth_ScheduleAckLeft( _In_ StrandBoth* self ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitAckOther_Left );
}

MI_INLINE
void StrandBoth_ScheduleAckRight( _In_ StrandBoth* self ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitAckOther_Right );
}

MI_INLINE
void StrandMany_ScheduleAck( _In_ StrandMany* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_PARENT(&self->strand) );
    _Strand_Schedule( &self->strand, BitAckOther_Many );
}

MI_INLINE
void StrandEntry_ScheduleAck( _In_ StrandEntry* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_ENTRY(&self->strand) );
    _Strand_Schedule( &self->strand, BitAckOther_Many );
}

// Dont use with a StrandBoth (use StrandBoth_ScheduleCloseLeft or StrandBoth_ScheduleCloseRight instead)
// (neither with a StrandMany/StrandEntry, see below instead)
MI_INLINE
void Strand_ScheduleClose( _In_ Strand* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( self ) );
    _Strand_Schedule( self, BitCloseOther );
}

MI_INLINE
void StrandBoth_ScheduleCloseLeft( _In_ StrandBoth* self ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitCloseOther_Left );
}

MI_INLINE
void StrandBoth_ScheduleCloseRight( _In_ StrandBoth* self ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitCloseOther_Right );
}

MI_INLINE
void StrandMany_ScheduleClose( _In_ StrandMany* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_PARENT(&self->strand) );
    _Strand_Schedule( &self->strand, BitCloseOther_Many );
}

MI_INLINE
void StrandEntry_ScheduleClose( _In_ StrandEntry* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_ENTRY(&self->strand) );
    _Strand_Schedule( &self->strand, BitCloseOther_Many );
}

// Dont use with a StrandBoth (use StrandBoth_ScheduleCancel instead)
// (neither with a StrandMany/StrandEntry, see below instead)
MI_INLINE
void Strand_ScheduleCancel( _In_ Strand* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( self ) );
    _Strand_Schedule( self, BitCancelSelf );
}

MI_INLINE
void StrandBoth_ScheduleCancel( _In_ StrandBoth* self ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitCancelSelf_Both );
}

MI_INLINE
void StrandMany_ScheduleCancel( _In_ StrandMany* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_PARENT(&self->strand) );
    _Strand_Schedule( &self->strand, BitCancelSelf_Many );
}

MI_INLINE
void StrandEntry_ScheduleCancel( _In_ StrandEntry* self ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_ENTRY(&self->strand) );
    _Strand_Schedule( &self->strand, BitCancelSelf_Many );
}

//------------------------------------------------------------------------------------------------------------

// Dont use with a StrandBoth/StrandMany/StrandEntry (use StrandBoth_ScheduleAuxLeft, StrandBoth_ScheduleAuxRight, StrandMany_ScheduleAux or StrandEntry_ScheduleAux instead)
MI_INLINE
void Strand_ScheduleAux( _In_ Strand* self, unsigned int auxMethodNumber ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_EDGE( self ) );
    _Strand_Schedule( self, BitAux0 << auxMethodNumber );
}

MI_INLINE
void StrandBoth_ScheduleAuxLeft( _In_ StrandBoth* self, unsigned int auxMethodNumber ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitAux0_Left << auxMethodNumber );
}

MI_INLINE
void StrandBoth_ScheduleAuxRight( _In_ StrandBoth* self, unsigned int auxMethodNumber ) 
{
    DEBUG_ASSERT( STRAND_TYPE_MIDDLE == self->base.strandType );
    _Strand_Schedule( &self->base, BitAux0_Right << auxMethodNumber );
}

MI_INLINE
void StrandMany_ScheduleAux( _In_ StrandMany* self, unsigned int auxMethodNumber ) 
{
    DEBUG_ASSERT( STRAND_ISTYPE_PARENT( &self->strand ) );
    _Strand_Schedule( &self->strand, BitAux0_Many << auxMethodNumber );
}

MI_INLINE
void StrandEntry_ScheduleAux( _In_ StrandEntry* self, unsigned int auxMethodNumber ) 
{
    DEBUG_ASSERT( STRAND_TYPE_ENTRY == self->strand.strandType );
    _Strand_Schedule( &self->strand, BitAux0_Many << auxMethodNumber );
}

//------------------------------------------------------------------------------------------------------------

// Call these ONLY from Parent strand
MI_INLINE
void StrandMany_CancelEntry( _In_ StrandEntry* entry )
{
    STRAND_ASSERTONSTRAND( &entry->parent->strand );
    _Strand_Schedule( &entry->strand, BitCancelInternal );
}
MI_INLINE
void StrandMany_CloseEntry( _In_ StrandEntry* entry )
{
    STRAND_ASSERTONSTRAND( &entry->parent->strand );
    _Strand_Schedule( &entry->strand, BitCloseInternal );
}
MI_INLINE
void StrandMany_AckEntry( _In_ StrandEntry* entry )
{
    STRAND_ASSERTONSTRAND( &entry->parent->strand );
    _Strand_Schedule( &entry->strand, BitAckInternal );
}
void StrandMany_CancelAllEntries( _In_ StrandMany* self );
void StrandMany_CloseAllEntries( _In_ StrandMany* self );
void StrandMany_PostEntry( _In_ StrandEntry* entry, _In_ Message* msg );
void StrandMany_PostAll( _In_ StrandMany* self, _In_ Message* msg );
MI_Boolean StrandMany_PostFindEntry( _In_ StrandMany* self, _In_ Message* msg );
void StrandMany_PostControlEntry( _In_ StrandEntry* entry, _In_ Message* msg );
void StrandMany_PostControlAll( _In_ StrandMany* self, _In_ Message* msg );
MI_Boolean StrandMany_PostControlFindEntry( _In_ StrandMany* self, _In_ Message* msg );

// internal use only
void _StrandEntry_ScheduleParent( _In_ StrandEntry* self, EntryOperationMaskType entryOperationBit );

// Call these ONLY from a Entry strand
MI_INLINE
void StrandEntry_CancelParent( _In_ StrandEntry* self )
{
    STRAND_ASSERTONSTRAND( &self->strand );
    _StrandEntry_ScheduleParent( self, BitEntryCancel );
}
MI_INLINE
void StrandEntry_CloseParent( _In_ StrandEntry* self )
{
    STRAND_ASSERTONSTRAND( &self->strand );
    _StrandEntry_ScheduleParent( self, BitEntryClose );
}

void StrandEntry_PostParent( _In_ StrandEntry* self, _In_ Message* msg );

// Use this if the msg comes from the interaction
// Takes care of delivering Ack on the interaction once Parent has actually
// being able to Post (manages flow control internally)
void StrandEntry_PostParentPassthru( _In_ StrandEntry* self, _In_ Message* msg );

void StrandEntry_PostControlParent( _In_ StrandEntry* self, _In_ Message* msg );

MI_INLINE
void StrandEntry_ScheduleAuxParent( _In_ StrandEntry* self, unsigned int auxMethodNumber  )
{
    STRAND_ASSERTONSTRAND( &self->strand );
    DEBUG_ASSERT( (BitEntryAux0 << auxMethodNumber) < BitEntryDeleted );
    _StrandEntry_ScheduleParent( self, BitEntryAux0 << auxMethodNumber );
}


//------------------------------------------------------------------------------------------------------------
// Timer methods and types
//
// Note: These were moved from a separate header file to resolve the circular
//       dependency caused by Strand using Timer and Timer functions taking a
//       Strand as an argument.

typedef enum _TimerResult
{
    TimerResult_Success         = 0,
    TimerResult_Failed          = 1,
    TimerResult_InvalidArgument = 2
}
TimerResult;

/*
 * Specifies a single use timer that will timeout after a specified amount
 * of time.  The timer may be triggered early through manual intervention.
 */
struct _Timer
{
    /* The timeout value to use, specified in microseconds. */
    MI_Uint64 timeoutInUsec;

    /* Specifies the reason of calling the timeout callback: expired, manually fired, etc. */
    TimerReason reason;
    
    /* Internal OS-Specific data */
#if defined(CONFIG_OS_WINDOWS)
    PTP_TIMER pTimer;
#endif

#if defined(CONFIG_POSIX)
    Handler handler;
    Selector* selector;
#endif
    /* End OS-Specific data */
};

/*
 * Doesn't start the actual timer or extend an already scheduled Timer.
 * It just sets the Timer's specified timeout period.  This should be set 
 * prior to the first call to Timer_Start.
 * 
 * Updates to its value will take effect the next time Timer_Start is called.
 */
MI_INLINE
void Timer_SetTime( 
    _In_ Timer* timer, 
    _In_ MI_Uint64 timeUsec )
{
    DEBUG_ASSERT( timer );
    timer->timeoutInUsec = timeUsec;
}

/* 
 * Starts an initialized Timer with a previously specified timeout value. 
 * Also used to restart a timer after completion. 
 */
TimerResult Timer_Start( 
    _In_ Timer* timer, 
    _In_ Strand* strand );

/* 
 * Manually force early execution of a Timer. 
 */
void Timer_Fire( 
    _In_ Timer* timer, 
    _In_ Strand* strand,
         TimerReason reason );

/*
 * Cleans up a Timer from a previous run, but leaves it ready for re-use via
 * Timer_Start().
 *
 * Note: This is designed to be used by a Strand and not to be used via
 *       independent calls.
 */
void Timer_Close(
    _In_ Timer* timer );

/*
 * Sets a global internal selector to avoid requiring it to be passed in via
 * Timer_Init().
 */
void Timer_SetSelector(
    _In_ Selector* selector );

/*
 * Timer manipulation functions for Strands
 */
void Strand_StartTimer( _In_ Strand* self, _In_ Timer* timer, _In_ MI_Uint64 timeusecs );
void Strand_FireTimer( _In_ Strand* self );
MI_Boolean Strand_HaveTimer( _In_ Strand* self );

// Internal Use
MI_INLINE
MI_Boolean _Strand_ShouldFinish(
    _In_ Strand* self )
{
    MI_Boolean shouldFinish = (*self->strandMethods[0])(self);    

    if( shouldFinish && NULL != self->timer )
    {
        if( (self->flags & STRAND_FLAG_FINISHWAITSFORTIMER ) == 0 )
        {
            // Canceled reason overwrites any other reason
            Timer_Fire( self->timer, self, TimerReason_Canceled );
        }
        shouldFinish = MI_FALSE;   // In any case we cannot finish until timer is not set anymore
    }

    return shouldFinish;
}

// Internal Use 
// This is not needed if everything is called inside the strand (for UT use)
// If close/ack are called outside the strand then call this afterwards
// ( can be used with any type of strand )
MI_INLINE
void _Strand_CheckDelete(
    _In_ Strand* self )
{
    STRAND_ASSERTONSTRAND( self );
    if( (*self->strandMethods[0])(self) )
    {
        _Strand_Finish( self );
    }
}

/*
**==============================================================================
*/

END_EXTERNC

#endif /* _Strand_h */



ViewCVS 0.9.2