1 /***
2   This file is part of PulseAudio.
3 
4   Copyright 2004-2006 Lennart Poettering
5   Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
6 
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as
9   published by the Free Software Foundation; either version 2.1 of the
10   License, or (at your option) any later version.
11 
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   Lesser General Public License for more details
16 
17   You should have received a copy of the GNU Lesser General Public
18   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
19 ***/
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #ifndef LOG_TAG
26 #define LOG_TAG "Memblock"
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <signal.h>
34 #include <errno.h>
35 
36 #ifdef HAVE_VALGRIND_MEMCHECK_H
37 #include <valgrind/memcheck.h>
38 #endif
39 
40 #include <pulse/xmalloc.h>
41 #include <pulse/def.h>
42 
43 #include <pulsecore/log.h>
44 #include <pulsecore/hashmap.h>
45 #include <pulsecore/semaphore.h>
46 #include <pulsecore/mutex.h>
47 #include <pulsecore/macro.h>
48 #include <pulsecore/llist.h>
49 #include <pulsecore/core-util.h>
50 
51 #include "memblock.h"
52 
53 /* We can allocate 64*1024*1024 bytes at maximum. That's 64MB. Please
54  * note that the footprint is usually much smaller, since the data is
55  * stored in SHM and our OS does not commit the memory before we use
56  * it for the first time. */
57 #define PA_MEMPOOL_SLOTS_MAX 1024
58 #define PA_MEMPOOL_SLOT_SIZE (64*1024)
59 
60 #define PA_MEMEXPORT_SLOTS_MAX 128
61 
62 #define PA_MEMIMPORT_SLOTS_MAX 160
63 #define PA_MEMIMPORT_SEGMENTS_MAX 16
64 /*
65  * If true, this segment's lifetime will not be limited by the
66  * number of active blocks (seg->n_blocks) using its shared memory.
67  * Rather, it will exist for the full lifetime of the memimport it
68  * is attached to.
69  *
70  * This is done to support memfd blocks transport.
71  *
72  * To transfer memfd-backed blocks without passing their fd every
73  * time, thus minimizing overhead and avoiding fd leaks, a command
74  * is sent with the memfd fd as ancil data very early on.
75  *
76  * This command has an ID that identifies the memfd region. Further
77  * block references are then exclusively done using this ID. On the
78  * receiving end, such logic is enabled by the memimport's segment
79  * hash and 'permanent' segments below.
80  */
segment_is_permanent(pa_memimport_segment *seg)81 static bool segment_is_permanent(pa_memimport_segment *seg) {
82     pa_assert(seg);
83     return seg->memory.type == PA_MEM_TYPE_SHARED_MEMFD;
84 }
85 
86 /* A collection of multiple segments */
87 struct pa_memimport {
88     pa_mutex *mutex;
89 
90     pa_mempool *pool;
91     pa_hashmap *segments;
92     pa_hashmap *blocks;
93 
94     /* Called whenever an imported memory block is no longer
95      * needed. */
96     pa_memimport_release_cb_t release_cb;
97     void *userdata;
98 
99     PA_LLIST_FIELDS(pa_memimport);
100 };
101 
102 struct memexport_slot {
103     PA_LLIST_FIELDS(struct memexport_slot);
104     pa_memblock *block;
105 };
106 
107 struct pa_memexport {
108     pa_mutex *mutex;
109     pa_mempool *pool;
110 
111     struct memexport_slot slots[PA_MEMEXPORT_SLOTS_MAX];
112 
113     PA_LLIST_HEAD(struct memexport_slot, free_slots);
114     PA_LLIST_HEAD(struct memexport_slot, used_slots);
115     unsigned n_init;
116     unsigned baseidx;
117 
118     /* Called whenever a client from which we imported a memory block
119        which we in turn exported to another client dies and we need to
120        revoke the memory block accordingly */
121     pa_memexport_revoke_cb_t revoke_cb;
122     void *userdata;
123 
124     PA_LLIST_FIELDS(pa_memexport);
125 };
126 
127 struct pa_mempool {
128     /* Reference count the mempool
129      *
130      * Any block allocation from the pool itself, or even just imported from
131      * another process through SHM and attached to it (PA_MEMBLOCK_IMPORTED),
132      * shall increase the refcount.
133      *
134      * This is done for per-client mempools: global references to blocks in
135      * the pool, or just to attached ones, can still be lingering around when
136      * the client connection dies and all per-client objects are to be freed.
137      * That is, current PulseAudio design does not guarantee that the client
138      * mempool blocks are referenced only by client-specific objects.
139      *
140      * For further details, please check:
141      * https://lists.freedesktop.org/archives/pulseaudio-discuss/2016-February/025587.html
142      */
143     PA_REFCNT_DECLARE;
144 
145     pa_semaphore *semaphore;
146     pa_mutex *mutex;
147 
148     pa_shm memory;
149 
150     bool global;
151 
152     size_t block_size;
153     unsigned n_blocks;
154     bool is_remote_writable;
155 
156     pa_atomic_t n_init;
157 
158     PA_LLIST_HEAD(pa_memimport, imports);
159     PA_LLIST_HEAD(pa_memexport, exports);
160 
161     /* A list of free slots that may be reused */
162     pa_flist *free_slots;
163 
164     pa_mempool_stat stat;
165 };
166 
167 static void segment_detach(pa_memimport_segment *seg);
168 
169 PA_STATIC_FLIST_DECLARE(unused_memblocks, 0, pa_xfree);
170 
171 /* No lock necessary */
stat_add(pa_memblock*b)172 static void stat_add(pa_memblock*b) {
173     pa_assert(b);
174     pa_assert(b->pool);
175 
176     pa_atomic_inc(&b->pool->stat.n_allocated);
177     pa_atomic_add(&b->pool->stat.allocated_size, (int) b->length);
178 
179     pa_atomic_inc(&b->pool->stat.n_accumulated);
180     pa_atomic_add(&b->pool->stat.accumulated_size, (int) b->length);
181 
182     if (b->type == PA_MEMBLOCK_IMPORTED) {
183         pa_atomic_inc(&b->pool->stat.n_imported);
184         pa_atomic_add(&b->pool->stat.imported_size, (int) b->length);
185     }
186 
187     pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]);
188     pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]);
189 }
190 
191 /* No lock necessary */
stat_remove(pa_memblock *b)192 static void stat_remove(pa_memblock *b) {
193     pa_assert(b);
194     pa_assert(b->pool);
195 
196     pa_assert(pa_atomic_load(&b->pool->stat.n_allocated) > 0);
197     pa_assert(pa_atomic_load(&b->pool->stat.allocated_size) >= (int) b->length);
198 
199     pa_atomic_dec(&b->pool->stat.n_allocated);
200     pa_atomic_sub(&b->pool->stat.allocated_size, (int) b->length);
201 
202     if (b->type == PA_MEMBLOCK_IMPORTED) {
203         pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0);
204         pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length);
205 
206         pa_atomic_dec(&b->pool->stat.n_imported);
207         pa_atomic_sub(&b->pool->stat.imported_size, (int) b->length);
208     }
209 
210     pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]);
211 }
212 
213 static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length);
214 
215 /* No lock necessary */
pa_memblock_new(pa_mempool *p, size_t length)216 pa_memblock *pa_memblock_new(pa_mempool *p, size_t length) {
217     pa_memblock *b;
218 
219     pa_assert(p);
220     pa_assert(length);
221 
222     if (!(b = pa_memblock_new_pool(p, length)))
223         b = memblock_new_appended(p, length);
224 
225     return b;
226 }
227 
228 /* No lock necessary */
memblock_new_appended(pa_mempool *p, size_t length)229 static pa_memblock *memblock_new_appended(pa_mempool *p, size_t length) {
230     pa_memblock *b;
231 
232     pa_assert(p);
233     pa_assert(length);
234 
235     /* If -1 is passed as length we choose the size for the caller. */
236 
237     if (length == (size_t) -1)
238         length = pa_mempool_block_size_max(p);
239 
240     b = pa_xmalloc(PA_ALIGN(sizeof(pa_memblock)) + length);
241     PA_REFCNT_INIT(b);
242     b->pool = p;
243     pa_mempool_ref(b->pool);
244     b->type = PA_MEMBLOCK_APPENDED;
245     b->read_only = b->is_silence = false;
246     pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock)));
247     b->length = length;
248     pa_atomic_store(&b->n_acquired, 0);
249     pa_atomic_store(&b->please_signal, 0);
250 
251     stat_add(b);
252     return b;
253 }
254 
255 /* No lock necessary */
mempool_allocate_slot(pa_mempool *p)256 static struct mempool_slot* mempool_allocate_slot(pa_mempool *p) {
257     struct mempool_slot *slot;
258     pa_assert(p);
259 
260     if (!(slot = pa_flist_pop(p->free_slots))) {
261         int idx;
262 
263         /* The free list was empty, we have to allocate a new entry */
264 
265         if ((unsigned) (idx = pa_atomic_inc(&p->n_init)) >= p->n_blocks)
266             pa_atomic_dec(&p->n_init);
267         else
268             slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * (size_t) idx));
269 
270         if (!slot) {
271             if (pa_log_ratelimit(PA_LOG_DEBUG))
272                 pa_log_debug("Pool full");
273             pa_atomic_inc(&p->stat.n_pool_full);
274             return NULL;
275         }
276     }
277 
278 /* #ifdef HAVE_VALGRIND_MEMCHECK_H */
279 /*     if (PA_UNLIKELY(pa_in_valgrind())) { */
280 /*         VALGRIND_MALLOCLIKE_BLOCK(slot, p->block_size, 0, 0); */
281 /*     } */
282 /* #endif */
283 
284     return slot;
285 }
286 
287 /* No lock necessary, totally redundant anyway */
mempool_slot_data(struct mempool_slot *slot)288 static inline void* mempool_slot_data(struct mempool_slot *slot) {
289     return slot;
290 }
291 
292 /* No lock necessary */
mempool_slot_idx(pa_mempool *p, void *ptr)293 static unsigned mempool_slot_idx(pa_mempool *p, void *ptr) {
294     pa_assert(p);
295 
296     pa_assert((uint8_t*) ptr >= (uint8_t*) p->memory.ptr);
297     pa_assert((uint8_t*) ptr < (uint8_t*) p->memory.ptr + p->memory.size);
298 
299     return (unsigned) ((size_t) ((uint8_t*) ptr - (uint8_t*) p->memory.ptr) / p->block_size);
300 }
301 
302 /* No lock necessary */
mempool_slot_by_ptr(pa_mempool *p, void *ptr)303 static struct mempool_slot* mempool_slot_by_ptr(pa_mempool *p, void *ptr) {
304     unsigned idx;
305 
306     if ((idx = mempool_slot_idx(p, ptr)) == (unsigned) -1)
307         return NULL;
308 
309     return (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (idx * p->block_size));
310 }
311 
312 /* No lock necessary */
pa_mempool_is_remote_writable(pa_mempool *p)313 bool pa_mempool_is_remote_writable(pa_mempool *p) {
314     pa_assert(p);
315     return p->is_remote_writable;
316 }
317 
318 /* No lock necessary */
pa_mempool_set_is_remote_writable(pa_mempool *p, bool writable)319 void pa_mempool_set_is_remote_writable(pa_mempool *p, bool writable) {
320     pa_assert(p);
321     pa_assert(!writable || pa_mempool_is_shared(p));
322     p->is_remote_writable = writable;
323 }
324 
325 /* No lock necessary */
pa_memblock_new_pool(pa_mempool *p, size_t length)326 pa_memblock *pa_memblock_new_pool(pa_mempool *p, size_t length) {
327     pa_memblock *b = NULL;
328     struct mempool_slot *slot;
329     static int mempool_disable = 0;
330 
331     pa_assert(p);
332     pa_assert(length);
333 
334     if (mempool_disable == 0)
335         mempool_disable = getenv("PULSE_MEMPOOL_DISABLE") ? 1 : -1;
336 
337     if (mempool_disable > 0)
338         return NULL;
339 
340     /* If -1 is passed as length we choose the size for the caller: we
341      * take the largest size that fits in one of our slots. */
342 
343     if (length == (size_t) -1)
344         length = pa_mempool_block_size_max(p);
345 
346     if (p->block_size >= PA_ALIGN(sizeof(pa_memblock)) + length) {
347 
348         if (!(slot = mempool_allocate_slot(p)))
349             return NULL;
350 
351         b = mempool_slot_data(slot);
352         b->type = PA_MEMBLOCK_POOL;
353         pa_atomic_ptr_store(&b->data, (uint8_t*) b + PA_ALIGN(sizeof(pa_memblock)));
354 
355     } else if (p->block_size >= length) {
356 
357         if (!(slot = mempool_allocate_slot(p)))
358             return NULL;
359 
360         if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
361             b = pa_xnew(pa_memblock, 1);
362 
363         b->type = PA_MEMBLOCK_POOL_EXTERNAL;
364         pa_atomic_ptr_store(&b->data, mempool_slot_data(slot));
365 
366     } else {
367         pa_log_debug("Memory block too large for pool: %lu > %lu",
368             (unsigned long) length, (unsigned long) p->block_size);
369         pa_atomic_inc(&p->stat.n_too_large_for_pool);
370         return NULL;
371     }
372 
373     PA_REFCNT_INIT(b);
374     b->pool = p;
375     pa_mempool_ref(b->pool);
376     b->read_only = b->is_silence = false;
377     b->length = length;
378     pa_atomic_store(&b->n_acquired, 0);
379     pa_atomic_store(&b->please_signal, 0);
380 
381     stat_add(b);
382     return b;
383 }
384 
385 /* No lock necessary */
pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, bool read_only)386 pa_memblock *pa_memblock_new_fixed(pa_mempool *p, void *d, size_t length, bool read_only) {
387     pa_memblock *b;
388 
389     pa_assert(p);
390     pa_assert(d);
391     pa_assert(length != (size_t) -1);
392     pa_assert(length);
393 
394     if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
395         b = pa_xnew(pa_memblock, 1);
396 
397     PA_REFCNT_INIT(b);
398     b->pool = p;
399     pa_mempool_ref(b->pool);
400     b->type = PA_MEMBLOCK_FIXED;
401     b->read_only = read_only;
402     b->is_silence = false;
403     pa_atomic_ptr_store(&b->data, d);
404     b->length = length;
405     pa_atomic_store(&b->n_acquired, 0);
406     pa_atomic_store(&b->please_signal, 0);
407 
408     stat_add(b);
409     return b;
410 }
411 
412 /* No lock necessary */
pa_memblock_new_user( pa_mempool *p, void *d, size_t length, pa_free_cb_t free_cb, void *free_cb_data, bool read_only)413 pa_memblock *pa_memblock_new_user(
414         pa_mempool *p,
415         void *d,
416         size_t length,
417         pa_free_cb_t free_cb,
418         void *free_cb_data,
419         bool read_only) {
420     pa_memblock *b;
421 
422     pa_assert(p);
423     pa_assert(d);
424     pa_assert(length);
425     pa_assert(length != (size_t) -1);
426     pa_assert(free_cb);
427 
428     if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
429         b = pa_xnew(pa_memblock, 1);
430 
431     PA_REFCNT_INIT(b);
432     b->pool = p;
433     pa_mempool_ref(b->pool);
434     b->type = PA_MEMBLOCK_USER;
435     b->read_only = read_only;
436     b->is_silence = false;
437     pa_atomic_ptr_store(&b->data, d);
438     b->length = length;
439     pa_atomic_store(&b->n_acquired, 0);
440     pa_atomic_store(&b->please_signal, 0);
441 
442     b->per_type.user.free_cb = free_cb;
443     b->per_type.user.free_cb_data = free_cb_data;
444 
445     stat_add(b);
446     return b;
447 }
448 
449 /* No lock necessary */
pa_memblock_is_ours(pa_memblock *b)450 bool pa_memblock_is_ours(pa_memblock *b) {
451     pa_assert(b);
452     pa_assert(PA_REFCNT_VALUE(b) > 0);
453 
454     return b->type != PA_MEMBLOCK_IMPORTED;
455 }
456 
457 /* No lock necessary */
pa_memblock_is_read_only(pa_memblock *b)458 bool pa_memblock_is_read_only(pa_memblock *b) {
459     pa_assert(b);
460     pa_assert(PA_REFCNT_VALUE(b) > 0);
461 
462     return b->read_only || PA_REFCNT_VALUE(b) > 1;
463 }
464 
465 /* No lock necessary */
pa_memblock_is_silence(pa_memblock *b)466 bool pa_memblock_is_silence(pa_memblock *b) {
467     pa_assert(b);
468     pa_assert(PA_REFCNT_VALUE(b) > 0);
469 
470     return b->is_silence;
471 }
472 
473 /* No lock necessary */
pa_memblock_set_is_silence(pa_memblock *b, bool v)474 void pa_memblock_set_is_silence(pa_memblock *b, bool v) {
475     pa_assert(b);
476     pa_assert(PA_REFCNT_VALUE(b) > 0);
477 
478     b->is_silence = v;
479 }
480 
481 /* No lock necessary */
pa_memblock_ref_is_one(pa_memblock *b)482 bool pa_memblock_ref_is_one(pa_memblock *b) {
483     int r;
484     pa_assert(b);
485 
486     pa_assert_se((r = PA_REFCNT_VALUE(b)) > 0);
487 
488     return r == 1;
489 }
490 
491 /* No lock necessary */
pa_memblock_acquire(pa_memblock *b)492 void* pa_memblock_acquire(pa_memblock *b) {
493     pa_assert(b);
494     pa_assert(PA_REFCNT_VALUE(b) > 0);
495 
496     pa_atomic_inc(&b->n_acquired);
497 
498     return pa_atomic_ptr_load(&b->data);
499 }
500 
501 /* No lock necessary */
pa_memblock_acquire_chunk(const pa_memchunk *c)502 void *pa_memblock_acquire_chunk(const pa_memchunk *c) {
503     pa_assert(c);
504 
505     return (uint8_t *) pa_memblock_acquire(c->memblock) + c->index;
506 }
507 
508 /* No lock necessary, in corner cases locks by its own */
pa_memblock_release(pa_memblock *b)509 void pa_memblock_release(pa_memblock *b) {
510     int r;
511     pa_assert(b);
512     pa_assert(PA_REFCNT_VALUE(b) > 0);
513 
514     r = pa_atomic_dec(&b->n_acquired);
515     pa_assert(r >= 1);
516 
517     /* Signal a waiting thread that this memblock is no longer used */
518     if (r == 1 && pa_atomic_load(&b->please_signal))
519         pa_semaphore_post(b->pool->semaphore);
520 }
521 
pa_memblock_get_length(pa_memblock *b)522 size_t pa_memblock_get_length(pa_memblock *b) {
523     pa_assert(b);
524     pa_assert(PA_REFCNT_VALUE(b) > 0);
525 
526     return b->length;
527 }
528 
529 /* Note! Always unref the returned pool after use */
pa_memblock_get_pool(pa_memblock *b)530 pa_mempool* pa_memblock_get_pool(pa_memblock *b) {
531     pa_assert(b);
532     pa_assert(PA_REFCNT_VALUE(b) > 0);
533     pa_assert(b->pool);
534 
535     pa_mempool_ref(b->pool);
536     return b->pool;
537 }
538 
539 /* No lock necessary */
pa_memblock_ref(pa_memblock*b)540 pa_memblock* pa_memblock_ref(pa_memblock*b) {
541     pa_assert(b);
542     pa_assert(PA_REFCNT_VALUE(b) > 0);
543 
544     PA_REFCNT_INC(b);
545     return b;
546 }
547 
memblock_free(pa_memblock *b)548 static void memblock_free(pa_memblock *b) {
549     pa_mempool *pool;
550 
551     pa_assert(b);
552     pa_assert(b->pool);
553     pa_assert(pa_atomic_load(&b->n_acquired) == 0);
554 
555     pool = b->pool;
556     stat_remove(b);
557 
558     switch (b->type) {
559         case PA_MEMBLOCK_USER :
560             pa_assert(b->per_type.user.free_cb);
561             b->per_type.user.free_cb(b->per_type.user.free_cb_data);
562 
563             /* Fall through */
564 
565         case PA_MEMBLOCK_FIXED:
566             if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
567                 pa_xfree(b);
568 
569             break;
570 
571         case PA_MEMBLOCK_APPENDED:
572 
573             /* We could attach it to unused_memblocks, but that would
574              * probably waste some considerable amount of memory */
575             pa_xfree(b);
576             break;
577 
578         case PA_MEMBLOCK_IMPORTED: {
579             pa_memimport_segment *segment;
580             pa_memimport *import;
581 
582             /* FIXME! This should be implemented lock-free */
583 
584             pa_assert_se(segment = b->per_type.imported.segment);
585             pa_assert_se(import = segment->import);
586 
587             pa_mutex_lock(import->mutex);
588 
589             pa_assert_se(pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)));
590 
591             pa_assert(segment->n_blocks >= 1);
592             if (-- segment->n_blocks <= 0)
593                 segment_detach(segment);
594 
595             pa_mutex_unlock(import->mutex);
596 
597             import->release_cb(import, b->per_type.imported.id, import->userdata);
598 
599             if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
600                 pa_xfree(b);
601 
602             break;
603         }
604 
605         case PA_MEMBLOCK_POOL_EXTERNAL:
606         case PA_MEMBLOCK_POOL: {
607             struct mempool_slot *slot;
608             bool call_free;
609 
610             pa_assert_se(slot = mempool_slot_by_ptr(b->pool, pa_atomic_ptr_load(&b->data)));
611 
612             call_free = b->type == PA_MEMBLOCK_POOL_EXTERNAL;
613 
614 /* #ifdef HAVE_VALGRIND_MEMCHECK_H */
615 /*             if (PA_UNLIKELY(pa_in_valgrind())) { */
616 /*                 VALGRIND_FREELIKE_BLOCK(slot, b->pool->block_size); */
617 /*             } */
618 /* #endif */
619 
620             /* The free list dimensions should easily allow all slots
621              * to fit in, hence try harder if pushing this slot into
622              * the free list fails */
623             while (pa_flist_push(b->pool->free_slots, slot) < 0)
624                 ;
625 
626             if (call_free)
627                 if (pa_flist_push(PA_STATIC_FLIST_GET(unused_memblocks), b) < 0)
628                     pa_xfree(b);
629 
630             break;
631         }
632 
633         case PA_MEMBLOCK_TYPE_MAX:
634         default:
635             pa_assert_not_reached();
636     }
637 
638     pa_mempool_unref(pool);
639 }
640 
641 /* No lock necessary */
pa_memblock_unref(pa_memblock*b)642 void pa_memblock_unref(pa_memblock*b) {
643     pa_assert(b);
644     pa_assert(PA_REFCNT_VALUE(b) > 0);
645 
646     if (PA_REFCNT_DEC(b) > 0)
647         return;
648 
649     memblock_free(b);
650 }
651 
652 /* Self locked */
memblock_wait(pa_memblock *b)653 static void memblock_wait(pa_memblock *b) {
654     pa_assert(b);
655 
656     if (pa_atomic_load(&b->n_acquired) > 0) {
657         /* We need to wait until all threads gave up access to the
658          * memory block before we can go on. Unfortunately this means
659          * that we have to lock and wait here. Sniff! */
660 
661         pa_atomic_inc(&b->please_signal);
662 
663         while (pa_atomic_load(&b->n_acquired) > 0)
664             pa_semaphore_wait(b->pool->semaphore);
665 
666         pa_atomic_dec(&b->please_signal);
667     }
668 }
669 
670 /* No lock necessary. This function is not multiple caller safe! */
memblock_make_local(pa_memblock *b)671 static void memblock_make_local(pa_memblock *b) {
672     pa_assert(b);
673 
674     pa_atomic_dec(&b->pool->stat.n_allocated_by_type[b->type]);
675 
676     if (b->length <= b->pool->block_size) {
677         struct mempool_slot *slot;
678 
679         if ((slot = mempool_allocate_slot(b->pool))) {
680             void *new_data;
681             /* We can move it into a local pool, perfect! */
682 
683             new_data = mempool_slot_data(slot);
684             memcpy(new_data, pa_atomic_ptr_load(&b->data), b->length);
685             pa_atomic_ptr_store(&b->data, new_data);
686 
687             b->type = PA_MEMBLOCK_POOL_EXTERNAL;
688             b->read_only = false;
689 
690             goto finish;
691         }
692     }
693 
694     /* Humm, not enough space in the pool, so lets allocate the memory with malloc() */
695     b->per_type.user.free_cb = pa_xfree;
696     pa_atomic_ptr_store(&b->data, pa_xmemdup(pa_atomic_ptr_load(&b->data), b->length));
697     b->per_type.user.free_cb_data = pa_atomic_ptr_load(&b->data);
698 
699     b->type = PA_MEMBLOCK_USER;
700     b->read_only = false;
701 
702 finish:
703     pa_atomic_inc(&b->pool->stat.n_allocated_by_type[b->type]);
704     pa_atomic_inc(&b->pool->stat.n_accumulated_by_type[b->type]);
705     memblock_wait(b);
706 }
707 
708 /* No lock necessary. This function is not multiple caller safe */
pa_memblock_unref_fixed(pa_memblock *b)709 void pa_memblock_unref_fixed(pa_memblock *b) {
710     pa_assert(b);
711     pa_assert(PA_REFCNT_VALUE(b) > 0);
712     pa_assert(b->type == PA_MEMBLOCK_FIXED);
713 
714     if (PA_REFCNT_VALUE(b) > 1)
715         memblock_make_local(b);
716 
717     pa_memblock_unref(b);
718 }
719 
720 /* No lock necessary. */
pa_memblock_will_need(pa_memblock *b)721 pa_memblock *pa_memblock_will_need(pa_memblock *b) {
722     void *p;
723 
724     pa_assert(b);
725     pa_assert(PA_REFCNT_VALUE(b) > 0);
726 
727     p = pa_memblock_acquire(b);
728     pa_will_need(p, b->length);
729     pa_memblock_release(b);
730 
731     return b;
732 }
733 
734 /* Self-locked. This function is not multiple-caller safe */
memblock_replace_import(pa_memblock *b)735 static void memblock_replace_import(pa_memblock *b) {
736     pa_memimport_segment *segment;
737     pa_memimport *import;
738 
739     pa_assert(b);
740     pa_assert(b->type == PA_MEMBLOCK_IMPORTED);
741 
742     pa_assert(pa_atomic_load(&b->pool->stat.n_imported) > 0);
743     pa_assert(pa_atomic_load(&b->pool->stat.imported_size) >= (int) b->length);
744     pa_atomic_dec(&b->pool->stat.n_imported);
745     pa_atomic_sub(&b->pool->stat.imported_size, (int) b->length);
746 
747     pa_assert_se(segment = b->per_type.imported.segment);
748     pa_assert_se(import = segment->import);
749 
750     pa_mutex_lock(import->mutex);
751 
752     pa_assert_se(pa_hashmap_remove(import->blocks, PA_UINT32_TO_PTR(b->per_type.imported.id)));
753 
754     memblock_make_local(b);
755 
756     pa_assert(segment->n_blocks >= 1);
757     if (-- segment->n_blocks <= 0)
758         segment_detach(segment);
759 
760     pa_mutex_unlock(import->mutex);
761 }
762 
763 /*@per_client: This is a security measure. By default this should
764  * be set to true where the created mempool is never shared with more
765  * than one client in the system. Set this to false if a global
766  * mempool, shared with all existing and future clients, is required.
767  *
768  * NOTE-1: Do not create any further global mempools! They allow data
769  * leaks between clients and thus conflict with the xdg-app containers
770  * model. They also complicate the handling of memfd-based pools.
771  *
772  * NOTE-2: Almost all mempools are now created on a per client basis.
773  * The only exception is the pa_core's mempool which is still shared
774  * between all clients of the system.
775  *
776  * Beside security issues, special marking for global mempools is
777  * required for memfd communication. To avoid fd leaks, memfd pools
778  * are registered with the connection pstream to create an ID<->memfd
779  * mapping on both PA endpoints. Such memory regions are then always
780  * referenced by their IDs and never by their fds and thus their fds
781  * can be quickly closed later.
782  *
783  * Unfortunately this scheme cannot work with global pools since the
784  * ID registration mechanism needs to happen for each newly connected
785  * client, and thus the need for a more special handling. That is,
786  * for the pool's fd to be always open :-(
787  *
788  * TODO-1: Transform the global core mempool to a per-client one
789  * TODO-2: Remove global mempools support */
pa_mempool_new(pa_mem_type_t type, size_t size, bool per_client)790 pa_mempool *pa_mempool_new(pa_mem_type_t type, size_t size, bool per_client) {
791     pa_log_debug("pa_mempool_new:type %d, size %zu, per_client %d,", type, size, per_client);
792     pa_mempool *p;
793     char t1[PA_BYTES_SNPRINT_MAX], t2[PA_BYTES_SNPRINT_MAX];
794     const size_t page_size = pa_page_size();
795 
796     p = pa_xnew0(pa_mempool, 1);
797     PA_REFCNT_INIT(p);
798 
799     p->block_size = PA_PAGE_ALIGN(PA_MEMPOOL_SLOT_SIZE);
800     if (p->block_size < page_size)
801         p->block_size = page_size;
802 
803     if (size <= 0)
804         p->n_blocks = PA_MEMPOOL_SLOTS_MAX;
805     else {
806         p->n_blocks = (unsigned) (size / p->block_size);
807 
808         if (p->n_blocks < 2)
809             p->n_blocks = 2;
810     }
811 
812     if (pa_shm_create_rw(&p->memory, type, p->n_blocks * p->block_size, 0700) < 0) {
813         pa_xfree(p);
814         return NULL;
815     }
816 
817     pa_log_debug("Using %s memory pool with %u slots of size %s each, total size is"
818                  "%s, maximum usable slot size is %lu",
819                  pa_mem_type_to_string(type),
820                  p->n_blocks,
821                  pa_bytes_snprint(t1, sizeof(t1), (unsigned) p->block_size),
822                  pa_bytes_snprint(t2, sizeof(t2), (unsigned) (p->n_blocks * p->block_size)),
823                  (unsigned long) pa_mempool_block_size_max(p));
824 
825     p->global = !per_client;
826 
827     pa_atomic_store(&p->n_init, 0);
828 
829     PA_LLIST_HEAD_INIT(pa_memimport, p->imports);
830     PA_LLIST_HEAD_INIT(pa_memexport, p->exports);
831 
832     p->mutex = pa_mutex_new(true, true);
833     p->semaphore = pa_semaphore_new(0);
834 
835     p->free_slots = pa_flist_new(p->n_blocks);
836 
837     return p;
838 }
839 
mempool_free(pa_mempool *p)840 static void mempool_free(pa_mempool *p) {
841     pa_assert(p);
842 
843     pa_mutex_lock(p->mutex);
844 
845     while (p->imports)
846         pa_memimport_free(p->imports);
847 
848     while (p->exports)
849         pa_memexport_free(p->exports);
850 
851     pa_mutex_unlock(p->mutex);
852 
853     pa_flist_free(p->free_slots, NULL);
854 
855     if (pa_atomic_load(&p->stat.n_allocated) > 0) {
856 
857         /* Ouch, somebody is retaining a memory block reference! */
858 
859 #ifdef DEBUG_REF
860         unsigned i;
861         pa_flist *list;
862 
863         /* Let's try to find at least one of those leaked memory blocks */
864 
865         list = pa_flist_new(p->n_blocks);
866 
867         for (i = 0; i < (unsigned) pa_atomic_load(&p->n_init); i++) {
868             struct mempool_slot *slot;
869             pa_memblock *b, *k;
870 
871             slot = (struct mempool_slot*) ((uint8_t*) p->memory.ptr + (p->block_size * (size_t) i));
872             b = mempool_slot_data(slot);
873 
874             while ((k = pa_flist_pop(p->free_slots))) {
875                 while (pa_flist_push(list, k) < 0)
876                     ;
877 
878                 if (b == k)
879                     break;
880             }
881 
882             if (!k)
883                 pa_log_error("REF: Leaked memory block %p", b);
884 
885             while ((k = pa_flist_pop(list)))
886                 while (pa_flist_push(p->free_slots, k) < 0)
887                     ;
888         }
889 
890         pa_flist_free(list, NULL);
891 
892 #endif
893 
894         pa_log_error("Memory pool destroyed but not all memory blocks freed! %u remain.",
895             pa_atomic_load(&p->stat.n_allocated));
896 
897 /*         PA_DEBUG_TRAP; */
898     }
899 
900     pa_shm_free(&p->memory);
901 
902     pa_mutex_free(p->mutex);
903     pa_semaphore_free(p->semaphore);
904 
905     pa_xfree(p);
906 }
907 
908 /* No lock necessary */
pa_mempool_get_stat(pa_mempool *p)909 const pa_mempool_stat* pa_mempool_get_stat(pa_mempool *p) {
910     pa_assert(p);
911 
912     return &p->stat;
913 }
914 
915 /* No lock necessary */
pa_mempool_block_size_max(pa_mempool *p)916 size_t pa_mempool_block_size_max(pa_mempool *p) {
917     pa_assert(p);
918 
919     return p->block_size - PA_ALIGN(sizeof(pa_memblock));
920 }
921 
922 /* No lock necessary */
pa_mempool_vacuum(pa_mempool *p)923 void pa_mempool_vacuum(pa_mempool *p) {
924     struct mempool_slot *slot;
925     pa_flist *list;
926 
927     pa_assert(p);
928 
929     list = pa_flist_new(p->n_blocks);
930 
931     while ((slot = pa_flist_pop(p->free_slots)))
932         while (pa_flist_push(list, slot) < 0)
933             ;
934 
935     while ((slot = pa_flist_pop(list))) {
936         pa_shm_punch(&p->memory, (size_t) ((uint8_t*) slot - (uint8_t*) p->memory.ptr), p->block_size);
937 
938         while (pa_flist_push(p->free_slots, slot))
939             ;
940     }
941 
942     pa_flist_free(list, NULL);
943 }
944 
945 /* No lock necessary */
pa_mempool_is_shared(pa_mempool *p)946 bool pa_mempool_is_shared(pa_mempool *p) {
947     pa_assert(p);
948 
949     return pa_mem_type_is_shared(p->memory.type);
950 }
951 
952 /* No lock necessary */
pa_mempool_is_memfd_backed(const pa_mempool *p)953 bool pa_mempool_is_memfd_backed(const pa_mempool *p) {
954     pa_assert(p);
955 
956     return (p->memory.type == PA_MEM_TYPE_SHARED_MEMFD);
957 }
958 
959 /* No lock necessary */
pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id)960 int pa_mempool_get_shm_id(pa_mempool *p, uint32_t *id) {
961     pa_assert(p);
962 
963     if (!pa_mempool_is_shared(p))
964         return -1;
965 
966     *id = p->memory.id;
967 
968     return 0;
969 }
970 
pa_mempool_ref(pa_mempool *p)971 pa_mempool* pa_mempool_ref(pa_mempool *p) {
972     pa_assert(p);
973     pa_assert(PA_REFCNT_VALUE(p) > 0);
974 
975     PA_REFCNT_INC(p);
976     return p;
977 }
978 
pa_mempool_unref(pa_mempool *p)979 void pa_mempool_unref(pa_mempool *p) {
980     pa_assert(p);
981     pa_assert(PA_REFCNT_VALUE(p) > 0);
982 
983     if (PA_REFCNT_DEC(p) <= 0)
984         mempool_free(p);
985 }
986 
987 /* No lock necessary
988  * Check pa_mempool_new() for per-client vs. global mempools */
pa_mempool_is_global(pa_mempool *p)989 bool pa_mempool_is_global(pa_mempool *p) {
990     pa_assert(p);
991 
992     return p->global;
993 }
994 
995 /* No lock necessary
996  * Check pa_mempool_new() for per-client vs. global mempools */
pa_mempool_is_per_client(pa_mempool *p)997 bool pa_mempool_is_per_client(pa_mempool *p) {
998     return !pa_mempool_is_global(p);
999 }
1000 
1001 /* Self-locked
1002  *
1003  * This is only for per-client mempools!
1004  *
1005  * After this method's return, the caller owns the file descriptor
1006  * and is responsible for closing it in the appropriate time. This
1007  * should only be called once during during a mempool's lifetime.
1008  *
1009  * Check pa_shm->fd and pa_mempool_new() for further context. */
pa_mempool_take_memfd_fd(pa_mempool *p)1010 int pa_mempool_take_memfd_fd(pa_mempool *p) {
1011     int memfd_fd;
1012 
1013     pa_assert(p);
1014     pa_assert(pa_mempool_is_shared(p));
1015     pa_assert(pa_mempool_is_memfd_backed(p));
1016     pa_assert(pa_mempool_is_per_client(p));
1017 
1018     pa_mutex_lock(p->mutex);
1019 
1020     memfd_fd = p->memory.fd;
1021     p->memory.fd = -1;
1022 
1023     pa_mutex_unlock(p->mutex);
1024 
1025     pa_assert(memfd_fd != -1);
1026     return memfd_fd;
1027 }
1028 
1029 /* No lock necessary
1030  *
1031  * This is only for global mempools!
1032  *
1033  * Global mempools have their memfd descriptor always open. DO NOT
1034  * close the returned descriptor by your own.
1035  *
1036  * Check pa_mempool_new() for further context. */
pa_mempool_get_memfd_fd(pa_mempool *p)1037 int pa_mempool_get_memfd_fd(pa_mempool *p) {
1038     int memfd_fd;
1039 
1040     pa_assert(p);
1041     pa_assert(pa_mempool_is_shared(p));
1042     pa_assert(pa_mempool_is_memfd_backed(p));
1043     pa_assert(pa_mempool_is_global(p));
1044 
1045     memfd_fd = p->memory.fd;
1046     pa_assert(memfd_fd != -1);
1047 
1048     return memfd_fd;
1049 }
1050 
1051 /* For receiving blocks from other nodes */
pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata)1052 pa_memimport* pa_memimport_new(pa_mempool *p, pa_memimport_release_cb_t cb, void *userdata) {
1053     pa_memimport *i;
1054 
1055     pa_assert(p);
1056     pa_assert(cb);
1057 
1058     i = pa_xnew(pa_memimport, 1);
1059     i->mutex = pa_mutex_new(true, true);
1060     i->pool = p;
1061     pa_mempool_ref(i->pool);
1062     i->segments = pa_hashmap_new(NULL, NULL);
1063     i->blocks = pa_hashmap_new(NULL, NULL);
1064     i->release_cb = cb;
1065     i->userdata = userdata;
1066 
1067     pa_mutex_lock(p->mutex);
1068     PA_LLIST_PREPEND(pa_memimport, p->imports, i);
1069     pa_mutex_unlock(p->mutex);
1070 
1071     return i;
1072 }
1073 
1074 static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i);
1075 
1076 /* Should be called locked
1077  * Caller owns passed @memfd_fd and must close it down when appropriate. */
segment_attach(pa_memimport *i, pa_mem_type_t type, uint32_t shm_id, int memfd_fd, bool writable)1078 static pa_memimport_segment* segment_attach(pa_memimport *i, pa_mem_type_t type, uint32_t shm_id,
1079                                             int memfd_fd, bool writable) {
1080     pa_memimport_segment* seg;
1081     pa_assert(pa_mem_type_is_shared(type));
1082 
1083     if (pa_hashmap_size(i->segments) >= PA_MEMIMPORT_SEGMENTS_MAX)
1084         return NULL;
1085 
1086     seg = pa_xnew0(pa_memimport_segment, 1);
1087 
1088     if (pa_shm_attach(&seg->memory, type, shm_id, memfd_fd, writable) < 0) {
1089         pa_xfree(seg);
1090         return NULL;
1091     }
1092 
1093     seg->writable = writable;
1094     seg->import = i;
1095     seg->trap = pa_memtrap_add(seg->memory.ptr, seg->memory.size);
1096 
1097     pa_hashmap_put(i->segments, PA_UINT32_TO_PTR(seg->memory.id), seg);
1098     return seg;
1099 }
1100 
1101 /* Should be called locked */
segment_detach(pa_memimport_segment *seg)1102 static void segment_detach(pa_memimport_segment *seg) {
1103     pa_assert(seg);
1104     pa_assert(seg->n_blocks == (segment_is_permanent(seg) ? 1u : 0u));
1105 
1106     pa_hashmap_remove(seg->import->segments, PA_UINT32_TO_PTR(seg->memory.id));
1107     pa_shm_free(&seg->memory);
1108 
1109     if (seg->trap)
1110         pa_memtrap_remove(seg->trap);
1111 
1112     pa_xfree(seg);
1113 }
1114 
1115 /* Self-locked. Not multiple-caller safe */
pa_memimport_free(pa_memimport *i)1116 void pa_memimport_free(pa_memimport *i) {
1117     pa_memexport *e;
1118     pa_memblock *b;
1119     pa_memimport_segment *seg;
1120     void *state = NULL;
1121 
1122     pa_assert(i);
1123 
1124     pa_mutex_lock(i->mutex);
1125 
1126     while ((b = pa_hashmap_first(i->blocks)))
1127         memblock_replace_import(b);
1128 
1129     /* Permanent segments exist for the lifetime of the memimport. Now
1130      * that we're freeing the memimport itself, clear them all up.
1131      *
1132      * Careful! segment_detach() internally removes itself from the
1133      * memimport's hash; the same hash we're now using for iteration. */
1134     PA_HASHMAP_FOREACH(seg, i->segments, state) {
1135         if (segment_is_permanent(seg))
1136             segment_detach(seg);
1137     }
1138     pa_assert(pa_hashmap_size(i->segments) == 0);
1139 
1140     pa_mutex_unlock(i->mutex);
1141 
1142     pa_mutex_lock(i->pool->mutex);
1143 
1144     /* If we've exported this block further we need to revoke that export */
1145     for (e = i->pool->exports; e; e = e->next)
1146         memexport_revoke_blocks(e, i);
1147 
1148     PA_LLIST_REMOVE(pa_memimport, i->pool->imports, i);
1149 
1150     pa_mutex_unlock(i->pool->mutex);
1151 
1152     pa_mempool_unref(i->pool);
1153     pa_hashmap_free(i->blocks);
1154     pa_hashmap_free(i->segments);
1155 
1156     pa_mutex_free(i->mutex);
1157 
1158     pa_xfree(i);
1159 }
1160 
1161 /* Create a new memimport's memfd segment entry, with passed SHM ID
1162  * as key and the newly-created segment (with its mmap()-ed memfd
1163  * memory region) as its value.
1164  *
1165  * Note! check comments at 'pa_shm->fd', 'segment_is_permanent()',
1166  * and 'pa_pstream_register_memfd_mempool()' for further details.
1167  *
1168  * Caller owns passed @memfd_fd and must close it down when appropriate. */
pa_memimport_attach_memfd(pa_memimport *i, uint32_t shm_id, int memfd_fd, bool writable)1169 int pa_memimport_attach_memfd(pa_memimport *i, uint32_t shm_id, int memfd_fd, bool writable) {
1170     pa_memimport_segment *seg;
1171     int ret = -1;
1172 
1173     pa_assert(i);
1174     pa_assert(memfd_fd != -1);
1175 
1176     pa_mutex_lock(i->mutex);
1177 
1178     if (!(seg = segment_attach(i, PA_MEM_TYPE_SHARED_MEMFD, shm_id, memfd_fd, writable)))
1179         goto finish;
1180 
1181     /* n_blocks acts as a segment reference count. To avoid the segment
1182      * being deleted when receiving silent memchunks, etc., mark our
1183      * permanent presence by incrementing that refcount. */
1184     seg->n_blocks++;
1185 
1186     pa_assert(segment_is_permanent(seg));
1187     ret = 0;
1188 
1189 finish:
1190     pa_mutex_unlock(i->mutex);
1191     return ret;
1192 }
1193 
1194 /* Self-locked */
pa_memimport_get(pa_memimport *i, pa_mem_type_t type, uint32_t block_id, uint32_t shm_id, size_t offset, size_t size, bool writable)1195 pa_memblock* pa_memimport_get(pa_memimport *i, pa_mem_type_t type, uint32_t block_id, uint32_t shm_id,
1196                               size_t offset, size_t size, bool writable) {
1197     pa_memblock *b = NULL;
1198     pa_memimport_segment *seg;
1199 
1200     pa_assert(i);
1201     pa_assert(pa_mem_type_is_shared(type));
1202 
1203     pa_mutex_lock(i->mutex);
1204 
1205     if ((b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(block_id)))) {
1206         pa_memblock_ref(b);
1207         goto finish;
1208     }
1209 
1210     if (pa_hashmap_size(i->blocks) >= PA_MEMIMPORT_SLOTS_MAX)
1211         goto finish;
1212 
1213     if (!(seg = pa_hashmap_get(i->segments, PA_UINT32_TO_PTR(shm_id)))) {
1214         if (type == PA_MEM_TYPE_SHARED_MEMFD) {
1215             pa_log_error("Bailing out! No cached memimport segment for memfd ID %u", shm_id);
1216             pa_log_error("Did the other PA endpoint forget registering its memfd pool?");
1217             goto finish;
1218         }
1219 
1220         pa_assert(type == PA_MEM_TYPE_SHARED_POSIX);
1221         if (!(seg = segment_attach(i, type, shm_id, -1, writable)))
1222             goto finish;
1223     }
1224 
1225     if (writable && !seg->writable) {
1226         pa_log_error("Cannot import cached segment in write mode - previously mapped as read-only");
1227         goto finish;
1228     }
1229 
1230     if (offset+size > seg->memory.size)
1231         goto finish;
1232 
1233     if (!(b = pa_flist_pop(PA_STATIC_FLIST_GET(unused_memblocks))))
1234         b = pa_xnew(pa_memblock, 1);
1235 
1236     PA_REFCNT_INIT(b);
1237     b->pool = i->pool;
1238     pa_mempool_ref(b->pool);
1239     b->type = PA_MEMBLOCK_IMPORTED;
1240     b->read_only = !writable;
1241     b->is_silence = false;
1242     pa_atomic_ptr_store(&b->data, (uint8_t*) seg->memory.ptr + offset);
1243     b->length = size;
1244     pa_atomic_store(&b->n_acquired, 0);
1245     pa_atomic_store(&b->please_signal, 0);
1246     b->per_type.imported.id = block_id;
1247     b->per_type.imported.segment = seg;
1248 
1249     pa_hashmap_put(i->blocks, PA_UINT32_TO_PTR(block_id), b);
1250 
1251     seg->n_blocks++;
1252 
1253     stat_add(b);
1254 
1255 finish:
1256     pa_mutex_unlock(i->mutex);
1257 
1258     return b;
1259 }
1260 
pa_memimport_process_revoke(pa_memimport *i, uint32_t id)1261 int pa_memimport_process_revoke(pa_memimport *i, uint32_t id) {
1262     pa_memblock *b;
1263     int ret = 0;
1264     pa_assert(i);
1265 
1266     pa_mutex_lock(i->mutex);
1267 
1268     if (!(b = pa_hashmap_get(i->blocks, PA_UINT32_TO_PTR(id)))) {
1269         ret = -1;
1270         goto finish;
1271     }
1272 
1273     memblock_replace_import(b);
1274 
1275 finish:
1276     pa_mutex_unlock(i->mutex);
1277 
1278     return ret;
1279 }
1280 
1281 /* For sending blocks to other nodes */
pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata)1282 pa_memexport* pa_memexport_new(pa_mempool *p, pa_memexport_revoke_cb_t cb, void *userdata) {
1283     pa_memexport *e;
1284 
1285     static pa_atomic_t export_baseidx = PA_ATOMIC_INIT(0);
1286 
1287     pa_assert(p);
1288     pa_assert(cb);
1289 
1290     if (!pa_mempool_is_shared(p))
1291         return NULL;
1292 
1293     e = pa_xnew(pa_memexport, 1);
1294     e->mutex = pa_mutex_new(true, true);
1295     e->pool = p;
1296     pa_mempool_ref(e->pool);
1297     PA_LLIST_HEAD_INIT(struct memexport_slot, e->free_slots);
1298     PA_LLIST_HEAD_INIT(struct memexport_slot, e->used_slots);
1299     e->n_init = 0;
1300     e->revoke_cb = cb;
1301     e->userdata = userdata;
1302 
1303     pa_mutex_lock(p->mutex);
1304 
1305     PA_LLIST_PREPEND(pa_memexport, p->exports, e);
1306     e->baseidx = (uint32_t) pa_atomic_add(&export_baseidx, PA_MEMEXPORT_SLOTS_MAX);
1307 
1308     pa_mutex_unlock(p->mutex);
1309     return e;
1310 }
1311 
pa_memexport_free(pa_memexport *e)1312 void pa_memexport_free(pa_memexport *e) {
1313     pa_assert(e);
1314 
1315     pa_mutex_lock(e->mutex);
1316     while (e->used_slots)
1317         pa_memexport_process_release(e, (uint32_t) (e->used_slots - e->slots + e->baseidx));
1318     pa_mutex_unlock(e->mutex);
1319 
1320     pa_mutex_lock(e->pool->mutex);
1321     PA_LLIST_REMOVE(pa_memexport, e->pool->exports, e);
1322     pa_mutex_unlock(e->pool->mutex);
1323 
1324     pa_mempool_unref(e->pool);
1325     pa_mutex_free(e->mutex);
1326     pa_xfree(e);
1327 }
1328 
1329 /* Self-locked */
pa_memexport_process_release(pa_memexport *e, uint32_t id)1330 int pa_memexport_process_release(pa_memexport *e, uint32_t id) {
1331     pa_memblock *b;
1332 
1333     pa_assert(e);
1334 
1335     pa_mutex_lock(e->mutex);
1336 
1337     if (id < e->baseidx)
1338         goto fail;
1339     id -= e->baseidx;
1340 
1341     if (id >= e->n_init)
1342         goto fail;
1343 
1344     if (!e->slots[id].block)
1345         goto fail;
1346 
1347     b = e->slots[id].block;
1348     e->slots[id].block = NULL;
1349 
1350     PA_LLIST_REMOVE(struct memexport_slot, e->used_slots, &e->slots[id]);
1351     PA_LLIST_PREPEND(struct memexport_slot, e->free_slots, &e->slots[id]);
1352 
1353     pa_mutex_unlock(e->mutex);
1354 
1355 /*     pa_log("Processing release for %u", id); */
1356 
1357     pa_assert(pa_atomic_load(&e->pool->stat.n_exported) > 0);
1358     pa_assert(pa_atomic_load(&e->pool->stat.exported_size) >= (int) b->length);
1359 
1360     pa_atomic_dec(&e->pool->stat.n_exported);
1361     pa_atomic_sub(&e->pool->stat.exported_size, (int) b->length);
1362 
1363     pa_memblock_unref(b);
1364 
1365     return 0;
1366 
1367 fail:
1368     pa_mutex_unlock(e->mutex);
1369 
1370     return -1;
1371 }
1372 
1373 /* Self-locked */
memexport_revoke_blocks(pa_memexport *e, pa_memimport *i)1374 static void memexport_revoke_blocks(pa_memexport *e, pa_memimport *i) {
1375     struct memexport_slot *slot, *next;
1376     pa_assert(e);
1377     pa_assert(i);
1378 
1379     pa_mutex_lock(e->mutex);
1380 
1381     for (slot = e->used_slots; slot; slot = next) {
1382         uint32_t idx;
1383         next = slot->next;
1384 
1385         if (slot->block->type != PA_MEMBLOCK_IMPORTED ||
1386             slot->block->per_type.imported.segment->import != i)
1387             continue;
1388 
1389         idx = (uint32_t) (slot - e->slots + e->baseidx);
1390         e->revoke_cb(e, idx, e->userdata);
1391         pa_memexport_process_release(e, idx);
1392     }
1393 
1394     pa_mutex_unlock(e->mutex);
1395 }
1396 
1397 /* No lock necessary */
memblock_shared_copy(pa_mempool *p, pa_memblock *b)1398 static pa_memblock *memblock_shared_copy(pa_mempool *p, pa_memblock *b) {
1399     pa_memblock *n;
1400 
1401     pa_assert(p);
1402     pa_assert(b);
1403 
1404     if (b->type == PA_MEMBLOCK_IMPORTED ||
1405         b->type == PA_MEMBLOCK_POOL ||
1406         b->type == PA_MEMBLOCK_POOL_EXTERNAL) {
1407         pa_assert(b->pool == p);
1408         return pa_memblock_ref(b);
1409     }
1410 
1411     if (!(n = pa_memblock_new_pool(p, b->length)))
1412         return NULL;
1413 
1414     memcpy(pa_atomic_ptr_load(&n->data), pa_atomic_ptr_load(&b->data), b->length);
1415     return n;
1416 }
1417 
1418 /* Self-locked */
pa_memexport_put(pa_memexport *e, pa_memblock *b, pa_mem_type_t *type, uint32_t *block_id, uint32_t *shm_id, size_t *offset, size_t * size)1419 int pa_memexport_put(pa_memexport *e, pa_memblock *b, pa_mem_type_t *type, uint32_t *block_id,
1420                      uint32_t *shm_id, size_t *offset, size_t * size) {
1421     pa_shm  *memory;
1422     struct memexport_slot *slot;
1423     void *data;
1424 
1425     pa_assert(e);
1426     pa_assert(b);
1427     pa_assert(type);
1428     pa_assert(block_id);
1429     pa_assert(shm_id);
1430     pa_assert(offset);
1431     pa_assert(size);
1432     pa_assert(b->pool == e->pool);
1433 
1434     if (!(b = memblock_shared_copy(e->pool, b)))
1435         return -1;
1436 
1437     pa_mutex_lock(e->mutex);
1438 
1439     if (e->free_slots) {
1440         slot = e->free_slots;
1441         PA_LLIST_REMOVE(struct memexport_slot, e->free_slots, slot);
1442     } else if (e->n_init < PA_MEMEXPORT_SLOTS_MAX)
1443         slot = &e->slots[e->n_init++];
1444     else {
1445         pa_mutex_unlock(e->mutex);
1446         pa_memblock_unref(b);
1447         return -1;
1448     }
1449 
1450     PA_LLIST_PREPEND(struct memexport_slot, e->used_slots, slot);
1451     slot->block = b;
1452     *block_id = (uint32_t) (slot - e->slots + e->baseidx);
1453 
1454     pa_mutex_unlock(e->mutex);
1455 /*     pa_log("Got block id %u", *block_id); */
1456 
1457     data = pa_memblock_acquire(b);
1458 
1459     if (b->type == PA_MEMBLOCK_IMPORTED) {
1460         pa_assert(b->per_type.imported.segment);
1461         memory = &b->per_type.imported.segment->memory;
1462     } else {
1463         pa_assert(b->type == PA_MEMBLOCK_POOL || b->type == PA_MEMBLOCK_POOL_EXTERNAL);
1464         pa_assert(b->pool);
1465         pa_assert(pa_mempool_is_shared(b->pool));
1466         memory = &b->pool->memory;
1467     }
1468 
1469     pa_assert(data >= memory->ptr);
1470     pa_assert((uint8_t*) data + b->length <= (uint8_t*) memory->ptr + memory->size);
1471 
1472     *type = memory->type;
1473     *shm_id = memory->id;
1474     *offset = (size_t) ((uint8_t*) data - (uint8_t*) memory->ptr);
1475     *size = b->length;
1476 
1477     pa_memblock_release(b);
1478 
1479     pa_atomic_inc(&e->pool->stat.n_exported);
1480     pa_atomic_add(&e->pool->stat.exported_size, (int) b->length);
1481 
1482     return 0;
1483 }
1484