#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <assert.h>
#include <unistd.h>
#include <TargetConditionals.h>
#include "test_support.h"
static pthread_t sMainThread;
static pthread_t sWorker1;
static pthread_t sWorker2;
static bool sMainThreadInitialized = false;
static bool sWorker1Initialized = false;
static bool sWorker2Initialized = false;
static bool sMainThreadFinalized = false;
static bool sWorker1Finalized = false;
static bool sWorker2Finalized = false;
struct Struct {
Struct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
sInitializer = true;
}
~Struct() {
sFinalizer = true;
}
bool& getInitializer() {
if (pthread_equal(pthread_self(), sMainThread)) {
return sMainThreadInitialized;
}
if (pthread_equal(pthread_self(), sWorker1)) {
return sWorker1Initialized;
}
if (pthread_equal(pthread_self(), sWorker2)) {
return sWorker2Initialized;
}
assert(false);
}
bool& getFinalizer() {
if (pthread_equal(pthread_self(), sMainThread)) {
return sMainThreadFinalized;
}
if (pthread_equal(pthread_self(), sWorker1)) {
return sWorker1Finalized;
}
if (pthread_equal(pthread_self(), sWorker2)) {
return sWorker2Finalized;
}
assert(false);
}
void doWork() {
}
bool& sInitializer;
bool& sFinalizer;
};
static thread_local Struct s;
static bool sMainThreadInitialized_Another = false;
static bool sWorker1Initialized_Another = false;
static bool sWorker2Initialized_Another = false;
static bool sMainThreadFinalized_Another = false;
static bool sWorker1Finalized_Another = false;
static bool sWorker2Finalized_Another = false;
struct AnotherStruct {
AnotherStruct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
sInitializer = true;
}
~AnotherStruct() {
sFinalizer = true;
}
bool& getInitializer() {
if (pthread_equal(pthread_self(), sMainThread)) {
return sMainThreadInitialized_Another;
}
if (pthread_equal(pthread_self(), sWorker1)) {
return sWorker1Initialized_Another;
}
if (pthread_equal(pthread_self(), sWorker2)) {
return sWorker2Initialized_Another;
}
assert(false);
}
bool& getFinalizer() {
if (pthread_equal(pthread_self(), sMainThread)) {
return sMainThreadFinalized_Another;
}
if (pthread_equal(pthread_self(), sWorker1)) {
return sWorker1Finalized_Another;
}
if (pthread_equal(pthread_self(), sWorker2)) {
return sWorker2Finalized_Another;
}
assert(false);
}
void doWork() {
}
bool& sInitializer;
bool& sFinalizer;
};
static thread_local AnotherStruct sAnotherStruct;
static void* work2(void* arg)
{
s.doWork();
return NULL;
}
static void* work1(void* arg)
{
s.doWork();
if ( pthread_create(&sWorker2, NULL, work2, NULL) != 0 ) {
FAIL("pthread_create");
}
void* dummy;
pthread_join(sWorker2, &dummy);
return NULL;
}
bool passedChecksInMain = false;
void checkMainThreadFinalizer() {
if ( !passedChecksInMain )
return;
#if TARGET_OS_OSX
bool shouldFinalize = true;
#else
bool shouldFinalize = false;
#endif
if ( sMainThreadFinalized != shouldFinalize )
FAIL("Main thread finalisation not as expected");
else if ( sMainThreadFinalized_Another != shouldFinalize )
FAIL("Main thread other struct finalisation not as expected");
else
PASS("Success");
}
int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
sMainThread = pthread_self();
s.doWork();
sAnotherStruct.doWork();
atexit(&checkMainThreadFinalizer);
if ( pthread_create(&sWorker1, NULL, work1, NULL) != 0 ) {
FAIL("pthread_create");
}
void* dummy;
pthread_join(sWorker1, &dummy);
if ( !sMainThreadInitialized )
FAIL("Main thread was not initialized");
else if ( !sWorker1Initialized )
FAIL("Thread 1 was not initialized");
else if ( !sWorker2Initialized )
FAIL("Thread 2 was not initialized");
else if ( !sWorker1Finalized )
FAIL("Thread 1 was not finalised");
else if ( !sWorker2Finalized )
FAIL("Thread 2 was not finalised");
else if ( !sMainThreadInitialized_Another )
FAIL("Main thread other variable was not initialized");
else if ( !sWorker1Initialized_Another )
FAIL("Thread 1 other variable was not initialized");
else if ( !sWorker2Initialized_Another )
FAIL("Thread 2 other variable was not initialized");
else if ( !sWorker1Finalized_Another )
FAIL("Thread 1 other variable was not finalised");
else if ( !sWorker2Finalized_Another )
FAIL("Thread 2 other variable was not finalised");
else
passedChecksInMain = true;
return 0;
}