// bslmt_semaphore.h                                                  -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BSLMT_SEMAPHORE
#define INCLUDED_BSLMT_SEMAPHORE

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a semaphore class.
//
//@CLASSES:
//  bslmt::Semaphore: semaphore class
//
//@SEE_ALSO: bslmt_timedsemaphore
//
//@DESCRIPTION: This component defines a portable and efficient thread
// synchronization primitive.  In particular, 'bslmt::Semaphore' is an
// efficient synchronization primitive that enables sharing of a counted number
// of resources or exclusive access.  The usage model of this facility is
// modeled on POSIX semaphores and Windows semaphores.
//
///Usage
///-----
// This example illustrates a very simple queue where potential clients can
// push integers to a queue, and later retrieve the integer values from the
// queue in FIFO order.  It illustrates two potential uses of semaphores: to
// enforce exclusive access, and to allow resource sharing.
//..
//  class IntQueue {
//      // FIFO queue of integer values.
//
//      // DATA
//      bsl::deque<int> d_queue;        // underlying queue
//      bslmt::Semaphore d_mutexSem;     // mutual-access semaphore
//      bslmt::Semaphore d_resourceSem;  // resource-availability semaphore
//
//      // NOT IMPLEMENTED
//      IntQueue(const IntQueue&);
//      IntQueue& operator=(const IntQueue&);
//
//    public:
//      // CREATORS
//      explicit IntQueue(bslma::Allocator *basicAllocator = 0);
//          // Create an 'IntQueue' object.  Optionally specified a
//          // 'basicAllocator' used to supply memory.  If 'basicAllocator' is
//          // 0, the currently installed default allocator is used.
//
//      ~IntQueue();
//          // Destroy this 'IntQueue' object.
//
//      // MANIPULATORS
//      int getInt();
//          // Retrieve an integer from this 'IntQueue' object.  Integer values
//          // are obtained from the queue in FIFO order.
//
//      void pushInt(int value);
//          // Push the specified 'value' to this 'IntQueue' object.
//  };
//..
// Note that the 'IntQueue' constructor increments the count of the semaphore
// to 1 so that values can be pushed into the queue immediately following
// construction:
//..
//  // CREATORS
//  IntQueue::IntQueue(bslma::Allocator *basicAllocator)
//  : d_queue(basicAllocator)
//  {
//      d_mutexSem.post();
//  }
//
//  IntQueue::~IntQueue()
//  {
//      d_mutexSem.wait();  // Wait for potential modifier.
//  }
//
//  // MANIPULATORS
//  int IntQueue::getInt()
//  {
//      // Waiting for resources.
//      d_resourceSem.wait();
//
//      // 'd_mutexSem' is used for exclusive access.
//      d_mutexSem.wait();        // lock
//      const int ret = d_queue.back();
//      d_queue.pop_back();
//      d_mutexSem.post();        // unlock
//
//      return ret;
//  }
//
//  void IntQueue::pushInt(int value)
//  {
//      d_mutexSem.wait();
//      d_queue.push_front(value);
//      d_mutexSem.post();
//
//      d_resourceSem.post();  // Signal we have resources available.
//  }
//..

#include <bslscm_version.h>

#include <bslmt_semaphoreimpl_counted.h>
#include <bslmt_semaphoreimpl_pthread.h>
#include <bslmt_semaphoreimpl_win32.h>
#include <bslmt_platform.h>

namespace BloombergLP {
namespace bslmt {

template <class SEMAPHORE_POLICY>
class SemaphoreImpl;

                             // ===============
                             // class Semaphore
                             // ===============

class Semaphore {
    // This class implements a portable semaphore type for thread
    // synchronization.  It forwards all requests to an appropriate
    // platform-specific implementation.

    // DATA
    SemaphoreImpl<Platform::SemaphorePolicy> d_impl;  // platform-specific
                                                      // implementation

    // NOT IMPLEMENTED
    Semaphore(const Semaphore&);
    Semaphore& operator=(const Semaphore&);

  public:
    // CREATORS
    Semaphore();
        // Create a semaphore initially having a count of 0.

    explicit
    Semaphore(int count);
        // Create a semaphore initially having the specified 'count'.

    ~Semaphore();
        // Destroy this semaphore.

    // MANIPULATORS
    void post();
        // Atomically increment the count of this semaphore.

    void post(int value);
        // Atomically increase the count of this semaphore by the specified
        // 'value'.  The behavior is undefined unless 'value > 0'.

    int tryWait();
        // If the count of this semaphore is positive, atomically decrement the
        // count and return 0; otherwise, return a non-zero value with no
        // effect on the count.

    void wait();
        // Block until the count of this semaphore is a positive value, then
        // atomically decrement the count and return.

    // ACCESSORS
    int getValue() const;
        // Return the value of the current count of this semaphore.
};

}  // close package namespace

// ============================================================================
//                             INLINE DEFINITIONS
// ============================================================================

                             // ---------------
                             // class Semaphore
                             // ---------------

// CREATORS
inline
bslmt::Semaphore::Semaphore()
: d_impl(0)
{
}

inline
bslmt::Semaphore::Semaphore(int count)
: d_impl(count)
{
}

inline
bslmt::Semaphore::~Semaphore()
{
}

inline
void bslmt::Semaphore::post()
{
    d_impl.post();
}

inline
void bslmt::Semaphore::post(int value)
{
    d_impl.post(value);
}

inline
int bslmt::Semaphore::tryWait()
{
    return d_impl.tryWait();
}

inline
void bslmt::Semaphore::wait()
{
    d_impl.wait();
}

// ACCESSORS
inline
int bslmt::Semaphore::getValue() const
{
    return d_impl.getValue();
}

}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------