#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_ */