Skip to content

Commit d89a4a0

Browse files
committed
vregion: add a reference count and locking
Vregions can be used by multiple asynchronous users. Add a refcount and a lock. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent 6d2176b commit d89a4a0

3 files changed

Lines changed: 100 additions & 26 deletions

File tree

src/include/sof/lib/vregion.h

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,26 @@ enum vregion_mem_type {
4141
struct vregion *vregion_create(size_t lifetime_size, size_t interim_size);
4242

4343
/**
44-
* @brief Destroy a virtual region instance.
44+
* @brief Increment virtual region's user count.
4545
*
46-
* Free all associated resources and deallocate the virtual region instance.
46+
* The creator of the virtual region is its first user, for any additional users
47+
* increment the region's use-count.
4748
*
48-
* @param[in] vr Pointer to the virtual region instance to destroy.
49+
* @param[in] vr Pointer to the virtual region instance to release.
50+
* @return struct vregion* Pointer to the virtual region instance.
4951
*/
50-
void vregion_destroy(struct vregion *vr);
52+
struct vregion *vregion_get(struct vregion *vr);
53+
54+
/**
55+
* @brief Decrement virtual region's user count or destroy it.
56+
*
57+
* Decrement virtual region's user count, when it reaches 0 free all associated
58+
* resources.
59+
*
60+
* @param[in] vr Pointer to the virtual region instance to release.
61+
* @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed.
62+
*/
63+
struct vregion *vregion_put(struct vregion *vr);
5164

5265
/**
5366
* @brief Allocate memory from the specified virtual region.
@@ -112,11 +125,31 @@ void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start);
112125

113126
#else /* CONFIG_SOF_VREGIONS */
114127

128+
#include <rtos/alloc.h>
129+
130+
struct vregion {
131+
unsigned int use_count;
132+
};
133+
115134
static inline struct vregion *vregion_create(size_t lifetime_size, size_t interim_size)
116135
{
117-
return NULL;
136+
struct vregion *vr = rmalloc(0, sizeof(*vr));
137+
138+
vr->use_count = 1;
139+
return vr;
140+
}
141+
static inline struct vregion *vregion_get(struct vregion *vr)
142+
{
143+
if (vr)
144+
vr->use_count++;
145+
return vr;
146+
}
147+
static inline struct vregion *vregion_put(struct vregion *vr)
148+
{
149+
if (vr && !--vr->use_count)
150+
rfree(vr);
151+
return vr;
118152
}
119-
static inline void vregion_destroy(struct vregion *vr) {}
120153
static inline void *vregion_alloc(struct vregion *vr, enum vregion_mem_type type, size_t size)
121154
{
122155
return NULL;

zephyr/lib/vregion.c

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ struct vregion {
8484
uint8_t *base; /* base address of entire region */
8585
size_t size; /* size of whole region in bytes */
8686
unsigned int pages; /* size of whole region in pages */
87+
struct k_mutex lock; /* protect vregion heaps and use-count */
88+
unsigned int use_count;
8789

8890
/* interim heap */
8991
struct interim_heap interim; /* interim heap */
@@ -152,6 +154,10 @@ struct vregion *vregion_create(size_t lifetime_size, size_t interim_size)
152154
/* init interim heaps */
153155
k_heap_init(&vr->interim.heap, vr->interim.heap.heap.init_mem, interim_size);
154156

157+
k_mutex_init(&vr->lock);
158+
/* The creator is the first user */
159+
vr->use_count = 1;
160+
155161
/* log the new vregion */
156162
LOG_INF("new at base %p size %#zx pages %u struct embedded at %p",
157163
(void *)vr->base, total_size, pages, (void *)vr);
@@ -161,20 +167,46 @@ struct vregion *vregion_create(size_t lifetime_size, size_t interim_size)
161167
return vr;
162168
}
163169

170+
struct vregion *vregion_get(struct vregion *vr)
171+
{
172+
if (!vr)
173+
return NULL;
174+
175+
k_mutex_lock(&vr->lock, K_FOREVER);
176+
vr->use_count++;
177+
k_mutex_unlock(&vr->lock);
178+
179+
return vr;
180+
}
181+
164182
/**
165-
* @brief Destroy a virtual region instance.
183+
* @brief Decrement virtual region's user count or destroy it.
166184
*
167-
* @param[in] vr Pointer to the virtual region instance to destroy.
185+
* @param[in] vr Pointer to the virtual region instance to release.
186+
* @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed.
168187
*/
169-
void vregion_destroy(struct vregion *vr)
188+
struct vregion *vregion_put(struct vregion *vr)
170189
{
190+
unsigned int use_count;
191+
171192
if (!vr)
172-
return;
193+
return NULL;
194+
195+
k_mutex_lock(&vr->lock, K_FOREVER);
196+
use_count = --vr->use_count;
197+
k_mutex_unlock(&vr->lock);
198+
199+
if (use_count)
200+
return vr;
201+
202+
/* Last user: nobody else can access the instance. */
173203

174204
/* log the vregion being destroyed */
175205
LOG_DBG("destroy %p size %#zx pages %u", (void *)vr->base, vr->size, vr->pages);
176206
LOG_DBG(" lifetime used %zu free count %d", vr->lifetime.used, vr->lifetime.free_count);
177207
vpage_free(vr->base);
208+
209+
return NULL;
178210
}
179211

180212
/**
@@ -275,25 +307,24 @@ void vregion_free(struct vregion *vr, void *ptr)
275307
if (!vr || !ptr)
276308
return;
277309

310+
k_mutex_lock(&vr->lock, K_FOREVER);
311+
278312
if (sys_cache_is_ptr_uncached(ptr))
279313
ptr = sys_cache_cached_ptr_get(ptr);
280314

281-
/* check if pointer is in interim heap */
282315
if (ptr >= (void *)vr->interim.heap.heap.init_mem &&
283316
ptr < (void *)((uint8_t *)vr->interim.heap.heap.init_mem +
284-
vr->interim.heap.heap.init_bytes)) {
317+
vr->interim.heap.heap.init_bytes))
318+
/* pointer is in interim heap */
285319
interim_free(&vr->interim, ptr);
286-
return;
287-
}
288-
289-
/* check if pointer is in lifetime heap */
290-
if (ptr >= (void *)vr->lifetime.base &&
291-
ptr < (void *)(vr->lifetime.base + vr->lifetime.size)) {
320+
else if (ptr >= (void *)vr->lifetime.base &&
321+
ptr < (void *)(vr->lifetime.base + vr->lifetime.size))
322+
/* pointer is in lifetime heap */
292323
lifetime_free(&vr->lifetime, ptr);
293-
return;
294-
}
324+
else
325+
LOG_ERR("error: vregion free invalid pointer %p", ptr);
295326

296-
LOG_ERR("error: vregion free invalid pointer %p", ptr);
327+
k_mutex_unlock(&vr->lock);
297328
}
298329
EXPORT_SYMBOL(vregion_free);
299330

@@ -310,21 +341,31 @@ EXPORT_SYMBOL(vregion_free);
310341
void *vregion_alloc_align(struct vregion *vr, enum vregion_mem_type type,
311342
size_t size, size_t alignment)
312343
{
344+
void *p;
345+
313346
if (!vr || !size)
314347
return NULL;
315348

316349
if (alignment < PLATFORM_DCACHE_ALIGN)
317350
alignment = PLATFORM_DCACHE_ALIGN;
318351

352+
k_mutex_lock(&vr->lock, K_FOREVER);
353+
319354
switch (type) {
320355
case VREGION_MEM_TYPE_INTERIM:
321-
return interim_alloc(&vr->interim, size, alignment);
356+
p = interim_alloc(&vr->interim, size, alignment);
357+
break;
322358
case VREGION_MEM_TYPE_LIFETIME:
323-
return lifetime_alloc(&vr->lifetime, size, alignment);
359+
p = lifetime_alloc(&vr->lifetime, size, alignment);
360+
break;
324361
default:
325362
LOG_ERR("error: invalid memory type %d", type);
326-
return NULL;
363+
p = NULL;
327364
}
365+
366+
k_mutex_unlock(&vr->lock);
367+
368+
return p;
328369
}
329370
EXPORT_SYMBOL(vregion_alloc_align);
330371

zephyr/test/vregion.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static void test_vreg_alloc_lifet(struct vregion *vreg)
3131

3232
zassert_not_null(ptr);
3333

34-
void *ptr_align = vregion_alloc_align(vreg, VREGION_MEM_TYPE_LIFETIME, 2000, 16);
34+
void *ptr_align = vregion_alloc_align(vreg, VREGION_MEM_TYPE_LIFETIME, 1600, 16);
3535

3636
zassert_not_null(ptr_align);
3737
zassert_equal((uintptr_t)ptr_align & 15, 0);
@@ -76,7 +76,7 @@ static void test_vreg_alloc_tmp(struct vregion *vreg)
7676
static void test_vreg_destroy(struct vregion *vreg)
7777
{
7878
vregion_info(vreg);
79-
vregion_destroy(vreg);
79+
vregion_put(vreg);
8080
}
8181

8282
ZTEST(sof_boot, vregion)

0 commit comments

Comments
 (0)