1 #define _GNU_SOURCE
2 
3 #include <assert.h>
4 #include <stdalign.h>
5 #include <stddef.h>
6 #include <stdio.h>
7 #include <stdint.h>
8 
9 #include <limits.h>
10 
11 #include "pthread.h"
12 
13 /* For _PDCLIB_time -> reconstructing struct _PDCLIB_timespec */
14 #include "_PDCLIB_config.h"
15 
16 #define symbol2string( x ) #x
17 #define value2string( x ) symbol2string( x )
18 
19 struct _PDCLIB_timespec
20 {
21     _PDCLIB_time_t tv_sec;
22     long tv_nsec;
23 };
24 
print_mutex(const char * define,pthread_mutex_t mutex)25 static void print_mutex( const char * define, pthread_mutex_t mutex )
26 {
27     printf( "%s { {", define );
28 
29     for ( size_t i = 0; i < sizeof( pthread_mutex_t ); ++i )
30     {
31         if ( i > 0 )
32         {
33             printf( "," );
34         }
35 
36         if ( !( i % 8 ) )
37         {
38             printf( "\\\n    " );
39         }
40 
41         printf( " 0x%02hhx", ( ( unsigned char * )&mutex )[i] );
42     }
43 
44     printf( " } }\n" );
45 }
46 
print_recursive_mutex_data(void)47 static int print_recursive_mutex_data( void )
48 {
49     pthread_mutexattr_t mutex_attr;
50 
51     if ( pthread_mutexattr_init( &mutex_attr ) == 0 )
52     {
53         if ( pthread_mutexattr_settype( &mutex_attr, PTHREAD_MUTEX_RECURSIVE ) == 0 )
54         {
55             pthread_mutex_t mutex;
56 
57             if ( pthread_mutex_init( &mutex, &mutex_attr ) == 0 )
58             {
59                 print_mutex( "#define _PDCLIB_MTX_RECURSIVE_INIT", mutex );
60                 pthread_mutexattr_destroy( &mutex_attr );
61                 return 1;
62             }
63         }
64     }
65 
66     return 0;
67 }
68 
print_plain_mutex_data(void)69 static int print_plain_mutex_data( void )
70 {
71     pthread_mutex_t mutex;
72 
73     if ( pthread_mutex_init( &mutex, NULL ) == 0 )
74     {
75         print_mutex( "#define _PDCLIB_MTX_PLAIN_INIT", mutex );
76         return 1;
77     }
78 
79     return 0;
80 }
81 
main(int argc,char * argv[])82 int main( int argc, char * argv[] )
83 {
84     pthread_cond_t      cond;
85     pthread_mutex_t     mutex;
86     pthread_condattr_t  cnd_attr;
87     pthread_mutexattr_t mtx_attr;
88     pthread_attr_t      thrd_attr;
89 
90     /* In interfacing 'our' threads.h functions with pthread, we assume
91        that 'our' struct timespec and the host system's struct timespec
92        can be safely cast to each other. So we check that the layout is
93        identical.
94        If these asserts fail, you need to find out what the platform uses
95        for struct timespec, and adjust the timespec definition here and
96        in PDCLib's _PDCLIB_config.h / time.h.
97     */
98     struct timespec ts;
99     struct _PDCLIB_timespec pts;
100 
101     assert( sizeof( ts.tv_sec ) == sizeof( pts.tv_sec ) );
102     assert( alignof( ts.tv_sec ) == alignof( pts.tv_sec ) );
103     assert( sizeof( ts.tv_nsec ) == sizeof( pts.tv_nsec ) );
104     assert( sizeof( struct timespec ) == sizeof( struct _PDCLIB_timespec ) );
105     assert( offsetof( struct timespec, tv_sec ) == offsetof( struct _PDCLIB_timespec, tv_sec ) );
106     assert( offsetof( struct timespec, tv_nsec ) == offsetof( struct _PDCLIB_timespec, tv_nsec ) );
107 
108     /* Similarly, we assume (in the threads/ files) that 'our' thrd_t can be
109        safely cast to pthread_t and back, mtx_t to pthread_mutex_t, cnd_t to
110        pthread_cond_t, tss_t to pthread_key_t, and once_flag to pthread_once_t.
111        What we assert here is that the types used by the platform's pthread
112        implementation are, indeed, the fundamental types assumed here.
113        (Which are then printed out for inclusion in _PDCLIB_config.h, so
114        that PDCLib's structures are compatible.)
115        If these assertions fail, you need to find out the fundamental types
116        used by the platform's pthread implementation (on my x86_64 machine
117        in /usr/include/x86_64-linux-gnu/bits/pthreadtypes.h), and adjust
118        both the assert() statements and the printf() statements accordingly.
119     */
120 
121     puts( "/* Use this in _PDCLIB_config.h, 'threads' section, for interfacing pthread.  */" );
122 
123     /* Thread */
124 #if defined( __CYGWIN__ )
125     assert( sizeof( pthread_t ) == sizeof( struct { char __dummy; } * ) );
126     printf( "typedef struct { char __dummy; } * _PDCLIB_thrd_t;\n" );
127 #elif defined( __ANDROID__ )
128     assert( sizeof( pthread_t ) == sizeof( long int ) );
129     printf( "typedef long int _PDCLIB_thrd_t;\n" );
130 #else
131     assert( sizeof( pthread_t ) == sizeof( unsigned long int ) );
132     printf( "typedef unsigned long int _PDCLIB_thrd_t;\n" );
133 #endif
134 
135     /* Condition */
136 #if defined( __CYGWIN__ )
137     assert( sizeof( pthread_cond_t ) == sizeof( struct { char __dummy; } * ) );
138     printf( "typedef struct { char __dummy; } * _PDCLIB_cnd_t;\n" );
139 #elif defined( __ANDROID__ )
140     assert( sizeof( pthread_cond_t ) == sizeof( struct { int32_t __dummy[12]; } ) );
141     printf( "typedef struct { int32_t __dummy[12]; } _PDCLIB_cnd_t;\n" );
142 #else
143     assert( sizeof( cond.__align ) == sizeof( long long int ) );
144     printf( "typedef union { unsigned char _PDCLIB_cnd_t_data[ %zd ]; long long int _PDCLIB_cnd_t_align; } _PDCLIB_cnd_t;\n", sizeof( pthread_cond_t ) );
145 #endif
146 
147     /* Mutex */
148 #if defined( __CYGWIN__ )
149     assert( sizeof( pthread_mutex_t ) == sizeof( struct { char __dummy; } * ) );
150     printf( "typedef struct { char __dummy; } * _PDCLIB_mtx_t;\n" );
151 #elif defined( __ANDROID__ )
152     assert( sizeof( pthread_mutex_t ) == sizeof( struct { int32_t __dummy[10]; } ) );
153     printf( "typedef struct { int32_t __dummy[10]; } _PDCLIB_mtx_t;\n" );
154 #else
155     assert( sizeof( mutex.__align ) == sizeof( long int ) );
156     printf( "typedef union { unsigned char _PDCLIB_mtx_t_data[ %zd ]; long int _PDCLIB_mtx_t_align; } _PDCLIB_mtx_t;\n", sizeof( pthread_mutex_t ) );
157 #endif
158 
159     /* Thread Specific Storage */
160 #if defined( __CYGWIN__ )
161     assert( sizeof( pthread_key_t ) == sizeof( struct { char __dummy; } * ) );
162     printf( "typedef struct { char __dummy; } * _PDCLIB_tss_t;\n" );
163 #elif defined( __ANDROID__ )
164     assert( sizeof( pthread_key_t ) == sizeof( int ) );
165     printf( "typedef int _PDCLIB_tss_t;\n" );
166 #else
167     assert( sizeof( pthread_key_t ) == sizeof( unsigned int ) );
168     printf( "typedef unsigned int _PDCLIB_tss_t;\n" );
169 #endif
170 
171     /* once_flag */
172 #ifdef __CYGWIN__
173     assert( sizeof( pthread_once_t ) == sizeof( struct { pthread_mutex_t __dummy1; int __dummy2; } ) );
174     printf( "typedef struct { _PDCLIB_mtx_t mutex; int state; } _PDCLIB_once_flag;\n" );
175 #else /* Both Linux and Android */
176     assert( sizeof( pthread_once_t ) == sizeof( int ) );
177     assert( alignof( pthread_once_t ) == alignof( int ) );
178     printf( "typedef int _PDCLIB_once_flag;\n" );
179 #endif
180 
181     /* once_flag init */
182 #if defined( __CYGWIN__ )
183     printf( "#define _PDCLIB_ONCE_FLAG_INIT { %s, 0 }\n", value2string( PTHREAD_MUTEX_INITIALIZER ) );
184 #else /* Both Linux and Android */
185     printf( "#define _PDCLIB_ONCE_FLAG_INIT %s\n", value2string( PTHREAD_ONCE_INIT ) );
186 #endif
187 
188 #if defined( __CYGWIN__ )
189     printf( "#define _PDCLIB_RECURSIVE_MUTEX_INIT %s\n", value2string( PTHREAD_MUTEX_INITIALIZER ) );
190 #else /* Both Linux and Android */
191     printf( "#define _PDCLIB_RECURSIVE_MUTEX_INIT %s\n", symbol2string( PTHREAD_MUTEX_INITIALIZER ) );
192 #endif
193 
194     /* _PDCLIB_TSS_DTOR_ITERATIONS */
195     printf( "/* This one is actually hidden in <limits.h>, and only if __USE_POSIX is      */\n"
196             "/* defined prior to #include <limits.h> (PTHREAD_DESTRUCTOR_ITERATIONS).      */\n"
197             "#define _PDCLIB_TSS_DTOR_ITERATIONS %d\n", PTHREAD_DESTRUCTOR_ITERATIONS );
198 
199     /* Pthread attibutes */
200 
201     printf( "/* The following are not made public in any header, but used internally for   */\n"
202             "/* interfacing with the pthread API.                                          */\n" );
203 
204 #if defined( __CYGWIN__ )
205     assert( sizeof( pthread_condattr_t ) == sizeof( struct { char __dummy; } * ) );
206     printf( "typedef struct { char __dummy; } * _PDCLIB_cnd_attr_t;\n" );
207 #elif defined( __ANDROID__ )
208     assert( sizeof( pthread_condattr_t ) == sizeof( long int ) );
209     printf( "typedef long int pthread_condattr_t;\n" );
210 #else
211     assert( sizeof( cnd_attr.__align ) == sizeof( int ) );
212     printf( "typedef union { unsigned char _PDCLIB_cnd_attr_t_data[ %zd ]; int _PDCLIB_cnd_attr_t_align; } _PDCLIB_cnd_attr_t;\n", sizeof( pthread_condattr_t ) );
213 #endif
214 
215 #if defined( __CYGWIN__ )
216     assert( sizeof( pthread_mutexattr_t ) == sizeof( struct { char __dummy; } * ) );
217     printf( "typedef struct { char __dummy; } * _PDCLIB_mtx_attr_t;\n" );
218 #elif defined( __ANDROID__ )
219     assert( sizeof( pthread_mutexattr_t ) == sizeof( long int ) );
220     printf( "typedef long int pthread_mutexattr_t;\n" );
221 #else
222     assert( sizeof( mtx_attr.__align ) == sizeof( int ) );
223     printf( "typedef union { unsigned char _PDCLIB_mtx_attr_t_data[ %zd ]; int _PDCLIB_mtx_attr_t_align; } _PDCLIB_mtx_attr_t;\n", sizeof( pthread_mutexattr_t ) );
224 #endif
225 
226 #if defined( __CYGWIN__ )
227     assert( sizeof( pthread_attr_t ) == sizeof( struct { char __dummy; } * ) );
228     printf( "typedef struct { char __dummy; } * _PDCLIB_thrd_attr_t;\n" );
229 #elif defined( __ANDROID__ )
230     assert( sizeof( pthread_attr_t ) == sizeof( struct { uint32_t __dummy1; void * __dummy2; size_t __dummy3; size_t __dummy4; int32_t __dummy5; int32_t __dummy6; char __dummy7[16]; } ) );
231     printf( "typedef struct { uint32_t flags; void * stack_base; size_t stack_size; size_t guard_size; int32_t sched_policy; int32_t sched_priority; char reserved[16]; } _PDCLIB_thrd_attr_t;\n" );
232 #else
233     assert( sizeof( thrd_attr.__align ) == sizeof( long int ) );
234     printf( "typedef union { unsigned char _PDCLIB_thrd_attr_t_data[ %zd ]; long int _PDCLIB_thrd_attr_t_align; } _PDCLIB_thrd_attr_t;\n", sizeof( pthread_attr_t ) );
235 #endif
236 
237     printf( "/* Static initialization of recursive mutex.                                  */\n" );
238     print_recursive_mutex_data();
239 
240     printf( "/* Static initialization of plain / timeout mutex (identical with pthread).   */\n" );
241     print_plain_mutex_data();
242 }
243