I was reading the header files of the pthreads library and found this particular definition of the mutex (and other types) in bits/pthreadtypes.h:
typedef union
{
struct __pthread_mutex_s
{
int __lock;
unsigned int __count;
int __owner;
/* KIND must stay at this position in the structure to maintain
binary compatibility. */
int __kind;
unsigned int __nusers;
__extension__ union
{
int __spins;
__pthread_slist_t __list;
};
} __data;
char __size[__SIZEOF_PTHREAD_MUTEX_T];
long int __align;
} pthread_mutex_t;
It's not exactly like this but I've simplified it for clarity. Creating a struct with two different definitions in the header and in the implementation file, being the implementation the real struct definition and the header just a character buffer of the size of the real struct, is used as a technique to hide the implementation (opaque type) but still allocate the correct amount of memory when calling malloc or allocating an object in the stack.
This particular implementation is using a union and still exposing both the definition of the struct and the character buffer, but doesn't seem to provide any benefits in terms of hiding the type as the struct is still exposed and the binary compatibility is still dependent on the structures being unchanged.
My take is that __size
and __align
fields specify (guess what :-) ) the size and alignment of the structure independently of the __data
structure. So, the data can be of a less size and have less alignment requirements, it can be modified freely without breaking these basic assumptions about it. And vice-versa, these basic characteristics can be changed without altering the data structure, like here.
It is important to note that if the size of the __data
becomes bigger than specified by __SIZEOF_PTHREAD_MUTEX_T
, an assertion fails in __pthread_mutex_init()
:
assert (sizeof (pthread_mutex_t) <= __SIZEOF_PTHREAD_MUTEX_T);
Consider this assertion as an essential part of this approach.
So, the conclusion is that this was done not to hide the implementation details, but to make the data structure more predictable and manageable. It is very important for a widely-used library which should care a lot about backward compatibility and performance impact to other codes from the changes which can be made to this structure.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With