You are looking at the HTML representation of the XML format.
HTML is good for debugging, but is unsuitable for application use.
Specify the format parameter to change the output format.
To see the non HTML representation of the XML format, set format=xml.
See the complete documentation, or
API help for more information.
<?xml version="1.0"?>
<api>
<query-continue>
<allpages gapcontinue="SCTP_Macros" />
</query-continue>
<query>
<pages>
<page pageid="387" ns="0" title="Running Multiple Instances of Treck">
<revisions>
<rev contentformat="text/x-wiki" contentmodel="wikitext" xml:space="preserve">[[Table of Contents]] >> [[Appendix A: Configuration Notes]]
A set of new APIs described in this section have been added to allow users to run multiple instances of the Treck TCP/IP stack. Each instance of the Treck stack needs to be run in a given context. If the user wants to run multiple instances of the Treck TCP/IP stack, any Treck TCP/IP stack function should be called after a context has been set, except for the context insensitive functions described below.
==Context Insensitive Functions==
These Treck TCP/IP stack functions can be called from any context or prior to setting any context.
{| border="1" cellspacing="0" cellpadding="5" style="font-family:courier new;"
! width="20%" | Function
! width="80%" | Comments
|- valign="top"
| <tt>[[tfInitTreckMultipleContext]]()</tt>
| This function initializes the Treck global variables, prior to any context creation.
|- valign="top"
| <tt>[[tfTimerUpdate]]()</tt>
| Called from a Timer task.
|- valign="top"
| <tt>[[tfTimerUpdateIsr]]()</tt>
| Called from Timer ISR.
|}
==Initialization Sequence==
First initialization, called before any other Treck TCP/IP stack call:
<c>
tfInitTreckMultipleContext(void);
</c>
For each context:
<c>
contextHandle = tfCreateTreckContext();
if (contextHandle != (ttUserContext)0)
{
tfSetCurrentContext(contextHandle);
errorCode = tfStartTreck();
}
</c>
==Summary of New Context API's==
{| border="1" cellspacing="0" cellpadding="5" style="font-family:courier new;"
! width="20%" | Function
! width="80%" | Comments
|- valign="top"
| <tt>[[tfInitTreckMultipleContext]]()</tt>
| Initializes multiple context global variables (valid across all contexts).
|- valign="top"
| <tt>[[tfCreateTreckContext]]()</tt>
| Create a Treck context, i.e. allocate a structure containing all Treck variables for an instance of the Treck stack, and returns a pointer to the newly allocated structure.
|- valign="top"
| <tt>[[tfSetCurrentContext]]()</tt>
| Set the current context handle to the one passed in (i.e. set the Treck global variable <tt>'tvCurrentContext'</tt> to the passed parameter).
|- valign="top"
| <tt>[[tfGetCurrentContext]]()</tt>
| Get the current context handle (i.e. the context handle stored in <tt>'tvCurrentContext'</tt>).
|}
==Enabling the Multiple Instances Code in Treck==
To enable the multiple instances code in the Treck stack, enable the following macro in your <tt><trsystem.h></tt>:
<c>#define TM_MULTIPLE_CONTEXT</c>
For details and more compile time macros please see [[Compile Time Macros#TM_MULTIPLE_CONTEXT|the Compile Time Macros page]].
==Blocking Mode/Non-Blocking Mode==
The following indicates the modifications needed for each type of embedded kernel:
:#[[#No kernel|No kernel]]
:#[[#Non-preemptive kernel|Non-preemptive kernel]]
:#[[#Preemptive kernel|Preemptive kernel]]
===No kernel===
All applications have to run in non-blocking mode. All calls to the Treck stack are made from a main loop. Example with 2 contexts and 2 interfaces per context:
<c>
errorCode = tfInitTreckMultipleContext();
contextHandle1 = tfCreateTreckContext();
contextHandle2 = tfCreateTreckContext();
tfSetCurrentContext(contextHandle1);
errorCode = tfStartTreck();
context1InterfaceHandle1 = tfAddInterface(...);
errorCode = tfOpenInterface(context1InterfaceHandle1, ...);
context1InterfaceHandle2 = tfAddInterface(...);
errorCode = tfOpenInterface(context1InterfaceHandle2, ...);
tfSetCurrentContext(contextHandle2);
errorCode = tfStartTreck();
context2InterfaceHandle1 = tfAddInterface(...);
errorCode = tfOpenInterface(context1InterfaceHandle1, ...);
context2InterfaceHandle2 = tfAddInterface(...);
errorCode = tfOpenInterface(context2InterfaceHandle2, ...);
for (;;)
{
tfSetCurrentContext(contextHandle1);
tfTimerExecute();
if (tfCheckReceiveInterface(context1InterfaceHandle1) == TM_ENOERROR)
{
tfRecvInterface(context1InterfaceHandle1);
}
if (tfCheckReceiveInterface(context1InterfaceHandle2) == TM_ENOERROR)
{
tfRecvInterface(context1InterfaceHandle2);
}
<...Non-blocking application code for context 1...>
tfSetCurrentContext(contextHandle2);
tfTimerExecute();
if (tfCheckReceiveInterface(context2InterfaceHandle1) == TM_ENOERROR)
{
tfRecvInterface(context2InterfaceHandle1);
}
if (tfCheckReceiveInterface(context2InterfaceHandle2) == TM_ENOERROR)
{
tfRecvInterface(context2InterfaceHandle2);
}
<...Non-blocking application code for context 2...>
}
</c>
{{NoteBox|This sample code does not check for errors for ease of reading.
Also, for more than 2 contexts, it would make sense to save the context variables, and interface handles in a 2 dimensional array, and loop on the array indices.}}
===Non-preemptive kernel===
In this case, the applications can run in blocking mode.
:#Each application task will have to set its Treck context prior to making the first Treck call.
:#Inside each tfKernel...() call, the user must save the current Treck context before calling the OS and then restore the Treck context upon return from the OS call, since the current task could be pre-empted by a higher priority task during the OS call.
<c>
int tfKernel...(...)
{
ttUserContext contextHandle;
contextHandle = tfGetCurrentContext();
<Make the OS call>
tfSetCurrentContext(contextHandle);
}
</c>
===Preemptive kernel===
In this case, the OS could switch out a task at any time.
:#Each application task will have to set its Treck context prior to making the first Treck call.
:#Depending on the services provided by your kernel, you may need to save the Treck context handle in memory that is private to each task. Do this before the task makes its first Treck call.
:#Check the level of support provided by your kernel and do one of the following:
:##If the kernel provides a callback whenever a task resumes execution, you can use this callback to get the Treck context handle from the current task's private memory (saved in step 2 above) and call <tt>[[tfSetCurrentContext]]()</tt>. The application can run in blocking mode, as described in the previous section.<!--
--><p>If the kernel also provides a callback whenever a task suspends or gets preempted, you can use this callback to get the current Treck context (<tt>[[tfGetCurrentContext]]()</tt>) and save it in the current task's private memory. This means you can skip step 2 above.</p>
:##If the user can modify the OS to save the current Treck context on a task stack prior to a task being switched out, and restore the task Treck context when the task resumes, then the application can run in blocking mode, as described in the previous section.<!--
--><p>The user will need to modify the OS to save the current Treck context on a task stack prior to a task being switched out and restore the Treck context when the task resumes.</p>
:##If your kernel provides functions for allocating thread-local storage such that the Treck context handle can be retrieved in a task-specific way whenever it is needed, then follow the directions in the subsection below, [[#Keeping the Current Treck Context Handle in Thread Local Storage|Keeping the Current Treck Context Handle in Thread Local Storage]].
:##If none of the above methods can be applied, then the application will have to run in non-blocking mode from a single Treck task. All the calls to the Treck stack will be made from a main loop from within that single task as described in the [[#No kernel|No Kernel]] section above.
====Keeping the Current Treck Context Handle in Thread Local Storage====
Most preemptive, multitasking kernels support some form of storage that is private to each task. The C runtime library <tt>errno</tt> variable is a perfect example of this. If <tt>errno</tt> is global and shared by all tasks then it becomes useless because various tasks will be calling C functions that change <tt>errno</tt> and there is no guarantee that it will contain the correct value by the time that your task is able to read it.
The multitasking issues for the current Treck context are the same as those for <tt>errno</tt>. The solution is to replace the reference to the global variable with a call to a function that reads the value from the current task's private memory. That way, you are guaranteed to get the same value back that you set earlier in the task.
If your kernel supports thread-local storage, you can configure Treck to keep the current context in thread-local storage by uncommenting the following [[Compile Time Macros#TM_USE_KERNEL_CONTEXT|compile time macro]] in your <tt>&lt;trsystem.h&gt;</tt>:
<c>#define TM_USE_KERNEL_CONTEXT</c>
The Treck functions, <tt>[[tfSetCurrentContext]]()</tt> and <tt>[[tfGetCurrentContext]]()</tt>, will now reference functions <tt>[[tfKernelSetContext]]()</tt> and <tt>[[tfKernelGetContext]]()</tt> that you must provide when you [[Creating a Kernel Interface|create your kernel interface]].
<c>void tfKernelSetContext(ttUserContext context)
{
/*
* Store 'context' in the current task's local memory.
*/
}
ttUserContext tfKernelGetContext(void)
{
ttUserContext context;
/*
* Load 'context' from the current task's local memory.
*/
return context;
}</c>
===Device Driver Modifications===
Each device driver should be modified as described in the [[Adding a Device Driver#Further Device Driver Modifications to allow a device driver to be shared by several Ethernet Interfaces|"Further Device Driver Modifications to allow a device driver to be shared by several Ethernet Interfaces"]] section. The modification to the Device driver ISR is a little bit different, and is described below.
===Device Driver ISR===
The user should keep a global mapping between an interrupt vector, and an interface handle/context pair, instead of just a global mapping between an interrupt vector and an interface handle. In the device driver ISR, the user should save the current context, and then the user should set the Treck context as found in the global mapping described here, and call <tt>[[tfDeviceGetPointer]]()</tt> in order to access the device driver specific data. Before returning from the ISR, the user should set the context to the saved value at the beginning of the ISR function.
[[Table of Contents]] >> [[Appendix A: Configuration Notes]]</rev>
</revisions>
</page>
<page pageid="952" ns="0" title="SCTP">
<revisions>
<rev contentformat="text/x-wiki" contentmodel="wikitext" xml:space="preserve">#REDIRECT [[Stream Control Transmission Protocol]]</rev>
</revisions>
</page>
</pages>
</query>
</api>