1/* This program is used to test that one-time-construction
2 * works correctly, even in the presence of several threads.
3 */
4
5#include <new>
6#include <pthread.h>
7#include <stdio.h>
8
9#define MAX_THREADS 100
10
11class Foo {
12public:
13    Foo() { mValue++; }
14    int getValue() { return mValue; }
15private:
16    static int  mValue;
17};
18
19int Foo::mValue;
20
21static Foo*  getInstance(void)
22{
23    // This construct forces the static creation of _instance
24    // the first time that getInstance() is called, in a thread-safe
25    // way.
26    static Foo  _instance;
27    return &_instance;
28}
29
30static Foo*       sInstances[MAX_THREADS];
31static pthread_t  sThreads[MAX_THREADS];
32
33static void* thread_run(void* arg)
34{
35    int index = reinterpret_cast<int>(arg);
36    sInstances[index] = getInstance();
37    return NULL;
38}
39
40int main(void)
41{
42    /* Create all the threads */
43    for (int nn = 0; nn < MAX_THREADS; nn++) {
44        pthread_create( &sThreads[nn], NULL, thread_run, reinterpret_cast<void*>(nn) );
45    }
46    /* Wait for their completion */
47    for (int nn = 0; nn < MAX_THREADS; nn++) {
48        void* dummy;
49        pthread_join( sThreads[nn], &dummy );
50    }
51    /* Get the instance */
52    Foo*  foo = getInstance();
53
54    if (foo == NULL) {
55        fprintf(stderr, "ERROR: Foo instance is NULL!\n");
56        return 1;
57    }
58
59    if (foo->getValue() != 1) {
60        fprintf(stderr, "ERROR: Foo constructor called %d times (1 expected)\n",
61                foo->getValue());
62        return 2;
63    }
64
65    int count = 0;
66    for (int nn = 0; nn < MAX_THREADS; nn++) {
67        if (sInstances[nn] != foo)
68            count++;
69    }
70
71    if (count != 0) {
72        fprintf(stderr, "ERROR: There are %d invalid instance pointers!\n", count);
73        return 3;
74    }
75    return 0;
76}
77