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