FreeCalypso > hg > fc-tourmaline
comparison src/nucleus/dmc.c @ 0:4e78acac3d88
src/{condat,cs,gpf,nucleus}: import from Selenite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:23:26 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4e78acac3d88 |
---|---|
1 /*************************************************************************/ | |
2 /* */ | |
3 /* Copyright Mentor Graphics Corporation 2002 */ | |
4 /* All Rights Reserved. */ | |
5 /* */ | |
6 /* THIS WORK CONTAINS TRADE SECRET AND PROPRIETARY INFORMATION WHICH IS */ | |
7 /* THE PROPERTY OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS AND IS */ | |
8 /* SUBJECT TO LICENSE TERMS. */ | |
9 /* */ | |
10 /*************************************************************************/ | |
11 | |
12 /*************************************************************************/ | |
13 /* */ | |
14 /* FILE NAME VERSION */ | |
15 /* */ | |
16 /* dmc.c Nucleus PLUS 1.14 */ | |
17 /* */ | |
18 /* COMPONENT */ | |
19 /* */ | |
20 /* DM - Dynamic Memory Management */ | |
21 /* */ | |
22 /* DESCRIPTION */ | |
23 /* */ | |
24 /* This file contains the core routines for the Dynamic Memory */ | |
25 /* Management component. */ | |
26 /* */ | |
27 /* DATA STRUCTURES */ | |
28 /* */ | |
29 /* None */ | |
30 /* */ | |
31 /* FUNCTIONS */ | |
32 /* */ | |
33 /* DMC_Create_Memory_Pool Create a dynamic memory pool */ | |
34 /* DMC_Delete_Memory_Pool Delete a dynamic memory pool */ | |
35 /* DMC_Allocate_Memory Allocate a memory block from */ | |
36 /* a dynamic memory pool */ | |
37 /* DMC_Deallocate_Memory Deallocate a memory block */ | |
38 /* from a dynamic memory pool */ | |
39 /* DMC_Cleanup Cleanup on timeout or a */ | |
40 /* terminate condition */ | |
41 /* */ | |
42 /* DEPENDENCIES */ | |
43 /* */ | |
44 /* cs_extr.h Common Service functions */ | |
45 /* tc_extr.h Thread Control functions */ | |
46 /* dm_extr.h Partition functions */ | |
47 /* hi_extr.h History functions */ | |
48 /* */ | |
49 /* HISTORY */ | |
50 /* */ | |
51 /* DATE REMARKS */ | |
52 /* */ | |
53 /* 03-01-1993 Created initial version 1.0 */ | |
54 /* 04-19-1993 Verified version 1.0 */ | |
55 /* 08-09-1993 Corrected pointer retrieval */ | |
56 /* loop, resulting in version 1.0a */ | |
57 /* 08-09-1993 Verified version 1.0a */ | |
58 /* 03-01-1994 Moved non-core functions into */ | |
59 /* supplemental files, changed */ | |
60 /* function interfaces to match */ | |
61 /* those in prototype, added */ | |
62 /* register options, changed */ | |
63 /* protection logic to reduce */ | |
64 /* overhead, resulting in */ | |
65 /* version 1.1 */ | |
66 /* */ | |
67 /* 03-18-1994 Verified version 1.1 */ | |
68 /* 04-17-1996 updated to version 1.2 */ | |
69 /* 03-24-1998 Released version 1.3. */ | |
70 /* 03-26-1999 Released 1.11m (new release */ | |
71 /* numbering scheme) */ | |
72 /* 04-17-2002 Released version 1.13m */ | |
73 /* 11-07-2002 Released version 1.14 */ | |
74 /*************************************************************************/ | |
75 #define NU_SOURCE_FILE | |
76 | |
77 | |
78 #include "cs_extr.h" /* Common service functions */ | |
79 #include "tc_extr.h" /* Thread control functions */ | |
80 #include "dm_extr.h" /* Dynamic memory functions */ | |
81 #include "hi_extr.h" /* History functions */ | |
82 #include "profiler.h" /* ProView interface */ | |
83 | |
84 | |
85 /* Define external inner-component global data references. */ | |
86 | |
87 extern CS_NODE *DMD_Created_Pools_List; | |
88 extern UNSIGNED DMD_Total_Pools; | |
89 extern TC_PROTECT DMD_List_Protect; | |
90 | |
91 | |
92 /* Define internal component function prototypes. */ | |
93 | |
94 VOID DMC_Cleanup(VOID *information); | |
95 | |
96 | |
97 /*************************************************************************/ | |
98 /* */ | |
99 /* FUNCTION */ | |
100 /* */ | |
101 /* DMC_Create_Memory_Pool */ | |
102 /* */ | |
103 /* DESCRIPTION */ | |
104 /* */ | |
105 /* This function creates a dynamic memory pool and then places it */ | |
106 /* on the list of created dynamic memory pools. */ | |
107 /* */ | |
108 /* CALLED BY */ | |
109 /* */ | |
110 /* Application */ | |
111 /* DMCE_Create_Memory_Pool Error checking shell */ | |
112 /* */ | |
113 /* CALLS */ | |
114 /* */ | |
115 /* CSC_Place_On_List Add node to linked-list */ | |
116 /* [HIC_Make_History_Entry] Make entry in history log */ | |
117 /* [TCT_Check_Stack] Stack checking function */ | |
118 /* TCT_Protect Data structure protect */ | |
119 /* TCT_Unprotect Un-protect data structure */ | |
120 /* */ | |
121 /* INPUTS */ | |
122 /* */ | |
123 /* pool_ptr Memory pool control block */ | |
124 /* pointer */ | |
125 /* name Memory pool name */ | |
126 /* start_address Starting address of the pool */ | |
127 /* pool_size Number of bytes in the pool */ | |
128 /* min_allocation Minimum allocation size */ | |
129 /* suspend_type Suspension type */ | |
130 /* */ | |
131 /* OUTPUTS */ | |
132 /* */ | |
133 /* NU_SUCCESS */ | |
134 /* */ | |
135 /* HISTORY */ | |
136 /* */ | |
137 /* DATE REMARKS */ | |
138 /* */ | |
139 /* 03-01-1993 Created initial version 1.0 */ | |
140 /* 04-19-1993 Verified version 1.0 */ | |
141 /* 03-01-1994 Changed function interfaces to */ | |
142 /* match those in prototype, */ | |
143 /* added register options, */ | |
144 /* resulting in version 1.1 */ | |
145 /* */ | |
146 /* 03-18-1994 Verified version 1.1 */ | |
147 /* */ | |
148 /*************************************************************************/ | |
149 STATUS DMC_Create_Memory_Pool(NU_MEMORY_POOL *pool_ptr, CHAR *name, | |
150 VOID *start_address, UNSIGNED pool_size, | |
151 UNSIGNED min_allocation, OPTION suspend_type) | |
152 { | |
153 | |
154 R1 DM_PCB *pool; /* Pool control block ptr */ | |
155 INT i; /* Working index variable */ | |
156 DM_HEADER *header_ptr; /* Partition block header ptr*/ | |
157 NU_SUPERV_USER_VARIABLES | |
158 | |
159 /* Switch to supervisor mode */ | |
160 NU_SUPERVISOR_MODE(); | |
161 | |
162 /* Move input pool pointer into internal pointer. */ | |
163 pool = (DM_PCB *) pool_ptr; | |
164 | |
165 | |
166 #ifdef NU_ENABLE_STACK_CHECK | |
167 | |
168 /* Call stack checking function to check for an overflow condition. */ | |
169 TCT_Check_Stack(); | |
170 | |
171 #endif | |
172 | |
173 #ifdef NU_ENABLE_HISTORY | |
174 | |
175 /* Make an entry that corresponds to this function in the system history | |
176 log. */ | |
177 HIC_Make_History_Entry(NU_CREATE_MEMORY_POOL_ID, (UNSIGNED) pool, | |
178 (UNSIGNED) start_address, (UNSIGNED) pool_size); | |
179 | |
180 #endif | |
181 | |
182 /* First, clear the partition pool ID just in case it is an old | |
183 pool control block. */ | |
184 pool -> dm_id = 0; | |
185 | |
186 /* Fill in the partition pool name. */ | |
187 for (i = 0; i < NU_MAX_NAME; i++) | |
188 pool -> dm_name[i] = name[i]; | |
189 | |
190 /* Convert the pool's size into something that is evenly divisible by | |
191 the sizeof an UNSIGNED data element. */ | |
192 pool_size = (pool_size/sizeof(UNSIGNED)) * sizeof(UNSIGNED); | |
193 | |
194 /* Save the starting address and size parameters in the dynamic memory | |
195 control block. */ | |
196 pool -> dm_start_address = start_address; | |
197 pool -> dm_pool_size = pool_size; | |
198 pool -> dm_min_allocation = | |
199 ((min_allocation + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * | |
200 sizeof(UNSIGNED); | |
201 | |
202 /* Setup the dynamic memory pool suspension type. */ | |
203 if (suspend_type == NU_FIFO) | |
204 | |
205 /* FIFO suspension is selected, setup the flag accordingly. */ | |
206 pool -> dm_fifo_suspend = NU_TRUE; | |
207 else | |
208 | |
209 /* Priority suspension is selected. */ | |
210 pool -> dm_fifo_suspend = NU_FALSE; | |
211 | |
212 /* Clear the suspension list pointer. */ | |
213 pool -> dm_suspension_list = NU_NULL; | |
214 | |
215 /* Clear the number of tasks waiting on the dynamic memory pool. */ | |
216 pool -> dm_tasks_waiting = 0; | |
217 | |
218 /* Initialize link pointers. */ | |
219 pool -> dm_created.cs_previous = NU_NULL; | |
220 pool -> dm_created.cs_next = NU_NULL; | |
221 | |
222 /* Build a single block that has all of the memory. */ | |
223 header_ptr = (DM_HEADER *) start_address; | |
224 | |
225 /* Initialize the memory parameters. */ | |
226 pool -> dm_available = pool_size - (2 * DM_OVERHEAD); | |
227 pool -> dm_memory_list = header_ptr; | |
228 pool -> dm_search_ptr = header_ptr; | |
229 | |
230 /* Build the block header. */ | |
231 header_ptr -> dm_memory_pool = pool; | |
232 header_ptr -> dm_memory_free = NU_TRUE; | |
233 header_ptr -> dm_next_memory = (DM_HEADER *) | |
234 (((BYTE_PTR) header_ptr) + pool -> dm_available + DM_OVERHEAD); | |
235 header_ptr -> dm_previous_memory = header_ptr -> dm_next_memory; | |
236 | |
237 /* Build the small trailer block that prevents block merging when the | |
238 pool wraps around. Note that the list is circular so searching can | |
239 wrap across the physical end of the memory pool. */ | |
240 header_ptr = header_ptr -> dm_next_memory; | |
241 header_ptr -> dm_next_memory = (DM_HEADER *) start_address; | |
242 header_ptr -> dm_previous_memory = (DM_HEADER *) start_address; | |
243 header_ptr -> dm_memory_pool = pool; | |
244 header_ptr -> dm_memory_free = NU_FALSE; | |
245 | |
246 /* Initialize the protection structure. */ | |
247 pool -> dm_protect.tc_tcb_pointer = NU_NULL; | |
248 | |
249 /* Protect against access to the list of created memory pools. */ | |
250 TCT_Protect(&DMD_List_Protect); | |
251 | |
252 /* At this point the dynamic memory pool is completely built. The ID can | |
253 now be set and it can be linked into the created dynamic memory | |
254 pool list. */ | |
255 pool -> dm_id = DM_DYNAMIC_ID; | |
256 | |
257 /* Link the memory pool into the list of created memory pools and | |
258 increment the total number of pools in the system. */ | |
259 CSC_Place_On_List(&DMD_Created_Pools_List, &(pool -> dm_created)); | |
260 DMD_Total_Pools++; | |
261 | |
262 #ifdef INCLUDE_PROVIEW | |
263 _RTProf_DumpMemoryPool(RT_PROF_CREATE_MEMORY_POOL,pool,RT_PROF_OK); | |
264 #endif /*INCLUDE_PROVIEW*/ | |
265 /* Release protection against access to the list of created memory | |
266 pools. */ | |
267 TCT_Unprotect(); | |
268 | |
269 /* Return to user mode */ | |
270 NU_USER_MODE(); | |
271 | |
272 /* Return successful completion. */ | |
273 return(NU_SUCCESS); | |
274 } | |
275 | |
276 | |
277 /*************************************************************************/ | |
278 /* */ | |
279 /* FUNCTION */ | |
280 /* */ | |
281 /* DMC_Delete_Memory_Pool */ | |
282 /* */ | |
283 /* DESCRIPTION */ | |
284 /* */ | |
285 /* This function deletes a dynamic memory pool and removes it from */ | |
286 /* the list of created memory pools. All tasks suspended on the */ | |
287 /* memory pool are resumed with the appropriate error status. */ | |
288 /* Note that this function does not free any memory associated with */ | |
289 /* either the pool area or the pool control block. */ | |
290 /* */ | |
291 /* CALLED BY */ | |
292 /* */ | |
293 /* Application */ | |
294 /* DMCE_Delete_Memory_Pool Error checking shell */ | |
295 /* */ | |
296 /* CALLS */ | |
297 /* */ | |
298 /* CSC_Remove_From_List Remove node from list */ | |
299 /* [HIC_Make_History_Entry] Make entry in history log */ | |
300 /* TCC_Resume_Task Resume a suspended task */ | |
301 /* [TCT_Check_Stack] Stack checking function */ | |
302 /* TCT_Control_To_System Transfer control to system */ | |
303 /* TCT_Protect Protect created list */ | |
304 /* TCT_Set_Current_Protect Modify current protection */ | |
305 /* TCT_System_Protect Setup system protection */ | |
306 /* TCT_System_Unprotect Release system protection */ | |
307 /* TCT_Unprotect Release protection */ | |
308 /* */ | |
309 /* INPUTS */ | |
310 /* */ | |
311 /* pool_ptr Memory pool control block */ | |
312 /* pointer */ | |
313 /* */ | |
314 /* OUTPUTS */ | |
315 /* */ | |
316 /* NU_SUCCESS */ | |
317 /* */ | |
318 /* HISTORY */ | |
319 /* */ | |
320 /* DATE REMARKS */ | |
321 /* */ | |
322 /* 03-01-1993 Created initial version 1.0 */ | |
323 /* 04-19-1993 Verified version 1.0 */ | |
324 /* 03-01-1994 Changed function interfaces to */ | |
325 /* match those in prototype, */ | |
326 /* added register options, changed */ | |
327 /* protection logic to reduce */ | |
328 /* overhead, resulting in */ | |
329 /* version 1.1 */ | |
330 /* */ | |
331 /* 03-18-1994 Verified version 1.1 */ | |
332 /* */ | |
333 /*************************************************************************/ | |
334 STATUS DMC_Delete_Memory_Pool(NU_MEMORY_POOL *pool_ptr) | |
335 { | |
336 | |
337 R1 DM_PCB *pool; /* Pool control block ptr */ | |
338 DM_SUSPEND *suspend_ptr; /* Suspend block pointer */ | |
339 DM_SUSPEND *next_ptr; /* Next suspend block */ | |
340 STATUS preempt; /* Status for resume call */ | |
341 NU_SUPERV_USER_VARIABLES | |
342 | |
343 /* Switch to supervisor mode */ | |
344 NU_SUPERVISOR_MODE(); | |
345 | |
346 /* Move input pool pointer into internal pointer. */ | |
347 pool = (DM_PCB *) pool_ptr; | |
348 | |
349 #ifdef NU_ENABLE_STACK_CHECK | |
350 | |
351 /* Call stack checking function to check for an overflow condition. */ | |
352 TCT_Check_Stack(); | |
353 | |
354 #endif | |
355 | |
356 #ifdef NU_ENABLE_HISTORY | |
357 | |
358 /* Make an entry that corresponds to this function in the system history | |
359 log. */ | |
360 HIC_Make_History_Entry(NU_DELETE_MEMORY_POOL_ID, (UNSIGNED) pool, | |
361 (UNSIGNED) 0, (UNSIGNED) 0); | |
362 | |
363 #endif | |
364 | |
365 /* Protect against simultaneous access to the memory pool. */ | |
366 TCT_Protect(&(pool -> dm_protect)); | |
367 | |
368 #ifdef INCLUDE_PROVIEW | |
369 _RTProf_DumpMemoryPool(RT_PROF_DELETE_MEMORY_POOL,pool,RT_PROF_OK); | |
370 #endif /*INCLUDE_PROVIEW*/ | |
371 /* Clear the memory pool ID. */ | |
372 pool -> dm_id = 0; | |
373 | |
374 /* Release protection. */ | |
375 TCT_Unprotect(); | |
376 | |
377 /* Protect against access to the list of created memory pools. */ | |
378 TCT_Protect(&DMD_List_Protect); | |
379 | |
380 /* Remove the memory pool from the list of created memory pools. */ | |
381 CSC_Remove_From_List(&DMD_Created_Pools_List, &(pool -> dm_created)); | |
382 | |
383 /* Decrement the total number of created memory pools. */ | |
384 DMD_Total_Pools--; | |
385 | |
386 /* Pickup the suspended task pointer list. */ | |
387 suspend_ptr = pool -> dm_suspension_list; | |
388 | |
389 /* Walk the chain task(s) currently suspended on the memory pool. */ | |
390 preempt = 0; | |
391 while (suspend_ptr) | |
392 { | |
393 | |
394 /* Protect against system access. */ | |
395 TCT_System_Protect(); | |
396 | |
397 /* Resume the suspended task. Insure that the status returned is | |
398 NU_POOL_DELETED. */ | |
399 suspend_ptr -> dm_return_pointer = NU_NULL; | |
400 suspend_ptr -> dm_return_status = NU_POOL_DELETED; | |
401 | |
402 /* Point to the next suspend structure in the link. */ | |
403 next_ptr = (DM_SUSPEND *) (suspend_ptr -> dm_suspend_link.cs_next); | |
404 | |
405 /* Resume the specified task. */ | |
406 preempt = preempt | | |
407 TCC_Resume_Task((NU_TASK *) suspend_ptr -> dm_suspended_task, | |
408 NU_MEMORY_SUSPEND); | |
409 | |
410 /* Determine if the next is the same as the current pointer. */ | |
411 if (next_ptr == pool -> dm_suspension_list) | |
412 | |
413 /* Clear the suspension pointer to signal the end of the list | |
414 traversal. */ | |
415 suspend_ptr = NU_NULL; | |
416 else | |
417 | |
418 /* Move the next pointer into the suspend block pointer. */ | |
419 suspend_ptr = next_ptr; | |
420 | |
421 /* Modify current protection. */ | |
422 TCT_Set_Current_Protect(&DMD_List_Protect); | |
423 | |
424 /* Clear the system protection. */ | |
425 TCT_System_Unprotect(); | |
426 } | |
427 | |
428 /* Determine if preemption needs to occur. */ | |
429 if (preempt) | |
430 | |
431 /* Transfer control to system to facilitate preemption. */ | |
432 TCT_Control_To_System(); | |
433 | |
434 /* Release protection against access to the list of created memory | |
435 pools. */ | |
436 TCT_Unprotect(); | |
437 | |
438 /* Return to user mode */ | |
439 NU_USER_MODE(); | |
440 | |
441 /* Return a successful completion. */ | |
442 return(NU_SUCCESS); | |
443 } | |
444 | |
445 | |
446 /*************************************************************************/ | |
447 /* */ | |
448 /* FUNCTION */ | |
449 /* */ | |
450 /* DMC_Allocate_Memory */ | |
451 /* */ | |
452 /* DESCRIPTION */ | |
453 /* */ | |
454 /* This function allocates memory from the specified dynamic memory */ | |
455 /* pool. If dynamic memory is currently available, this function */ | |
456 /* is completed immediately. Otherwise, if there is not enough */ | |
457 /* memory currently available, task suspension is possible. */ | |
458 /* */ | |
459 /* CALLED BY */ | |
460 /* */ | |
461 /* Application */ | |
462 /* DMCE_Allocate_Memory Error checking shell */ | |
463 /* */ | |
464 /* CALLS */ | |
465 /* */ | |
466 /* CSC_Place_On_List Place on suspend list */ | |
467 /* [HIC_Make_History_Entry] Make entry in history log */ | |
468 /* TCC_Suspend_Task Suspend calling task */ | |
469 /* TCC_Task_Priority Pickup task priority */ | |
470 /* [TCT_Check_Stack] Stack checking function */ | |
471 /* TCT_Current_Thread Pickup current thread pointer*/ | |
472 /* TCT_Protect Protect memory pool */ | |
473 /* TCT_Set_Suspend_Protect Save suspend protection */ | |
474 /* TCT_System_Protect Protect system structures */ | |
475 /* TCT_Unprotect Release protection */ | |
476 /* TCT_Unprotect_Specific Release specific protection */ | |
477 /* */ | |
478 /* INPUTS */ | |
479 /* */ | |
480 /* pool_ptr Memory pool pointer */ | |
481 /* return_pointer Pointer to the destination */ | |
482 /* memory pointer */ | |
483 /* size Number of bytes requested */ | |
484 /* suspend Suspension option if full */ | |
485 /* */ | |
486 /* OUTPUTS */ | |
487 /* */ | |
488 /* NU_SUCCESS If service is successful */ | |
489 /* NU_NO_MEMORY Memory not available */ | |
490 /* NU_TIMEOUT If timeout on service */ | |
491 /* NU_POOL_DELETED If memory pool deleted */ | |
492 /* during suspension */ | |
493 /* */ | |
494 /* HISTORY */ | |
495 /* */ | |
496 /* DATE REMARKS */ | |
497 /* */ | |
498 /* 03-01-1993 Created initial version 1.0 */ | |
499 /* 04-19-1993 Verified version 1.0 */ | |
500 /* 03-01-1994 Changed function interfaces to */ | |
501 /* match those in prototype, */ | |
502 /* added register options, changed */ | |
503 /* protection logic to reduce */ | |
504 /* overhead, resulting in */ | |
505 /* version 1.1 */ | |
506 /* */ | |
507 /* 03-18-1994 Verified version 1.1 */ | |
508 /* */ | |
509 /*************************************************************************/ | |
510 STATUS DMC_Allocate_Memory(NU_MEMORY_POOL *pool_ptr, VOID **return_pointer, | |
511 UNSIGNED size, UNSIGNED suspend) | |
512 { | |
513 | |
514 R1 DM_PCB *pool; /* Pool control block ptr */ | |
515 R2 DM_SUSPEND *suspend_ptr; /* Pointer to suspend block */ | |
516 DM_SUSPEND suspend_block; /* Allocate suspension block */ | |
517 R4 DM_HEADER *memory_ptr; /* Pointer to memory */ | |
518 R3 DM_HEADER *new_ptr; /* New split block pointer */ | |
519 UNSIGNED free_size; /* Size of block found */ | |
520 TC_TCB *task; /* Task pointer */ | |
521 STATUS status; /* Completion status */ | |
522 NU_SUPERV_USER_VARIABLES | |
523 | |
524 /* Switch to supervisor mode */ | |
525 NU_SUPERVISOR_MODE(); | |
526 | |
527 /* Move input pool pointer into internal pointer. */ | |
528 pool = (DM_PCB *) pool_ptr; | |
529 | |
530 | |
531 #ifdef NU_ENABLE_STACK_CHECK | |
532 | |
533 /* Call stack checking function to check for an overflow condition. */ | |
534 TCT_Check_Stack(); | |
535 | |
536 #endif | |
537 | |
538 #ifdef NU_ENABLE_HISTORY | |
539 | |
540 /* Make an entry that corresponds to this function in the system history | |
541 log. */ | |
542 HIC_Make_History_Entry(NU_ALLOCATE_MEMORY_ID, (UNSIGNED) pool, | |
543 (UNSIGNED) return_pointer, (UNSIGNED) size); | |
544 | |
545 #endif | |
546 | |
547 /* Initialize the status as successful. */ | |
548 status = NU_SUCCESS; | |
549 | |
550 /* Adjust the request to a size evenly divisible by the number of bytes | |
551 in an UNSIGNED data element. Also, check to make sure it is of the | |
552 minimum size. */ | |
553 if (size < pool -> dm_min_allocation) | |
554 | |
555 /* Change size to the minimum allocation. */ | |
556 size = pool -> dm_min_allocation; | |
557 else | |
558 | |
559 /* Insure that size is a multiple of the UNSIGNED size. */ | |
560 size = | |
561 ((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED); | |
562 | |
563 /* Protect against simultaneous access to the memory pool. */ | |
564 TCT_Protect(&(pool -> dm_protect)); | |
565 | |
566 /* Search the memory list for the first available block of memory that | |
567 satisfies the request. Note that blocks are merged during the | |
568 deallocation function. */ | |
569 memory_ptr = pool -> dm_search_ptr; | |
570 do | |
571 { | |
572 | |
573 /* Determine if the block is free and if it can satisfy the request. */ | |
574 if (memory_ptr -> dm_memory_free) | |
575 | |
576 /* Calculate the free block size. */ | |
577 free_size = (((BYTE_PTR) (memory_ptr -> dm_next_memory)) - | |
578 ((BYTE_PTR) memory_ptr)) - DM_OVERHEAD; | |
579 else | |
580 | |
581 /* There are no free bytes available. */ | |
582 free_size = 0; | |
583 | |
584 /* Determine if the search should continue. */ | |
585 if (free_size < size) | |
586 | |
587 /* Large enough block has not been found. Move the search | |
588 pointer to the next block. */ | |
589 memory_ptr = memory_ptr -> dm_next_memory; | |
590 } while((free_size < size) && (memory_ptr != pool -> dm_search_ptr)); | |
591 | |
592 /* Determine if the memory is available. */ | |
593 if (free_size >= size) | |
594 { | |
595 | |
596 /* A block that satisfies the request has been found. */ | |
597 | |
598 /* Determine if the block needs to be split. */ | |
599 if (free_size >= (size + DM_OVERHEAD + pool -> dm_min_allocation)) | |
600 { | |
601 | |
602 /* Yes, split the block. */ | |
603 new_ptr = (DM_HEADER *) (((BYTE_PTR) memory_ptr) + size + | |
604 DM_OVERHEAD); | |
605 | |
606 /* Mark the new block as free. */ | |
607 new_ptr -> dm_memory_free = NU_TRUE; | |
608 | |
609 /* Put the pool pointer into the new block. */ | |
610 new_ptr -> dm_memory_pool = pool; | |
611 | |
612 /* Build the necessary pointers. */ | |
613 new_ptr -> dm_previous_memory = memory_ptr; | |
614 new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory; | |
615 (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; | |
616 memory_ptr -> dm_next_memory = new_ptr; | |
617 | |
618 /* Decrement the available byte count. */ | |
619 pool -> dm_available = pool -> dm_available - size - DM_OVERHEAD; | |
620 } | |
621 else | |
622 | |
623 /* Decrement the entire free size from the available bytes | |
624 count. */ | |
625 pool -> dm_available = pool -> dm_available - free_size; | |
626 | |
627 /* Mark the allocated block as not available. */ | |
628 memory_ptr -> dm_memory_free = NU_FALSE; | |
629 | |
630 /* Should the search pointer be moved? */ | |
631 if (pool -> dm_search_ptr == memory_ptr) | |
632 | |
633 /* Move the search pointer to the next free memory slot. */ | |
634 pool -> dm_search_ptr = memory_ptr -> dm_next_memory; | |
635 | |
636 /* Return a memory address to the caller. */ | |
637 *return_pointer = (VOID *) (((BYTE_PTR) memory_ptr) + DM_OVERHEAD); | |
638 #ifdef INCLUDE_PROVIEW | |
639 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_OK); | |
640 #endif /*INCLUDE_PROVIEW*/ | |
641 } | |
642 else | |
643 { | |
644 | |
645 /* Enough dynamic memory is not available. Determine if suspension is | |
646 required. */ | |
647 if (suspend) | |
648 { | |
649 | |
650 /* Suspension is selected. */ | |
651 | |
652 /* Increment the number of tasks waiting. */ | |
653 pool -> dm_tasks_waiting++; | |
654 | |
655 #ifdef INCLUDE_PROVIEW | |
656 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_WAIT); | |
657 #endif /*INCLUDE_PROVIEW*/ | |
658 /* Setup the suspend block and suspend the calling task. */ | |
659 suspend_ptr = &suspend_block; | |
660 suspend_ptr -> dm_memory_pool = pool; | |
661 suspend_ptr -> dm_request_size = size; | |
662 suspend_ptr -> dm_suspend_link.cs_next = NU_NULL; | |
663 suspend_ptr -> dm_suspend_link.cs_previous = NU_NULL; | |
664 task = (TC_TCB *) TCT_Current_Thread(); | |
665 suspend_ptr -> dm_suspended_task = task; | |
666 | |
667 /* Determine if priority or FIFO suspension is associated with the | |
668 memory pool. */ | |
669 if (pool -> dm_fifo_suspend) | |
670 { | |
671 | |
672 /* FIFO suspension is required. Link the suspend block into | |
673 the list of suspended tasks on this memory pool. */ | |
674 CSC_Place_On_List((CS_NODE **) | |
675 &(pool -> dm_suspension_list), | |
676 &(suspend_ptr -> dm_suspend_link)); | |
677 } | |
678 else | |
679 { | |
680 | |
681 /* Get the priority of the current thread so the suspend block | |
682 can be placed in the appropriate place. */ | |
683 suspend_ptr -> dm_suspend_link.cs_priority = | |
684 TCC_Task_Priority(task); | |
685 | |
686 CSC_Priority_Place_On_List((CS_NODE **) | |
687 &(pool -> dm_suspension_list), | |
688 &(suspend_ptr -> dm_suspend_link)); | |
689 } | |
690 | |
691 /* Protect against system access. */ | |
692 TCT_System_Protect(); | |
693 | |
694 /* Save the list protection in preparation for suspension. */ | |
695 TCT_Set_Suspend_Protect(&(pool -> dm_protect)); | |
696 | |
697 /* Release protection of dynamic memory pool. */ | |
698 TCT_Unprotect_Specific(&(pool -> dm_protect)); | |
699 | |
700 /* Finally, suspend the calling task. Note that the suspension call | |
701 automatically clears the system protection. */ | |
702 TCC_Suspend_Task((NU_TASK *) task, NU_MEMORY_SUSPEND, | |
703 DMC_Cleanup, suspend_ptr, suspend); | |
704 | |
705 /* Pickup the return status. */ | |
706 status = suspend_ptr -> dm_return_status; | |
707 *return_pointer = suspend_ptr -> dm_return_pointer; | |
708 } | |
709 else | |
710 { | |
711 | |
712 /* No suspension requested. Simply return an error status. */ | |
713 status = NU_NO_MEMORY; | |
714 *return_pointer = NU_NULL; | |
715 #ifdef INCLUDE_PROVIEW | |
716 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_FAIL); | |
717 #endif /*INCLUDE_PROVIEW*/ | |
718 } | |
719 } | |
720 | |
721 /* Release protection of the memory pool. */ | |
722 TCT_Unprotect(); | |
723 | |
724 /* Return to user mode */ | |
725 NU_USER_MODE(); | |
726 | |
727 /* Return the completion status. */ | |
728 return(status); | |
729 } | |
730 | |
731 | |
732 /*************************************************************************/ | |
733 /* */ | |
734 /* FUNCTION */ | |
735 /* */ | |
736 /* DMC_Deallocate_Memory */ | |
737 /* */ | |
738 /* DESCRIPTION */ | |
739 /* */ | |
740 /* This function deallocates a previously allocated dynamic memory */ | |
741 /* block. The deallocated dynamic memory block is merged with any */ | |
742 /* adjacent neighbors. This insures that there are no consecutive */ | |
743 /* blocks of free memory in the pool (makes the search easier!). */ | |
744 /* If there is a task waiting for dynamic memory, a determination */ | |
745 /* of whether or not the request can now be satisfied is made after */ | |
746 /* the deallocation is complete. */ | |
747 /* */ | |
748 /* CALLED BY */ | |
749 /* */ | |
750 /* Application */ | |
751 /* DMCE_Deallocate_Memory Error checking shell */ | |
752 /* */ | |
753 /* CALLS */ | |
754 /* */ | |
755 /* CSC_Remove_From_List Remove from suspend list */ | |
756 /* [HIC_Make_History_Entry] Make entry in history log */ | |
757 /* TCC_Resume_Task Resume a suspended task */ | |
758 /* [TCT_Check_Stack] Stack checking function */ | |
759 /* TCT_Control_To_System Transfer control to system */ | |
760 /* TCT_Set_Current_Protect Set current protection */ | |
761 /* TCT_System_Protect Protect system structures */ | |
762 /* TCT_System_Unprotect Release system protection */ | |
763 /* TCT_Protect Protect dynamic memory pool */ | |
764 /* TCT_Unprotect Release protection */ | |
765 /* */ | |
766 /* INPUTS */ | |
767 /* */ | |
768 /* memory Pointer to dynamic memory */ | |
769 /* */ | |
770 /* OUTPUTS */ | |
771 /* */ | |
772 /* NU_SUCCESS */ | |
773 /* */ | |
774 /* HISTORY */ | |
775 /* */ | |
776 /* DATE REMARKS */ | |
777 /* */ | |
778 /* 03-01-1993 Created initial version 1.0 */ | |
779 /* 04-19-1993 Verified version 1.0 */ | |
780 /* 03-01-1994 Added register options, changed */ | |
781 /* protection logic to reduce */ | |
782 /* overhead, resulting in */ | |
783 /* version 1.1 */ | |
784 /* */ | |
785 /* 03-18-1994 Verified version 1.1 */ | |
786 /* */ | |
787 /*************************************************************************/ | |
788 STATUS DMC_Deallocate_Memory(VOID *memory) | |
789 { | |
790 | |
791 R1 DM_PCB *pool; /* Pool pointer */ | |
792 R3 DM_SUSPEND *suspend_ptr; /* Pointer to suspend block */ | |
793 R2 DM_HEADER *header_ptr; /* Pointer to memory hdr */ | |
794 R4 DM_HEADER *new_ptr; /* New memory block pointer */ | |
795 UNSIGNED size; /* Suspended task request */ | |
796 UNSIGNED free_size; /* Amount of free bytes */ | |
797 STATUS preempt; /* Preemption flag */ | |
798 STATUS status; /* Completion status */ | |
799 NU_SUPERV_USER_VARIABLES | |
800 | |
801 /* Switch to supervisor mode */ | |
802 NU_SUPERVISOR_MODE(); | |
803 | |
804 #ifdef NU_ENABLE_STACK_CHECK | |
805 | |
806 /* Call stack checking function to check for an overflow condition. */ | |
807 TCT_Check_Stack(); | |
808 | |
809 #endif | |
810 | |
811 #ifdef NU_ENABLE_HISTORY | |
812 | |
813 /* Make an entry that corresponds to this function in the system history | |
814 log. */ | |
815 HIC_Make_History_Entry(NU_DEALLOCATE_MEMORY_ID, (UNSIGNED) memory, | |
816 (UNSIGNED) 0, (UNSIGNED) 0); | |
817 | |
818 #endif | |
819 | |
820 /* Initialize the status as successful. */ | |
821 status = NU_SUCCESS; | |
822 | |
823 /* Pickup the associated pool's pointer. It is inside the header of | |
824 each memory. */ | |
825 header_ptr = (DM_HEADER *) (((BYTE_PTR) memory) - DM_OVERHEAD); | |
826 pool = header_ptr -> dm_memory_pool; | |
827 | |
828 /* Protect against simultaneous access to the memory pool. */ | |
829 TCT_Protect(&(pool -> dm_protect)); | |
830 | |
831 /* Mark the memory as available. */ | |
832 header_ptr -> dm_memory_free = NU_TRUE; | |
833 | |
834 /* Adjust the available number of bytes. */ | |
835 pool -> dm_available = pool -> dm_available + | |
836 (((BYTE_PTR) (header_ptr -> dm_next_memory)) - | |
837 ((BYTE_PTR) header_ptr)) - DM_OVERHEAD; | |
838 | |
839 /* Determine if the block can be merged with the previous neighbor. */ | |
840 if ((header_ptr -> dm_previous_memory) -> dm_memory_free) | |
841 { | |
842 | |
843 /* Adjust the available number of bytes. */ | |
844 pool -> dm_available = pool -> dm_available + DM_OVERHEAD; | |
845 | |
846 /* Yes, merge block with previous neighbor. */ | |
847 (header_ptr -> dm_previous_memory) -> dm_next_memory = | |
848 header_ptr -> dm_next_memory; | |
849 (header_ptr -> dm_next_memory) -> dm_previous_memory = | |
850 header_ptr -> dm_previous_memory; | |
851 | |
852 /* Move header pointer to previous. */ | |
853 header_ptr = header_ptr -> dm_previous_memory; | |
854 | |
855 /* Adjust the search pointer to the new merged block. */ | |
856 pool -> dm_search_ptr = header_ptr; | |
857 } | |
858 | |
859 /* Determine if the block can be merged with the next neighbor. */ | |
860 if ((header_ptr -> dm_next_memory) -> dm_memory_free) | |
861 { | |
862 | |
863 /* Adjust the available number of bytes. */ | |
864 pool -> dm_available = pool -> dm_available + DM_OVERHEAD; | |
865 | |
866 /* Yes, merge block with next neighbor. */ | |
867 new_ptr = header_ptr -> dm_next_memory; | |
868 (new_ptr -> dm_next_memory) -> dm_previous_memory = | |
869 header_ptr; | |
870 header_ptr -> dm_next_memory = new_ptr -> dm_next_memory; | |
871 | |
872 /* Adjust the search pointer to the new merged block. */ | |
873 pool -> dm_search_ptr = header_ptr; | |
874 } | |
875 | |
876 #ifdef INCLUDE_PROVIEW | |
877 _RTProf_DumpMemoryPool(RT_PROF_DEALLOCATE_MEMORY,pool,RT_PROF_OK); | |
878 #endif /*INCLUDE_PROVIEW*/ | |
879 /* Determine if another task is waiting for memory from the pool. */ | |
880 suspend_ptr = pool -> dm_suspension_list; | |
881 preempt = 0; | |
882 while (suspend_ptr) | |
883 { | |
884 | |
885 /* Yes, another task is waiting for memory from the pool. Search | |
886 the pool in the same manner as the memory allocation function. */ | |
887 size = suspend_ptr -> dm_request_size; | |
888 header_ptr = pool -> dm_search_ptr; | |
889 do | |
890 { | |
891 | |
892 /* Determine if the block is free and if it can satisfy the request | |
893 of the first task waiting. */ | |
894 if (header_ptr -> dm_memory_free) | |
895 | |
896 /* Calculate the free block size. */ | |
897 free_size = (((BYTE_PTR) (header_ptr -> dm_next_memory)) - | |
898 ((BYTE_PTR) header_ptr)) - DM_OVERHEAD; | |
899 else | |
900 | |
901 /* There are no free bytes available. */ | |
902 free_size = 0; | |
903 | |
904 /* Determine if the search should continue. */ | |
905 if (free_size < size) | |
906 | |
907 /* Large enough block has not been found. Move the search | |
908 pointer to the next block. */ | |
909 header_ptr = header_ptr -> dm_next_memory; | |
910 } while((free_size < size) && (header_ptr != pool -> dm_search_ptr)); | |
911 | |
912 /* Determine if the memory is available. */ | |
913 if (free_size >= size) | |
914 { | |
915 | |
916 /* A block that satisfies the request has been found. */ | |
917 | |
918 /* Determine if the block needs to be split. */ | |
919 if (free_size >= (size + DM_OVERHEAD + pool -> dm_min_allocation)) | |
920 { | |
921 | |
922 /* Yes, split the block. */ | |
923 new_ptr = (DM_HEADER *) (((BYTE_PTR) header_ptr) + size + | |
924 DM_OVERHEAD); | |
925 | |
926 /* Mark the new block as free. */ | |
927 new_ptr -> dm_memory_free = NU_TRUE; | |
928 | |
929 /* Put the pool pointer into the new block. */ | |
930 new_ptr -> dm_memory_pool = pool; | |
931 | |
932 /* Build the necessary pointers. */ | |
933 new_ptr -> dm_previous_memory = header_ptr; | |
934 new_ptr -> dm_next_memory = header_ptr -> dm_next_memory; | |
935 (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr; | |
936 header_ptr -> dm_next_memory = new_ptr; | |
937 | |
938 /* Decrement the available byte count. */ | |
939 pool -> dm_available = pool -> dm_available - | |
940 size - DM_OVERHEAD; | |
941 } | |
942 else | |
943 | |
944 /* Decrement the entire free size from the available bytes | |
945 count. */ | |
946 pool -> dm_available = pool -> dm_available - free_size; | |
947 | |
948 /* Mark the allocated block as not available. */ | |
949 header_ptr -> dm_memory_free = NU_FALSE; | |
950 | |
951 /* Should the search pointer be moved? */ | |
952 if (pool -> dm_search_ptr == header_ptr) | |
953 | |
954 /* Move the search pointer to the next free memory slot. */ | |
955 pool -> dm_search_ptr = header_ptr -> dm_next_memory; | |
956 | |
957 /* Decrement the number of tasks waiting counter. */ | |
958 pool -> dm_tasks_waiting--; | |
959 | |
960 /* Remove the first suspended block from the list. */ | |
961 CSC_Remove_From_List((CS_NODE **) &(pool -> dm_suspension_list), | |
962 &(suspend_ptr -> dm_suspend_link)); | |
963 | |
964 /* Setup the appropriate return value. */ | |
965 suspend_ptr -> dm_return_status = NU_SUCCESS; | |
966 suspend_ptr -> dm_return_pointer = (VOID *) | |
967 (((BYTE_PTR) header_ptr) + DM_OVERHEAD); | |
968 | |
969 /* Setup system protect while task is being resumed. */ | |
970 TCT_System_Protect(); | |
971 | |
972 /* Resume the suspended task. */ | |
973 preempt = preempt | | |
974 TCC_Resume_Task((NU_TASK *) suspend_ptr -> dm_suspended_task, | |
975 NU_MEMORY_SUSPEND); | |
976 | |
977 /* Switch back to the pool protection. */ | |
978 TCT_Set_Current_Protect(&(pool -> dm_protect)); | |
979 | |
980 /* Release system protection. */ | |
981 TCT_System_Unprotect(); | |
982 | |
983 /* Pickup the next suspension pointer. */ | |
984 suspend_ptr = pool -> dm_suspension_list; | |
985 } | |
986 else | |
987 | |
988 /* Not enough memory for suspended task. */ | |
989 suspend_ptr = NU_NULL; | |
990 } | |
991 | |
992 /* Determine if a preempt condition is present. */ | |
993 if (preempt) | |
994 | |
995 /* Transfer control to the system if the resumed task function | |
996 detects a preemption condition. */ | |
997 TCT_Control_To_System(); | |
998 | |
999 /* Release protection of the memory pool. */ | |
1000 TCT_Unprotect(); | |
1001 | |
1002 /* Return to user mode */ | |
1003 NU_USER_MODE(); | |
1004 | |
1005 /* Return the completion status. */ | |
1006 return(status); | |
1007 } | |
1008 | |
1009 | |
1010 /*************************************************************************/ | |
1011 /* */ | |
1012 /* FUNCTION */ | |
1013 /* */ | |
1014 /* DMC_Cleanup */ | |
1015 /* */ | |
1016 /* DESCRIPTION */ | |
1017 /* */ | |
1018 /* This function is responsible for removing a suspension block */ | |
1019 /* from a memory pool. It is not called unless a timeout or */ | |
1020 /* a task terminate is in progress. Note that protection is */ | |
1021 /* already in effect - the same protection at suspension time. */ | |
1022 /* */ | |
1023 /* CALLED BY */ | |
1024 /* */ | |
1025 /* TCC_Timeout Task timeout */ | |
1026 /* TCC_Terminate Task terminate */ | |
1027 /* */ | |
1028 /* CALLS */ | |
1029 /* */ | |
1030 /* CSC_Remove_From_List Remove suspend block from */ | |
1031 /* the suspension list */ | |
1032 /* */ | |
1033 /* INPUTS */ | |
1034 /* */ | |
1035 /* information Pointer to suspend block */ | |
1036 /* */ | |
1037 /* OUTPUTS */ | |
1038 /* */ | |
1039 /* None */ | |
1040 /* */ | |
1041 /* HISTORY */ | |
1042 /* */ | |
1043 /* DATE REMARKS */ | |
1044 /* */ | |
1045 /* 03-01-1993 Created initial version 1.0 */ | |
1046 /* 04-19-1993 Verified version 1.0 */ | |
1047 /* */ | |
1048 /*************************************************************************/ | |
1049 VOID DMC_Cleanup(VOID *information) | |
1050 { | |
1051 | |
1052 DM_SUSPEND *suspend_ptr; /* Suspension block pointer */ | |
1053 NU_SUPERV_USER_VARIABLES | |
1054 | |
1055 /* Switch to supervisor mode */ | |
1056 NU_SUPERVISOR_MODE(); | |
1057 | |
1058 /* Use the information pointer as a suspend pointer. */ | |
1059 suspend_ptr = (DM_SUSPEND *) information; | |
1060 | |
1061 /* By default, indicate that the service timed-out. It really does not | |
1062 matter if this function is called from a terminate request since | |
1063 the task does not resume. */ | |
1064 suspend_ptr -> dm_return_status = NU_TIMEOUT; | |
1065 suspend_ptr -> dm_return_pointer = NU_NULL; | |
1066 | |
1067 /* Decrement the number of tasks waiting counter. */ | |
1068 (suspend_ptr -> dm_memory_pool) -> dm_tasks_waiting--; | |
1069 | |
1070 /* Unlink the suspend block from the suspension list. */ | |
1071 CSC_Remove_From_List((CS_NODE **) | |
1072 &((suspend_ptr -> dm_memory_pool) -> dm_suspension_list), | |
1073 &(suspend_ptr -> dm_suspend_link)); | |
1074 | |
1075 /* Return to user mode */ | |
1076 NU_USER_MODE(); | |
1077 } | |
1078 | |
1079 | |
1080 | |
1081 | |
1082 | |
1083 | |
1084 |