1 | /****************************************************************************** |
2 | * |
3 | * Module Name: utcache - local cache allocation routines |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, 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 < 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 | |
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 ((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 | |