int main(int argc, char *argv[]) {

    int test = argc > 1 ? atoi(argv[1]) : 0;
    int verbose = argc > 2;
    int veryVerbose = argc > 3;
    int veryVeryVerbose = argc > 4;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;

    switch (test) { case 0:
    case 7: {
        // --------------------------------------------------------------------
        // TESTING CONCURRENT SEMAPHORE CREATION
        //
        // Concerns:
        // 1. On Darwin the creation of the semaphore object is synchronized
        //    because it's implemented via named semaphores.  Concurrent
        //    creation of multiple semaphores should not lead to invalid
        //    semaphore objects or deadlock.
        //
        // Plan:
        // 1. In multiple threads, create a number of semaphore objects and
        //    verify that they are valid.
        // --------------------------------------------------------------------

        if (verbose) cout << "Testing concurrent creation\n"
                          << "===========================\n";

        vector<bslmt::ThreadUtil::Handle> threads(16);

        for (int i = 0; i != threads.size(); ++i) {
            int rc = bslmt::ThreadUtil::create(&threads[i],
                                              &createSemaphoresWorker,
                                              NULL);
            ASSERT(rc == 0);
        }

        for (int i = 0; i != threads.size(); ++i) {
            bslmt::ThreadUtil::join(threads[i]);
        }

    } break;
      case 6: {
        // --------------------------------------------------------------------
        // TESTING MULTIPLE POST
        //
        // Concern: that 'post(n)' for large n works properly.  Two test modes:
        // when threads are not waiting, and when they are concurrently
        // waiting.
        // --------------------------------------------------------------------
        enum {
            k_NUM_POST = 1048704,
            k_NUM_WAIT_THREADS = 8
        };

        BSLMF_ASSERT(0 == k_NUM_POST % k_NUM_WAIT_THREADS);

        Obj sem(0);

        bslmt::ThreadUtil::Handle threads[k_NUM_WAIT_THREADS];
        MyBarrier barrier(k_NUM_WAIT_THREADS+1);

        struct ThreadInfo4 info;
        info.d_numIterations = k_NUM_POST / k_NUM_WAIT_THREADS;
        info.d_barrier = &barrier;
        info.d_sem = &sem;
        for (int i = 0; i < k_NUM_WAIT_THREADS; ++i) {
            int rc = bslmt::ThreadUtil::create(&threads[i],
                                              thread6wait,
                                              &info);
            ASSERT(0 == rc);
        }

        if (verbose) {
            bsl::cout << "case 6 mode 1: concurrent waiting"
                      << bsl::endl;
        }

        // MODE 1: THREADS WAITING

        barrier.wait();
        bslmt::ThreadUtil::microSleep(10000); // 10 ms
        sem.post(k_NUM_POST);
        for (int i = 0; i < k_NUM_WAIT_THREADS; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

        // if we reach here, we woke up all the threads the correct number of
        // times

        for (int i = 0; i < k_NUM_WAIT_THREADS; ++i) {
            int rc = bslmt::ThreadUtil::create(&threads[i],
                                              thread6wait,
                                              &info);
            ASSERT(0 == rc);
        }

        if (verbose) {
            bsl::cout << "case 6 mode 2: no concurrent waiting"
                      << bsl::endl;
        }

        // MODE 2: NO THREADS WAITING

        sem.post(k_NUM_POST);
        barrier.wait();
        for (int i = 0; i < k_NUM_WAIT_THREADS; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

        // if we reach here, we woke up all the threads the correct number of
        // times

      } break;

      case 5: {
///Usage
///-----
// This component is an implementation detail of 'bslmt' and is *not* intended
// for direct client use.  It is subject to change without notice.  As such, a
// usage example is not provided.

        // USAGE EXAMPLE
        IntQueue testQueue;

        testQueue.pushInt(1);
        ASSERT(1 == testQueue.getInt());
        testQueue.pushInt(2);
        ASSERT(2 == testQueue.getInt());
      } break;
      case 4: {
        // --------------------------------------------------------------------
        // TESTING 'tryWait'
        //
        // Concerns:
        //   1. 'tryWait' decrements the count if resources are available,
        //      or return an error otherwise.
        //
        // Plan:
        // We create two groups of threads.  One will call 'post', the other
        // 'tryWait'.  First, we make sure that 'tryWait' fails if no resources
        // is available.  Then we will make sure it succeeds if resources are.
        // We will also test 'tryWait' in the steady state works fine.
        //
        // Testing:
        //   void tryWait();
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'trywait'" << endl
                          << "=================" << endl;

        bslmt::ThreadUtil::Handle threads[10];
        MyBarrier barrier(10);
        Obj sem(0);

        struct ThreadInfo4 info;
        info.d_numIterations = 5000; // number of ops per thread / 3
        info.d_barrier = &barrier;
        info.d_sem = &sem;

        for (int i = 0; i < 5; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2],
                                                 thread4Post,
                                                 &info));

            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2 + 1],
                                                   thread4Wait,
                                                   &info));
        }
        for (int i = 0; i < 10; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

      } break;
      case 3: {
        // --------------------------------------------------------------------
        // TESTING 'post(int)'
        //
        // Concerns:
        //   1. post(int) increments the count by the expected number
        //
        // Plan:
        // Create a set of threads calling 'wait' and use a thread to post a
        // number smaller than the set of threads.
        //
        // Testing:
        //   void post(int number);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'post(int number)'" << endl
                          << "==========================" << endl;

        bslmt::ThreadUtil::Handle threads[6];
        MyBarrier barrier(6);
        Obj sem(0);

        struct ThreadInfo3 info;
        info.d_numIterations = 10000; // number of ops per thread
        info.d_numWaitThreads = 5;
        info.d_barrier = &barrier;
        info.d_sem = &sem;

        for (int i = 0; i < 5; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i],
                                                 thread3Wait,
                                                 &info));
        }
        ASSERT(0 == bslmt::ThreadUtil::create(&threads[5],
                                             thread3Post,
                                             &info));
        for (int i = 0; i < 6; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

      } break;
      case 2: {
        // --------------------------------------------------------------------
        // TESTING 'wait' and 'post'
        //
        // Concerns:
        //   1. wait() blocks the thread when no resource is available,
        //      and then decrements the count
        //   2. post() increments the count
        //
        // Plan:
        //  Create two groups of threads: one will call 'post' and the other
        //  will call 'wait'.  To address concern 1, we will use a barrier and
        //  a counter to make sure that waiting threads are blocked into wait
        //  state before any calls to 'post'.  After that, we will post a small
        //  limited number of times (between 0 and 5), and check that the
        //  semaphore can indeed satisfy that number of waiters.  Then we try
        //  to reach a steady state by calling the two functions 'post' and
        //  'wait' in a number of threads each, perturbing the 'post' operation
        //  by adding small delays to exercise different parts of the code.
        //
        // Testing:
        //   void post();
        //   void wait(int *signalInterrupted = 0);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'wait' and 'post'" << endl
                          << "=========================" << endl;

        enum {
            k_NUM_POSTERS = 5,
            k_NUM_WAITERS = 5
        };

        for (int n = 0; n < 5; ++n) {
            if (veryVerbose) cout << "\tPosting " << n << " first." << endl;

            bslmt::ThreadUtil::Handle threads[k_NUM_POSTERS + k_NUM_WAITERS];
            MyBarrier barrier(k_NUM_POSTERS+ 1);
            bsls::AtomicInt posts(n);
            bsls::AtomicInt past (0);
            Obj sem(0);

            struct ThreadInfo2 info;
            info.d_numIterations = 1000; // number of ops per thread
            info.d_barrier = &barrier;
            info.d_sem = &sem;
            info.d_past = &past;
            info.d_numInitialPosts = &posts;
            info.d_verbose = veryVeryVerbose;

            for (int i = 0; i < k_NUM_POSTERS; ++i) {
                ASSERT(0 == bslmt::ThreadUtil::create(&threads[i],
                                                     thread2Post,
                                                     &info));
            }

            for (int i = 0; i < k_NUM_WAITERS; ++i) {
                ASSERT(0 == bslmt::ThreadUtil::create(
                             &threads[i + k_NUM_POSTERS], thread2Wait, &info));
            }
            bslmt::ThreadUtil::microSleep(1000 * 100);
            ASSERT(0 == past);
            ASSERT(0 == past);
            barrier.wait();
            // Wait until the initial posters complete.
            if (veryVerbose) cout << "\t\tFirst barrier passed." << endl;
            while (n != past) {
                // Wait for some waiters to grab the posts.
                if (veryVeryVerbose)
                    MTCOUT << "\t\tWaiters still blocking, "
                           << posts << "." << MTENDL;
                bslmt::ThreadUtil::microSleep(1000 * 100);
            }
            barrier.wait();
            // Unleash the remaining posters.
            if (veryVerbose) cout << "\t\tSecond barrier passed." << endl;

            // The testing will complete once all the threads join, meaning
            // that all the waiters were satisfied.

            for (int i = 0; i < 10; ++i) {
                ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
            }
        }

      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST:
        //
        // Exercises basic functionality.
        // --------------------------------------------------------------------

        if (verbose) {
            cout << endl
                 << "Breathing Test" << endl
                 << "==============" << endl;
#if defined(BSLS_PLATFORM_OS_AIX) || defined(BSLS_PLATFORM_OS_LINUX)
            cout << "INFO: SEM_VALUE_MAX=" << SEM_VALUE_MAX
                 << endl;
#endif
        }
        {
            Obj X(0);
            X.post();
            X.post(2);
            X.wait();
            X.wait();
            ASSERT(0 == X.tryWait());
            ASSERT(0 != X.tryWait());
        }
      } break;
      case -2: {
        // --------------------------------------------------------------------
        // A SIMPLE BENCHMARK
        //
        // imitates a producer-consumer system with a fixed size queue using
        // two semaphores
        //

        int numProducers = atoi(argv[2]);
        int numConsumers = atoi(argv[3]);
        int queueSize = atoi(argv[4]);
        int seconds = 5;
        int samples = 5;
        if (verbose) cout << endl
                          << "Benchmarking....." << endl
                          << "=================" << endl
                          << "producers=" << numProducers << endl
                          << "consumers=" << numConsumers << endl
                          << "queue size=" << queueSize << endl;
        BenchData* producerData = new BenchData[numProducers];
        BenchData* consumerData = new BenchData[numConsumers];
        Obj resource(0);
        Obj queue(0);
        queue.post(queueSize);
        for(int i=0; i<numConsumers; i++) {
            consumerData[i].resource = &resource;
            consumerData[i].queue = &queue;
            consumerData[i].count = 0;
            consumerData[i].stop = false;
            bslmt::ThreadUtil::create(&consumerData[i].handle,
                                     benchConsumer,
                                     (void*)(consumerData+i));
        }
        for(int i=0; i<numProducers; i++) {
            producerData[i].resource = &resource;
            producerData[i].queue = &queue;
            producerData[i].stop = false;
            bslmt::ThreadUtil::create(&producerData[i].handle,
                                     benchProducer,
                                     (void*)(producerData+i));
        }
        for(int j=0; j<samples; j++) {
            bsls::Types::Int64 timeStart = bsls::TimeUtil::getTimer();
            bsls::Types::Int64 timeStartCPU = ::clock();
            int* consumerCount = new int[numConsumers];
            for(int i=0; i<numConsumers; i++) {
                consumerCount[i] = consumerData[i].count;
            }
            bsls::Types::Int64 throughput;
            bsls::Types::Int64 throughputCPU;
            for(int i=0; i<seconds; i++) {
                bslmt::ThreadUtil::microSleep(1000000);
                bsls::Types::Int64 totalMessages = 0;
                for(int i=0; i<numConsumers;i++) {
                    totalMessages += (consumerData[i].count-consumerCount[i]);
                }
                bsls::Types::Int64 elapsed_us =
                                   (bsls::TimeUtil::getTimer()-timeStart)/1000;
                bsls::Types::Int64 elapsed_usCPU = ::clock()-timeStartCPU;
                throughput = (totalMessages*1000000/elapsed_us);
                throughputCPU = (totalMessages*1000000/elapsed_usCPU);
                cout << "testing: "
                     << elapsed_us/1000
                     << " ms, "
                     << elapsed_usCPU*100/elapsed_us
                     << " CPU%, "
                     << totalMessages
                     << " msg, "
                     << fmt(throughput)
                     << " msg/s, "
                     << fmt(throughputCPU)
                     << " msg/CPUs"
                     << endl;
            }
            cout << "====== final:"
                 << fmt(throughput)
                 << " msg/s, "
                 << fmt(throughputCPU)
                 << " msg/CPUs\n"
                 << endl;
        }
        cout << "stopping: " << flush;
        for(int i=0; i<numProducers; i++) {
            producerData[i].stop = true;
        }
        for(int i=0; i<numProducers; i++) {
            bslmt::ThreadUtil::join(producerData[i].handle);
            cout << 'p' << flush;
        }
        for(int i=0; i<numConsumers; i++) {
            consumerData[i].stop = true;
        }
        resource.post(numConsumers);
        for(int i=0; i<numConsumers;i++) {
            bslmt::ThreadUtil::join(consumerData[i].handle);
            cout << 'c' << flush;
        }
        cout << endl;
        delete[] producerData;
        delete[] consumerData;
      } break;

      default: {
          testStatus = -1; break;
      }

    }
    return testStatus;
}
int main(int argc, char *argv[]) {

    int test = argc > 1 ? atoi(argv[1]) : 0;
    int verbose = argc > 2;

    cout << "TEST " << __FILE__ << " CASE " << test << endl;

    switch (test) { case 0:  // Zero is always the leading case.
      case 6: {
///Usage
///-----
// This component is an implementation detail of 'bslmt' and is *not* intended
// for direct client use.  It is subject to change without notice.  As such, a
// usage example is not provided.

        // USAGE EXAMPLE
        IntQueue testQueue;

        testQueue.pushInt(1);
        ASSERT(1 == testQueue.getInt());
        testQueue.pushInt(2);
        ASSERT(2 == testQueue.getInt());

      } break;
      case 5: {
        // --------------------------------------------------------------------
        // TESTING 'tryWait'
        //
        // Concerns:
        //   1. 'tryWait' decrements the count if resources are available,
        //      or return an error otherwise.
        //
        // Plan:
        //   We create two groups of threads.  One will call 'post', the other
        //   'tryWait'.  First, we make sure that 'tryWait' fails if no
        //   resources are available.  Then we will make sure it succeeds if
        //   resources are.  We will also test 'tryWait' in the steady state
        //   works fine.
        //
        // Testing:
        //   void tryWait();
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'trywait'" << endl
                          << "=================" << endl;

        bslmt::ThreadUtil::Handle threads[10];
        MyBarrier barrier(10);
        Obj sem;

        struct ThreadInfo5 info;
        info.d_numIterations = 5000; // number of ops per thread / 3
        info.d_barrier = &barrier;
        info.d_sem = &sem;

        for (int i = 0; i < 5; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2],
                                                 thread5Post,
                                                 &info));

            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2 + 1],
                                                   thread5Wait,
                                                   &info));
        }
        for (int i = 0; i < 10; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

      } break;
      case 4: {
        // --------------------------------------------------------------------
        // TESTING 'post(int)'
        //
        // Concerns:
        //   1. post(int) increments the count by the expected number
        //
        // Plan:
        //   Create a set of threads calling 'wait' and use a thread to post a
        //   number smaller than the set of threads.
        //
        // Testing:
        //   void post(int number);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'post(int number)'" << endl
                          << "==========================" << endl;

        bslmt::ThreadUtil::Handle threads[6];
        MyBarrier barrier(6);
        Obj sem;

        struct ThreadInfo4 info;
        info.d_numIterations = 10000; // number of ops per thread
        info.d_numWaitThreads = 5;
        info.d_barrier = &barrier;
        info.d_sem = &sem;

        for (int i = 0; i < 5; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i],
                                                 thread4Wait,
                                                 &info));
        }
        ASSERT(0 == bslmt::ThreadUtil::create(&threads[5],
                                             thread4Post,
                                             &info));
        for (int i = 0; i < 6; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

      } break;
      case 3: {
        // --------------------------------------------------------------------
        // TESTING 'timedWait'
        //
        // Concerns:
        //   1. timedWait() blocks the thread until a resource is available
        //      or the timeout expires.
        //
        // Plan:
        //  Create two groups of threads one will call 'post' and the other
        //  will call 'timedWait'.  First, we will make sure that the
        //  'timedWait' will timeout properly if no resource available by
        //  calling the function with a reasonable timeout before any calls to
        //  'post'.  Then, both groups of threads will enter a loop to simulate
        //  the steady state.  The 'post' loop will be perturbed to exercise
        //  different portions of code.  The specified timeout will be pretty
        //  important and we will make sure we do not timeout.  At the end
        //  of this first run, we will make a second run with a much lower
        //  timeout which will force *some* waits to timeout.
        //
        // Testing:
        //   void timedWait(bsls::TimeInterval timeout,
        //                  int              *signalInterrupted = 0);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'timedWait'" << endl
                          << "===================" << endl;

        testCase3(bsls::SystemClockType::e_REALTIME);
        testCase3(bsls::SystemClockType::e_MONOTONIC);

      } break;
      case 2: {
        // --------------------------------------------------------------------
        // TESTING 'wait' and 'post'
        //
        // Concerns:
        //   1. wait() blocks the thread when no resource is available,
        //      and then decrements the count
        //   2. post() increments the count
        //
        // Plan:
        //  Create two groups of threads one will call 'post' and the other
        //  will call 'wait'.  To address concern 1, we will use a barrier and
        //  a counter to make sure that waiting threads are blocked into wait
        //  state before any calls to 'post'.  After that, we will try to reach
        //  a steady state by calling the two functions in a loop and perturb
        //  the 'post' operation by adding small delays to exercise different
        //  parts of the code.
        //
        // Testing:
        //   void post();
        //   void wait(int *signalInterrupted = 0);
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Testing 'wait' and 'post'" << endl
                          << "=========================" << endl;

        bslmt::ThreadUtil::Handle threads[10];
        MyBarrier barrier(6);
        bsls::AtomicInt past(0);
        Obj sem;

        struct ThreadInfo2 info;
        info.d_numIterations = 10000; // number of ops per thread
        info.d_barrier = &barrier;
        info.d_sem = &sem;
        info.d_past = &past;

        for (int i = 0; i < 5; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2],
                                                 thread2Post,
                                                 &info));

            ASSERT(0 == bslmt::ThreadUtil::create(&threads[i * 2 + 1],
                                                 thread2Wait,
                                                 &info));
        }
        bslmt::ThreadUtil::microSleep(1000 * 100);
        ASSERT(0 == past);
        barrier.wait();
        bslmt::ThreadUtil::microSleep(1000 * 200);
        ASSERT(0 != past);

        for (int i = 0; i < 10; ++i) {
            ASSERT(0 == bslmt::ThreadUtil::join(threads[i]));
        }

      } break;
      case 1: {
        // --------------------------------------------------------------------
        // BREATHING TEST:
        //
        // Exercises basic functionality.
        // --------------------------------------------------------------------

        if (verbose) cout << endl
                          << "Breathing Test" << endl
                          << "==============" << endl;
        {
            Obj X;
            X.post();
            X.post(2);
            X.wait();
            ASSERT(0 == X.timedWait(bsls::SystemTime::nowRealtimeClock() +
                                    bsls::TimeInterval(60)));
            ASSERT(0 == X.tryWait());
            ASSERT(0 != X.tryWait());
            ASSERT(0 != X.timedWait(bsls::SystemTime::nowRealtimeClock() +
                                    bsls::TimeInterval(1)));
        }
      } break;
      default: {
        cerr << "WARNING: CASE `" << test << "' NOT FOUND." << endl;
        testStatus = -1;
      }
    }

    if (testStatus > 0) {
        cerr << "Error, non-zero test status = " << testStatus << "." << endl;
    }
    return testStatus;
}