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