utcache.c revision 1.10
1/******************************************************************************
2 *
3 * Module Name: utcache - local cache allocation routines
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2017, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include "acpi.h"
45#include "accommon.h"
46
47#define _COMPONENT          ACPI_UTILITIES
48        ACPI_MODULE_NAME    ("utcache")
49
50
51#ifdef ACPI_USE_LOCAL_CACHE
52/*******************************************************************************
53 *
54 * FUNCTION:    AcpiOsCreateCache
55 *
56 * PARAMETERS:  CacheName       - Ascii name for the cache
57 *              ObjectSize      - Size of each cached object
58 *              MaxDepth        - Maximum depth of the cache (in objects)
59 *              ReturnCache     - Where the new cache object is returned
60 *
61 * RETURN:      Status
62 *
63 * DESCRIPTION: Create a cache object
64 *
65 ******************************************************************************/
66
67ACPI_STATUS
68AcpiOsCreateCache (
69    const char              *CacheName,
70    UINT16                  ObjectSize,
71    UINT16                  MaxDepth,
72    ACPI_MEMORY_LIST        **ReturnCache)
73{
74    ACPI_MEMORY_LIST        *Cache;
75
76
77    ACPI_FUNCTION_ENTRY ();
78
79
80    if (!CacheName || !ReturnCache || (ObjectSize < 16))
81    {
82        return (AE_BAD_PARAMETER);
83    }
84
85    /* Create the cache object */
86
87    Cache = AcpiOsAllocate (sizeof (ACPI_MEMORY_LIST));
88    if (!Cache)
89    {
90        return (AE_NO_MEMORY);
91    }
92
93    /* Populate the cache object and return it */
94    memset (Cache, 0, sizeof (ACPI_MEMORY_LIST));
95    Cache->ListName   = __UNCONST(CacheName);
96    Cache->ObjectSize = ObjectSize;
97    Cache->MaxDepth = MaxDepth;
98
99    *ReturnCache = Cache;
100    return (AE_OK);
101}
102
103
104/*******************************************************************************
105 *
106 * FUNCTION:    AcpiOsPurgeCache
107 *
108 * PARAMETERS:  Cache           - Handle to cache object
109 *
110 * RETURN:      Status
111 *
112 * DESCRIPTION: Free all objects within the requested cache.
113 *
114 ******************************************************************************/
115
116ACPI_STATUS
117AcpiOsPurgeCache (
118    ACPI_MEMORY_LIST        *Cache)
119{
120    void                    *Next;
121    ACPI_STATUS             Status;
122
123
124    ACPI_FUNCTION_ENTRY ();
125
126
127    if (!Cache)
128    {
129        return (AE_BAD_PARAMETER);
130    }
131
132    Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
133    if (ACPI_FAILURE (Status))
134    {
135        return (Status);
136    }
137
138    /* Walk the list of objects in this cache */
139
140    while (Cache->ListHead)
141    {
142        /* Delete and unlink one cached state object */
143
144        Next = ACPI_GET_DESCRIPTOR_PTR (Cache->ListHead);
145        ACPI_FREE (Cache->ListHead);
146
147        Cache->ListHead = Next;
148        Cache->CurrentDepth--;
149    }
150
151    (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
152    return (AE_OK);
153}
154
155
156/*******************************************************************************
157 *
158 * FUNCTION:    AcpiOsDeleteCache
159 *
160 * PARAMETERS:  Cache           - Handle to cache object
161 *
162 * RETURN:      Status
163 *
164 * DESCRIPTION: Free all objects within the requested cache and delete the
165 *              cache object.
166 *
167 ******************************************************************************/
168
169ACPI_STATUS
170AcpiOsDeleteCache (
171    ACPI_MEMORY_LIST        *Cache)
172{
173    ACPI_STATUS             Status;
174
175
176    ACPI_FUNCTION_ENTRY ();
177
178
179   /* Purge all objects in the cache */
180
181    Status = AcpiOsPurgeCache (Cache);
182    if (ACPI_FAILURE (Status))
183    {
184        return (Status);
185    }
186
187    /* Now we can delete the cache object */
188
189    AcpiOsFree (Cache);
190    return (AE_OK);
191}
192
193
194/*******************************************************************************
195 *
196 * FUNCTION:    AcpiOsReleaseObject
197 *
198 * PARAMETERS:  Cache       - Handle to cache object
199 *              Object      - The object to be released
200 *
201 * RETURN:      None
202 *
203 * DESCRIPTION: Release an object to the specified cache. If cache is full,
204 *              the object is deleted.
205 *
206 ******************************************************************************/
207
208ACPI_STATUS
209AcpiOsReleaseObject (
210    ACPI_MEMORY_LIST        *Cache,
211    void                    *Object)
212{
213    ACPI_STATUS             Status;
214
215
216    ACPI_FUNCTION_ENTRY ();
217
218
219    if (!Cache || !Object)
220    {
221        return (AE_BAD_PARAMETER);
222    }
223
224    /* If cache is full, just free this object */
225
226    if (Cache->CurrentDepth >= Cache->MaxDepth)
227    {
228        ACPI_FREE (Object);
229        ACPI_MEM_TRACKING (Cache->TotalFreed++);
230    }
231
232    /* Otherwise put this object back into the cache */
233
234    else
235    {
236        Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
237        if (ACPI_FAILURE (Status))
238        {
239            return (Status);
240        }
241
242        /* Mark the object as cached */
243
244        memset (Object, 0xCA, Cache->ObjectSize);
245        ACPI_SET_DESCRIPTOR_TYPE (Object, ACPI_DESC_TYPE_CACHED);
246
247        /* Put the object at the head of the cache list */
248
249        ACPI_SET_DESCRIPTOR_PTR (Object, Cache->ListHead);
250        Cache->ListHead = Object;
251        Cache->CurrentDepth++;
252
253        (void) AcpiUtReleaseMutex (ACPI_MTX_CACHES);
254    }
255
256    return (AE_OK);
257}
258
259
260/*******************************************************************************
261 *
262 * FUNCTION:    AcpiOsAcquireObject
263 *
264 * PARAMETERS:  Cache           - Handle to cache object
265 *
266 * RETURN:      the acquired object. NULL on error
267 *
268 * DESCRIPTION: Get an object from the specified cache. If cache is empty,
269 *              the object is allocated.
270 *
271 ******************************************************************************/
272
273void *
274AcpiOsAcquireObject (
275    ACPI_MEMORY_LIST        *Cache)
276{
277    ACPI_STATUS             Status;
278    void                    *Object;
279
280
281    ACPI_FUNCTION_TRACE (OsAcquireObject);
282
283
284    if (!Cache)
285    {
286        return_PTR (NULL);
287    }
288
289    Status = AcpiUtAcquireMutex (ACPI_MTX_CACHES);
290    if (ACPI_FAILURE (Status))
291    {
292        return_PTR (NULL);
293    }
294
295    ACPI_MEM_TRACKING (Cache->Requests++);
296
297    /* Check the cache first */
298
299    if (Cache->ListHead)
300    {
301        /* There is an object available, use it */
302
303        Object = Cache->ListHead;
304        Cache->ListHead = ACPI_GET_DESCRIPTOR_PTR (Object);
305
306        Cache->CurrentDepth--;
307
308        ACPI_MEM_TRACKING (Cache->Hits++);
309        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
310            "Object %p from %s cache\n", Object, Cache->ListName));
311
312        Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
313        if (ACPI_FAILURE (Status))
314        {
315            return_PTR (NULL);
316        }
317
318        /* Clear (zero) the previously used Object */
319
320        memset (Object, 0, Cache->ObjectSize);
321    }
322    else
323    {
324        /* The cache is empty, create a new object */
325
326        ACPI_MEM_TRACKING (Cache->TotalAllocated++);
327
328#ifdef ACPI_DBG_TRACK_ALLOCATIONS
329        if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied)
330        {
331            Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed;
332        }
333#endif
334
335        /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
336
337        Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
338        if (ACPI_FAILURE (Status))
339        {
340            return_PTR (NULL);
341        }
342
343        Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize);
344        if (!Object)
345        {
346            return_PTR (NULL);
347        }
348    }
349
350    return_PTR (Object);
351}
352#endif /* ACPI_USE_LOCAL_CACHE */
353