]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - ipc/ipcdev.git/blob - packages/ti/sdo/ipc/heaps/HeapMultiBufMP.c
Initial commit
[ipc/ipcdev.git] / packages / ti / sdo / ipc / heaps / HeapMultiBufMP.c
1 /*
2  * Copyright (c) 2012-2013, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*
33  *  ======== HeapMultiBufMP.c ========
34  */
37 #include <xdc/std.h>
38 #include <xdc/runtime/Error.h>
39 #include <xdc/runtime/Assert.h>
40 #include <xdc/runtime/Memory.h>
41 #include <xdc/runtime/IHeap.h>
43 #include <string.h> /* for memcpy */
44 #include <stdlib.h> /* for qsort */
46 #include <ti/sysbios/hal/Cache.h>
48 #include <ti/sdo/ipc/_Ipc.h>
49 #include <ti/sdo/utils/_NameServer.h>
50 #include <ti/sdo/utils/_MultiProc.h>
51 #include <ti/sdo/ipc/heaps/_HeapMultiBufMP.h>
52 #include <ti/sdo/ipc/_SharedRegion.h>
53 #include <ti/sdo/ipc/_GateMP.h>
55 #include "package/internal/HeapMultiBufMP.xdc.h"
57 #ifdef __ti__
58     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_Params_init);
59     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_alloc);
60     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_close);
61     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_create);
62     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_delete);
63     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_free);
64     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_getExtendedStats);
65     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_getStats);
66     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_open);
67     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_openByAddr);
68     #pragma FUNC_EXT_CALLED(HeapMultiBufMP_sharedMemReq);
69 #endif
71 /*
72  *  ======== HeapMultiBufMP_getSharedParams ========
73  */
74 static Void HeapMultiBufMP_getSharedParams(HeapMultiBufMP_Params *sparams,
75         const ti_sdo_ipc_heaps_HeapMultiBufMP_Params *params)
76 {
77     sparams->gate        = (GateMP_Handle)params->gate;
78     sparams->exact       = params->exact;
79     sparams->name        = params->name;
80     sparams->numBuckets  = params->numBuckets;
81     sparams->bucketEntries =
82         (HeapMultiBufMP_Bucket *)params->bucketEntries;
83     sparams->regionId    =  params->regionId;
84     sparams->sharedAddr  =  params->sharedAddr;
85 }
87 /*
88  *  ======== HeapMultiBufMP_getRTSCParams ========
89  */
90 static Void HeapMultiBufMP_getRTSCParams(
91         ti_sdo_ipc_heaps_HeapMultiBufMP_Params *params,
92         const HeapMultiBufMP_Params *sparams)
93 {
94     ti_sdo_ipc_heaps_HeapMultiBufMP_Params_init(params);
96     params->gate = (ti_sdo_ipc_GateMP_Handle)sparams->gate;
97     params->exact = sparams->exact;
98     params->name = sparams->name;
99     params->numBuckets = sparams->numBuckets;
100     params->bucketEntries = (ti_sdo_ipc_heaps_HeapMultiBufMP_Bucket *)
101         sparams->bucketEntries;
102     params->regionId = sparams->regionId;
103     params->sharedAddr = sparams->sharedAddr;
106 /*
107  *  ======== HeapMultiBufMP_sizeAlignCompare ========
108  *  Comparison function for qsort. Compares Buckets first by blockSize, then
109  *  by align, in ascending order.
110  */
111 static int HeapMultiBufMP_sizeAlignCompare(const void *a, const void *b)
113     int diff;
114     HeapMultiBufMP_Bucket *bucketA, *bucketB;
116     bucketA = (HeapMultiBufMP_Bucket *)a;
117     bucketB = (HeapMultiBufMP_Bucket *)b;
119     diff = bucketA->blockSize - bucketB->blockSize;
121     /* If the blockSizes match, sort them by ascending align */
122     if (diff == 0) {
123         diff = bucketA->align - bucketB->align;
124     }
126     return (diff);
129 /*
130  *************************************************************************
131  *                       Common Header Functions
132  *************************************************************************
133  */
135 /*
136  *  ======== HeapMultiBufMP_Params_init ========
137  */
138 Void HeapMultiBufMP_Params_init(HeapMultiBufMP_Params *sparams)
140     ti_sdo_ipc_heaps_HeapMultiBufMP_Params params;
142     ti_sdo_ipc_heaps_HeapMultiBufMP_Params_init(&params);
143     HeapMultiBufMP_getSharedParams(sparams, &params);
146 /*
147  *  ======== HeapMultiBufMP_alloc ========
148  */
149 Ptr HeapMultiBufMP_alloc(HeapMultiBufMP_Handle handle,
150         SizeT size, SizeT align)
152     Error_Block eb;
154     Error_init(&eb);
156     return (ti_sdo_ipc_heaps_HeapMultiBufMP_alloc(
157         (ti_sdo_ipc_heaps_HeapMultiBufMP_Object *)handle, size, align, &eb));
160 /*
161  *  ======== HeapMultiBufMP_close ========
162  */
163 Int HeapMultiBufMP_close(HeapMultiBufMP_Handle *handlePtr)
165     HeapMultiBufMP_delete(handlePtr);
167     return (HeapMultiBufMP_S_SUCCESS);
170 /*
171  *  ======== HeapMultiBufMP_create ========
172  */
173 HeapMultiBufMP_Handle HeapMultiBufMP_create(
174         const HeapMultiBufMP_Params *sparams)
176     ti_sdo_ipc_heaps_HeapMultiBufMP_Params params;
177     ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj;
178     Error_Block eb;
180     Error_init(&eb);
182     if (sparams != NULL) {
183         HeapMultiBufMP_getRTSCParams(&params, (Ptr)sparams);
184         /* call the module create */
185         obj = ti_sdo_ipc_heaps_HeapMultiBufMP_create(&params, &eb);
186     }
187     else {
188         obj = ti_sdo_ipc_heaps_HeapMultiBufMP_create(NULL, &eb);
189     }
191     return ((HeapMultiBufMP_Handle)obj);
194 /*
195  *  ======== HeapMultiBufMP_delete ========
196  */
197 Int HeapMultiBufMP_delete(HeapMultiBufMP_Handle *handlePtr)
199     ti_sdo_ipc_heaps_HeapMultiBufMP_delete(
200         (ti_sdo_ipc_heaps_HeapMultiBufMP_Handle *)handlePtr);
202     return (HeapMultiBufMP_S_SUCCESS);
205 /*
206  *  ======== HeapMultiBufMP_free ========
207  */
208 Void HeapMultiBufMP_free(HeapMultiBufMP_Handle handle, Ptr addr, SizeT size)
210     ti_sdo_ipc_heaps_HeapMultiBufMP_free(
211         (ti_sdo_ipc_heaps_HeapMultiBufMP_Object *)handle, addr, size);
214 /*
215  *  ======== HeapMultiBufMP_getExtendedStats ========
216  */
217 Void HeapMultiBufMP_getExtendedStats(HeapMultiBufMP_Handle handle,
218         HeapMultiBufMP_ExtendedStats *stats)
220     IArg key;
221     UInt i;
222     ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj =
223         (ti_sdo_ipc_heaps_HeapMultiBufMP_Object *)handle;
225     key = GateMP_enter((GateMP_Handle)obj->gate);
227     stats->numBuckets = obj->numBuckets;
229     /* Make sure the attrs are not in cache */
230     if (obj->cacheEnabled) {
231         Cache_inv(obj->attrs, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs),
232             Cache_Type_ALL, TRUE);
233     }
235     /*
236      *  The maximum number of allocations for this HeapMultiBufMP (for any given
237      *  instance of time during its liftime) is computed as follows:
238      *
239      *  maxAllocatedBlocks = obj->numBlocks - obj->minFreeBlocks
240      *
241      *  Note that maxAllocatedBlocks is *not* the maximum allocation count, but
242      *  rather the maximum allocations seen at any snapshot of time in the
243      *  HeapMultiBufMP instance.
244      */
246     /* if nothing has been alloc'ed yet, return 0 */
247     for (i = 0; i < stats->numBuckets; i++) {
248         /* Get the blockSize and align for the buffer */
249         stats->numBlocks[i] = obj->attrs->buckets[i].numBlocks;
250         stats->blockSize[i] = obj->attrs->buckets[i].blockSize;
251         stats->align[i]     = obj->attrs->buckets[i].align;
253         /* if nothing has been alloc'ed yet, return 0 */
254         if ((Int)(obj->attrs->buckets[i].minFreeBlocks) == -1) {
255             stats->maxAllocatedBlocks[i] = 0;
256         }
257         else {
258             stats->maxAllocatedBlocks[i] = obj->attrs->buckets[i].numBlocks
259                                          - obj->attrs->buckets[i].minFreeBlocks;
260         }
261         /*
262          * current number of alloc'ed blocks is computed using curr # free
263          * blocks
264          */
265         stats->numAllocatedBlocks[i] = obj->attrs->buckets[i].numBlocks
266                                      - obj->attrs->buckets[i].numFreeBlocks;
267     }
269     GateMP_leave((GateMP_Handle)obj->gate, key);
271 /*
272  *  ======== HeapMultiBufMP_getStats ========
273  */
274 Void HeapMultiBufMP_getStats(HeapMultiBufMP_Handle handle, Ptr stats)
276     ti_sdo_ipc_heaps_HeapMultiBufMP_getStats(
277         (ti_sdo_ipc_heaps_HeapMultiBufMP_Handle)handle,
278         (Memory_Stats *)stats);
280 /*
281  *  ======== HeapMultiBufMP_open ========
282  */
283 Int HeapMultiBufMP_open(String name,
284         HeapMultiBufMP_Handle *handlePtr)
286     SharedRegion_SRPtr sharedShmBase;
287     Int status;
288     Ptr sharedAddr;
289     Error_Block eb;
291     Error_init(&eb);
293     /* Assert that a pointer has been supplied */
294     Assert_isTrue(handlePtr != NULL, ti_sdo_ipc_Ipc_A_nullArgument);
296     /* Assert that a name has been supplied */
297     Assert_isTrue(name != NULL, ti_sdo_ipc_Ipc_A_invParam);
299     /* Open by name */
300     status = NameServer_getUInt32(
301             (NameServer_Handle)HeapMultiBufMP_module->nameServer, name,
302             &sharedShmBase, ti_sdo_utils_MultiProc_procIdList);
304     if (status < 0) {
305         /* Name not found. */
306         *handlePtr = NULL;
307         return (HeapMultiBufMP_E_NOTFOUND);
308     }
310     sharedAddr = SharedRegion_getPtr(sharedShmBase);
312     status = HeapMultiBufMP_openByAddr(sharedAddr, handlePtr);
314     return (status);
317 /*
318  *  ======== HeapMultiBufMP_openByAddr ========
319  */
320 Int HeapMultiBufMP_openByAddr(Ptr sharedAddr,
321         HeapMultiBufMP_Handle *handlePtr)
323     ti_sdo_ipc_heaps_HeapMultiBufMP_Params params;
324     ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs *attrs;
325     Int status;
326     Error_Block eb;
328     Error_init(&eb);
330     ti_sdo_ipc_heaps_HeapMultiBufMP_Params_init(&params);
332     /* Tell Instance_init() that we're opening */
333     params.openFlag = TRUE;
335     params.sharedAddr = sharedAddr;
336     attrs = (ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs *)sharedAddr;
338     if (SharedRegion_isCacheEnabled(SharedRegion_getId(sharedAddr))) {
339         Cache_inv(attrs, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs),
340             Cache_Type_ALL, TRUE);
341     }
343     if (attrs->status != ti_sdo_ipc_heaps_HeapMultiBufMP_CREATED) {
344         *handlePtr = NULL;
345         status = HeapMultiBufMP_E_NOTFOUND;
346     }
347     else {
348         *handlePtr = (HeapMultiBufMP_Handle)
349             ti_sdo_ipc_heaps_HeapMultiBufMP_create(&params, &eb);
350         if (*handlePtr == NULL) {
351             status = HeapMultiBufMP_E_FAIL;
352         }
353         else {
354             status = HeapMultiBufMP_S_SUCCESS;
355         }
356     }
358     return (status);
361 /*
362  *  ======== HeapMultiBufMP_sharedMemReq ========
363  */
364 SizeT HeapMultiBufMP_sharedMemReq(const HeapMultiBufMP_Params *sparams)
366     SizeT   memReq, minAlign;
367     UInt    i;
368     ti_sdo_ipc_heaps_HeapMultiBufMP_Bucket
369         bucketEntries[HeapMultiBufMP_MAXBUCKETS];
370     UInt    numBuckets;
371     UInt16  regionId;
372     ti_sdo_ipc_heaps_HeapMultiBufMP_Params params;
374     /* Assert that the required params have been set */
375     Assert_isTrue(sparams->bucketEntries != NULL, ti_sdo_ipc_Ipc_A_invParam);
376     Assert_isTrue(sparams->numBuckets != 0, ti_sdo_ipc_Ipc_A_invParam);
378     if (sparams->sharedAddr == NULL) {
379         regionId = sparams->regionId;
380     }
381     else {
382         regionId = SharedRegion_getId(sparams->sharedAddr);
383     }
385     Assert_isTrue(regionId != SharedRegion_INVALIDREGIONID,
386             ti_sdo_ipc_Ipc_A_internal);
388     minAlign = Memory_getMaxDefaultTypeAlign();
389     if (SharedRegion_getCacheLineSize(regionId) > minAlign) {
390         minAlign = SharedRegion_getCacheLineSize(regionId);
391     }
393     memReq = _Ipc_roundup(sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs),
394         minAlign);
396     HeapMultiBufMP_getRTSCParams(&params, (Ptr)sparams);
398     /* Optimize the bucketEntries array */
399     numBuckets = HeapMultiBufMP_processBuckets(bucketEntries, &params,
400         regionId);
402     for (i = 0; i < numBuckets; i++) {
403         memReq = _Ipc_roundup(memReq, bucketEntries[i].align);
405         memReq += bucketEntries[i].blockSize * bucketEntries[i].numBlocks;
406     }
408     return (memReq);
411 /*
412  *************************************************************************
413  *                      Instance functions
414  *************************************************************************
415  */
417 /*
418  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_Instance_init ========
419  */
420 Int ti_sdo_ipc_heaps_HeapMultiBufMP_Instance_init(
421         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj,
422         const ti_sdo_ipc_heaps_HeapMultiBufMP_Params *params, Error_Block *eb)
424     SharedRegion_SRPtr sharedShmBase;
425     Ptr localAddr;
426     ti_sdo_ipc_heaps_HeapMultiBufMP_Bucket
427         optBucketEntries[HeapMultiBufMP_MAXBUCKETS];
428     Int status;
430     /* Ensure that bucketEntries has been supplied */
431     Assert_isTrue(params->openFlag ||
432                   params->bucketEntries != NULL, ti_sdo_ipc_Ipc_A_invParam);
435     /* Check numBuckets */
436     Assert_isTrue(params->openFlag ||
437                   params->numBuckets <= HeapMultiBufMP_MAXBUCKETS,
438                   ti_sdo_ipc_Ipc_A_invParam);
440     obj->nsKey          = NULL;
441     obj->allocSize      = 0;
443     if (params->openFlag) {
444         /* Opening the heap */
445         obj->attrs          = (ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs *)
446             params->sharedAddr;
447         obj->objType        = ti_sdo_ipc_Ipc_ObjType_OPENDYNAMIC;
448         obj->bucketEntries  = NULL; /* Never used in open */
450         /* No need to Cache_inv attrs- already done in openByAddr() */
451         obj->numBuckets     = obj->attrs->numBuckets;
452         obj->exact          = obj->attrs->exact == 1;
453         obj->buf            = SharedRegion_getPtr(
454                               obj->attrs->buckets[0].baseAddr);
455         obj->regionId       = SharedRegion_getId(obj->buf);
456         obj->cacheEnabled   = SharedRegion_isCacheEnabled(obj->regionId);
458         localAddr = SharedRegion_getPtr(obj->attrs->gateMPAddr);
460         status = GateMP_openByAddr(localAddr, (GateMP_Handle *)&(obj->gate));
461         if (status != GateMP_S_SUCCESS) {
462             Error_raise(eb, ti_sdo_ipc_Ipc_E_internal, 0, 0);
463             return (1);
464         }
466         /* Done opening */
467         return (0);
468     }
470     /* Creating the heap */
471     if (params->gate != NULL) {
472         obj->gate       = params->gate;
473     }
474     else {
475         /* If no gate specified, get the default system gate */
476         obj->gate       = (ti_sdo_ipc_GateMP_Handle)GateMP_getDefaultRemote();
477     }
479     if (params->sharedAddr == NULL) {
480         /* Creating using a shared region ID */
481         obj->objType    = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION;
482         obj->attrs      = NULL; /* Will be alloc'ed in postInit */
483         obj->regionId   = params->regionId;
484     }
485     else {
486         /* Creating using sharedAddr */
487         obj->regionId   = SharedRegion_getId(params->sharedAddr);
489         /* Assert that the buffer is in a valid shared region */
490         Assert_isTrue(obj->regionId != SharedRegion_INVALIDREGIONID,
491                       ti_sdo_ipc_Ipc_A_addrNotInSharedRegion);
493         /* Assert that sharedAddr is cached aligned if region cache aligned */
494         Assert_isTrue(((UInt32)params->sharedAddr %
495                       SharedRegion_getCacheLineSize(obj->regionId) == 0),
496                       ti_sdo_ipc_Ipc_A_addrNotCacheAligned);
498         obj->objType    = ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC;
500         /* obj->buf will get alignment-adjusted in postInit */
501         obj->buf        = (Ptr)((UInt32)params->sharedAddr +
502                                 sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs));
503         obj->attrs      = (ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs *)
504             params->sharedAddr;
505     }
507     obj->cacheEnabled = SharedRegion_isCacheEnabled(obj->regionId);
508     obj->exact        = params->exact;
509     /* Adjust & sort the copied bucket entries by blockSize & align */
510     obj->numBuckets = HeapMultiBufMP_processBuckets(optBucketEntries,
511         (ti_sdo_ipc_heaps_HeapMultiBufMP_Params *)params, obj->regionId);
512     obj->bucketEntries = optBucketEntries;
514     HeapMultiBufMP_postInit(obj, eb);
515     if (Error_check(eb)) {
516         return (1);
517     }
519     /* Set to NULL since optBucketEntries is on the stack */
520     obj->bucketEntries = NULL;
522     /* Add entry to NameServer */
523     if (params->name != NULL) {
524         /* We will store a shared pointer in the NameServer */
525         sharedShmBase = SharedRegion_getSRPtr(obj->attrs,
526                                               obj->regionId);
527         obj->nsKey = NameServer_addUInt32(
528                 (NameServer_Handle)HeapMultiBufMP_module->nameServer,
529                 params->name, (UInt32)sharedShmBase);
531         if (obj->nsKey == NULL) {
532             /* NameServer_addUInt32 failed */
533             Error_raise(eb, ti_sdo_ipc_Ipc_E_nameFailed, params->name, 0);
534             return (2);
535         }
536     }
538     return (0);
541 /*
542  *  ======== HeapMultiBufMP_Instance_finalize ========
543  */
544 Void ti_sdo_ipc_heaps_HeapMultiBufMP_Instance_finalize(
545         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, Int status)
547     /* First remove the NameServer entry */
548     if (obj->objType & (ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC |
549         ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION)) {
550         if (obj->nsKey != NULL) {
551             NameServer_removeEntry((NameServer_Handle)
552                     HeapMultiBufMP_module->nameServer, obj->nsKey);
553         }
555         if (obj->attrs != NULL) {
556             obj->attrs->status = 0;
558             if (obj->cacheEnabled) {
559                 Cache_wbInv(obj->attrs,
560                             sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs),
561                             Cache_Type_ALL, TRUE);
562             }
563         }
565         /*
566          *  Free the shared memory back to the region heap. If NULL, then the
567          *  Memory_alloc failed.
568          */
569         if (obj->objType == ti_sdo_ipc_Ipc_ObjType_CREATEDYNAMIC_REGION &&
570             obj->attrs != NULL) {
571             Memory_free(SharedRegion_getHeap(obj->regionId), obj->attrs,
572                         obj->allocSize);
573         }
574     }
575     else {
576         /* Heap is being closed */
577         /* Close the gate. If NULL, then GateMP_openByAddr failed. */
578         if (obj->gate != NULL) {
579             GateMP_close((GateMP_Handle *)&(obj->gate));
580         }
581     }
584 /*
585  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_alloc ========
586  *  Allocate a block.
587  */
588 Ptr ti_sdo_ipc_heaps_HeapMultiBufMP_alloc(
589         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, SizeT size, SizeT align,
590         Error_Block *eb)
592     ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *block;
593     UInt index;
594     IArg key;
595     Bool alignMatches, sizeMatches;
597     /* Read-only field, so no cache/gate concerns */
598     for (index = 0; index < obj->numBuckets; index++) {
599         sizeMatches = (size <= obj->attrs->buckets[index].blockSize);
600         alignMatches = (align <= obj->attrs->buckets[index].align);
602         if (sizeMatches && alignMatches) {
603             if (obj->exact && size != obj->attrs->buckets[index].blockSize) {
604                 Error_raise(eb, ti_sdo_ipc_heaps_HeapMultiBufMP_E_exactFail,
605                             size, obj->attrs->buckets[index].blockSize);
606                 return (NULL);
607             }
608             break;
609         }
610     }
612     if (index == obj->attrs->numBuckets) {
613         /* Couldn't find a buffer with suitable size/align */
614         Error_raise(eb, ti_sdo_ipc_heaps_HeapMultiBufMP_E_size,
615                 size, align);
617         return (NULL);
618     }
620     /* At this point, we know the bucket number. Enter the gate */
621     key = GateMP_enter((GateMP_Handle)obj->gate);
623     if (obj->cacheEnabled) {
624         Cache_inv(&(obj->attrs->buckets[index]),
625                   sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_BucketAttrs),
626                   Cache_Type_ALL, TRUE);
627     }
629     /* Get the first block */
630     block = HeapMultiBufMP_getHead(obj, index);
632     /* Make sure that a valid pointer was returned. */
633     if (block == NULL) {
634         /* No more blocks left in the buffer */
635         GateMP_leave((GateMP_Handle)obj->gate, key);
636         Error_raise(eb, ti_sdo_ipc_heaps_HeapMultiBufMP_E_noBlocksLeft,
637                     obj->attrs->buckets[index].blockSize,
638                     obj->attrs->buckets[index].align);
640         return (NULL);
641     }
643     obj->attrs->buckets[index].numFreeBlocks--;
645     /*
646      *  Keep track of the [min] number of free for this HeapMultiBufMP, if user
647      *  has set the config variable trackMaxAllocs to true.
648      *
649      *  The min number of free blocks, 'minFreeBlocks', will be used to compute
650      *  the "all time" maximum number of allocated blocks in getExtendedStats()
651      */
652     if (ti_sdo_ipc_heaps_HeapMultiBufMP_trackMaxAllocs) {
653         if (obj->attrs->buckets[index].numFreeBlocks <
654                 obj->attrs->buckets[index].minFreeBlocks) {
655             /* save the new minimum */
656             obj->attrs->buckets[index].minFreeBlocks =
657             obj->attrs->buckets[index].numFreeBlocks;
658         }
659     }
661     /* Results of getHead and trackMaxAllocs written out to memory */
662     if (obj->cacheEnabled) {
663         Cache_wbInv(&(obj->attrs->buckets[index]),
664             sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_BucketAttrs), Cache_Type_ALL,
665             TRUE);
666     }
668     /* Leave the gate */
669     GateMP_leave((GateMP_Handle)obj->gate, key);
671     return (block);
674 /*
675  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_free ========
676  *  Frees the block to this HeapMultiBufMP.
677  */
678 Void ti_sdo_ipc_heaps_HeapMultiBufMP_free(
679         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, Ptr block, SizeT size)
681     Int  index;
682     IArg key;
683     SharedRegion_SRPtr blockSRPtr;
685     /* Check for invalid arguments */
686     Assert_isTrue(size != 0, ti_sdo_ipc_Ipc_A_nullArgument);
688     /*
689      *  invaliate the block here so that stale data isn't evicted from cache
690      *  at some later point
691      */
692     if (obj->cacheEnabled) {
693         Cache_inv(block, size, Cache_Type_ALL, FALSE);
694     }
696     /* First search by block */
697     blockSRPtr = SharedRegion_getSRPtr(block, obj->regionId);
699     Assert_isTrue(blockSRPtr >= obj->attrs->buckets[0].baseAddr &&
700                   blockSRPtr <
701                   (obj->attrs->buckets[obj->attrs->numBuckets - 1].baseAddr +
702                    obj->attrs->buckets[obj->attrs->numBuckets - 1].numBlocks *
703                    obj->attrs->buckets[obj->attrs->numBuckets - 1].blockSize),
704                    ti_sdo_ipc_heaps_HeapMultiBufMP_A_addrNotFound);
706     for (index = obj->numBuckets - 1; index >= 0; index--) {
707         /* We can compare SRPtrs because they are both in the same region */
708         if (obj->attrs->buckets[index].baseAddr <= blockSRPtr) {
709             break;
710         }
711     }
713     /* Assert if the size does not match the found bucket */
714     Assert_isTrue((size <= obj->attrs->buckets[index].blockSize) &&
715                   (obj->attrs->exact == 0) ||
716                   (size == obj->attrs->buckets[index].blockSize) &&
717                   (obj->attrs->exact == 1),
718                     ti_sdo_ipc_heaps_HeapMultiBufMP_A_sizeNotFound);
720     /* Enter the gate */
721     key = GateMP_enter((GateMP_Handle)obj->gate);
723     if (obj->cacheEnabled) {
724         Cache_inv(block, obj->attrs->buckets[index].blockSize, Cache_Type_ALL,
725                   FALSE);
726         Cache_inv(&(obj->attrs->buckets[index]),
727                   sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_BucketAttrs),
728                   Cache_Type_ALL, TRUE);
729     }
731     HeapMultiBufMP_putTail(obj, index, block);
733     /*
734      *  Only need to write back the HeapMultiBufMP_Elem (top) part of the the
735      *  block being freed.  The rest of the block must also be invalidated
736      *  to ensure that stale data isn't evicted from cache at some later point
737      */
738     if (obj->cacheEnabled) {
739         Cache_wb(block, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Elem),
740                  Cache_Type_ALL, FALSE);
741     }
743     obj->attrs->buckets[index].numFreeBlocks++;
744     if (obj->cacheEnabled) {
745         Cache_wbInv(&(obj->attrs->buckets[index]),
746                  sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_BucketAttrs),
747                  Cache_Type_ALL, TRUE);
748     }
750     /* Leave the gate */
751     GateMP_leave((GateMP_Handle)obj->gate, key);
754 /*
755  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_getHead ========
756  */
757 ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *ti_sdo_ipc_heaps_HeapMultiBufMP_getHead(
758         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, Int index)
760     ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *block;
761     SharedRegion_SRPtr sharedBlock;
763     /* obj->attrs->buckets[index] should have already been invalidated */
764     if (obj->attrs->buckets[index].head !=
765             ti_sdo_ipc_SharedRegion_INVALIDSRPTR) {
766         sharedBlock = obj->attrs->buckets[index].head;
767         block = SharedRegion_getPtr(sharedBlock);
769         if (obj->cacheEnabled) {
770             /*
771              *  Only need to invalidate the elem, not the entire block.
772              */
773             Cache_inv(block, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Elem),
774                       Cache_Type_ALL, FALSE);
775         }
776         obj->attrs->buckets[index].head = block->next;
777         if (obj->attrs->buckets[index].head ==
778                 ti_sdo_ipc_SharedRegion_INVALIDSRPTR) {
779             /* We've removed the last block from the bucket */
780             obj->attrs->buckets[index].tail =
781                 ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
782         }
784         /*
785          *  No need to write back here since obj->attrs->buckets[index]
786          *  written back in HeapMultiBufMP_alloc
787          */
788     }
789     else {
790         block = NULL;
791     }
793     return (block);
796 /*
797  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_getStats ========
798  */
799 Void ti_sdo_ipc_heaps_HeapMultiBufMP_getStats(
800         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, Memory_Stats *stats)
802     IArg key;
803     SizeT totalSize = 0;
804     SizeT totalFreeSize = 0;
805     SizeT largestFreeSize = 0;
806     UInt i;
808     if (obj->cacheEnabled) {
809         Cache_inv(obj->attrs, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs),
810             Cache_Type_ALL, TRUE);
811     }
813     /*
814      * Protect this section so that numFreeBlocks doesn't change between
815      * totalFreeSize and largestFreeSize
816      */
817     key = GateMP_enter((GateMP_Handle)obj->gate);
819     for (i = 0; i < obj->attrs->numBuckets; i++) {
820         /* Check largest free block. */
821         if (obj->attrs->buckets[i].blockSize > largestFreeSize
822             && obj->attrs->buckets[i].numFreeBlocks > 0) {
823             largestFreeSize = obj->attrs->buckets[i].blockSize;
824         }
825         totalSize += obj->attrs->buckets[i].blockSize *
826                      obj->attrs->buckets[i].numBlocks;
827         totalFreeSize += obj->attrs->buckets[i].blockSize *
828                          obj->attrs->buckets[i].numFreeBlocks;
829     }
831     stats->totalSize = totalSize;
832     stats->totalFreeSize = totalFreeSize;
833     stats->largestFreeSize = largestFreeSize;
835     GateMP_leave((GateMP_Handle)obj->gate, key);
838 /*
839  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_isBlocking ========
840  */
841 Bool ti_sdo_ipc_heaps_HeapMultiBufMP_isBlocking(
842         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj)
844     Bool flag = FALSE;
846     // TODO figure out how to determine whether the gate is blocking...
847     return (flag);
850 /*
851  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_putTail ========
852  */
853 Void ti_sdo_ipc_heaps_HeapMultiBufMP_putTail(
854         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, Int index,
855         ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *block)
857     SharedRegion_SRPtr sharedBlock;
858     ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *temp;
860     sharedBlock = SharedRegion_getSRPtr(block, obj->regionId);
862     /* obj->attrs->buckets[index] should have already been invalidated */
863     if (obj->attrs->buckets[index].tail == ti_sdo_ipc_SharedRegion_INVALIDSRPTR) {
864         obj->attrs->buckets[index].head = sharedBlock;
865     }
866     else {
867         temp = (ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *)
868                 SharedRegion_getPtr(obj->attrs->buckets[index].tail);
869         temp->next = sharedBlock;
871         /*
872          *  No need to wait here because cache operation after putTail() will
873          *  wait
874          */
875         Cache_wbInv(temp, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Elem),
876                  Cache_Type_ALL, FALSE);
877     }
878     obj->attrs->buckets[index].tail = sharedBlock;
879     block->next = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
881     /*
882      *  No need to write back here since obj->attrs->buckets[index]
883      *  and 'block' written back in HeapMultiBufMP_alloc
884      */
887 /*
888  *************************************************************************
889  *                       Internal functions
890  *************************************************************************
891  */
893 /*
894  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_postInit ========
895  *  Slice and dice the buffer up into the correct size blocks and
896  *  add to the freelist.
897  */
898 Void ti_sdo_ipc_heaps_HeapMultiBufMP_postInit(
899         ti_sdo_ipc_heaps_HeapMultiBufMP_Object *obj, Error_Block *eb)
901     UInt i;
902     UInt j;
903     Char *buf;
904     SizeT minAlign;
905     HeapMultiBufMP_Params sparams;
906     IHeap_Handle regionHeap;
908     if (obj->attrs == NULL) {
909         /* Need to allocate from the heap */
910         HeapMultiBufMP_Params_init(&sparams);
911         sparams.regionId      = obj->regionId;
912         sparams.bucketEntries = (HeapMultiBufMP_Bucket *)obj->bucketEntries;
913         sparams.numBuckets    = obj->numBuckets;
914         obj->allocSize =  HeapMultiBufMP_sharedMemReq(&sparams);
916         minAlign = Memory_getMaxDefaultTypeAlign();
917         if (minAlign < SharedRegion_getCacheLineSize(obj->regionId)) {
918             minAlign = SharedRegion_getCacheLineSize(obj->regionId);
919         }
921         regionHeap = SharedRegion_getHeap(obj->regionId);
922         Assert_isTrue(regionHeap != NULL, ti_sdo_ipc_SharedRegion_A_noHeap);
923         obj->attrs = Memory_alloc(regionHeap, obj->allocSize, minAlign, eb);
924         if (obj->attrs == NULL) {
925             return;
926         }
928         obj->buf = (Ptr)((UInt32)obj->attrs +
929             sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs));
930     }
932     obj->attrs->numBuckets  = obj->numBuckets;
933     obj->attrs->exact       = obj->exact ? 1 : 0;
934     obj->attrs->gateMPAddr  = ti_sdo_ipc_GateMP_getSharedAddr(obj->gate);
936     for (i = 0; i < obj->numBuckets; i++) {
937         obj->attrs->buckets[i].head = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
938         obj->attrs->buckets[i].tail = ti_sdo_ipc_SharedRegion_INVALIDSRPTR;
939         obj->attrs->buckets[i].minFreeBlocks = (UInt)-1;
940         obj->attrs->buckets[i].blockSize     = obj->bucketEntries[i].blockSize;
941         obj->attrs->buckets[i].numBlocks     = obj->bucketEntries[i].numBlocks;
942         obj->attrs->buckets[i].numFreeBlocks = obj->bucketEntries[i].numBlocks;
943         obj->attrs->buckets[i].align         = obj->bucketEntries[i].align;
944     }
946     /* obj->buf should point to base of first buffer */
947     obj->buf = buf = (Ptr)_Ipc_roundup(obj->buf, obj->attrs->buckets[0].align);
948     for (i = 0; i < obj->numBuckets; i++) {
950         /* Make sure buffer is buffer-aligned (not just min-Align'ed) */
951         buf = (Ptr)_Ipc_roundup(buf, obj->attrs->buckets[i].align);
953         /* Put a shared pointer to the buf in attrs */
954         obj->attrs->buckets[i].baseAddr =
955                 SharedRegion_getSRPtr(buf, obj->regionId);
957         /*
958          * Split the buffer into blocks that are length "blockSize" and
959          * add into the freeList Queue.
960          */
961         for (j = 0; j < obj->attrs->buckets[i].numBlocks; j++) {
962             /* Put the free block on the end of the linked list */
963             HeapMultiBufMP_putTail(obj, i,
964                 (ti_sdo_ipc_heaps_HeapMultiBufMP_Elem *)buf);
966             buf += obj->attrs->buckets[i].blockSize;
967         }
968     }
970     /* At the end of the loop, buf points to the end of shared memory */
971     if (obj->cacheEnabled) {
972         /*
973          *  Write back the entire buffer. Don't cache-wait since the
974          *  Cache_wbInv below will.
975          */
976         Cache_wbInv(obj->buf, buf - obj->buf, Cache_Type_ALL, FALSE);
977     }
979     /* Last thing, set the status */
980     obj->attrs->status = ti_sdo_ipc_heaps_HeapMultiBufMP_CREATED;
981     if (obj->cacheEnabled) {
982         Cache_wbInv(obj->attrs, sizeof(ti_sdo_ipc_heaps_HeapMultiBufMP_Attrs),
983             Cache_Type_ALL, TRUE);
984     }
987 /*
988  *  ======== ti_sdo_ipc_heaps_HeapMultiBufMP_processBuckets ========
989  *  1) Adjust the blockSize and alignments for each buffer
990  *      - Alignment adjusted for cacheLineSize, cacheAlign
991  *      - blockSize adjusted for alignment
992  *  2) Sort buckets by blockSize and then by alignment
993  *  3) Merge buckets with same blockSize and same alignment
994  */
995 UInt ti_sdo_ipc_heaps_HeapMultiBufMP_processBuckets(
996         ti_sdo_ipc_heaps_HeapMultiBufMP_Bucket *optBucketEntries,
997         ti_sdo_ipc_heaps_HeapMultiBufMP_Params *params,
998         UInt16 regionId)
1000     UInt i, j;
1001     Int optNumBuckets;
1003     /* Copy the supplied buckets to a modifiable area */
1004     memcpy(optBucketEntries,
1005            params->bucketEntries,
1006            sizeof(HeapMultiBufMP_Bucket) * params->numBuckets);
1008     /* Combine if blockSizes (and alignments) are equal and shrink the array */
1009     for (i = 0; i < params->numBuckets; i++) {
1010         /* Ensure that align is a power of two */
1011         Assert_isTrue((optBucketEntries[i].align &
1012                       (optBucketEntries[i].align - 1)) == 0,
1013                       ti_sdo_ipc_heaps_HeapMultiBufMP_A_invalidAlign);
1015         /* First fix the alignment */
1016         if (optBucketEntries[i].align <
1017             SharedRegion_getCacheLineSize(regionId)) {
1018             optBucketEntries[i].align = SharedRegion_getCacheLineSize(regionId);
1019         }
1020         else if (optBucketEntries[i].align <
1021                  Memory_getMaxDefaultTypeAlign()) {
1022             /* Cache is disabled, use the default alignment */
1023             optBucketEntries[i].align = Memory_getMaxDefaultTypeAlign();
1024         }
1026         /* Fix the blockSize if blockSize isn't a multiple of alignment */
1027         optBucketEntries[i].blockSize =
1028             (optBucketEntries[i].blockSize + (optBucketEntries[i].align - 1))
1029              & ~(optBucketEntries[i].align - 1);
1030     }
1032     /* Sort optBucketEntries by blockSize and then alignment */
1033     qsort(optBucketEntries, params->numBuckets, sizeof(HeapMultiBufMP_Bucket),
1034           HeapMultiBufMP_sizeAlignCompare);
1036     optNumBuckets = 0;
1038     /* Combine if blockSizes (and alignments) are equal and shrink the array */
1039     for (i = 0; i < params->numBuckets; i++) {
1040         if (optBucketEntries[i].numBlocks != 0) {
1041             memcpy(&(optBucketEntries[optNumBuckets]), &(optBucketEntries[i]),
1042                    sizeof(HeapMultiBufMP_Bucket));
1043             for (j = i + 1 ; j < params->numBuckets; j++) {
1044                 if (optBucketEntries[optNumBuckets].blockSize ==
1045                         optBucketEntries[j].blockSize &&
1046                     optBucketEntries[optNumBuckets].align ==
1047                         optBucketEntries[j].align) {
1048                     /* Combine the buckets */
1049                     optBucketEntries[optNumBuckets].numBlocks +=
1050                                   optBucketEntries[j].numBlocks;
1051                     optBucketEntries[j].numBlocks = 0;
1052                 }
1053             }
1054             optNumBuckets++ ;
1055         }
1056     }
1058     return (optNumBuckets);