126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner/* This program is used to test that one-time-construction
226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner * works correctly, even in the presence of several threads.
326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner */
426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner#include <new>
626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner#include <pthread.h>
726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner#include <stdio.h>
826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner#define MAX_THREADS 100
1026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
1126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerclass Foo {
1226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerpublic:
1326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    Foo() { mValue++; }
1426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    int getValue() { return mValue; }
1526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerprivate:
1626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    static int  mValue;
1726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner};
1826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
1926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerint Foo::mValue;
2026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
2126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerstatic Foo*  getInstance(void)
2226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner{
2326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    // This construct forces the static creation of _instance
2426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    // the first time that getInstance() is called, in a thread-safe
2526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    // way.
2626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    static Foo  _instance;
2726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    return &_instance;
2826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner}
2926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
3026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerstatic Foo*       sInstances[MAX_THREADS];
3126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerstatic pthread_t  sThreads[MAX_THREADS];
3226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
3326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerstatic void* thread_run(void* arg)
3426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner{
35638f6c2e430b6a10513b088a0e3a379950051c4aWenHan Gu    int index = (int)(intptr_t)arg;
3626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    sInstances[index] = getInstance();
3726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    return NULL;
3826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner}
3926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
4026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turnerint main(void)
4126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner{
4226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    /* Create all the threads */
4326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    for (int nn = 0; nn < MAX_THREADS; nn++) {
4426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        pthread_create( &sThreads[nn], NULL, thread_run, reinterpret_cast<void*>(nn) );
4526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    }
4626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    /* Wait for their completion */
4726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    for (int nn = 0; nn < MAX_THREADS; nn++) {
4826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        void* dummy;
4926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        pthread_join( sThreads[nn], &dummy );
5026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    }
5126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    /* Get the instance */
5226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    Foo*  foo = getInstance();
5326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
5426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    if (foo == NULL) {
5526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        fprintf(stderr, "ERROR: Foo instance is NULL!\n");
5626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        return 1;
5726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    }
5826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
5926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    if (foo->getValue() != 1) {
6026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        fprintf(stderr, "ERROR: Foo constructor called %d times (1 expected)\n",
6126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner                foo->getValue());
6226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        return 2;
6326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    }
6426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
6526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    int count = 0;
6626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    for (int nn = 0; nn < MAX_THREADS; nn++) {
6726cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        if (sInstances[nn] != foo)
6826cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner            count++;
6926cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    }
7026cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner
7126cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    if (count != 0) {
7226cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        fprintf(stderr, "ERROR: There are %d invalid instance pointers!\n", count);
7326cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner        return 3;
7426cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    }
7526cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner    return 0;
7626cc9e3109d9df4dd7726edcb02982c26c207d20David 'Digit' Turner}
77