1 /*---------------------------------------------------------------------------*
2 Project: MEM library
3 File: thread_safe.cpp
4 Programmers: Takano Makoto
5
6 Copyright 2005 Nintendo. All rights reserved.
7
8 These coded instructions, statements, and computer programs contain
9 proprietary information of Nintendo of America Inc. and/or Nintendo
10 Company Ltd., and are protected by Federal copyright law. They may
11 not be disclosed to third parties or copied or duplicated in any form,
12 in whole or in part, without the prior written consent of Nintendo.
13 *---------------------------------------------------------------------------*/
14
15 /*---------------------------------------------------------------------------*
16 Note: Demo to confirm thread safety of extended heap
17
18 1. Creates a thread with medium priority that wakes at fixed intervals using Alarm, and calls Alloc and Free once.
19
20
21 2. Creates a check thread with high priority that wakes each time PAD is sampled and dumps the heap state when the START button is pushed.
22
23
24 3. The low-priority main thread repeatedly allocates and frees memory.
25 4. The memory size obtained by each thread differs, and thus it is possible to determine which thread has allocated a memory based on the size.
26
27 5. Ends in an error when THREAD_SAFE_ON define is invalidated, resulting in MEM_HEAP_OPT_THREAD_SAFE option not getting specified.
28
29 *---------------------------------------------------------------------------*/
30
31 #include <revolution/mem.h>
32 #include <revolution.h>
33
34
35 // Outputs the heap status for non-debug builds.
36 static void ReportExpHeap( MEMHeapHandle heap );
37
38 // Heap's thread safe enable switch
39 #define THREAD_SAFE_ON
40
41
42 #define HEAP_BUF_ELEMENT_NUM (4096 / sizeof(u32))
43
44 // Memory area for heap
45 static u32 sHeapBuf[ HEAP_BUF_ELEMENT_NUM ];
46 static MEMHeapHandle hExpHeap;
47
48 // Thread structure
49 static OSThread sThread1;
50 static u8 sThreadStack1[4096];
51 static OSThread sCheckThread;
52 static u8 sCheckThreadStack[4096];
53
54 // Alarm to switch between threads
55 static OSAlarm sAlarm;
56
57 static volatile BOOL sPadTrig = 0;
58
59
60 /*---------------------------------------------------------------------------*
61 Name: RunThread1
62
63 Description: Main function for thread
64 Repeatedly allocates and frees memory.
65 If it is Thread 1, it executes once and then suspends.
66
67 Arguments: param: Parameter arguments
68
69 Returns: None
70 *---------------------------------------------------------------------------*/
71 static void*
RunThread1(void * param)72 RunThread1( void* param )
73 {
74 #pragma unused( param )
75
76 while ( TRUE )
77 {
78 void* pMBlocks;
79
80 (void)MEMSetGroupIDForExpHeap( hExpHeap, 0x1 );
81
82 // Obtains memory from the heap
83 pMBlocks = MEMAllocFromExpHeap( hExpHeap, 100 );
84
85 // Returns memory to the heap.
86 MEMFreeToExpHeap( hExpHeap, pMBlocks );
87
88 // After executing once, suspends until the next alarm.
89 (void)OSSuspendThread( OSGetCurrentThread() );
90 }
91 return NULL;
92 }
93
94 /*---------------------------------------------------------------------------*
95 Name: RunAlarm
96
97 Description: Alarm handler
98 Wakes Thread 1, which has a high priority.
99
100 Arguments: alarm: Unused
101 context: Unused
102
103 Returns: None
104 *---------------------------------------------------------------------------*/
105 static void
RunAlarm(OSAlarm * alarm,OSContext * context)106 RunAlarm( OSAlarm* alarm, OSContext* context )
107 {
108 #pragma unused( alarm, context )
109 // Wakes Thread 1.
110 (void)OSResumeThread( &sThread1 );
111 }
112
113
114 /*---------------------------------------------------------------------------*
115 Name: CheckThreadMain
116
117 Description: Outputs the heap state when the START button is pressed.
118 Main function for heap state check thread
119
120 Arguments: None
121
122 Returns: None
123 *---------------------------------------------------------------------------*/
124 static void*
CheckThreadMain(void * param)125 CheckThreadMain( void* param )
126 {
127 #pragma unused( param )
128 while ( TRUE )
129 {
130 // When the START button is pressed, the state of the current heap is dumped.
131 if ( sPadTrig )
132 {
133 sPadTrig = 0;
134 #ifdef _DEBUG
135 MEMDumpHeap( hExpHeap );
136 #else
137 ReportExpHeap( hExpHeap );
138 #endif
139 }
140
141 // After executing once, suspends until the next PAD sampling.
142 (void)OSSuspendThread( OSGetCurrentThread() );
143 }
144 }
145
146
147 /*---------------------------------------------------------------------------*
148 Name: RunPad
149
150 Description: Callback function during PAD sampling
151 Dumps the heap state when the START button is triggered.
152
153 Arguments: None
154
155 Returns: None
156 *---------------------------------------------------------------------------*/
157 static void
RunPad(void)158 RunPad( void )
159 {
160 static u16 lastPad = 0;
161 PADStatus pad[ PAD_MAX_CONTROLLERS ];
162 (void)PADRead( pad );
163
164 if ( PADButtonDown( lastPad, pad[0].button ) & PAD_BUTTON_START )
165 {
166 sPadTrig = 1;
167 }
168 lastPad = pad[0].button;
169
170 // Wakes the thread for heap status check.
171 (void)OSResumeThread( &sCheckThread );
172 }
173
174
175 /*---------------------------------------------------------------------------*
176 Name: main
177 *---------------------------------------------------------------------------*/
178 void
main(void)179 main( void )
180 {
181 OSInit();
182 VIInit();
183 (void)PADInit();
184
185 // Creation of the expanded heap
186 #if defined(THREAD_SAFE_ON)
187 // Creates heap using the thread-safe option.
188 hExpHeap = MEMCreateExpHeapEx( sHeapBuf, sizeof sHeapBuf, MEM_HEAP_OPT_THREAD_SAFE );
189 #else
190 hExpHeap = MEMCreateExpHeapEx( sHeapBuf, sizeof sHeapBuf, 0 );
191 #endif
192
193 // Create Thread 1 (medium priority)
194 (void)OSCreateThread(
195 &sThread1,
196 RunThread1,
197 NULL, // Parameter NULL
198 sThreadStack1 + sizeof sThreadStack1,
199 sizeof sThreadStack1,
200 15, // Higher priority than the default thread
201 OS_THREAD_ATTR_DETACH );
202
203 // Create thread for status check (high priority)
204 (void)OSCreateThread(
205 &sCheckThread,
206 CheckThreadMain,
207 NULL, // Parameter NULL
208 sCheckThreadStack + sizeof sCheckThreadStack,
209 sizeof sCheckThreadStack,
210 14, // Priority is highest
211 OS_THREAD_ATTR_DETACH );
212
213 // Callback setting during PAD sampling (Used to display heap status)
214 (void)PADSetSamplingCallback( RunPad );
215
216 // Creates alarm and wakes the thread at fixed intervals using the timer.
217 OSCreateAlarm( &sAlarm );
218
219 OSSetPeriodicAlarm(
220 &sAlarm,
221 OSGetTick() + OSMicrosecondsToTicks(1000),
222 OSMicrosecondsToTicks(10),
223 RunAlarm );
224
225 while ( TRUE )
226 {
227 // Repeatedly allocates and releases memory.
228 void* pMBlocks[ 20 ];
229 u32 i;
230
231 (void)MEMSetGroupIDForExpHeap( hExpHeap, 0x2 );
232
233 // Obtains memory from the heap
234 for ( i = 0; i < 20; i++ )
235 {
236 pMBlocks[ i ] = MEMAllocFromExpHeap( hExpHeap, 50 );
237 }
238
239 for ( i = 0; i < 20; i++ )
240 {
241 // Returns memory to the heap.
242 MEMFreeToExpHeap( hExpHeap, pMBlocks[ i ] );
243 }
244 }
245 }
246
247
248 /* ------------------------------------------------------------------------
249 * This is the code for outputting the heap state as a sample for non-debug build.
250 *
251 * Normally, more detailed output can be derived during a debug build by using the MEMDumpHeap function.
252 */
253 #ifndef _DEBUG
254 /*
255 Structure that gets information for reports.
256 Used to specify parameters when calling the visitor function.
257 */
258 typedef struct
259 {
260 u32 size; // Data size storage region
261 u32 cnt; // Number of memory blocks used
262 } TReportParam;
263
264 /*---------------------------------------------------------------------------*
265 Name: ReportVisitorFunc
266
267 Description: A Visitor function for outputting the heap state.
268
269 Arguments: memBlock: The memory block
270 heap: Handle for expanded heap
271 userParam: call parameter for the visitor function
272 Gets the total memory size.
273
274 Returns: None.
275 *---------------------------------------------------------------------------*/
276 static void
ReportVisitorFunc(void * memBlock,MEMHeapHandle heap,u32 userParam)277 ReportVisitorFunc(
278 void* memBlock,
279 MEMHeapHandle heap,
280 u32 userParam
281 )
282 {
283 #pragma unused( heap )
284 TReportParam* pParam = (TReportParam*)userParam;
285 u16 allocDir = MEMGetAllocDirForMBlockExpHeap( memBlock );
286 u16 groupId = MEMGetGroupIDForMBlockExpHeap ( memBlock );
287 u32 size = MEMGetSizeForMBlockExpHeap ( memBlock );
288
289 pParam->size += MEMGetSizeForMBlockExpHeap( memBlock );
290 pParam->cnt++;
291
292 OSReport(" %s %08x: %8d %3d\n",
293 allocDir == MEM_EXPHEAP_ALLOC_DIR_REAR ? " rear" : "front",
294 (u32)memBlock,
295 size,
296 groupId
297 );
298 }
299
300 /*---------------------------------------------------------------------------*
301 Name: ReportExpHeap
302
303 Description: Outputs the state of the expanded heap.
304 The MEMDumpHeap will provide detailed output for debug builds.
305
306 Arguments: heap: heap handle
307
308 Returns: None.
309 *---------------------------------------------------------------------------*/
310 static void
ReportExpHeap(MEMHeapHandle heap)311 ReportExpHeap( MEMHeapHandle heap )
312 {
313 TReportParam param = { 0, 0 };
314
315 OSReport("[OS Foundation Exp Heap]\n");
316
317 OSReport(" whole [%p - %p)\n", MEMGetHeapStartAddress( heap ), MEMGetHeapEndAddress( heap ) );
318 OSReport(" attr address: size gid\n"); // Header line
319
320 MEMVisitAllocatedForExpHeap(
321 heap, // The heap handle
322 ReportVisitorFunc, // visitor function
323 (u32)¶m // User parameters
324 );
325
326 OSReport("\n");
327
328 {
329 u32 usedSize = param.size;
330 u32 usedCnt = param.cnt;
331
332 OSReport(" %d bytes allocated (U:%d)\n",
333 usedSize, usedCnt);
334 }
335 OSReport("\n");
336 }
337
338 #endif
339
340
341