#ifndef _xmk_xthread_h_ #define _xmk_xthread_h_ /*---------------------------------------------------------------------------- ** SUMMARY: XMK Extended Thread Interfaces (XTHR) ** ** DESCRIPTION: ** This file provides the interface for extended/enhanced threading ** operations. ** ** CONFIGURATION OPTION: USE_XMK_EXTENDED_THREADS ** ** DEPENDENCIES: ** To use this interface the following XMK service(s) MUST always be ** enabled/configured: ** USE_XMK_CORE_KERNEL ** USE_XMK_SCHEDULER_EI_DI_SWITCHING ** ** NOTES: ** 1. For efficiency/optimization some methods are 'inlined'. The inlining ** is done by using the preprocessor/macros. The application should ** treat all methods as function calls and not rely on the fact they may ** be currently defined as a macro. ** ----------------------------------------------------------------------------*/ #include "xmkcfg.h" /* For: Project/Application kernel configuration */ #ifdef __cplusplus extern "C" { #endif /*-------------- MAGIC CONSTANTS -------------------------------------------*/ /** Maximum number of threads that can be created/active at any one time */ #define XMK_MAX_THREAD_COUNT _XMK_MAX_THREAD_COUNT /** The maximum length (not including the null terminator) of a thread name */ #define XMK_MAX_THREAD_NAME_LENGTH _XMK_MAX_THREAD_NAME_LENGTH /** Selects blocking semantics when calling Xmk_createThreadEx() */ #define XMK_CREATETHREADEX_WAIT_FOR_MEMORY 1 /** Selects non-blocking semantics when calling Xmk_createThreadEx() */ #define XMK_CREATETHREADEX_FAIL_IF_NO_MEMORY 0 /* ** ERROR CODES */ /** The thread being deleted owns the 'super thread' token, i.e. the current thread has disabled thread scheduling and is terminating itself before re-enabling thread scheduling! */ #define XMK_ERRFATAL_XTHREAD_DELETING_SUPER_THREAD _XMK_ERRFATAL_XTHREAD_DELETING_SUPER_THREAD /** Xmk_createTheadEx() was called with blocking semantics AND the the application has currently disabled scheduling. This scenerio will deadlock the application when Xmk_createThreadEx() blocks due to lack of memory! */ #define XMK_ERRFATAL_XTHREAD_ILLEGAL_CREATE_THREADEX_CALL _XMK_ERRFATAL_XTHREAD_ILLEGAL_CREATE_THREADEX_CALL /** Internal kernel error: Attempted to run a deleted thread. */ #define XMK_ERRFATAL_XTHREAD_RUN_DELETED_THREAD _XMK_ERRFATAL_XTHREAD_RUN_DELETED_THREAD /*-------------- PUBLIC/PUBLISHED API --------------------------------------*/ /** This method is the same as the basic Kernel method Xmk_createThread(), except for: 1) Allows the application to give the thread a "name". 2) Will dynamically create threads.
    The method returns the handle of the newly created thread.

    DETAILS
    -------
    Call Restrictions:
        This method can ONLY be called AFTER the call to Xmk_start(). This 
        method can NEVER be called from an interrupt service routine.

    Naming:
        The specified 'threadName' must be a null terminated string that is
        no longer than XMK_MAX_THREAD_NAME_LENGTH.  If the specified string
        exceeded the maximum length, it will be truncated. 

    Dynamic Thread Creation:
        The method will return the handle to the newly created thread or
        XMK_NULL_THREADHDL if there is no memory available to create the
        thread.  The maximum number of threads is a XMK configuration 
        parameter that is set at compile time (i.e. all of the TCBs are 
        statically allocated).
        NOTE: If XMK is configured to use the 'basic scheduler' then a 
              thread's priority is also the thread's handle.  This means 
              that an attempt to create a new thread at the same priority 
              of an existing thread will be treated as 'no memory available'
              error.  It is the application's responsibility to properly 
              manage dynamic threads.

    Deleting Threads:
        There is no method to forcibly terminate or a kill a thread.  A
        thread is only deleted/terminated with its 'start' function
        returns.  This is intentional!  These delete semantics ensure that
        any resources held by a thread are released before it is
        terminated, since ONLY the thread in question "knows" and/or
        "can-do" what clean-up is required.
         
    Static vs. Dynamic Threads:
        The application can mix "static" threads created with 
        Xmk_createThread() and "dynamic" threads created with 
        Xmk_createThreadEx().  If fact, the application is required to 
        create AT LEAST ONE  "static" thread since Xmk_createThreadEx()
        can NOT be called before Xmk_start().

    Blocking vs non-blocking Call semantics:
        The function parameter 'blockingCallFlag' determines if the call
        to Xmk_createThreadEx() is blocking or non-blocking.  If 
        'blockCallFlag' is true, then Xmk_createThreadEx() will not 
        return until a thread is successfully created.  If there is no
        memory initially available, the calling thread will be suspended
        (i.e. yield the CPU) until memory becomes available.  When 
        'blockCallFlag' is true, the method ALWAYS returns a valid
        thread handle.  If 'blockCallFlag' is false and there is no
        memory available to create the new thread, XMK_NULL_THREADHDL
        is returned immediately.        
        NOTE: Be careful using the blocking call semantics!  If the
              dynamic threads are not managed properly you can
              deadlock the calling thread - in that it can end up
              waiting forever for Xmk_createThreadEx() to return
              (especially if using the basic scheduler model of
              a thread's priority is its thread handle).

    More on Blocking Call semantics:
        It is possible to have more than one thread waiting on the
        call to Xmk_createThreadEx() when using the blocking call
        semantics.  Which of the blocked threads is 'released' when 
        memory for a thread becomes available?  The answer is the blocked 
        thread with the highest priority is serviced first.
        NOTE: If XMK is using the basic scheduler model of a thread's
              priority is its thread handle, a additional qualifier
              exists.  The list of blocked threads is FIRST filtered
              by the priority of threads their are to TRYING CREATE.  This 
              is because the only requests that can be potentially satisfied 
              is dependent on the priority of thread that is being 'freed' 
              (since all priorites are unique).  After the priority-being-
              requested filter operation is completed, the 
              rule of highest-blocked-thread-first is then is applied.

    Thread Handles:
        Thread handles are NOT guaranteed to be unique over time.  As
        threads are created and deleted over time a newly create thread
        may have the same thread handle as a thread that previously existed.
        Thread handles are only guaranteed to be unique with respect
        to the current set of active/created threads.  

    Stack Memory:
        The application is responsible for providing and/or managing
        the memory for the thread's stack.

    Prototype:
        XMK_THREADHDL Xmk_createThreadEx
            ( 
            const char*         threadName,
            XMK_THREADPRIORITY  priority, 
            XMK_ENTRYFUNC       start, 
            void*               args,
            XMK_SP              topOfStackMemory, 
            XMK_BYTE            initialState, 
            XMK_BOOL            blockingCallFlag
            );
*/ #define Xmk_createThreadEx(n,p,f,a,m,i,b) _Xmk_createThreadEx(n,p,f,a,m,i,b) /** This method returns the thread's priority, and thread name of the specified thread. The method will return false if the specified thread does not exists. NOTES: o This method can ONLY be called AFTER the call to Xmk_start(). Also, this method can NEVER be called from an interrupt service routine. o Beware of thread handles! See Xmk_createThreadEx() for a discussion of the non-uniqueness of thread handles. o The caller must supply the memory for storing the returned thread priority and thread name. The parameter 'nameBuffer' must point to buffer that is at least XMK_MAX_THREAD_NAME_LENGTH+1 bytes in size. Prototype: XMK_BOOL Xmk_getThreadInfo( XMK_THREADHDL handle, XMK_THREADPRIORITY* threadPriority char* nameBuffer ); */ #define Xmk_getThreadInfo(h,p,n) _Xmk_getThreadInfo(h,p,n) /** This method returns the thread's name. If the thread handle is invalid, NULL is returned. Prototype: const char* Xmk_getThreadName(void); */ #define Xmk_getThreadName() _Xmk_getThreadName() /** This method returns the current number of created/active threads. It also returns a transaction ID that is incremented every time a thread is created and deleted. The intent of the method is to provide the application a means for detecting when threads are created and deleted. Granted the application has to poll for the information, but since XMK does not force applications to use a specific Message passing and/or Inter-Thread-Communication paradigm, it's the best that we can do. NOTES: o This method can ONLY be called AFTER the call to Xmk_start(). Also, this method can NEVER be called from an interrupt service routine. o The function parameter, kernelTransactionId, can be set ZERO. When kernelTransactionId is set to zero the transaction ID is (obviously) not returned. Prototype: XMK_THREADCOUNT Xmk_getThreadCount( XMK_U32* kernelTransactionId ); */ #define Xmk_getThreadCount(t) _Xmk_getThreadCount(t) /** This method provide a mechanism for walking XMK's list of currently create threads. The specified callback function is called once for every created thread. The callback routine can prematurely terminate the traversal by returning false, else true to continue the traversal. During the callback, the application may call other Xmk_getThreadInfo() or other methods to get more details about each thread. The function signature of the callback is: XMK_BOOL myCallback( XMK_THREADHDL threadHandle ); NOTES: o This method can ONLY be called AFTER the call to Xmk_start(). Also, this method can NEVER be called from an interrupt service routine. o Thread scheduling is temporarily suspended until the traversal is completed. So be careful/prudent on how much time you spend in the callback routine. Echoing the data out a serial port would NOT be a good idea! o There is NO guaranteed order to the traversal - only that all created threads will be reported. o DO NOT, repeat DO NOT, call Xmk_createThreadEx() directly or indirectly from the callback routine. o The IDLE thread is not included in the list of threads. Prototype: void Xmk_walkThreadList( XMK_CBFUNC_THREADLIST callbackFunc ); */ #define Xmk_walkThreadList(f) _Xmk_walkThreadList(f) #ifdef __cplusplus } #endif /*--------------------------------------------------------------------------*/ #endif /* end _xmk_xthread_h_ */