comparison src/nucleus/dms.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 /* dms.c Nucleus PLUS 1.14 */
17 /* */
18 /* COMPONENT */
19 /* */
20 /* DM - Dynamic Memory Management */
21 /* */
22 /* DESCRIPTION */
23 /* */
24 /* This file contains the supplemental routines for the Dynamic */
25 /* Memory Management component. */
26 /* */
27 /* DATA STRUCTURES */
28 /* */
29 /* None */
30 /* */
31 /* FUNCTIONS */
32 /* */
33 /* DMS_Allocate_Aligned_Memory Allocate an aligned memory */
34 /* block from a dynamic */
35 /* memory pool */
36 /* DEPENDENCIES */
37 /* */
38 /* cs_extr.h Common Service functions */
39 /* tc_extr.h Thread Control functions */
40 /* dm_extr.h Partition functions */
41 /* hi_extr.h History functions */
42 /* */
43 /* HISTORY */
44 /* */
45 /* DATE REMARKS */
46 /* */
47 /* 01-15-1999 Created initial revision */
48 /* 03-26-1999 Released 1.11m (new release */
49 /* numbering scheme) */
50 /* 04-17-2002 Released version 1.13m */
51 /* 11-07-2002 Released version 1.14 */
52 /*************************************************************************/
53 #define NU_SOURCE_FILE
54
55 #include "cs_extr.h" /* Common service functions */
56 #include "tc_extr.h" /* Thread control functions */
57 #include "dm_extr.h" /* Dynamic memory functions */
58 #include "hi_extr.h" /* History functions */
59 #include "profiler.h" /* ProView interface */
60
61
62 /* Define external inner-component global data references. */
63
64
65 /* Define internal component function prototypes. */
66 VOID DMC_Cleanup(VOID *information);
67
68
69 /*************************************************************************/
70 /* */
71 /* FUNCTION */
72 /* */
73 /* DMS_Allocate_Aligned_Memory */
74 /* */
75 /* DESCRIPTION */
76 /* */
77 /* This function allocates memory from the specified dynamic memory */
78 /* pool. If dynamic memory is currently available, this function */
79 /* is completed immediately. Otherwise, if there is not enough */
80 /* memory currently available, task suspension is possible. */
81 /* */
82 /* CALLED BY */
83 /* */
84 /* Application */
85 /* */
86 /* CALLS */
87 /* */
88 /* CSC_Place_On_List Place on suspend list */
89 /* [HIC_Make_History_Entry] Make entry in history log */
90 /* TCC_Suspend_Task Suspend calling task */
91 /* TCC_Task_Priority Pickup task priority */
92 /* [TCT_Check_Stack] Stack checking function */
93 /* TCT_Current_Thread Pickup current thread pointer*/
94 /* TCT_Protect Protect memory pool */
95 /* TCT_Set_Suspend_Protect Save suspend protection */
96 /* TCT_System_Protect Protect system structures */
97 /* TCT_Unprotect Release protection */
98 /* TCT_Unprotect_Specific Release specific protection */
99 /* */
100 /* INPUTS */
101 /* */
102 /* pool_ptr Memory pool pointer */
103 /* return_pointer Pointer to the destination */
104 /* memory pointer */
105 /* size Number of bytes requested */
106 /* alignment Required alignment of */
107 /* destination memory pointer */
108 /* suspend Suspension option if full */
109 /* */
110 /* OUTPUTS */
111 /* */
112 /* NU_SUCCESS If service is successful */
113 /* NU_NO_MEMORY Memory not available */
114 /* NU_TIMEOUT If timeout on service */
115 /* NU_POOL_DELETED If memory pool deleted */
116 /* during suspension */
117 /* */
118 /* HISTORY */
119 /* */
120 /* NAME DATE REMARKS */
121 /* */
122 /* T. Larsen 01-15-1999 Created initial revision */
123 /* R. Baum 06-06-2002 Fixed problem with DM_OVERHEAD */
124 /* allocation. Added Proview */
125 /* support. */
126 /* */
127 /*************************************************************************/
128 STATUS DMS_Allocate_Aligned_Memory(NU_MEMORY_POOL *pool_ptr,
129 VOID **return_pointer, UNSIGNED size,
130 UNSIGNED alignment, UNSIGNED suspend)
131 {
132 R1 DM_PCB *pool; /* Pool control block ptr */
133 R2 DM_SUSPEND *suspend_ptr; /* Pointer to suspend block */
134 DM_SUSPEND suspend_block; /* Allocate suspension block */
135 R4 DM_HEADER *memory_ptr; /* Pointer to memory */
136 R3 DM_HEADER *new_ptr; /* New split block pointer */
137 UNSIGNED free_size; /* Size of block found */
138 TC_TCB *task; /* Task pointer */
139 STATUS status; /* Completion status */
140 UNSIGNED address; /* Address of start of block */
141 UNSIGNED split_size; /* Bytes for front split */
142 UNSIGNED next_aligned; /* Next aligned block addr */
143 NU_SUPERV_USER_VARIABLES
144
145 /* Switch to supervisor mode */
146 NU_SUPERVISOR_MODE();
147
148 /* Move input pool pointer into internal pointer. */
149 pool = (DM_PCB *) pool_ptr;
150
151
152 #ifdef NU_ENABLE_STACK_CHECK
153
154 /* Call stack checking function to check for an overflow condition. */
155 TCT_Check_Stack();
156
157 #endif
158
159 #ifdef NU_ENABLE_HISTORY
160
161 /* Make an entry that corresponds to this function in the system history
162 log. */
163 HIC_Make_History_Entry(NU_ALLOCATE_ALIGNED_ID, (UNSIGNED) pool,
164 (UNSIGNED) return_pointer, (UNSIGNED) size);
165
166 #endif
167
168 /* Initialize the status as successful. */
169 status = NU_SUCCESS;
170
171 /* Adjust the request to a size evenly divisible by the number of bytes
172 in an UNSIGNED data element. Also, check to make sure it is of the
173 minimum size. */
174 if (size < pool -> dm_min_allocation)
175
176 /* Change size to the minimum allocation. */
177 size = pool -> dm_min_allocation;
178 else
179
180 /* Insure that size is a multiple of the UNSIGNED size. */
181 size =
182 ((size + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED);
183
184 /* Adjust the requested alignment to one evenly divisible by the number of
185 bytes in an UNSIGNED data element. */
186 alignment =
187 ((alignment + sizeof(UNSIGNED) - 1)/sizeof(UNSIGNED)) * sizeof(UNSIGNED);
188
189 /* Protect against simultaneous access to the memory pool. */
190 TCT_Protect(&(pool -> dm_protect));
191
192 /* Search the memory list for the first available block of memory that
193 satisfies the request. Note that blocks are merged during the
194 deallocation function. */
195 memory_ptr = pool -> dm_search_ptr;
196 do
197 {
198
199 /* Determine if the block is free and if it can satisfy the request. */
200 if (memory_ptr -> dm_memory_free)
201
202 /* Calculate the free block size. */
203 free_size = (((BYTE_PTR) (memory_ptr -> dm_next_memory)) -
204 ((BYTE_PTR) memory_ptr)) - DM_OVERHEAD;
205 else
206
207 /* There are no free bytes available. */
208 free_size = 0;
209
210 /* Free block may be large enough, now check alignment */
211 if (free_size >= size)
212 {
213 address = ((UNSIGNED)(memory_ptr)) + DM_OVERHEAD;
214
215 /* Is this free block, minus the overhead, already aligned? */
216 if (address % alignment != 0)
217 {
218 /* Not aligned, can the free block be split in front? */
219 next_aligned = address + (alignment - 1);
220 next_aligned /= alignment;
221 next_aligned *= alignment;
222 split_size = next_aligned - address;
223
224 /* Is space from start of block to aligned location large enough
225 to contain 2 DM_OVERHEAD plus pool -> dm_min_allocation? */
226 if (split_size < ((2 * DM_OVERHEAD) + pool -> dm_min_allocation))
227 {
228 /* No, so try to make space for overhead and dm_min_allocation */
229 next_aligned = address + (2 * DM_OVERHEAD) +
230 (pool -> dm_min_allocation) + (alignment - 1);
231 next_aligned /= alignment;
232 next_aligned *= alignment;
233 split_size = next_aligned - address;
234 }
235
236 /* Adjust free_size for result of front split */
237 if (free_size > split_size)
238
239 free_size -= split_size;
240
241 else
242
243 /* Can't adjust block beginning, so keep searching */
244 free_size = 0;
245 }
246 }
247
248 /* Determine if the search should continue. */
249 if (free_size < size)
250
251 /* Large enough block has not been found. Move the search
252 pointer to the next block. */
253 memory_ptr = memory_ptr -> dm_next_memory;
254 } while((free_size < size) && (memory_ptr != pool -> dm_search_ptr));
255
256 /* Determine if the memory is available. */
257 if (free_size >= size)
258 {
259
260 /* A block that satisfies the request has been found. */
261
262 /* Is a front split required? The front split will represent the chunk
263 of memory that goes from the last pointer to the aligned address. */
264 if(address % alignment != 0)
265 {
266 /* Not aligned, front split the block, leaving an allocated block. */
267 new_ptr = (DM_HEADER*)(((UNSIGNED)(memory_ptr)) + split_size);
268
269 /* Mark the new block as free. */
270 new_ptr -> dm_memory_free = NU_TRUE;
271
272 /* Put the pool pointer into the new block. */
273 new_ptr -> dm_memory_pool = pool;
274
275 /* Build the necessary pointers. */
276 new_ptr -> dm_previous_memory = memory_ptr;
277 new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory;
278 (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr;
279 memory_ptr -> dm_next_memory = new_ptr;
280
281 /* Decrement the available byte count by one DM_OVERHEAD. */
282 pool -> dm_available = pool -> dm_available - DM_OVERHEAD;
283
284 /* Point to new aligned free block. */
285 memory_ptr = new_ptr;
286 }
287
288 /* Determine if the remaining block needs to be tail split. */
289 if (free_size >= (size + DM_OVERHEAD + pool -> dm_min_allocation))
290 {
291
292 /* Yes, split the block. */
293 new_ptr = (DM_HEADER *) (((BYTE_PTR) memory_ptr) + size +
294 DM_OVERHEAD);
295
296 /* Mark the new block as free. */
297 new_ptr -> dm_memory_free = NU_TRUE;
298
299 /* Put the pool pointer into the new block. */
300 new_ptr -> dm_memory_pool = pool;
301
302 /* Build the necessary pointers. */
303 new_ptr -> dm_previous_memory = memory_ptr;
304 new_ptr -> dm_next_memory = memory_ptr -> dm_next_memory;
305 (new_ptr -> dm_next_memory) -> dm_previous_memory = new_ptr;
306 memory_ptr -> dm_next_memory = new_ptr;
307
308 /* Decrement the available byte count. */
309 pool -> dm_available = pool -> dm_available - size - DM_OVERHEAD;
310 }
311 else
312
313 /* Decrement the entire free size from the available bytes
314 count. */
315 pool -> dm_available = pool -> dm_available - free_size;
316
317 /* Mark the allocated block as not available. */
318 memory_ptr -> dm_memory_free = NU_FALSE;
319
320 /* Should the search pointer be moved? */
321 if (pool -> dm_search_ptr == memory_ptr)
322
323 /* Move the search pointer to the next free memory slot. */
324 pool -> dm_search_ptr = memory_ptr -> dm_next_memory;
325
326 /* Return a memory address to the caller. */
327 *return_pointer = (VOID *) (((BYTE_PTR) memory_ptr) + DM_OVERHEAD);
328 #ifdef INCLUDE_PROVIEW
329 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_OK);
330 #endif /*INCLUDE_PROVIEW*/
331 }
332 else
333 {
334
335 /* Enough dynamic memory is not available. Determine if suspension is
336 required. */
337 if (suspend)
338 {
339
340 /* Suspension is selected. */
341
342 /* Increment the number of tasks waiting. */
343 pool -> dm_tasks_waiting++;
344
345 #ifdef INCLUDE_PROVIEW
346 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_WAIT);
347 #endif /*INCLUDE_PROVIEW*/
348 /* Setup the suspend block and suspend the calling task. */
349 suspend_ptr = &suspend_block;
350 suspend_ptr -> dm_memory_pool = pool;
351 suspend_ptr -> dm_request_size = size;
352 suspend_ptr -> dm_suspend_link.cs_next = NU_NULL;
353 suspend_ptr -> dm_suspend_link.cs_previous = NU_NULL;
354 task = (TC_TCB *) TCT_Current_Thread();
355 suspend_ptr -> dm_suspended_task = task;
356
357 /* Determine if priority or FIFO suspension is associated with the
358 memory pool. */
359 if (pool -> dm_fifo_suspend)
360 {
361
362 /* FIFO suspension is required. Link the suspend block into
363 the list of suspended tasks on this memory pool. */
364 CSC_Place_On_List((CS_NODE **)
365 &(pool -> dm_suspension_list),
366 &(suspend_ptr -> dm_suspend_link));
367 }
368 else
369 {
370
371 /* Get the priority of the current thread so the suspend block
372 can be placed in the appropriate place. */
373 suspend_ptr -> dm_suspend_link.cs_priority =
374 TCC_Task_Priority(task);
375
376 CSC_Priority_Place_On_List((CS_NODE **)
377 &(pool -> dm_suspension_list),
378 &(suspend_ptr -> dm_suspend_link));
379 }
380
381 /* Protect against system access. */
382 TCT_System_Protect();
383
384 /* Save the list protection in preparation for suspension. */
385 TCT_Set_Suspend_Protect(&(pool -> dm_protect));
386
387 /* Release protection of dynamic memory pool. */
388 TCT_Unprotect_Specific(&(pool -> dm_protect));
389
390 /* Finally, suspend the calling task. Note that the suspension call
391 automatically clears the system protection. */
392 TCC_Suspend_Task((NU_TASK *) task, NU_MEMORY_SUSPEND,
393 DMC_Cleanup, suspend_ptr, suspend);
394
395 /* Pickup the return status. */
396 status = suspend_ptr -> dm_return_status;
397 *return_pointer = suspend_ptr -> dm_return_pointer;
398 }
399 else
400 {
401
402 /* No suspension requested. Simply return an error status. */
403 status = NU_NO_MEMORY;
404 *return_pointer = NU_NULL;
405 #ifdef INCLUDE_PROVIEW
406 _RTProf_DumpMemoryPool(RT_PROF_ALLOCATE_MEMORY,pool,RT_PROF_FAIL);
407 #endif /*INCLUDE_PROVIEW*/
408 }
409 }
410
411 /* Release protection of the memory pool. */
412 TCT_Unprotect();
413
414 /* Return to user mode */
415 NU_USER_MODE();
416
417 /* Return the completion status. */
418 return(status);
419 }
420
421
422
423
424
425