00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #if !defined(IN_CONFIGURE) && !defined(WIN32)
00024 #include "postgres.h"
00025 #else
00026
00027 #ifndef bool
00028 typedef char bool;
00029 #endif
00030
00031 #ifndef true
00032 #define true ((bool) 1)
00033 #endif
00034
00035 #ifndef false
00036 #define false ((bool) 0)
00037 #endif
00038 #endif
00039
00040 #include <stdio.h>
00041 #include <stdlib.h>
00042 #include <unistd.h>
00043 #include <netdb.h>
00044 #include <sys/types.h>
00045 #include <pwd.h>
00046 #include <string.h>
00047 #include <fcntl.h>
00048 #include <errno.h>
00049
00050
00051 #ifdef __CYGWIN__
00052 #include <sys/param.h>
00053 #endif
00054
00055 #ifdef WIN32
00056 #define MAXHOSTNAMELEN 63
00057 #include <winsock2.h>
00058 #endif
00059
00060
00061
00062 #include <signal.h>
00063 int sigwait(const sigset_t *set, int *sig);
00064
00065
00066 #if !defined(ENABLE_THREAD_SAFETY) && !defined(IN_CONFIGURE) && !defined(WIN32)
00067 int
00068 main(int argc, char *argv[])
00069 {
00070 fprintf(stderr, "This PostgreSQL build does not support threads.\n");
00071 fprintf(stderr, "Perhaps rerun 'configure' using '--enable-thread-safety'.\n");
00072 return 1;
00073 }
00074 #else
00075
00076
00077 #include <pthread.h>
00078
00079 #define TEMP_FILENAME_1 "thread_test.1"
00080 #define TEMP_FILENAME_2 "thread_test.2"
00081
00082 static void func_call_1(void);
00083 static void func_call_2(void);
00084
00085 static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
00086
00087 static volatile int thread1_done = 0;
00088 static volatile int thread2_done = 0;
00089
00090 static volatile int errno1_set = 0;
00091 static volatile int errno2_set = 0;
00092
00093 #ifndef HAVE_STRERROR_R
00094 static char *strerror_p1;
00095 static char *strerror_p2;
00096 static bool strerror_threadsafe = false;
00097 #endif
00098
00099 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
00100 static struct passwd *passwd_p1;
00101 static struct passwd *passwd_p2;
00102 static bool getpwuid_threadsafe = false;
00103 #endif
00104
00105 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
00106 static struct hostent *hostent_p1;
00107 static struct hostent *hostent_p2;
00108 static char myhostname[MAXHOSTNAMELEN];
00109 static bool gethostbyname_threadsafe = false;
00110 #endif
00111
00112 static bool platform_is_threadsafe = true;
00113
00114 int
00115 main(int argc, char *argv[])
00116 {
00117 pthread_t thread1,
00118 thread2;
00119 int rc;
00120
00121 #ifdef WIN32
00122 WSADATA wsaData;
00123 int err;
00124 #endif
00125
00126 if (argc > 1)
00127 {
00128 fprintf(stderr, "Usage: %s\n", argv[0]);
00129 return 1;
00130 }
00131
00132 #ifdef IN_CONFIGURE
00133
00134 close(1);
00135 dup(5);
00136 #endif
00137
00138 #ifdef WIN32
00139 err = WSAStartup(MAKEWORD(1, 1), &wsaData);
00140 if (err != 0)
00141 {
00142 fprintf(stderr, "Cannot start the network subsystem - %d**\nexiting\n", err);
00143 exit(1);
00144 }
00145 #endif
00146
00147 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
00148 if (gethostname(myhostname, MAXHOSTNAMELEN) != 0)
00149 {
00150 fprintf(stderr, "Cannot get local hostname **\nexiting\n");
00151 exit(1);
00152 }
00153 #endif
00154
00155
00156 pthread_mutex_lock(&init_mutex);
00157
00158 rc = pthread_create(&thread1, NULL, (void *(*) (void *)) func_call_1, NULL);
00159 if (rc != 0)
00160 {
00161 fprintf(stderr, "Failed to create thread 1: %s **\nexiting\n",
00162 strerror(errno));
00163 exit(1);
00164 }
00165 rc = pthread_create(&thread2, NULL, (void *(*) (void *)) func_call_2, NULL);
00166 if (rc != 0)
00167 {
00168
00169
00170
00171
00172 fprintf(stderr, "Failed to create thread 2 **\nexiting\n");
00173 exit(1);
00174 }
00175
00176 while (thread1_done == 0 || thread2_done == 0)
00177 sched_yield();
00178
00179
00180
00181
00182 #ifdef WIN32
00183 printf("Your GetLastError() is thread-safe.\n");
00184 #else
00185 printf("Your errno is thread-safe.\n");
00186 #endif
00187
00188 #ifndef HAVE_STRERROR_R
00189 if (strerror_p1 != strerror_p2)
00190 strerror_threadsafe = true;
00191 #endif
00192
00193 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
00194 if (passwd_p1 != passwd_p2)
00195 getpwuid_threadsafe = true;
00196 #endif
00197
00198 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
00199 if (hostent_p1 != hostent_p2)
00200 gethostbyname_threadsafe = true;
00201 #endif
00202
00203
00204
00205 pthread_mutex_unlock(&init_mutex);
00206
00207 pthread_join(thread1, NULL);
00208 pthread_join(thread2, NULL);
00209
00210
00211
00212 #ifdef HAVE_STRERROR_R
00213 printf("Your system has sterror_r(); it does not need strerror().\n");
00214 #else
00215 printf("Your system uses strerror() which is ");
00216 if (strerror_threadsafe)
00217 printf("thread-safe.\n");
00218 else
00219 {
00220 printf("not thread-safe. **\n");
00221 platform_is_threadsafe = false;
00222 }
00223 #endif
00224
00225 #ifdef WIN32
00226 printf("getpwuid_r()/getpwuid() are not applicable to Win32 platforms.\n");
00227 #elif defined(HAVE_GETPWUID_R)
00228 printf("Your system has getpwuid_r(); it does not need getpwuid().\n");
00229 #else
00230 printf("Your system uses getpwuid() which is ");
00231 if (getpwuid_threadsafe)
00232 printf("thread-safe.\n");
00233 else
00234 {
00235 printf("not thread-safe. **\n");
00236 platform_is_threadsafe = false;
00237 }
00238 #endif
00239
00240 #ifdef HAVE_GETADDRINFO
00241 printf("Your system has getaddrinfo(); it does not need gethostbyname()\n"
00242 " or gethostbyname_r().\n");
00243 #elif defined(HAVE_GETHOSTBYNAME_R)
00244 printf("Your system has gethostbyname_r(); it does not need gethostbyname().\n");
00245 #else
00246 printf("Your system uses gethostbyname which is ");
00247 if (gethostbyname_threadsafe)
00248 printf("thread-safe.\n");
00249 else
00250 {
00251 printf("not thread-safe. **\n");
00252 platform_is_threadsafe = false;
00253 }
00254 #endif
00255
00256 if (platform_is_threadsafe)
00257 {
00258 printf("\nYour platform is thread-safe.\n");
00259 return 0;
00260 }
00261 else
00262 {
00263 printf("\n** YOUR PLATFORM IS NOT THREAD-SAFE. **\n");
00264 return 1;
00265 }
00266 }
00267
00268
00269
00270
00271 static void
00272 func_call_1(void)
00273 {
00274 #if !defined(HAVE_GETPWUID_R) || \
00275 (!defined(HAVE_GETADDRINFO) && \
00276 !defined(HAVE_GETHOSTBYNAME_R))
00277 void *p;
00278 #endif
00279 #ifdef WIN32
00280 HANDLE h1;
00281 #else
00282 int fd;
00283 #endif
00284
00285 unlink(TEMP_FILENAME_1);
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 #ifdef WIN32
00297 if ((h1 = CreateFile(TEMP_FILENAME_1, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, 0, NULL)) ==
00298 INVALID_HANDLE_VALUE)
00299 #else
00300 if ((fd = open(TEMP_FILENAME_1, O_RDWR | O_CREAT, 0600)) < 0)
00301 #endif
00302 {
00303 fprintf(stderr, "Could not create file %s in current directory\n",
00304 TEMP_FILENAME_1);
00305 exit(1);
00306 }
00307
00308 #ifdef WIN32
00309 if (CreateFile(TEMP_FILENAME_1, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL)
00310 != INVALID_HANDLE_VALUE)
00311 #else
00312 if (open(TEMP_FILENAME_1, O_RDWR | O_CREAT | O_EXCL, 0600) >= 0)
00313 #endif
00314 {
00315 fprintf(stderr,
00316 "Could not generate failure for exclusive file create of %s in current directory **\nexiting\n",
00317 TEMP_FILENAME_1);
00318 exit(1);
00319 }
00320
00321
00322
00323
00324
00325 errno1_set = 1;
00326 while (errno2_set == 0)
00327 sched_yield();
00328
00329 #ifdef WIN32
00330 if (GetLastError() != ERROR_FILE_EXISTS)
00331 #else
00332 if (errno != EEXIST)
00333 #endif
00334 {
00335 #ifdef WIN32
00336 fprintf(stderr, "GetLastError() not thread-safe **\nexiting\n");
00337 #else
00338 fprintf(stderr, "errno not thread-safe **\nexiting\n");
00339 #endif
00340 unlink(TEMP_FILENAME_1);
00341 exit(1);
00342 }
00343
00344 #ifdef WIN32
00345 CloseHandle(h1);
00346 #else
00347 close(fd);
00348 #endif
00349 unlink(TEMP_FILENAME_1);
00350
00351 #ifndef HAVE_STRERROR_R
00352
00353
00354
00355
00356
00357 strerror_p1 = strerror(EACCES);
00358 #endif
00359
00360 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
00361 passwd_p1 = getpwuid(0);
00362 p = getpwuid(1);
00363 if (passwd_p1 != p)
00364 {
00365 printf("Your getpwuid() changes the static memory area between calls\n");
00366 passwd_p1 = NULL;
00367 }
00368 #endif
00369
00370 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
00371
00372 hostent_p1 = gethostbyname(myhostname);
00373 p = gethostbyname("localhost");
00374 if (hostent_p1 != p)
00375 {
00376 printf("Your gethostbyname() changes the static memory area between calls\n");
00377 hostent_p1 = NULL;
00378 }
00379 #endif
00380
00381 thread1_done = 1;
00382 pthread_mutex_lock(&init_mutex);
00383 pthread_mutex_unlock(&init_mutex);
00384 }
00385
00386
00387
00388
00389
00390 static void
00391 func_call_2(void)
00392 {
00393 #if !defined(HAVE_GETPWUID_R) || \
00394 (!defined(HAVE_GETADDRINFO) && \
00395 !defined(HAVE_GETHOSTBYNAME_R))
00396 void *p;
00397 #endif
00398
00399 unlink(TEMP_FILENAME_2);
00400
00401
00402
00403
00404 if (unlink(TEMP_FILENAME_2) != -1)
00405 {
00406 fprintf(stderr,
00407 "Could not generate failure for unlink of %s in current directory **\nexiting\n",
00408 TEMP_FILENAME_2);
00409 exit(1);
00410 }
00411
00412
00413
00414
00415
00416 errno2_set = 1;
00417 while (errno1_set == 0)
00418 sched_yield();
00419
00420 #ifdef WIN32
00421 if (GetLastError() != ENOENT)
00422 #else
00423 if (errno != ENOENT)
00424 #endif
00425 {
00426 #ifdef WIN32
00427 fprintf(stderr, "GetLastError() not thread-safe **\nexiting\n");
00428 #else
00429 fprintf(stderr, "errno not thread-safe **\nexiting\n");
00430 #endif
00431 exit(1);
00432 }
00433
00434 #ifndef HAVE_STRERROR_R
00435
00436
00437
00438
00439
00440 strerror_p2 = strerror(EINVAL);
00441 #endif
00442
00443 #if !defined(WIN32) && !defined(HAVE_GETPWUID_R)
00444 passwd_p2 = getpwuid(2);
00445 p = getpwuid(3);
00446 if (passwd_p2 != p)
00447 {
00448 printf("Your getpwuid() changes the static memory area between calls\n");
00449 passwd_p2 = NULL;
00450 }
00451 #endif
00452
00453 #if !defined(HAVE_GETADDRINFO) && !defined(HAVE_GETHOSTBYNAME_R)
00454
00455 hostent_p2 = gethostbyname("localhost");
00456 p = gethostbyname(myhostname);
00457 if (hostent_p2 != p)
00458 {
00459 printf("Your gethostbyname() changes the static memory area between calls\n");
00460 hostent_p2 = NULL;
00461 }
00462 #endif
00463
00464 thread2_done = 1;
00465 pthread_mutex_lock(&init_mutex);
00466 pthread_mutex_unlock(&init_mutex);
00467 }
00468
00469 #endif