2011-03-05 13:11:47 +00:00
|
|
|
/* Test whether Objective-C runtime +initialize support is thread-safe
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "objc-common.g"
|
|
|
|
#include <pthread.h>
|
2011-03-06 11:53:57 +00:00
|
|
|
#include <stdio.h>
|
2011-03-05 14:47:58 +00:00
|
|
|
|
|
|
|
#if defined(_WIN32)
|
2011-03-06 13:00:46 +00:00
|
|
|
# define mySleep(X) usleep(1000*(X))
|
2011-03-05 14:47:58 +00:00
|
|
|
#else
|
2011-03-06 13:00:46 +00:00
|
|
|
# define mySleep(X) sleep(X)
|
2011-03-05 14:47:58 +00:00
|
|
|
#endif
|
|
|
|
|
2011-03-05 13:11:47 +00:00
|
|
|
static unsigned initialize_entered = 0;
|
|
|
|
static unsigned initialize_exited = 0;
|
|
|
|
static unsigned class_entered = 0;
|
|
|
|
static BOOL may_proceed = NO;
|
|
|
|
|
|
|
|
@interface MyClass : NSObject
|
|
|
|
@end
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-05 13:11:47 +00:00
|
|
|
@implementation MyClass
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-05 13:11:47 +00:00
|
|
|
+ (void) initialize
|
|
|
|
{
|
|
|
|
initialize_entered++;
|
|
|
|
while (NO == may_proceed)
|
2011-03-06 13:00:46 +00:00
|
|
|
;
|
2011-03-05 13:11:47 +00:00
|
|
|
initialize_exited++;
|
|
|
|
}
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-05 13:11:47 +00:00
|
|
|
+ (Class) class
|
|
|
|
{
|
|
|
|
class_entered++;
|
|
|
|
return self;
|
|
|
|
}
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-05 13:11:47 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
static void test(void *arg)
|
|
|
|
{
|
|
|
|
[MyClass class];
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main()
|
|
|
|
{
|
2011-03-06 11:53:57 +00:00
|
|
|
pthread_t t1;
|
|
|
|
pthread_t t2;
|
|
|
|
unsigned counter = 0;
|
2011-03-05 13:11:47 +00:00
|
|
|
|
|
|
|
if (0 == pthread_create(&t1, 0, test, 0))
|
|
|
|
{
|
|
|
|
while (0 == initialize_entered && counter++ < 3)
|
2011-03-06 13:00:46 +00:00
|
|
|
{
|
|
|
|
mySleep(1);
|
|
|
|
}
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-05 13:11:47 +00:00
|
|
|
if (0 == initialize_entered)
|
2011-03-06 13:00:46 +00:00
|
|
|
{
|
|
|
|
fprintf(stderr, "Failed to initialize\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2011-03-06 11:53:57 +00:00
|
|
|
|
|
|
|
if (0 == pthread_create(&t2, 0, test, 0))
|
|
|
|
{
|
2011-03-06 13:00:46 +00:00
|
|
|
/* Wait long enough for t2 to try calling +class
|
|
|
|
*/
|
|
|
|
mySleep(1);
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-06 13:00:46 +00:00
|
|
|
if (class_entered > 0)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "class entered prematurely\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-06 13:00:46 +00:00
|
|
|
/* Let t1 proceed and wait long enough for it to complete
|
|
|
|
* +initialize and for both threads to call +class
|
|
|
|
*/
|
|
|
|
may_proceed = YES;
|
|
|
|
mySleep(1);
|
2011-03-06 11:53:57 +00:00
|
|
|
|
2011-03-06 13:00:46 +00:00
|
|
|
if (2 == class_entered)
|
2011-03-06 11:53:57 +00:00
|
|
|
{
|
2011-03-06 13:00:46 +00:00
|
|
|
return 0; // OK
|
2011-03-06 11:53:57 +00:00
|
|
|
}
|
2011-03-06 13:00:46 +00:00
|
|
|
fprintf(stderr, "problem with initialize\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to create t2\n");
|
|
|
|
return 1;
|
|
|
|
}
|
2011-03-05 13:11:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fprintf(stderr, "failed to create t1\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|