[pulseaudio-discuss] Allowing anonymous structs and unions

Ahmed S. Darwish darwish.07 at gmail.com
Wed Sep 23 01:34:06 PDT 2015


Hi everyone,

On Wed, Sep 23, 2015 at 02:27:55AM -0400, Alexander E. Patrakov wrote:
> On 09/23/2015 02:12 AM, Tanu Kaskinen wrote:
> >Hi all,
> >
> >We haven't been using anonymous structs and unions so far, because
> >they've been non-standard in the past. C11 added support for them,
> >however. GCC has supported them longer than that, I don't know about
> >other compilers. Anonymous structs and unions are nice, and I think we
> >should start allowing them. Any objections?
> 
> I think it would be a good idea to send one small example patch that makes a
> use of them, just to demonstrate where exactly in PulseAudio they would make
> the code more elegant.
>

Sure, this pattern is used heavily in the memfd patches :-)

### Anonymous unions

Used to provide the mempool with polymorphic memory region access
regardless of the type of memory used:

    union {
        pa_mem mem;
        union {
            pa_shm shm;
            pa_memfd memfd;
            pa_privatemem privatemem;
        } per_type;
    };

This way, a lot of the mempools code can transparently access its
backend memory by using `mempool->mem.ptr' and `mempool->mem.size`.

This also saves us from polluting the mempool memblock.c code with
a huge number of switch cases ;-)

### Anonymous structs

They are also used in the memfd patches, but they're really used
to minimize code repetitions and make relationships explicit.

Basically, we want to build an inheritance relationship: pa_shm,
pa_memfd, and pa_privatemem has the common parent pa_mem. We also
want to make this relationship explicit since it's at the core of
the anonymous polymorphic union mentioned above.

To do so without introducing extra (compile-time) dereferences,
the following patten is used:

/* Parent anonymous structure representing a plain memory
 * area and its size. Different structures inherit from this,
 * representing different memory area types (e.g. Posix SHM,
 * Linux memfds, or private mallocs).
 *
 * To inherit from this object, just include PA_MEM_STRUCT as
 * the very first element of your structure definition. */
#define PA_MEM_STRUCT struct {   \
    void *ptr;                   \
    size_t size;                 \
} PA_GCC_PACKED

typedef struct pa_mem {
    PA_MEM_STRUCT;
} pa_mem;

This way, children pa_shm, pa_memfd, and pa_privatemem can be
defined as follows:

typedef struct pa_shm {
    PA_MEM_STRUCT;
    unsigned id;
    bool do_unlink;
} pa_shm;

typedef struct pa_memfd {
    PA_MEM_STRUCT;
    int fd;
} pa_memfd;

typedef struct pa_privatemem {
    PA_MEM_STRUCT;
} pa_privatemem;

..

So to summarize, such annotation explicitly shows the inheritance
relationship, minimize code repeition in the struct defintions, and
also saves us an extra compile-time dereference in shm.c, memfd.c,
and privatemem.c code. It also really works in tandem with the
earlier polymorphic union:

    union {
        pa_mem mem;
        union {
            pa_shm shm;
            pa_memfd memfd;
            pa_privatemem privatemem;
        } per_type;
    };

Hopefully these patterns will be OK from your side :-)

Regards,

-- 
Darwish
http://darwish.chasingpointers.com


More information about the pulseaudio-discuss mailing list