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