#include <dlfcn.h>
#include <atf-c++.hpp>
#include <cstdio>
#include <cstdlib>
#define AGAIN_CALL_LIMIT 20
static FILE *output = NULL;
static int again_counter = 0;
struct Foo {
Foo() { ATF_REQUIRE(fprintf(output, "Created\n") > 0); }
~Foo() { ATF_REQUIRE(fprintf(output, "Destroyed\n") > 0); }
void use() { ATF_REQUIRE(fprintf(output, "Used\n") > 0); }
};
static thread_local Foo f;
ATF_TEST_CASE_WITHOUT_HEAD(cxx__nothr);
ATF_TEST_CASE_BODY(cxx__nothr)
{
void *libthr_handle;
output = stderr;
libthr_handle = dlopen("libthr.so.3", RTLD_LAZY | RTLD_GLOBAL |
RTLD_NOLOAD);
ATF_REQUIRE(libthr_handle == NULL);
}
static void
check_local_main(void)
{
static const char out_log[] = "Created\nUsed\nDestroyed\n";
fflush(output);
ATF_REQUIRE(atf::utils::compare_file("test_main.txt", out_log));
}
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_main);
ATF_TEST_CASE_BODY(cxx__thread_local_main)
{
ATF_REQUIRE((output = fopen("test_main.txt", "w")) != NULL);
f.use();
atexit(check_local_main);
}
extern "C" int __cxa_thread_atexit(void (*)(void *), void *, void *);
static void
again(void *arg)
{
if (again_counter < AGAIN_CALL_LIMIT) {
again_counter++;
__cxa_thread_atexit(again, arg, &output);
}
}
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_inf_dtors);
ATF_TEST_CASE_BODY(cxx__thread_inf_dtors)
{
skip("Skip since we only have main thread");
again(NULL);
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, cxx__nothr);
ATF_ADD_TEST_CASE(tcs, cxx__thread_local_main);
ATF_ADD_TEST_CASE(tcs, cxx__thread_inf_dtors);
}