📄 ex10_stack.htm
字号:
<html><head><title>EXAMPLE 10: DETERMINING STACK SIZE</title><link rel="stylesheet" type="text/css" href="style.css"></head><body><a href="./ex09_ledclock.htm">[previous]</a><a href="./tutorial.htm#index">[index]</a><a href="./ex11_jitter.htm">[next]</a><h1>Example 10: Determining Stack Size</h1><p>This example shows how to determine the stack size needed for yourreal-time tasks. So far, we've just used a 1K stack. In general you'llneed to determine just how much stack to allocate. Too little, andyou'll crash your system when your functions nest too deeply. Here'swhat you see when that happens:<!-- text of black screen of deathUnable to handle kernel paging request at virtual address 0001b2d6 printing eip:e0a1b396*pde = 00000000Oops: 0000CPU: 0EIP: 0010:[<e0a1b396>] Not taintedEFLAGS: 00010212eax: ca0a0020 ebx: 00000004 ecx: ca0a0010 edx: 00000010esi: ca0a0020 edi: 0001b2d6 epb: 00000030 esp: c9a85f20ds: 0018 es: 0018 ss: 0018Process rmmod.modutils (pid: 1387, stackpage=c9a85000)Stack: 00000004 00000004 00000000 00000030 e0a14774 ca0a0020 e0a0b349 00001000 e0a2c000 00000001 00000200 e0a0f4ec e0a0f3ec e0a0f3ec 0000000c e0a0b43a 00000000 e0a2568b 00000200 e0a28000 fffffff0 e0a28000 c9a85f90 00000065Call Trace: [<e0a14774>] [<e0a0b349>] [<e0a0f4ec>] [<e0a0f3ec>] [<e0a0f3ec>] [<e0a0b43a>] [<e0a2568b>] [<e0a28277>] [<c011a4f3>] [<c0110087>] [<c01088e3>]Code: 3b 3f 0f 85 f2 00 00 00 39 4e f4 0f 85 e9 00 00 00 8b 56 f8--><p><img src="./bksmall.png"><p>The "Black Screen of Death". Normal Linux applications won't causethis, since they run in protected mode. RT code runs in privilegedkernel space. Too little stack and you'll clobber the kernel, and seethis screen. Time to reboot.<p>Refer to the <ahref="../ex10_stack/stack_task.c">commented source code</a> of the example for the details.<h2>Principle of Operation</h2><ul><li>The stack size for a task is the space needed for its arguments, itsstack variables, and all the variables encountered through thedeepest series of functions it may call during the life of thetask, including any padding for alignment of data.<li>To get an accurate measure of the necessary stack depth requires adetailed analysis of these functions, and if we ever encountersomething for which we have no source code, we have to guess.<li>Thecompiler also introduces some uncertainty since it may overlapstacks if it determines that a function has finished referencingsome of its stack before it calls another function. This means thatin practice analytical stack size determination involves detaileddetective work.<li>One technique to quickly estimate stack size is to initialize thestack with some recognizable pattern, run the task for a while, andlook at how much of the pattern remains. That's the unused stack.Often this pattern is 0xDEADBEEF, a clever hex integer that iseasily visible in hex memory dump utilities.<li>In the example, we initialize the unused part of the stack to0xDEADBEEF, run the task for while, then dump the stack and look forhow much 0xDEADBEEF was eaten up.<li>Cutting to the chase, the example shows two functions that youcall in your task code to initialize the stack at the beginning, andcheck it after your task has run for a while. These are:<pre>int rt_task_stack_init(RT_TASK * task, int pattern);int rt_task_stack_check(RT_TASK * task, int pattern)</pre><li>The first function initializes the stack with the integer 'pattern' (e.g.,0xDEADBEEF), taking care not to clobber the part of the stack that RTLinux set up.<li>The second function takes the same pattern, looks through thestack for that pattern, and returns the number of unused bytes.<li>Youwill always want some unused bytes: if all the 0xDEADBEEF is eaten up,your stack ran out and you will likely clobber the Linux kernel andget a nasty Black Screen of Death:</ul><h2>The Gory Details</h2>(This section shows the analysis that led to the example code. Youcan skip this; the example code contains the functions you'll need.)<ul><li>To apply this technique to RTAI, we need to know how the stack isallocated and initialized, so we don't clobber anything RTAI hasset up for us on our stack. Recall that a task's stack is allocatedand initialized in 'rt_task_init()':<pre>rt_task_init(RT_TASK *task, void *rt_thread, int data, int stack_size, /* here's the size, in bytes */ int priority, int uses_fpu, void *signal);</pre><li>If you inspect the RTAI scheduler header file<rtai_sched.h>,you'll see that the RT_TASK structure contains, among other things,the pointers to the top and bottom of the stack: <pre>typedef struct rt_task_struct { ... int *stack; int *stack_bottom; ...}</pre><li>Further inspecting the RTAI source code, specifically<rtai_sched.c> and <asm/rtai_sched.h>, we can see thedetails of how RTAI sets up the task stack.<ul><li>In 'rt_task_init()', RTAI allocates 'stack_size' bytes with'sched_malloc()', and sets the bottom of the stack,task->stack_bottom, to this memory.<li>The top of the stack,task->stack, is set to the bottom plus stack_size bytes minus 16bytes, rounded down to the nearest integer boundary.<li>5 integers arethen pushed onto the stack.<br>The top integer (4 bytes) of the stackis set to 0.<br>The next integer down is set to the initial 'data'argument for the task.<br>The next integer down is set to the'rt_thread' code for the task.<br>The next integer down is set to0.<br>The next integer down is set to some RTAI startup code, and thestack is left pointing to this. When initializing the stack, we muststop short of this.</ul><li>In our examples, we start with a stack size of 1K. If this is not enough,we will have strange problems which defy debugging, at which point wecan try increasing stack size and hope the problem goes away. <li>In the example program, the hex output (from the console, or/var/log/messages) shows the part of the stack used by our code whenit is stopped:<pre>DCC2034C: 76DCC20348: 75DCC20344: 74DCC20340: 73DCC2033C: 72DCC20338: 71DCC20334: 70DCC20330: 6FDCC2032C: 6EDCC20328: 6DDCC20324: 6CDCC20320: 6BDCC2031C: 6ADCC20318: 69DCC20314: 68DCC20310: 67DCC2030C: 66DCC20308: 65DCC20304: 64DCC20300: DEADBEEF...DCC20020: DEADBEEF740 unused stack bytes</pre><li>The bottom of the stack is at address 0xDCC20020, and it grows upwardtoward 0xDCC2034C, which is close to the top of the stack. <li>Here we seethe unused stack portion at the bottom, from integers at 0xDCC20020through 0xDCC20300, inclusive, or 740 bytes. This is corroborated bya count made from the bottom of the stack up to the first non-DEADBEEFoccurrence.<li>The problem with this technique is that all the code paths may notbe exercised during the run, and later your code may enter a deeperarea that was not entered before.<li>Since there is no performance impacton the task with this technique, it may be wise to leave the stackinitialization and checking intact in init_module() and cleanup_module(),respectively.</ul><h2>Running the Demo</h2>To run the demo, change to the 'ex10_stack' subdirectory of thetop-level tutorial directory, and run the 'run' script by typing<pre>./run</pre>Alternatively, change to the top-level tutorial directory and run the'runall' script there by typing<pre>./runall</pre>and selecting the "Stack Testing" button.<p>You'll see diagnostics messages printing out.<p><a href="../ex10_stack/stack_task.c">See the Code</a><hr><a href="./ex11_jitter.htm">Next: Example 11, Measuring Timing Jitter</a><p><a href="./ex09_ledclock.htm">Back: Example 9, Displaying Messages on an LED Wand Clock</a></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -