xref: /netbsd-src/sys/external/bsd/acpica/dist/utilities/utcache.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /******************************************************************************
2  *
3  * Module Name: utcache - local cache allocation routines
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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 
67 ACPI_STATUS
68 AcpiOsCreateCache (
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)
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 
116 ACPI_STATUS
117 AcpiOsPurgeCache (
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 
169 ACPI_STATUS
170 AcpiOsDeleteCache (
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 
208 ACPI_STATUS
209 AcpiOsReleaseObject (
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 
273 void *
274 AcpiOsAcquireObject (
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_RAW ((ACPI_DB_EXEC,
310             "%s: Object %p from %s cache\n",
311             ACPI_GET_FUNCTION_NAME, Object, Cache->ListName));
312 
313         Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
314         if (ACPI_FAILURE (Status))
315         {
316             return_PTR (NULL);
317         }
318 
319         /* Clear (zero) the previously used Object */
320 
321         memset (Object, 0, Cache->ObjectSize);
322     }
323     else
324     {
325         /* The cache is empty, create a new object */
326 
327         ACPI_MEM_TRACKING (Cache->TotalAllocated++);
328 
329 #ifdef ACPI_DBG_TRACK_ALLOCATIONS
330         if ((Cache->TotalAllocated - Cache->TotalFreed) > Cache->MaxOccupied)
331         {
332             Cache->MaxOccupied = Cache->TotalAllocated - Cache->TotalFreed;
333         }
334 #endif
335 
336         /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
337 
338         Status = AcpiUtReleaseMutex (ACPI_MTX_CACHES);
339         if (ACPI_FAILURE (Status))
340         {
341             return_PTR (NULL);
342         }
343 
344         Object = ACPI_ALLOCATE_ZEROED (Cache->ObjectSize);
345         if (!Object)
346         {
347             return_PTR (NULL);
348         }
349     }
350 
351     return_PTR (Object);
352 }
353 #endif /* ACPI_USE_LOCAL_CACHE */
354