/*++

Copyright (c) 1989-1998 Microsoft Corporation

Module Name:

    threads.h

Abstract:

    This module is the header file for thread pools. Thread pools can be used for
    one time execution of tasks, for waits and for one shot or periodic timers.

Author:

    Gurdeep Singh Pall (gurdeep) Nov 13, 1997

Environment:

    The thread pool routines are statically linked in the caller's
    executable and are callable only from user mode. They make use of
    Nt system services.


Revision History:

    Aug-19 lokeshs - modifications to thread pool apis.
    Rob Earhart (earhart) September 29, 2000
      Moved globals to threads.c
      Split up thread pools to seperate modules
      Moved module-specific interfaces to modules

--*/

//todo remove below
#define DBG1 1



// Structures used by the Thread pool

// Timer structures

// Timer Queues and Timer entries both use RTLP_GENERIC_TIMER structure below.
// Timer Queues are linked using List.
// Timers are attached to the Timer Queue using TimerList
// Timers are linked to each other using List

#define RTLP_TIMER RTLP_GENERIC_TIMER
#define PRTLP_TIMER PRTLP_GENERIC_TIMER

#define RTLP_TIMER_QUEUE RTLP_GENERIC_TIMER
#define PRTLP_TIMER_QUEUE PRTLP_GENERIC_TIMER

struct _RTLP_WAIT ;

typedef struct _RTLP_GENERIC_TIMER {

    LIST_ENTRY List ;                   // All Timers and Queues are linked using this.
    ULONG DeltaFiringTime ;             // Time difference in Milliseconds from the TIMER entry
                                        // just before this entry
    union {
        ULONG RefCount ;        // Timer RefCount
        ULONG * RefCountPtr ;   // Pointer to Wait->Refcount
    } ;                         // keeps count of async callbacks still executing

    ULONG State ;               // State of timer: CREATED, DELETE, ACTIVE. DONT_FIRE

    union {

        // Used for Timer Queues

        struct  {

            LIST_ENTRY  TimerList ;     // Timers Hanging off of the queue
            LIST_ENTRY  UncancelledTimerList ;// List of one shot timers not cancelled
                                              // not used for wait timers
#if DBG1
            ULONG NextDbgId;
#endif
            
        } ;

        // Used for Timers

        struct  {
            struct _RTLP_GENERIC_TIMER *Queue ;// Queue to which this timer belongs
            struct _RTLP_WAIT *Wait ;  // Pointer to Wait event if timer is part of waits. else NULL
            ULONG Flags ;              // Flags indicating special treatment for this timer
            PVOID Function ;           // Function to call when timer fires
            PVOID Context ;            // Context to pass to function when timer fires
            PACTIVATION_CONTEXT ActivationContext; // Activation context to activate around callbacks to Function
            ULONG Period ;             // In Milliseconds. Used for periodic timers.
            LIST_ENTRY TimersToFireList;//placed in this list if the timer is fired
            HANDLE ImpersonationToken;  // Token to use for callouts
        } ;
    } ;

    HANDLE CompletionEvent ;   // Event signalled when the timer is finally deleted

#if DBG1
    ULONG DbgId;
    ULONG ThreadId ;
    ULONG ThreadId2 ;
#endif

}  RTLP_GENERIC_TIMER, *PRTLP_GENERIC_TIMER ;

// Structures used by Wait Threads

// Wait structure

typedef struct _RTLP_WAIT {
    struct _RTLP_WAIT_THREAD_CONTROL_BLOCK *ThreadCB ;
    HANDLE WaitHandle ;         // Object to wait on
    ULONG State ;               // REGISTERED, ACTIVE,DELETE state flags
    ULONG RefCount ;            // initially set to 1. When 0, then ready to be deleted
    HANDLE CompletionEvent ;
    struct _RTLP_GENERIC_TIMER *Timer ; // For timeouts on the wait
    ULONG Flags ;               // Flags indicating special treatment for this wait
    PVOID Function ;            // Function to call when wait completes
    PVOID Context ;             // Context to pass to function
    ULONG Timeout ;             // In Milliseconds.
    PACTIVATION_CONTEXT ActivationContext; // Activation context to activate around calls out to function
    HANDLE ImpersonationToken;  // Token to use for callouts
#if DBG1
    ULONG DbgId ;
    ULONG ThreadId ;
    ULONG ThreadId2 ;
#endif
    
} RTLP_WAIT, *PRTLP_WAIT ;


// Wait Thread Control Block

typedef struct _RTLP_WAIT_THREAD_CONTROL_BLOCK {

    LIST_ENTRY WaitThreadsList ;// List of all the thread control blocks

    HANDLE ThreadHandle ;       // Handle for this thread
    ULONG ThreadId ;            // Used to check if callback is in WaitThread

    ULONG NumWaits ;            // Number of active waits + handles pending waits
    ULONG NumActiveWaits ;      // Number of active waits (reflects ActiveWaitArray)
    ULONG NumRegisteredWaits ;  // Number of waits that are registered
    HANDLE ActiveWaitArray[MAXIMUM_WAIT_OBJECTS] ;// Array used for waiting
    PRTLP_WAIT ActiveWaitPointers[MAXIMUM_WAIT_OBJECTS] ;// Array of pointers to active Wait blocks.
    HANDLE TimerHandle ;        // Handle to the NT timer used for timeouts
    RTLP_TIMER_QUEUE TimerQueue;// Queue in which all timers are kept

    LARGE_INTEGER Current64BitTickCount ;
    LONGLONG Firing64BitTickCount ;
    
    RTL_CRITICAL_SECTION WaitThreadCriticalSection ;
                                // Used for addition and deletion of waits

} RTLP_WAIT_THREAD_CONTROL_BLOCK, *PRTLP_WAIT_THREAD_CONTROL_BLOCK ;


// Structure used for attaching all I/O worker threads

typedef struct _RTLP_IOWORKER_TCB {

    LIST_ENTRY List ;           // List of IO Worker threads
    HANDLE     ThreadHandle ;   // Handle of this thread
    ULONG      Flags ;          // WT_EXECUTEINPERSISTENTIOTHREAD
    BOOLEAN    LongFunctionFlag ;// Is the thread currently executing long fn
} RTLP_IOWORKER_TCB, *PRTLP_IOWORKER_TCB ;

typedef struct _RTLP_WAITWORKER {
    union {
        PRTLP_WAIT Wait ;
        PRTLP_TIMER Timer ;
    } ;
    BOOLEAN WaitThreadCallback ; //callback queued by Wait thread or Timer thread
    BOOLEAN TimerCondition ;//true if fired because wait timed out.
} RTLP_ASYNC_CALLBACK, * PRTLP_ASYNC_CALLBACK ;



// structure used for calling worker function

typedef struct _RTLP_WORK {

    WORKERCALLBACKFUNC Function ;
    ULONG Flags ;
    PACTIVATION_CONTEXT ActivationContext;
    HANDLE ImpersonationToken;
    
} RTLP_WORK, *PRTLP_WORK ;



// Structure used for storing events

typedef struct _RTLP_EVENT {

    SINGLE_LIST_ENTRY Link ;
    HANDLE Handle ;
    
} RTLP_EVENT, *PRTLP_EVENT ;

// Defines used in the thread pool

#define THREAD_CREATION_DAMPING_TIME1    1000    // In Milliseconds. Time between starting successive threads.
#define THREAD_CREATION_DAMPING_TIME2    15000    // In Milliseconds. Time between starting successive threads.
#define THREAD_TERMINATION_DAMPING_TIME 10000    // In Milliseconds. Time between stopping successive threads.
#define NEW_THREAD_THRESHOLD            7       // Number of requests outstanding before we start a new thread
#define NEW_THREAD_THRESHOLD2            14
#define MAX_WORKER_THREADS              1000    // Max effective worker threads
#define INFINITE_TIME                   (ULONG)~0   // In milliseconds
#define PSEUDO_INFINITE_TIME            0x80000000  // In milliseconds
#define RTLP_MAX_TIMERS                 0x00080000  // 524288 timers per process
#define MAX_UNUSED_EVENTS               40
#define NEEDS_IO_THREAD(Flags) (Flags & (WT_EXECUTEINIOTHREAD                   \
                                       | WT_EXECUTEINUITHREAD                   \
                                       | WT_EXECUTEINPERSISTENTIOTHREAD))

// Macros


#define ONE_MILLISECOND_TIMEOUT(TimeOut) {      \
        TimeOut.LowPart  = 0xffffd8f0 ;         \
        TimeOut.HighPart = 0xffffffff ;         \
        }

#define HUNDRED_MILLISECOND_TIMEOUT(TimeOut) {  \
        TimeOut.LowPart  = 0xfff0bdc0 ;         \
        TimeOut.HighPart = 0xffffffff ;         \
        }

#define ONE_SECOND_TIMEOUT(TimeOut) {           \
        TimeOut.LowPart  = 0xff676980 ;         \
        TimeOut.HighPart = 0xffffffff ;         \
        }

#define USE_PROCESS_HEAP 1

#define RtlpFreeTPHeap(Ptr) \
    RtlFreeHeap( RtlProcessHeap(), 0, (Ptr) )

#define RtlpAllocateTPHeap(Size, Flags) \
    RtlAllocateHeap( RtlProcessHeap(), (Flags), (Size) )

// used to allocate Wait thread

#define ACQUIRE_GLOBAL_WAIT_LOCK() \
    RtlEnterCriticalSection (&WaitCriticalSection)

#define RELEASE_GLOBAL_WAIT_LOCK() \
    RtlLeaveCriticalSection(&WaitCriticalSection)


// taken before a timer/queue is deleted and when the timers
// are being fired. Used to assure that no timers will be fired later.

#define ACQUIRE_GLOBAL_TIMER_LOCK() \
    RtlEnterCriticalSection (&TimerCriticalSection)

#define RELEASE_GLOBAL_TIMER_LOCK() \
    RtlLeaveCriticalSection(&TimerCriticalSection)

// used in RtlpThreadPoolCleanup to find if a component is initialized

#define IS_COMPONENT_INITIALIZED(StartedVariable, CompletedVariable, Flag) \
{\
    LARGE_INTEGER TimeOut ;     \
    Flag = FALSE ;              \
                                \
    if ( StartedVariable ) {    \
                                \
        if ( !CompletedVariable ) { \
                                    \
            ONE_MILLISECOND_TIMEOUT(TimeOut) ;  \
                                                \
            while (!*((ULONG volatile *)&CompletedVariable)) \
                NtDelayExecution (FALSE, &TimeOut) ;    \
                                                        \
            if (CompletedVariable == 1)                 \
                Flag = TRUE ;                           \
                                                        \
        } else {                                        \
            Flag = TRUE ;                               \
        }                                               \
    }                                                   \
}    


// macro used to set dbg function/context

#define DBG_SET_FUNCTION(Fn, Context) { \
    CallbackFn1 = CallbackFn2 ;         \
    CallbackFn2 = (Fn) ;                \
    Context1 = Context2 ;               \
    Context2 = (Context ) ;             \
}


// used to move the wait array
/*
VOID
RtlpShiftWaitArray(
    PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB ThreadCB,
    ULONG SrcIndex,
    ULONG DstIndex,
    ULONG Count
    )
*/
#define RtlpShiftWaitArray(ThreadCB, SrcIndex, DstIndex, Count) {  \
                                                            \
    RtlMoveMemory (&(ThreadCB)->ActiveWaitArray[DstIndex],  \
                    &(ThreadCB)->ActiveWaitArray[SrcIndex], \
                    sizeof (HANDLE) * (Count)) ;            \
                                                            \
    RtlMoveMemory (&(ThreadCB)->ActiveWaitPointers[DstIndex],\
                    &(ThreadCB)->ActiveWaitPointers[SrcIndex],\
                    sizeof (HANDLE) * (Count)) ;            \
}

// signature for timer and wait entries

#define SET_WAIT_SIGNATURE(ptr)     RtlInterlockedSetBitsDiscardReturn(&(ptr)->State, 0xfedc0100)
#define SET_TIMER_SIGNATURE(ptr)    RtlInterlockedSetBitsDiscardReturn(&(ptr)->State, 0xfedc0200)
#define SET_TIMER_QUEUE_SIGNATURE(ptr)    RtlInterlockedSetBitsDiscardReturn(&(ptr)->State, 0xfedc0300)
#define IS_WAIT_SIGNATURE(ptr)      (((ptr)->State & 0x00000f00) == 0x00000100)
#define IS_TIMER_SIGNATURE(ptr)     (((ptr)->State & 0x00000f00) == 0x00000200)
#define CHECK_SIGNATURE(ptr)        ASSERTMSG( InvalidSignatureMsg, \
                                               ((ptr)->State & 0xffff0000) == 0xfedc0000 )
#define SET_DEL_SIGNATURE(ptr)      RtlInterlockedSetBitsDiscardReturn(&(ptr)->State, 0x0000b000)
#define CHECK_DEL_SIGNATURE(ptr)    ASSERTMSG( InvalidDelSignatureMsg, \
                                               (((ptr)->State & 0xffff0000) == 0xfedc0000) \
                                               && ( ! ((ptr)->State & 0x0000f000)) )
#define IS_DEL_SIGNATURE_SET(ptr)   ((ptr)->State & 0x0000f000)
#define CLEAR_SIGNATURE(ptr)        RtlInterlockedSetClearBits(&(ptr)->State, \
                                               0xcdef0000, \
                                               0xfedc0000 & ~(0xcdef0000))
#define SET_DEL_TIMERQ_SIGNATURE(ptr)  RtlInterlockedSetBitsDiscardReturn(&(ptr)->State, 0x00000a00)


// debug prints
#define RTLP_THREADPOOL_ERROR_MASK   (0x01 | DPFLTR_MASK)
#define RTLP_THREADPOOL_WARNING_MASK (0x02 | DPFLTR_MASK)
#define RTLP_THREADPOOL_INFO_MASK    (0x04 | DPFLTR_MASK)
#define RTLP_THREADPOOL_TRACE_MASK   (0x08 | DPFLTR_MASK)
#define RTLP_THREADPOOL_VERBOSE_MASK (0x10 | DPFLTR_MASK)

#if DBG
extern CHAR InvalidSignatureMsg[];
extern CHAR InvalidDelSignatureMsg[];
#endif

extern ULONG MaxThreads;

extern BOOLEAN LdrpShutdownInProgress;

NTSTATUS
NTAPI
RtlpStartThreadpoolThread(
    PUSER_THREAD_START_ROUTINE Function,
    PVOID   Parameter,
    HANDLE *ThreadHandleReturn
    );

extern PRTLP_EXIT_THREAD RtlpExitThreadFunc;

#if DBG1
extern PVOID CallbackFn1, CallbackFn2, Context1, Context2 ;
#endif

// Timer globals needed by worker
extern ULONG StartedTimerInitialization ;      // Used by Timer thread startup synchronization
extern ULONG CompletedTimerInitialization ;    // Used for to check if Timer thread is initialized
extern HANDLE TimerThreadHandle;

VOID
RtlpAsyncWaitCallbackCompletion(
    IN PVOID Context
    );

NTSTATUS
RtlpInitializeTimerThreadPool (
    ) ;

NTSTATUS
RtlpTimerCleanup(
    VOID
    );

NTSYSAPI
NTSTATUS
NTAPI
RtlpWaitCleanup(
    VOID
    );

NTSYSAPI
NTSTATUS
NTAPI
RtlpWorkerCleanup(
    VOID
    );

NTSYSAPI
VOID
NTAPI
RtlpThreadCleanup (
    VOID
    );

VOID
RtlpResetTimer (
    HANDLE TimerHandle,
    ULONG DueTime,
    PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB
    ) ;


BOOLEAN
RtlpInsertInDeltaList (
    PLIST_ENTRY DeltaList,
    PRTLP_GENERIC_TIMER NewTimer,
    ULONG TimeRemaining,
    ULONG *NewFiringTime
    ) ;

BOOLEAN
RtlpRemoveFromDeltaList (
    PLIST_ENTRY DeltaList,
    PRTLP_GENERIC_TIMER Timer,
    ULONG TimeRemaining,
    ULONG* NewFiringTime
    ) ;

BOOLEAN
RtlpReOrderDeltaList (
    PLIST_ENTRY DeltaList,
    PRTLP_GENERIC_TIMER Timer,
    ULONG TimeRemaining,
    ULONG* NewFiringTime,
    ULONG ChangedFiringTime
    ) ;

NTSTATUS
RtlpDeactivateWait (
    PRTLP_WAIT Wait,
    BOOLEAN OkayToFreeTheTimer
    ) ;

VOID
RtlpDeleteWait (
    PRTLP_WAIT Wait
    ) ;

VOID
RtlpProcessTimeouts (
    PRTLP_WAIT_THREAD_CONTROL_BLOCK ThreadCB
    ) ;

ULONG
RtlpGetTimeRemaining (
    HANDLE TimerHandle
    ) ;

#define THREAD_TYPE_WORKER 1
#define THREAD_TYPE_IO_WORKER 2

VOID
RtlpDeleteTimer (
    PRTLP_TIMER Timer
    ) ;

PRTLP_EVENT
RtlpGetWaitEvent (
    VOID
    ) ;

VOID
RtlpFreeWaitEvent (
    PRTLP_EVENT Event
    ) ;

VOID
RtlpDoNothing (
    PVOID NotUsed1,
    PVOID NotUsed2,
    PVOID NotUsed3
    ) ;

VOID
RtlpExecuteWorkerRequest (
    NTSTATUS Status,
    PVOID Context,
    PVOID ActualFunction
    ) ;

NTSTATUS
RtlpWaitForEvent (
    HANDLE Event,
    HANDLE ThreadHandle
    ) ;

NTSYSAPI
NTSTATUS
NTAPI
RtlThreadPoolCleanup (
    ULONG Flags
    ) ;

VOID
RtlpWaitOrTimerCallout(WAITORTIMERCALLBACKFUNC Function,
                       PVOID Context,
                       BOOLEAN TimedOut,
                       PACTIVATION_CONTEXT ActivationContext,
                       HANDLE ImpersonationToken);

VOID
RtlpApcCallout(APC_CALLBACK_FUNCTION Function,
               NTSTATUS Status,
               PVOID Context1,
               PVOID Context2);

VOID
RtlpWorkerCallout(WORKERCALLBACKFUNC Function,
                  PVOID Context,
                  PACTIVATION_CONTEXT ActivationContext,
                  HANDLE ImpersonationToken);

// Waits and timers may specify that their callbacks must execute
// within worker threads of various types.  This can cause a problem
// if those worker threads are unavailable.  RtlpAcquireWorker
// guarantees that at least one worker thread of the appropriate type
// will be available to handle callbacks until a matching call to
// RtlpReleaseWorker is made.

NTSTATUS
RtlpAcquireWorker(ULONG Flags);

VOID
RtlpReleaseWorker(ULONG Flags);

//to make sure that a wait is not deleted before being registered
#define STATE_REGISTERED   0x0001

//set when wait registered. Removed when one shot wait fired.
//when deregisterWait called, tells whether to be removed from ActiveArray
//If timer active, then have to remove it from delta list and reset the timer.
#define STATE_ACTIVE       0x0002

//when deregister wait is called(RefCount may be >0)
#define STATE_DELETE       0x0004

//set when cancel timer called. The APC will clean it up.
#define STATE_DONTFIRE     0x0008

//set when one shot timer fired.
#define STATE_ONE_SHOT_FIRED 0x0010