libs-base/config/config.initialize.m
rfm ab4587dbcf use volatile variables
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@32482 72102866-910b-0410-8b05-ffd578937521
2011-03-07 10:47:04 +00:00

110 lines
1.9 KiB
Objective-C

/* Test whether Objective-C runtime +initialize support is thread-safe
*/
#include "objc-common.g"
#include <pthread.h>
#include <stdio.h>
#if defined(_WIN32)
# define mySleep(X) usleep(1000*(X))
#else
# define mySleep(X) sleep(X)
#endif
/* Use volatile variables so compiler optimisation won't prevent one thread
* from seeing changes made by another.
*/
static volatile unsigned initialize_entered = 0;
static volatile unsigned initialize_exited = 0;
static volatile unsigned class_entered = 0;
static volatile BOOL may_proceed = NO;
@interface MyClass : NSObject
@end
@implementation MyClass
+ (void) initialize
{
initialize_entered++;
while (NO == may_proceed)
;
initialize_exited++;
}
+ (Class) class
{
class_entered++;
return self;
}
@end
static void *
test(void *arg)
{
[MyClass class];
return 0;
}
int
main()
{
pthread_t t1;
pthread_t t2;
unsigned counter;
if (0 == pthread_create(&t1, 0, test, 0))
{
for (counter = 0; 0 == initialize_entered && counter < 5; counter++)
{
mySleep(1);
}
if (0 == initialize_entered)
{
fprintf(stderr, "Failed to initialize\n");
return 1;
}
if (0 == pthread_create(&t2, 0, test, 0))
{
/* Wait long enough for t2 to try calling +class
*/
mySleep(1);
if (class_entered > 0)
{
fprintf(stderr, "class entered prematurely\n");
return 1;
}
/* Let t1 proceed and wait long enough for it to complete
* +initialize and for both threads to call +class
*/
may_proceed = YES;
for (counter = 0; 2 > class_entered && counter < 5; counter++)
{
mySleep(1);
}
if (2 == class_entered)
{
return 0; // OK
}
fprintf(stderr, "problem with initialize\n");
return 1;
}
else
{
fprintf(stderr, "failed to create t2\n");
return 1;
}
}
else
{
fprintf(stderr, "failed to create t1\n");
return 1;
}
}