<commit_before>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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.
 *
 */

#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include <functional>
#include <memory>
#include <thread>

#include <gtest/gtest.h>

#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/slice/slice_internal.h"

#include "test/core/util/port.h"
#include "test/core/util/test_config.h"

namespace grpc_core {
namespace test {
namespace {

// A gRPC server, running in its own thread.
class ServerThread {
 public:
  explicit ServerThread(const char* address) : address_(address) {}

  void Start() {
    // Start server with 1-second handshake timeout.
    grpc_arg arg;
    arg.type = GRPC_ARG_INTEGER;
    arg.key = const_cast<char*>(GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS);
    arg.value.integer = 1000;
    grpc_channel_args args = {1, &arg};
    server_ = grpc_server_create(&args, nullptr);
    ASSERT_TRUE(grpc_server_add_insecure_http2_port(server_, address_));
    cq_ = grpc_completion_queue_create_for_next(nullptr);
    grpc_server_register_completion_queue(server_, cq_, nullptr);
    grpc_server_start(server_);
    thread_.reset(new std::thread(std::bind(&ServerThread::Serve, this)));
  }

  void Shutdown() {
    grpc_completion_queue* shutdown_cq =
        grpc_completion_queue_create_for_pluck(nullptr);
    grpc_server_shutdown_and_notify(server_, shutdown_cq, nullptr);
    GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, nullptr,
                                           grpc_timeout_seconds_to_deadline(1),
                                           nullptr)
                   .type == GRPC_OP_COMPLETE);
    grpc_completion_queue_destroy(shutdown_cq);
    grpc_server_destroy(server_);
    grpc_completion_queue_destroy(cq_);
    thread_->join();
  }

 private:
  void Serve() {
    // The completion queue should not return anything other than shutdown.
    grpc_event ev = grpc_completion_queue_next(
        cq_, gpr_inf_future(GPR_CLOCK_MONOTONIC), nullptr);
    ASSERT_EQ(GRPC_QUEUE_SHUTDOWN, ev.type);
  }

  const char* address_;  // Do not own.
  grpc_server* server_ = nullptr;
  grpc_completion_queue* cq_ = nullptr;
  std::unique_ptr<std::thread> thread_;
};

// A TCP client that connects to the server, reads data until the server
// closes, and then terminates.
class Client {
 public:
  explicit Client(const char* server_address)
      : server_address_(server_address) {}

  void Connect() {
    grpc_core::ExecCtx exec_ctx;
    grpc_resolved_addresses* server_addresses = nullptr;
    grpc_error* error =
        grpc_blocking_resolve_address(server_address_, "80", &server_addresses);
    ASSERT_EQ(GRPC_ERROR_NONE, error) << grpc_error_string(error);
    ASSERT_GE(server_addresses->naddrs, 1UL);
    pollset_ = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
    grpc_pollset_init(pollset_, &mu_);
    grpc_pollset_set* pollset_set = grpc_pollset_set_create();
    grpc_pollset_set_add_pollset(pollset_set, pollset_);
    EventState state;
    grpc_tcp_client_connect(state.closure(), &endpoint_, pollset_set,
                            nullptr /* channel_args */, server_addresses->addrs,
                            1000);
    ASSERT_TRUE(PollUntilDone(
        &state,
        grpc_timespec_to_millis_round_up(gpr_inf_future(GPR_CLOCK_MONOTONIC))));
    ASSERT_EQ(GRPC_ERROR_NONE, state.error());
    grpc_pollset_set_destroy(pollset_set);
    grpc_endpoint_add_to_pollset(endpoint_, pollset_);
    grpc_resolved_addresses_destroy(server_addresses);
  }

  // Reads until an error is returned.
  // Returns true if an error was encountered before the deadline.
  bool ReadUntilError() {
    grpc_core::ExecCtx exec_ctx;
    grpc_slice_buffer read_buffer;
    grpc_slice_buffer_init(&read_buffer);
    bool retval = true;
    // Use a deadline of 3 seconds, which is a lot more than we should
    // need for a 1-second timeout, but this helps avoid flakes.
    grpc_millis deadline = grpc_core::ExecCtx::Get()->Now() + 3000;
    while (true) {
      EventState state;
      grpc_endpoint_read(endpoint_, &read_buffer, state.closure(),
                         /*urgent=*/true);
      if (!PollUntilDone(&state, deadline)) {
        retval = false;
        break;
      }
      if (state.error() != GRPC_ERROR_NONE) break;
      gpr_log(GPR_INFO, "client read %" PRIuPTR " bytes", read_buffer.length);
      grpc_slice_buffer_reset_and_unref_internal(&read_buffer);
    }
    grpc_endpoint_shutdown(endpoint_,
                           GRPC_ERROR_CREATE_FROM_STATIC_STRING("shutdown"));
    grpc_slice_buffer_destroy_internal(&read_buffer);
    return retval;
  }

  void Shutdown() {
    grpc_core::ExecCtx exec_ctx;
    grpc_endpoint_destroy(endpoint_);
    grpc_pollset_shutdown(pollset_,
                          GRPC_CLOSURE_CREATE(&Client::PollsetDestroy, pollset_,
                                              grpc_schedule_on_exec_ctx));
  }

 private:
  // State used to wait for an I/O event.
  class EventState {
   public:
    EventState() {
      GRPC_CLOSURE_INIT(&closure_, &EventState::OnEventDone, this,
                        grpc_schedule_on_exec_ctx);
    }

    ~EventState() { GRPC_ERROR_UNREF(error_); }

    grpc_closure* closure() { return &closure_; }

    bool done() const { return gpr_atm_acq_load(&done_atm_) != 0; }

    // Caller does NOT take ownership of the error.
    grpc_error* error() const { return error_; }

   private:
    static void OnEventDone(void* arg, grpc_error* error) {
      gpr_log(GPR_INFO, "OnEventDone(): %s", grpc_error_string(error));
      EventState* state = static_cast<EventState*>(arg);
      state->error_ = GRPC_ERROR_REF(error);
      gpr_atm_rel_store(&state->done_atm_, 1);
    }

    grpc_closure closure_;
    gpr_atm done_atm_ = 0;
    grpc_error* error_ = GRPC_ERROR_NONE;
  };

  // Returns true if done, or false if deadline exceeded.
  bool PollUntilDone(EventState* state, grpc_millis deadline) {
    while (true) {
      grpc_pollset_worker* worker = nullptr;
      gpr_mu_lock(mu_);
      GRPC_LOG_IF_ERROR(
          "grpc_pollset_work",
          grpc_pollset_work(pollset_, &worker,
                            grpc_core::ExecCtx::Get()->Now() + 1000));
      // Flushes any work scheduled before or during polling.
      grpc_core::ExecCtx::Get()->Flush();
      gpr_mu_unlock(mu_);
      if (state != nullptr && state->done()) return true;
      if (grpc_core::ExecCtx::Get()->Now() >= deadline) return false;
    }
  }

  static void PollsetDestroy(void* arg, grpc_error* /*error*/) {
    grpc_pollset* pollset = static_cast<grpc_pollset*>(arg);
    grpc_pollset_destroy(pollset);
    gpr_free(pollset);
  }

  const char* server_address_;  // Do not own.
  grpc_endpoint* endpoint_;
  gpr_mu* mu_;
  grpc_pollset* pollset_;
};

TEST(SettingsTimeout, Basic) {
  // Construct server address string.
  const int server_port = grpc_pick_unused_port_or_die();
  char* server_address_string;
  gpr_asprintf(&server_address_string, "localhost:%d", server_port);
  // Start server.
  gpr_log(GPR_INFO, "starting server on %s", server_address_string);
  ServerThread server_thread(server_address_string);
  server_thread.Start();
  // Create client and connect to server.
  gpr_log(GPR_INFO, "starting client connect");
  Client client(server_address_string);
  client.Connect();
  // Client read.  Should fail due to server dropping connection.
  gpr_log(GPR_INFO, "starting client read");
  EXPECT_TRUE(client.ReadUntilError());
  // Shut down client.
  gpr_log(GPR_INFO, "shutting down client");
  client.Shutdown();
  // Shut down server.
  gpr_log(GPR_INFO, "shutting down server");
  server_thread.Shutdown();
  // Clean up.
  gpr_free(server_address_string);
}

}  // namespace
}  // namespace test
}  // namespace grpc_core

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  grpc::testing::TestEnvironment env(argc, argv);
  grpc_init();
  int result = RUN_ALL_TESTS();
  grpc_shutdown();
  return result;
}
<commit_msg>Fixing the settings_timeout_test flake by reducing pollset_work deadline<commit_after>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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.
 *
 */

#include <grpc/grpc.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/string_util.h>

#include <functional>
#include <memory>
#include <thread>

#include <gtest/gtest.h>

#include "src/core/lib/iomgr/endpoint.h"
#include "src/core/lib/iomgr/error.h"
#include "src/core/lib/iomgr/pollset.h"
#include "src/core/lib/iomgr/pollset_set.h"
#include "src/core/lib/iomgr/resolve_address.h"
#include "src/core/lib/iomgr/tcp_client.h"
#include "src/core/lib/slice/slice_internal.h"

#include "test/core/util/port.h"
#include "test/core/util/test_config.h"

namespace grpc_core {
namespace test {
namespace {

// A gRPC server, running in its own thread.
class ServerThread {
 public:
  explicit ServerThread(const char* address) : address_(address) {}

  void Start() {
    // Start server with 1-second handshake timeout.
    grpc_arg arg;
    arg.type = GRPC_ARG_INTEGER;
    arg.key = const_cast<char*>(GRPC_ARG_SERVER_HANDSHAKE_TIMEOUT_MS);
    arg.value.integer = 1000;
    grpc_channel_args args = {1, &arg};
    server_ = grpc_server_create(&args, nullptr);
    ASSERT_TRUE(grpc_server_add_insecure_http2_port(server_, address_));
    cq_ = grpc_completion_queue_create_for_next(nullptr);
    grpc_server_register_completion_queue(server_, cq_, nullptr);
    grpc_server_start(server_);
    thread_.reset(new std::thread(std::bind(&ServerThread::Serve, this)));
  }

  void Shutdown() {
    grpc_completion_queue* shutdown_cq =
        grpc_completion_queue_create_for_pluck(nullptr);
    grpc_server_shutdown_and_notify(server_, shutdown_cq, nullptr);
    GPR_ASSERT(grpc_completion_queue_pluck(shutdown_cq, nullptr,
                                           grpc_timeout_seconds_to_deadline(1),
                                           nullptr)
                   .type == GRPC_OP_COMPLETE);
    grpc_completion_queue_destroy(shutdown_cq);
    grpc_server_destroy(server_);
    grpc_completion_queue_destroy(cq_);
    thread_->join();
  }

 private:
  void Serve() {
    // The completion queue should not return anything other than shutdown.
    grpc_event ev = grpc_completion_queue_next(
        cq_, gpr_inf_future(GPR_CLOCK_MONOTONIC), nullptr);
    ASSERT_EQ(GRPC_QUEUE_SHUTDOWN, ev.type);
  }

  const char* address_;  // Do not own.
  grpc_server* server_ = nullptr;
  grpc_completion_queue* cq_ = nullptr;
  std::unique_ptr<std::thread> thread_;
};

// A TCP client that connects to the server, reads data until the server
// closes, and then terminates.
class Client {
 public:
  explicit Client(const char* server_address)
      : server_address_(server_address) {}

  void Connect() {
    grpc_core::ExecCtx exec_ctx;
    grpc_resolved_addresses* server_addresses = nullptr;
    grpc_error* error =
        grpc_blocking_resolve_address(server_address_, "80", &server_addresses);
    ASSERT_EQ(GRPC_ERROR_NONE, error) << grpc_error_string(error);
    ASSERT_GE(server_addresses->naddrs, 1UL);
    pollset_ = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size()));
    grpc_pollset_init(pollset_, &mu_);
    grpc_pollset_set* pollset_set = grpc_pollset_set_create();
    grpc_pollset_set_add_pollset(pollset_set, pollset_);
    EventState state;
    grpc_tcp_client_connect(state.closure(), &endpoint_, pollset_set,
                            nullptr /* channel_args */, server_addresses->addrs,
                            1000);
    ASSERT_TRUE(PollUntilDone(
        &state,
        grpc_timespec_to_millis_round_up(gpr_inf_future(GPR_CLOCK_MONOTONIC))));
    ASSERT_EQ(GRPC_ERROR_NONE, state.error());
    grpc_pollset_set_destroy(pollset_set);
    grpc_endpoint_add_to_pollset(endpoint_, pollset_);
    grpc_resolved_addresses_destroy(server_addresses);
  }

  // Reads until an error is returned.
  // Returns true if an error was encountered before the deadline.
  bool ReadUntilError() {
    grpc_core::ExecCtx exec_ctx;
    grpc_slice_buffer read_buffer;
    grpc_slice_buffer_init(&read_buffer);
    bool retval = true;
    // Use a deadline of 3 seconds, which is a lot more than we should
    // need for a 1-second timeout, but this helps avoid flakes.
    grpc_millis deadline = grpc_core::ExecCtx::Get()->Now() + 3000;
    while (true) {
      EventState state;
      grpc_endpoint_read(endpoint_, &read_buffer, state.closure(),
                         /*urgent=*/true);
      if (!PollUntilDone(&state, deadline)) {
        retval = false;
        break;
      }
      if (state.error() != GRPC_ERROR_NONE) break;
      gpr_log(GPR_INFO, "client read %" PRIuPTR " bytes", read_buffer.length);
      grpc_slice_buffer_reset_and_unref_internal(&read_buffer);
    }
    grpc_endpoint_shutdown(endpoint_,
                           GRPC_ERROR_CREATE_FROM_STATIC_STRING("shutdown"));
    grpc_slice_buffer_destroy_internal(&read_buffer);
    return retval;
  }

  void Shutdown() {
    grpc_core::ExecCtx exec_ctx;
    grpc_endpoint_destroy(endpoint_);
    grpc_pollset_shutdown(pollset_,
                          GRPC_CLOSURE_CREATE(&Client::PollsetDestroy, pollset_,
                                              grpc_schedule_on_exec_ctx));
  }

 private:
  // State used to wait for an I/O event.
  class EventState {
   public:
    EventState() {
      GRPC_CLOSURE_INIT(&closure_, &EventState::OnEventDone, this,
                        grpc_schedule_on_exec_ctx);
    }

    ~EventState() { GRPC_ERROR_UNREF(error_); }

    grpc_closure* closure() { return &closure_; }

    bool done() const { return gpr_atm_acq_load(&done_atm_) != 0; }

    // Caller does NOT take ownership of the error.
    grpc_error* error() const { return error_; }

   private:
    static void OnEventDone(void* arg, grpc_error* error) {
      gpr_log(GPR_INFO, "OnEventDone(): %s", grpc_error_string(error));
      EventState* state = static_cast<EventState*>(arg);
      state->error_ = GRPC_ERROR_REF(error);
      gpr_atm_rel_store(&state->done_atm_, 1);
    }

    grpc_closure closure_;
    gpr_atm done_atm_ = 0;
    grpc_error* error_ = GRPC_ERROR_NONE;
  };

  // Returns true if done, or false if deadline exceeded.
  bool PollUntilDone(EventState* state, grpc_millis deadline) {
    while (true) {
      grpc_pollset_worker* worker = nullptr;
      gpr_mu_lock(mu_);
      GRPC_LOG_IF_ERROR(
          "grpc_pollset_work",
          grpc_pollset_work(pollset_, &worker,
                            grpc_core::ExecCtx::Get()->Now() + 100));
      // Flushes any work scheduled before or during polling.
      grpc_core::ExecCtx::Get()->Flush();
      gpr_mu_unlock(mu_);
      if (state != nullptr && state->done()) return true;
      if (grpc_core::ExecCtx::Get()->Now() >= deadline) return false;
    }
  }

  static void PollsetDestroy(void* arg, grpc_error* /*error*/) {
    grpc_pollset* pollset = static_cast<grpc_pollset*>(arg);
    grpc_pollset_destroy(pollset);
    gpr_free(pollset);
  }

  const char* server_address_;  // Do not own.
  grpc_endpoint* endpoint_;
  gpr_mu* mu_;
  grpc_pollset* pollset_;
};

TEST(SettingsTimeout, Basic) {
  // Construct server address string.
  const int server_port = grpc_pick_unused_port_or_die();
  char* server_address_string;
  gpr_asprintf(&server_address_string, "localhost:%d", server_port);
  // Start server.
  gpr_log(GPR_INFO, "starting server on %s", server_address_string);
  ServerThread server_thread(server_address_string);
  server_thread.Start();
  // Create client and connect to server.
  gpr_log(GPR_INFO, "starting client connect");
  Client client(server_address_string);
  client.Connect();
  // Client read.  Should fail due to server dropping connection.
  gpr_log(GPR_INFO, "starting client read");
  EXPECT_TRUE(client.ReadUntilError());
  // Shut down client.
  gpr_log(GPR_INFO, "shutting down client");
  client.Shutdown();
  // Shut down server.
  gpr_log(GPR_INFO, "shutting down server");
  server_thread.Shutdown();
  // Clean up.
  gpr_free(server_address_string);
}

}  // namespace
}  // namespace test
}  // namespace grpc_core

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  grpc::testing::TestEnvironment env(argc, argv);
  grpc_init();
  int result = RUN_ALL_TESTS();
  grpc_shutdown();
  return result;
}
<|endoftext|>


<commit_before>//******************************************************************
//
// Copyright 2014 Samsung Electronics All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// 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.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// OCClient.cpp : Defines the entry point for the console application.
//
#include <string>
#include <cstdlib>
#include <pthread.h>
#include <map>
#include <vector>
#include "OCPlatform.h"
#include "OCApi.h"
#include "ThingsManager.h"

using namespace OC;
using namespace OIC;

int g_Steps = 0;
int isWaiting = 0; //0: none to wait, 1: wait for the response of "getConfigurationValue"

const int SUCCESS_RESPONSE = 0;

static ThingsManager* g_thingsmanager;

OCResourceHandle configurationCollectionHandle;
std::shared_ptr< OCResource > g_configurationCollection; // for a group of multiple resources
std::shared_ptr< OCResource > g_configurationResource; // For a single resource

OCResourceHandle diagnosticsCollectionHandle;
std::shared_ptr< OCResource > g_diagnosticsCollection; // for a group of multiple resources
std::shared_ptr< OCResource > g_diagnosticsResource; // For a single resource

OCResourceHandle setCollectionHandle;
std::shared_ptr< OCResource > g_setCollection; // for a group of multiple resources
std::shared_ptr< OCResource > g_setResource; // For a single resource

std::map< std::string, std::shared_ptr< OCResource > > resourceTable;
std::vector< OCResourceHandle > resourceHandleVector;

typedef std::function<
        void(const HeaderOptions& headerOptions,
                const OCRepresentation& rep, const int eCode) > ConfigurationCallback;
typedef std::function<
        void(const HeaderOptions& headerOptions,
                const OCRepresentation& rep, const int eCode) > DiagnosticsCallback;

typedef std::string ConfigurationName;
typedef std::string ConfigurationValue;

void timeCheck(int timeSec)
{
    sleep(timeSec);
    isWaiting = 0;
}

void onReboot(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
{
    isWaiting = 0;

    if (eCode != SUCCESS_RESPONSE)
    {
        return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;
    std::cout << "\t\tReboot:" << rep.getValue< std::string >("value") << std::endl;
}

void onFactoryReset(const HeaderOptions& headerOptions, const OCRepresentation& rep,
        const int eCode)
{
    isWaiting = 0;

    if (eCode != SUCCESS_RESPONSE)
    {
       return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;
    std::cout << "\t\tFactoryReset:" << rep.getValue< std::string >("value") << std::endl;
}

void onUpdate(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
{
    isWaiting = 0;

    if (eCode != SUCCESS_RESPONSE)
    {
        return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;

    if (rep.hasAttribute("loc"))
        std::cout << "\t\tLocation:" << rep.getValue< std::string >("loc") << std::endl;
    if (rep.hasAttribute("st"))
        std::cout << "\t\tSystemTime:" << rep.getValue< std::string >("st") << std::endl;
    if (rep.hasAttribute("c"))
        std::cout << "\t\tCurrency:" << rep.getValue< std::string >("c") << std::endl;
    if (rep.hasAttribute("r"))
        std::cout << "\t\tRegion:" << rep.getValue< std::string >("r") << std::endl;
}

void onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
{
    isWaiting = 0;

    if (eCode != SUCCESS_RESPONSE)
    {
        return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;

    if (rep.hasAttribute("loc"))
        std::cout << "\t\tLocation:" << rep.getValue< std::string >("loc") << std::endl;
    if (rep.hasAttribute("st"))
        std::cout << "\t\tSystemTime:" << rep.getValue< std::string >("st") << std::endl;
    if (rep.hasAttribute("c"))
        std::cout << "\t\tCurrency:" << rep.getValue< std::string >("c") << std::endl;
    if (rep.hasAttribute("r"))
        std::cout << "\t\tRegion:" << rep.getValue< std::string >("r") << std::endl;
}

// Callback to found collection resource
void onFoundCollectionResource(std::vector< std::shared_ptr< OCResource > > resources)
{
    std::string resourceURI;
    std::string hostAddress;
    try
    {
        // Do some operations with resource object.
        for (unsigned int i = 0; i < resources.size(); ++i)
        {
            std::shared_ptr< OCResource > resource = resources.at(i);

            if (resource)
            {
                if (resource->uri() == "/core/a/configuration/resourceset")
                    g_configurationCollection = resource;
                else if (resource->uri() == "/core/a/diagnostics/resourceset")
                    g_diagnosticsCollection = resource;
                else if (resource->uri() == "/core/a/factoryset/resourceset")
                    g_setCollection = resource;
                else
                {
                    isWaiting = 0;
                    return;
                }
            }
            else
            {
                // Resource is invalid
                std::cout << "Resource is invalid" << std::endl;
            }
        }

    }
    catch (std::exception& e)
    {
        //log(e.what());
    }

    isWaiting = 0;
}

// Callback to found resources
void onFoundCandidateResource(std::vector< std::shared_ptr< OCResource > > resources)
{

    std::string resourceURI;
    std::string hostAddress;

    try
    {
        // Do some operations with resource object.
        for (unsigned int i = 0; i < resources.size(); ++i)
        {
            std::shared_ptr< OCResource > resource = resources.at(i);

            if (resource)
            {
                // Check if the resource is new one. If so, store it.

                std::map< std::string, std::shared_ptr< OCResource > >::iterator iter =
                        resourceTable.find(resource->host() + resource->uri());

                if (iter == resourceTable.end()) // new one
                {
                    resourceTable[resource->host() + resource->uri()] = resource;

                    OCResourceHandle foundResourceHandle;
                    OCStackResult result = OCPlatform::registerResource(foundResourceHandle,
                            resource);
                    std::cout << "\tResource ( " << resource->host() << " ) is registed!\t"
                            << std::endl;
                    if (result == OC_STACK_OK)
                    {
                        if (resource->uri() == "/oic/con")
                        {
                            OCPlatform::bindResource(configurationCollectionHandle,
                                    foundResourceHandle);
                            if (g_configurationResource == NULL)
                                g_configurationResource = resource;
                        }
                        else if (resource->uri() == "/oic/diag")
                        {
                            OCPlatform::bindResource(diagnosticsCollectionHandle,
                                    foundResourceHandle);
                            if (g_diagnosticsResource == NULL)
                                g_diagnosticsResource = resource;
                        }
                        else if (resource->uri() == "/factorySet")
                        {
                            OCPlatform::bindResource(setCollectionHandle, foundResourceHandle);
                            if (g_setResource == NULL)
                                g_setResource = resource;
                        }

                        resourceHandleVector.push_back(foundResourceHandle);
                    }
                    else
                    {
                        cout << "\tresource Error!" << endl;
                    }

                }

            }
            else
            {
                // Resource is invalid
                std::cout << "Resource is invalid" << std::endl;
            }
        }

    }
    catch (std::exception& e)
    {
        //log(e.what());
    }

    isWaiting = 0;
}

int main(int argc, char* argv[])
{
    std::string str_steps;

    //**************************************************************
    // STEP 0
    PlatformConfig cfg
    { OC::ServiceType::InProc, OC::ModeType::Both, "0.0.0.0", 0, OC::QualityOfService::LowQos };

    OCPlatform::Configure(cfg);
    g_thingsmanager = new ThingsManager();

    //**************************************************************

    while (true)
    {

        if (isWaiting > 0)
            continue;

        isWaiting = 0;

        cout << endl << endl << "(0) Quit" << std::endl;
        cout << "(1) Find all resources(URI: /oic/con, /oic/diag, /factoryset)" << std::endl;
        cout << "(2) Find all groups" << std::endl;
        cout << "(3) Get a Configuration resource" << std::endl;
        cout << "(4) Update a region attribute value" << std::endl;
        cout << "(5) FactoryReset (for the group)" << std::endl;
        cout << "(6) Reboot (for the group)" << std::endl;
        cout << "(10) Show Configuration Units" << std::endl;

        try
        {
            std::getline (std::cin, str_steps);

            if(str_steps == "")
                continue;
            else
                g_Steps = std::stoi(str_steps);
        }
        catch(std::invalid_argument&)
        {
            std::cout << "Please put a digit, not string" << std::endl;
            continue;
        }

        if (g_Steps == 0)
            break;
        else if (g_Steps == 1)
        {
            std::vector< std::string > types;

            // For Registering a collection resource for configuration resources
            if (configurationCollectionHandle == NULL)
            {
                string resourceURI = "/core/a/configuration/resourceset";
                string resourceTypeName = "core.configuration.resourceset";
                string resourceInterface = BATCH_INTERFACE;

                OCPlatform::registerResource(configurationCollectionHandle, resourceURI,
                    resourceTypeName, resourceInterface, NULL,
                    //&entityHandler, // entityHandler
                    OC_DISCOVERABLE);

                OCPlatform::bindInterfaceToResource(configurationCollectionHandle, GROUP_INTERFACE);
                OCPlatform::bindInterfaceToResource(configurationCollectionHandle,
                    DEFAULT_INTERFACE);
            }

            // For Registering a collection resource for diagnostics resources
            if (diagnosticsCollectionHandle == NULL)
            {
                string resourceURI = "/core/a/diagnostics/resourceset";
                string resourceTypeName = "core.diagnostics.resourceset";
                string resourceInterface = BATCH_INTERFACE;

                OCPlatform::registerResource(diagnosticsCollectionHandle, resourceURI,
                    resourceTypeName, resourceInterface, NULL,
                    //&entityHandler, // entityHandler
                    OC_DISCOVERABLE);

                OCPlatform::bindInterfaceToResource(diagnosticsCollectionHandle, GROUP_INTERFACE);
                OCPlatform::bindInterfaceToResource(diagnosticsCollectionHandle, DEFAULT_INTERFACE);
            }

            // For Registering a collection resource for set resources
            if (setCollectionHandle == NULL)
            {
                string resourceURI = "/core/a/factoryset/resourceset";
                string resourceTypeName = "core.factoryset.resourceset";
                string resourceInterface = BATCH_INTERFACE;

                OCPlatform::registerResource(setCollectionHandle, resourceURI, resourceTypeName,
                    resourceInterface, NULL,
                    //&entityHandler, // entityHandler
                    OC_DISCOVERABLE);

                OCPlatform::bindInterfaceToResource(setCollectionHandle, GROUP_INTERFACE);
                OCPlatform::bindInterfaceToResource(setCollectionHandle, DEFAULT_INTERFACE);
            }

            types.push_back("oic.con");
            types.push_back("oic.diag");
            types.push_back("factorySet");

            std::cout << "Finding Configuration Resource... " << std::endl;
            std::cout << "Finding Diagnostics Resource... " << std::endl;
            std::cout << "Finding Set Resource... " << std::endl;

            g_thingsmanager->findCandidateResources(types, &onFoundCandidateResource, 5);

            isWaiting = 1;

            thread t(&timeCheck, 5);
            t.join();       // After 5 seconds, isWaiting value will be 0.
        }
        else if (g_Steps == 2) // make a group with found things
        {
            std::vector< std::string > types;
            types.push_back("core.configuration.resourceset");
            types.push_back("core.diagnostics.resourceset");
            types.push_back("core.factoryset.resourceset");

            g_thingsmanager->findCandidateResources(types, &onFoundCollectionResource, 5);

            std::cout << "Finding Collection resource... " << std::endl;

            isWaiting = 1;

            thread t(&timeCheck, 5);
            t.join();       // After 5 seconds, isWaiting value will be 0.
        }
        else if (g_Steps == 3)
        {
            // get a value

            ConfigurationName name = "all";

            std::cout << "For example, get configuration resources's value" << std::endl;

            std::vector< ConfigurationName > configurations;

            configurations.push_back(name);

            if (g_thingsmanager->getConfigurations(g_configurationCollection, configurations, &onGet)
                    != OC_STACK_ERROR)
                isWaiting = 1;
        }
        else if (g_Steps == 4)
        {
            ConfigurationName name = "r";
            ConfigurationValue value = "U.S.A (new region)";

            if(g_configurationCollection == NULL)
            {
                std::cout<<"Note that you first create a group to use this command." << std::endl;
                continue;
            }

            std::cout << "For example, change region resource's value" << std::endl;
            std::cout << g_configurationCollection->uri() << std::endl;

            std::map< ConfigurationName, ConfigurationValue > configurations;

            configurations.insert(std::make_pair(name, value));

            if (g_thingsmanager->updateConfigurations(g_configurationCollection, configurations,
                    &onUpdate) != OC_STACK_ERROR)
                isWaiting = 1;
        }
        else if (g_Steps == 5)
        {
            // factory reset
            if(g_diagnosticsCollection == NULL)
            {
                std::cout<<"Note that you first create a group to use this command." << std::endl;
                continue;
            }

            if (g_thingsmanager->factoryReset(g_diagnosticsCollection, &onFactoryReset)
                    != OC_STACK_ERROR)
                isWaiting = 1;
        }
        else if (g_Steps == 6)
        {
            // reboot
            if(g_diagnosticsCollection == NULL)
            {
                std::cout<<"Note that you first create a group to use this command." << std::endl;
                continue;
            }

            if (g_thingsmanager->reboot(g_diagnosticsCollection, &onReboot) != OC_STACK_ERROR)
                isWaiting = 1;
        }
        else if (g_Steps == 10)
        {
            std::cout << g_thingsmanager->getListOfSupportedConfigurationUnits() << std::endl;

        }

    }

    return 0;
}

<commit_msg>Fix an unexpected halt problem in con-client app.<commit_after>//******************************************************************
//
// Copyright 2014 Samsung Electronics All Rights Reserved.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// 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.
//
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

// OCClient.cpp : Defines the entry point for the console application.
//
#include <string>
#include <cstdlib>
#include <pthread.h>
#include <map>
#include <vector>
#include "OCPlatform.h"
#include "OCApi.h"
#include "ThingsManager.h"

using namespace OC;
using namespace OIC;

int g_Steps = 0;
int isWaiting = 0; //0: none to wait, 1: wait for the response of "getConfigurationValue"
pthread_mutex_t mutex_lock;

const int SUCCESS_RESPONSE = 0;

static ThingsManager* g_thingsmanager;

OCResourceHandle configurationCollectionHandle;
std::shared_ptr< OCResource > g_configurationCollection; // for a group of multiple resources
std::shared_ptr< OCResource > g_configurationResource; // For a single resource

OCResourceHandle diagnosticsCollectionHandle;
std::shared_ptr< OCResource > g_diagnosticsCollection; // for a group of multiple resources
std::shared_ptr< OCResource > g_diagnosticsResource; // For a single resource

OCResourceHandle setCollectionHandle;
std::shared_ptr< OCResource > g_setCollection; // for a group of multiple resources
std::shared_ptr< OCResource > g_setResource; // For a single resource

std::map< std::string, std::shared_ptr< OCResource > > resourceTable;
std::vector< OCResourceHandle > resourceHandleVector;

typedef std::function<
        void(const HeaderOptions& headerOptions,
                const OCRepresentation& rep, const int eCode) > ConfigurationCallback;
typedef std::function<
        void(const HeaderOptions& headerOptions,
                const OCRepresentation& rep, const int eCode) > DiagnosticsCallback;

typedef std::string ConfigurationName;
typedef std::string ConfigurationValue;

void timeCheck(int timeSec)
{
    sleep(timeSec);
    pthread_mutex_lock(&mutex_lock);
    isWaiting = 0;
    pthread_mutex_unlock(&mutex_lock);
}

void onReboot(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
{
    pthread_mutex_lock(&mutex_lock);
    isWaiting = 0;
    pthread_mutex_unlock(&mutex_lock);

    if (eCode != SUCCESS_RESPONSE)
    {
        return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;
    std::cout << "\t\tReboot:" << rep.getValue< std::string >("value") << std::endl;
}

void onFactoryReset(const HeaderOptions& headerOptions, const OCRepresentation& rep,
        const int eCode)
{
    pthread_mutex_lock(&mutex_lock);
    isWaiting = 0;
    pthread_mutex_unlock(&mutex_lock);

    if (eCode != SUCCESS_RESPONSE)
    {
       return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;
    std::cout << "\t\tFactoryReset:" << rep.getValue< std::string >("value") << std::endl;
}

void onUpdate(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
{
    pthread_mutex_lock(&mutex_lock);
    isWaiting = 0;
    pthread_mutex_unlock(&mutex_lock);

    if (eCode != SUCCESS_RESPONSE)
    {
        return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;

    if (rep.hasAttribute("loc"))
        std::cout << "\t\tLocation:" << rep.getValue< std::string >("loc") << std::endl;
    if (rep.hasAttribute("st"))
        std::cout << "\t\tSystemTime:" << rep.getValue< std::string >("st") << std::endl;
    if (rep.hasAttribute("c"))
        std::cout << "\t\tCurrency:" << rep.getValue< std::string >("c") << std::endl;
    if (rep.hasAttribute("r"))
        std::cout << "\t\tRegion:" << rep.getValue< std::string >("r") << std::endl;
}

void onGet(const HeaderOptions& headerOptions, const OCRepresentation& rep, const int eCode)
{
    pthread_mutex_lock(&mutex_lock);
    isWaiting = 0;
    pthread_mutex_unlock(&mutex_lock);

    if (eCode != SUCCESS_RESPONSE)
    {
        return ;
    }

    std::cout << "\tResource URI: " << rep.getUri() << std::endl;

    if (rep.hasAttribute("loc"))
        std::cout << "\t\tLocation:" << rep.getValue< std::string >("loc") << std::endl;
    if (rep.hasAttribute("st"))
        std::cout << "\t\tSystemTime:" << rep.getValue< std::string >("st") << std::endl;
    if (rep.hasAttribute("c"))
        std::cout << "\t\tCurrency:" << rep.getValue< std::string >("c") << std::endl;
    if (rep.hasAttribute("r"))
        std::cout << "\t\tRegion:" << rep.getValue< std::string >("r") << std::endl;
}

// Callback to found collection resource
void onFoundCollectionResource(std::vector< std::shared_ptr< OCResource > > resources)
{
    std::string resourceURI;
    std::string hostAddress;
    try
    {
        // Do some operations with resource object.
        for (unsigned int i = 0; i < resources.size(); ++i)
        {
            std::shared_ptr< OCResource > resource = resources.at(i);

            if (resource)
            {
                if (resource->uri() == "/core/a/configuration/resourceset")
                    g_configurationCollection = resource;
                else if (resource->uri() == "/core/a/diagnostics/resourceset")
                    g_diagnosticsCollection = resource;
                else if (resource->uri() == "/core/a/factoryset/resourceset")
                    g_setCollection = resource;
                else
                {
                    isWaiting = 0;
                    return;
                }
            }
            else
            {
                // Resource is invalid
                std::cout << "Resource is invalid" << std::endl;
            }
        }

    }
    catch (std::exception& e)
    {
        //log(e.what());
    }

    isWaiting = 0;
}

// Callback to found resources
void onFoundCandidateResource(std::vector< std::shared_ptr< OCResource > > resources)
{
    std::string resourceURI;
    std::string hostAddress;

    try
    {
        // Do some operations with resource object.
        for (unsigned int i = 0; i < resources.size(); ++i)
        {
            std::shared_ptr< OCResource > resource = resources.at(i);

            if (resource)
            {
                // Check if the resource is new one. If so, store it.

                std::map< std::string, std::shared_ptr< OCResource > >::iterator iter =
                        resourceTable.find(resource->host() + resource->uri());

                if (iter == resourceTable.end()) // new one
                {
                    resourceTable[resource->host() + resource->uri()] = resource;

                    OCResourceHandle foundResourceHandle;
                    OCStackResult result = OCPlatform::registerResource(foundResourceHandle,
                            resource);
                    std::cout << "\tResource ( " << resource->host() << " ) is registed!\t"
                            << std::endl;
                    if (result == OC_STACK_OK)
                    {
                        if (resource->uri() == "/oic/con")
                        {
                            OCPlatform::bindResource(configurationCollectionHandle,
                                    foundResourceHandle);
                            if (g_configurationResource == NULL)
                                g_configurationResource = resource;
                        }
                        else if (resource->uri() == "/oic/diag")
                        {
                            OCPlatform::bindResource(diagnosticsCollectionHandle,
                                    foundResourceHandle);
                            if (g_diagnosticsResource == NULL)
                                g_diagnosticsResource = resource;
                        }
                        else if (resource->uri() == "/factorySet")
                        {
                            OCPlatform::bindResource(setCollectionHandle, foundResourceHandle);
                            if (g_setResource == NULL)
                                g_setResource = resource;
                        }

                        resourceHandleVector.push_back(foundResourceHandle);
                    }
                    else
                    {
                        cout << "\tresource Error!" << endl;
                    }

                }

            }
            else
            {
                // Resource is invalid
                std::cout << "Resource is invalid" << std::endl;
            }
        }

    }
    catch (std::exception& e)
    {
        //log(e.what());
    }

    isWaiting = 0;
}

int main(int argc, char* argv[])
{
    std::string str_steps;
    pthread_mutex_init(&mutex_lock, NULL);

    //**************************************************************
    // STEP 0
    PlatformConfig cfg
    { OC::ServiceType::InProc, OC::ModeType::Both, "0.0.0.0", 0, OC::QualityOfService::LowQos };

    OCPlatform::Configure(cfg);
    g_thingsmanager = new ThingsManager();

    //**************************************************************

    while (true)
    {
        pthread_mutex_lock(&mutex_lock);
        if (isWaiting > 0)
        {
            pthread_mutex_unlock(&mutex_lock);
            continue;
        }

        isWaiting = 0;
        pthread_mutex_unlock(&mutex_lock);

        cout << endl << endl << "(0) Quit" << std::endl;
        cout << "(1) Find all resources(URI: /oic/con, /oic/diag, /factoryset)" << std::endl;
        cout << "(2) Find all groups" << std::endl;
        cout << "(3) Get a Configuration resource" << std::endl;
        cout << "(4) Update a region attribute value" << std::endl;
        cout << "(5) FactoryReset (for the group)" << std::endl;
        cout << "(6) Reboot (for the group)" << std::endl;
        cout << "(10) Show Configuration Units" << std::endl;

        try
        {
            std::getline (std::cin, str_steps);

            if(str_steps == "")
            {
                continue;
            }
            else
            {
                g_Steps = std::stoi(str_steps);
            }
        }
        catch(std::invalid_argument&)
        {
            std::cout << "Please put a digit, not string" << std::endl;
            continue;
        }

        if (g_Steps == 0)
        {
            break;
        }
        else if (g_Steps == 1)
        {
            std::vector< std::string > types;

            // For Registering a collection resource for configuration resources
            if (configurationCollectionHandle == NULL)
            {
                string resourceURI = "/core/a/configuration/resourceset";
                string resourceTypeName = "core.configuration.resourceset";
                string resourceInterface = BATCH_INTERFACE;

                OCPlatform::registerResource(configurationCollectionHandle, resourceURI,
                    resourceTypeName, resourceInterface, NULL,
                    //&entityHandler, // entityHandler
                    OC_DISCOVERABLE);

                OCPlatform::bindInterfaceToResource(configurationCollectionHandle, GROUP_INTERFACE);
                OCPlatform::bindInterfaceToResource(configurationCollectionHandle,
                    DEFAULT_INTERFACE);
            }

            // For Registering a collection resource for diagnostics resources
            if (diagnosticsCollectionHandle == NULL)
            {
                string resourceURI = "/core/a/diagnostics/resourceset";
                string resourceTypeName = "core.diagnostics.resourceset";
                string resourceInterface = BATCH_INTERFACE;

                OCPlatform::registerResource(diagnosticsCollectionHandle, resourceURI,
                    resourceTypeName, resourceInterface, NULL,
                    //&entityHandler, // entityHandler
                    OC_DISCOVERABLE);

                OCPlatform::bindInterfaceToResource(diagnosticsCollectionHandle, GROUP_INTERFACE);
                OCPlatform::bindInterfaceToResource(diagnosticsCollectionHandle, DEFAULT_INTERFACE);
            }

            // For Registering a collection resource for set resources
            if (setCollectionHandle == NULL)
            {
                string resourceURI = "/core/a/factoryset/resourceset";
                string resourceTypeName = "core.factoryset.resourceset";
                string resourceInterface = BATCH_INTERFACE;

                OCPlatform::registerResource(setCollectionHandle, resourceURI, resourceTypeName,
                    resourceInterface, NULL,
                    //&entityHandler, // entityHandler
                    OC_DISCOVERABLE);

                OCPlatform::bindInterfaceToResource(setCollectionHandle, GROUP_INTERFACE);
                OCPlatform::bindInterfaceToResource(setCollectionHandle, DEFAULT_INTERFACE);
            }

            types.push_back("oic.con");
            types.push_back("oic.diag");
            types.push_back("factorySet");

            std::cout << "Finding Configuration Resource... " << std::endl;
            std::cout << "Finding Diagnostics Resource... " << std::endl;
            std::cout << "Finding Set Resource... " << std::endl;

            g_thingsmanager->findCandidateResources(types, &onFoundCandidateResource, 5);

            isWaiting = 1;

            thread t(&timeCheck, 5);
            t.join();       // After 5 seconds, isWaiting value will be 0.
        }
        else if (g_Steps == 2) // make a group with found things
        {
            std::vector< std::string > types;
            types.push_back("core.configuration.resourceset");
            types.push_back("core.diagnostics.resourceset");
            types.push_back("core.factoryset.resourceset");

            g_thingsmanager->findCandidateResources(types, &onFoundCollectionResource, 5);

            std::cout << "Finding Collection resource... " << std::endl;

            isWaiting = 1;

            thread t(&timeCheck, 5);
            t.join();       // After 5 seconds, isWaiting value will be 0.
        }
        else if (g_Steps == 3)
        {
            // get a value

            ConfigurationName name = "all";

            std::cout << "For example, get configuration resources's value" << std::endl;

            std::vector< ConfigurationName > configurations;

            configurations.push_back(name);

            if (g_thingsmanager->getConfigurations(g_configurationCollection, configurations, &onGet)
                    != OC_STACK_ERROR)
            {
                pthread_mutex_lock(&mutex_lock);
                isWaiting = 0;
                pthread_mutex_unlock(&mutex_lock);
            }
        }
        else if (g_Steps == 4)
        {
            ConfigurationName name = "r";
            ConfigurationValue value = "U.S.A (new region)";

            if(g_configurationCollection == NULL)
            {
                std::cout<<"Note that you first create a group to use this command." << std::endl;
                continue;
            }

            std::cout << "For example, change region resource's value" << std::endl;
            std::cout << g_configurationCollection->uri() << std::endl;

            std::map< ConfigurationName, ConfigurationValue > configurations;

            configurations.insert(std::make_pair(name, value));

            if (g_thingsmanager->updateConfigurations(g_configurationCollection, configurations,
                    &onUpdate) != OC_STACK_ERROR)
            {
                pthread_mutex_lock(&mutex_lock);
                isWaiting = 0;
                pthread_mutex_unlock(&mutex_lock);
            }
        }
        else if (g_Steps == 5)
        {
            // factory reset
            if(g_diagnosticsCollection == NULL)
            {
                std::cout<<"Note that you first create a group to use this command." << std::endl;
                continue;
            }

            if (g_thingsmanager->factoryReset(g_diagnosticsCollection, &onFactoryReset)
                    != OC_STACK_ERROR)
            {
                pthread_mutex_lock(&mutex_lock);
                isWaiting = 0;
                pthread_mutex_unlock(&mutex_lock);
            }
        }
        else if (g_Steps == 6)
        {
            // reboot
            if(g_diagnosticsCollection == NULL)
            {
                std::cout<<"Note that you first create a group to use this command." << std::endl;
                continue;
            }

            if (g_thingsmanager->reboot(g_diagnosticsCollection, &onReboot) != OC_STACK_ERROR)
            {
                pthread_mutex_lock(&mutex_lock);
                isWaiting = 0;
                pthread_mutex_unlock(&mutex_lock);
            }
        }
        else if (g_Steps == 10)
        {
            std::cout << g_thingsmanager->getListOfSupportedConfigurationUnits() << std::endl;

        }

    }

    return 0;
}

<|endoftext|>


<commit_before>// Author: Enric Tejedor CERN  06/2018
// Original PyROOT code by Wim Lavrijsen, LBL

/*************************************************************************
 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

// Bindings
#include "PyROOTPythonize.h"
#include "PyROOTStrings.h"
#include "PyROOTWrapper.h"
#include "RPyROOTApplication.h"
#include "FacadeHelpers.hxx"

// Cppyy
#include "CPyCppyy.h"
#include "CallContext.h"
#include "ProxyWrappers.h"
#include "Utility.h"

// ROOT
#include "TROOT.h"
#include "TSystem.h"
#include "RConfigure.h"

// Standard
#include <string>
#include <sstream>
#include <utility>
#include <vector>

using namespace CPyCppyy;

namespace PyROOT {
PyObject *gRootModule = 0;
}

// Methods offered by the interface
static PyMethodDef gPyROOTMethods[] = {
   {(char *)"AddDirectoryWritePyz", (PyCFunction)PyROOT::AddDirectoryWritePyz, METH_VARARGS,
    (char *)"Allow to use seamlessly from Python the templated TDirectory::WriteObject method"},
   {(char *)"AddCPPInstancePickling", (PyCFunction)PyROOT::AddCPPInstancePickling, METH_VARARGS,
    (char *)"Add a custom pickling mechanism for Cppyy Python proxy objects"},
   {(char *)"AddDirectoryGetAttrPyz", (PyCFunction)PyROOT::AddDirectoryGetAttrPyz, METH_VARARGS,
    (char *)"Attr syntax for TDirectory, TDirectoryFile and TFile"},
   {(char *)"AddBranchAttrSyntax", (PyCFunction)PyROOT::AddBranchAttrSyntax, METH_VARARGS,
    (char *)"Allow to access branches as tree attributes"},
   {(char *)"AddFileOpenPyz", (PyCFunction)PyROOT::AddFileOpenPyz, METH_VARARGS,
    (char *)"Make TFile::Open a constructor, adjusting for example the reference count"},
   {(char *)"AddTDirectoryFileGetPyz", (PyCFunction)PyROOT::AddTDirectoryFileGetPyz, METH_VARARGS,
    (char *)"Get objects inside TDirectoryFile and TFile instantiations"},
   {(char *)"AddTClassDynamicCastPyz", (PyCFunction)PyROOT::AddTClassDynamicCastPyz, METH_VARARGS,
    (char *)"Cast the void* returned by TClass::DynamicCast to the right type"},
   {(char *)"AddTObjectEqNePyz", (PyCFunction)PyROOT::AddTObjectEqNePyz, METH_VARARGS,
    (char *)"Add equality and inequality comparison operators to TObject"},
   {(char *)"AddUsingToClass", (PyCFunction)PyROOT::AddUsingToClass, METH_VARARGS,
    (char *)"Add 'using' overloads for a given method to a class"},
   {(char *)"SetBranchAddressPyz", (PyCFunction)PyROOT::SetBranchAddressPyz, METH_VARARGS,
    (char *)"Fully enable the use of TTree::SetBranchAddress from Python"},
   {(char *)"BranchPyz", (PyCFunction)PyROOT::BranchPyz, METH_VARARGS,
    (char *)"Fully enable the use of TTree::Branch from Python"},
   {(char *)"AddSetItemTCAPyz", (PyCFunction)PyROOT::AddSetItemTCAPyz, METH_VARARGS,
    (char *)"Customize the setting of an item of a TClonesArray"},
   {(char *)"AddPrettyPrintingPyz", (PyCFunction)PyROOT::AddPrettyPrintingPyz, METH_VARARGS,
    (char *)"Add pretty printing pythonization"},
   {(char *)"GetEndianess", (PyCFunction)PyROOT::GetEndianess, METH_NOARGS, (char *)"Get endianess of the system"},
   {(char *)"GetDataPointer", (PyCFunction)PyROOT::GetDataPointer, METH_VARARGS,
    (char *)"Get pointer to data of a C++ object"},
   {(char *)"GetSizeOfType", (PyCFunction)PyROOT::GetSizeOfType, METH_VARARGS, (char *)"Get size of data-type"},
   {(char *)"AsRVec", (PyCFunction)PyROOT::AsRVec, METH_O, (char *)"Get object with array interface as RVec"},
#ifdef R__HAS_DATAFRAME
   {(char *)"AsRTensor", (PyCFunction)PyROOT::AsRTensor, METH_O, (char *)"Get object with array interface as RTensor"},
   {(char *)"MakeNumpyDataFrame", (PyCFunction)PyROOT::MakeNumpyDataFrame, METH_O,
    (char *)"Make RDataFrame from dictionary of numpy arrays"},
#endif
   {(char *)"InitApplication", (PyCFunction)PyROOT::RPyROOTApplication::InitApplication, METH_VARARGS,
    (char *)"Initialize interactive ROOT use from Python"},
   {(char *)"InstallGUIEventInputHook", (PyCFunction)PyROOT::RPyROOTApplication::InstallGUIEventInputHook, METH_NOARGS,
    (char *)"Install an input hook to process GUI events"},
   {(char *)"_CPPInstance__expand__", (PyCFunction)PyROOT::CPPInstanceExpand, METH_VARARGS,
    (char *)"Deserialize a pickled object"},
   {(char *)"ClearProxiedObjects", (PyCFunction)PyROOT::ClearProxiedObjects, METH_NOARGS,
    (char *)"Clear proxied objects regulated by PyROOT"},
   {(char *)"CreateBufferFromAddress", (PyCFunction)PyROOT::CreateBufferFromAddress, METH_O,
    (char *)"Create a LowLevelView object on the received address"},
   {NULL, NULL, 0, NULL}};

#define QuoteIdent(ident) #ident
#define QuoteMacro(macro) QuoteIdent(macro)
#define LIBROOTPYZ_NAME "libROOTPythonizations" QuoteMacro(PY_MAJOR_VERSION) "_" QuoteMacro(PY_MINOR_VERSION)

#define CONCAT(a, b, c, d) a##b##c##d
#define LIBROOTPYZ_INIT_FUNCTION(a, b, c, d) CONCAT(a, b, c, d)

#if PY_VERSION_HEX >= 0x03000000
struct module_state {
   PyObject *error;
};

#define GETSTATE(m) ((struct module_state *)PyModule_GetState(m))

static int rootmodule_traverse(PyObject *m, visitproc visit, void *arg)
{
   Py_VISIT(GETSTATE(m)->error);
   return 0;
}

static int rootmodule_clear(PyObject *m)
{
   Py_CLEAR(GETSTATE(m)->error);
   return 0;
}

static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT,       LIBROOTPYZ_NAME,  NULL,
                                       sizeof(struct module_state), gPyROOTMethods,   NULL,
                                       rootmodule_traverse,         rootmodule_clear, NULL};

/// Initialization of extension module libROOTPythonizations

#define PYROOT_INIT_ERROR return NULL
LIBROOTPYZ_INIT_FUNCTION(extern "C" PyObject* PyInit_libROOTPythonizations, PY_MAJOR_VERSION, _, PY_MINOR_VERSION) ()
#else // PY_VERSION_HEX >= 0x03000000
#define PYROOT_INIT_ERROR return
LIBROOTPYZ_INIT_FUNCTION(extern "C" void initlibROOTPythonizations, PY_MAJOR_VERSION, _, PY_MINOR_VERSION) ()
#endif
{
   using namespace PyROOT;

   // load commonly used python strings
   if (!PyROOT::CreatePyStrings())
      PYROOT_INIT_ERROR;

// setup PyROOT
#if PY_VERSION_HEX >= 0x03000000
   gRootModule = PyModule_Create(&moduledef);
#else
   gRootModule = Py_InitModule(const_cast<char *>(LIBROOTPYZ_NAME), gPyROOTMethods);
#endif
   if (!gRootModule)
      PYROOT_INIT_ERROR;

   // keep gRootModule, but do not increase its reference count even as it is borrowed,
   // or a self-referencing cycle would be created

   // setup PyROOT
   PyROOT::Init();

   // signal policy: don't abort interpreter in interactive mode
   CallContext::SetGlobalSignalPolicy(!gROOT->IsBatch());

   // inject ROOT namespace for convenience
   PyModule_AddObject(gRootModule, (char *)"ROOT", CreateScopeProxy("ROOT"));

#if PY_VERSION_HEX >= 0x03000000
   Py_INCREF(gRootModule);
   return gRootModule;
#endif
}
<commit_msg>[PyROOT][6552] Import libcppyy during initialization of libROOTPythonizations<commit_after>// Author: Enric Tejedor CERN  06/2018
// Original PyROOT code by Wim Lavrijsen, LBL

/*************************************************************************
 * Copyright (C) 1995-2018, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

// Bindings
#include "PyROOTPythonize.h"
#include "PyROOTStrings.h"
#include "PyROOTWrapper.h"
#include "RPyROOTApplication.h"
#include "FacadeHelpers.hxx"

// Cppyy
#include "CPyCppyy.h"
#include "CallContext.h"
#include "ProxyWrappers.h"
#include "Utility.h"

// ROOT
#include "TROOT.h"
#include "TSystem.h"
#include "RConfigure.h"

// Standard
#include <string>
#include <sstream>
#include <utility>
#include <vector>

using namespace CPyCppyy;

namespace PyROOT {
PyObject *gRootModule = 0;
}

// Methods offered by the interface
static PyMethodDef gPyROOTMethods[] = {
   {(char *)"AddDirectoryWritePyz", (PyCFunction)PyROOT::AddDirectoryWritePyz, METH_VARARGS,
    (char *)"Allow to use seamlessly from Python the templated TDirectory::WriteObject method"},
   {(char *)"AddCPPInstancePickling", (PyCFunction)PyROOT::AddCPPInstancePickling, METH_VARARGS,
    (char *)"Add a custom pickling mechanism for Cppyy Python proxy objects"},
   {(char *)"AddDirectoryGetAttrPyz", (PyCFunction)PyROOT::AddDirectoryGetAttrPyz, METH_VARARGS,
    (char *)"Attr syntax for TDirectory, TDirectoryFile and TFile"},
   {(char *)"AddBranchAttrSyntax", (PyCFunction)PyROOT::AddBranchAttrSyntax, METH_VARARGS,
    (char *)"Allow to access branches as tree attributes"},
   {(char *)"AddFileOpenPyz", (PyCFunction)PyROOT::AddFileOpenPyz, METH_VARARGS,
    (char *)"Make TFile::Open a constructor, adjusting for example the reference count"},
   {(char *)"AddTDirectoryFileGetPyz", (PyCFunction)PyROOT::AddTDirectoryFileGetPyz, METH_VARARGS,
    (char *)"Get objects inside TDirectoryFile and TFile instantiations"},
   {(char *)"AddTClassDynamicCastPyz", (PyCFunction)PyROOT::AddTClassDynamicCastPyz, METH_VARARGS,
    (char *)"Cast the void* returned by TClass::DynamicCast to the right type"},
   {(char *)"AddTObjectEqNePyz", (PyCFunction)PyROOT::AddTObjectEqNePyz, METH_VARARGS,
    (char *)"Add equality and inequality comparison operators to TObject"},
   {(char *)"AddUsingToClass", (PyCFunction)PyROOT::AddUsingToClass, METH_VARARGS,
    (char *)"Add 'using' overloads for a given method to a class"},
   {(char *)"SetBranchAddressPyz", (PyCFunction)PyROOT::SetBranchAddressPyz, METH_VARARGS,
    (char *)"Fully enable the use of TTree::SetBranchAddress from Python"},
   {(char *)"BranchPyz", (PyCFunction)PyROOT::BranchPyz, METH_VARARGS,
    (char *)"Fully enable the use of TTree::Branch from Python"},
   {(char *)"AddSetItemTCAPyz", (PyCFunction)PyROOT::AddSetItemTCAPyz, METH_VARARGS,
    (char *)"Customize the setting of an item of a TClonesArray"},
   {(char *)"AddPrettyPrintingPyz", (PyCFunction)PyROOT::AddPrettyPrintingPyz, METH_VARARGS,
    (char *)"Add pretty printing pythonization"},
   {(char *)"GetEndianess", (PyCFunction)PyROOT::GetEndianess, METH_NOARGS, (char *)"Get endianess of the system"},
   {(char *)"GetDataPointer", (PyCFunction)PyROOT::GetDataPointer, METH_VARARGS,
    (char *)"Get pointer to data of a C++ object"},
   {(char *)"GetSizeOfType", (PyCFunction)PyROOT::GetSizeOfType, METH_VARARGS, (char *)"Get size of data-type"},
   {(char *)"AsRVec", (PyCFunction)PyROOT::AsRVec, METH_O, (char *)"Get object with array interface as RVec"},
#ifdef R__HAS_DATAFRAME
   {(char *)"AsRTensor", (PyCFunction)PyROOT::AsRTensor, METH_O, (char *)"Get object with array interface as RTensor"},
   {(char *)"MakeNumpyDataFrame", (PyCFunction)PyROOT::MakeNumpyDataFrame, METH_O,
    (char *)"Make RDataFrame from dictionary of numpy arrays"},
#endif
   {(char *)"InitApplication", (PyCFunction)PyROOT::RPyROOTApplication::InitApplication, METH_VARARGS,
    (char *)"Initialize interactive ROOT use from Python"},
   {(char *)"InstallGUIEventInputHook", (PyCFunction)PyROOT::RPyROOTApplication::InstallGUIEventInputHook, METH_NOARGS,
    (char *)"Install an input hook to process GUI events"},
   {(char *)"_CPPInstance__expand__", (PyCFunction)PyROOT::CPPInstanceExpand, METH_VARARGS,
    (char *)"Deserialize a pickled object"},
   {(char *)"ClearProxiedObjects", (PyCFunction)PyROOT::ClearProxiedObjects, METH_NOARGS,
    (char *)"Clear proxied objects regulated by PyROOT"},
   {(char *)"CreateBufferFromAddress", (PyCFunction)PyROOT::CreateBufferFromAddress, METH_O,
    (char *)"Create a LowLevelView object on the received address"},
   {NULL, NULL, 0, NULL}};

#define QuoteIdent(ident) #ident
#define QuoteMacro(macro) QuoteIdent(macro)
#define LIBROOTPYZ_NAME "libROOTPythonizations" QuoteMacro(PY_MAJOR_VERSION) "_" QuoteMacro(PY_MINOR_VERSION)
#define LIBCPPYY_NAME "libcppyy" QuoteMacro(PY_MAJOR_VERSION) "_" QuoteMacro(PY_MINOR_VERSION)

#define CONCAT(a, b, c, d) a##b##c##d
#define LIBROOTPYZ_INIT_FUNCTION(a, b, c, d) CONCAT(a, b, c, d)

#if PY_VERSION_HEX >= 0x03000000
struct module_state {
   PyObject *error;
};

#define GETSTATE(m) ((struct module_state *)PyModule_GetState(m))

static int rootmodule_traverse(PyObject *m, visitproc visit, void *arg)
{
   Py_VISIT(GETSTATE(m)->error);
   return 0;
}

static int rootmodule_clear(PyObject *m)
{
   Py_CLEAR(GETSTATE(m)->error);
   return 0;
}

static struct PyModuleDef moduledef = {PyModuleDef_HEAD_INIT,       LIBROOTPYZ_NAME,  NULL,
                                       sizeof(struct module_state), gPyROOTMethods,   NULL,
                                       rootmodule_traverse,         rootmodule_clear, NULL};

/// Initialization of extension module libROOTPythonizations

#define PYROOT_INIT_ERROR return NULL
LIBROOTPYZ_INIT_FUNCTION(extern "C" PyObject* PyInit_libROOTPythonizations, PY_MAJOR_VERSION, _, PY_MINOR_VERSION) ()
#else // PY_VERSION_HEX >= 0x03000000
#define PYROOT_INIT_ERROR return
LIBROOTPYZ_INIT_FUNCTION(extern "C" void initlibROOTPythonizations, PY_MAJOR_VERSION, _, PY_MINOR_VERSION) ()
#endif
{
   using namespace PyROOT;

   // load commonly used python strings
   if (!PyROOT::CreatePyStrings())
      PYROOT_INIT_ERROR;

// setup PyROOT
#if PY_VERSION_HEX >= 0x03000000
   gRootModule = PyModule_Create(&moduledef);
#else
   gRootModule = Py_InitModule(const_cast<char *>(LIBROOTPYZ_NAME), gPyROOTMethods);
#endif
   if (!gRootModule)
      PYROOT_INIT_ERROR;

   // keep gRootModule, but do not increase its reference count even as it is borrowed,
   // or a self-referencing cycle would be created

   // Make sure libcppyy has been imported
   PyImport_ImportModule(LIBCPPYY_NAME);

   // setup PyROOT
   PyROOT::Init();

   // signal policy: don't abort interpreter in interactive mode
   CallContext::SetGlobalSignalPolicy(!gROOT->IsBatch());

   // inject ROOT namespace for convenience
   PyModule_AddObject(gRootModule, (char *)"ROOT", CreateScopeProxy("ROOT"));

#if PY_VERSION_HEX >= 0x03000000
   Py_INCREF(gRootModule);
   return gRootModule;
#endif
}
<|endoftext|>


<commit_before>#include <gbAudio/impl/QueuedSource_OAL.hpp>

#include <gbAudio/impl/Buffer_OAL.hpp>
#include <gbAudio/impl/Error_OAL.hpp>

#include <gbAudio/Exceptions.hpp>

#include <gbBase/Assert.hpp>
#include <gbBase/Exception.hpp>
#include <gbBase/Log.hpp>

namespace GHULBUS_AUDIO_NAMESPACE
{
namespace impl
{

QueuedSource_OAL::QueuedSource_OAL(ALuint source_id)
    :m_source(source_id), m_userRequestedPlayState(State::Stopped)
{
}

QueuedSource_OAL::~QueuedSource_OAL()
{
    ErrorMonitor_OAL monitor;
    GHULBUS_LOG(Debug, "Deleting queued source #" << m_source << ".");
    alDeleteSources(1, &m_source);
}

void QueuedSource_OAL::play()
{
    GHULBUS_LOG(Trace, "Playing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePlay(m_source);
    m_userRequestedPlayState = State::Playing;
}

void QueuedSource_OAL::pause()
{
    GHULBUS_LOG(Trace, "Pausing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePause(m_source);
    m_userRequestedPlayState = State::Paused;
}

void QueuedSource_OAL::stop()
{
    GHULBUS_LOG(Trace, "Stopping queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceStop(m_source);
    m_userRequestedPlayState = State::Stopped;
}

void QueuedSource_OAL::rewind()
{
    GHULBUS_LOG(Trace, "Rewinding queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceRewind(m_source);
}

Playable::State QueuedSource_OAL::getPlayState() const
{
    ALint state;
    alGetSourcei(m_source, AL_SOURCE_STATE, &state);
    switch(state)
    {
    case AL_PLAYING: return State::Playing;
    case AL_PAUSED:  return State::Paused;
    default:         return State::Stopped;
    }
}

void QueuedSource_OAL::loop(bool do_loop)
{
    ErrorMonitor_OAL monitor;
    alSourcei(m_source, AL_LOOPING, (do_loop) ? AL_TRUE : AL_FALSE);
}

bool QueuedSource_OAL::isLooping() const
{
    ALint ret;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_LOOPING, &ret);
    return (ret == AL_TRUE);
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer)
{
    enqueueBuffer(buffer, BufferProcessedCallback());
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer, BufferProcessedCallback cb)
{
    auto& oal_buffer = dynamic_cast<Buffer_OAL&>(buffer);
    ALuint const buffer_id = oal_buffer.getBufferId_OAL();
    m_queue.emplace_back(&oal_buffer, std::move(cb));
    ErrorMonitor_OAL monitor;
    alSourceQueueBuffers(m_source, 1, &buffer_id);
    if(monitor.checkError()) {
        m_queue.pop_back();
        GHULBUS_THROW(Exceptions::OpenALError(), "Error when queuing buffers to source.");
    }
}

void QueuedSource_OAL::pump()
{
    ALint buffers_processed;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_processed);
    if(buffers_processed == 0) { return; }
    std::vector<ALuint> free_buffers(buffers_processed);
    alSourceUnqueueBuffers(m_source, buffers_processed, free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while unqueuing buffers from source.");
    }

    std::vector<ALuint> reinserted_buffers;
    reinserted_buffers.reserve(free_buffers.size());        // we assume that reinsertion is the typical case
    auto it = begin(free_buffers);
    while(it != end(free_buffers)) {
        auto const qe = m_queue.front();
        GHULBUS_ASSERT(qe.buffer->getBufferId_OAL() == *it);
        auto const buffer_action = qe.cb(*qe.buffer);
        if(buffer_action == BufferAction::Reinsert) {
            m_queue.push_back(qe);
            ++it;
        } else {
            GHULBUS_ASSERT(buffer_action == BufferAction::Drop);
            it = free_buffers.erase(it);
        }
        m_queue.pop_front();
    }

    if(!free_buffers.empty()) {
        alSourceQueueBuffers(m_source, static_cast<ALsizei>(free_buffers.size()), free_buffers.data());
        if(monitor.checkError()) {
            GHULBUS_THROW(Exceptions::OpenALError(), "Error while re-queuing buffers to source.");
        }
        // If a source stopped playing because it ran out of buffers, reinserting buffers will resume playback
        if(m_userRequestedPlayState == State::Playing && getPlayState() == State::Stopped)
        {
            alSourcePlay(m_source);
        }
    }
}

void QueuedSource_OAL::clearQueue()
{
    GHULBUS_PRECONDITION(getPlayState() == State::Stopped);
    ErrorMonitor_OAL monitor;
    std::vector<ALuint> free_buffers(m_queue.size());
    alSourceUnqueueBuffers(m_source, static_cast<ALsizei>(m_queue.size()), free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while clearing buffer queue on source.");
    }
}

}
}
<commit_msg>default version of enqueueBuffer no longer causes empty function invoke<commit_after>#include <gbAudio/impl/QueuedSource_OAL.hpp>

#include <gbAudio/impl/Buffer_OAL.hpp>
#include <gbAudio/impl/Error_OAL.hpp>

#include <gbAudio/Exceptions.hpp>

#include <gbBase/Assert.hpp>
#include <gbBase/Exception.hpp>
#include <gbBase/Log.hpp>

namespace GHULBUS_AUDIO_NAMESPACE
{
namespace impl
{

QueuedSource_OAL::QueuedSource_OAL(ALuint source_id)
    :m_source(source_id), m_userRequestedPlayState(State::Stopped)
{
}

QueuedSource_OAL::~QueuedSource_OAL()
{
    ErrorMonitor_OAL monitor;
    GHULBUS_LOG(Debug, "Deleting queued source #" << m_source << ".");
    alDeleteSources(1, &m_source);
}

void QueuedSource_OAL::play()
{
    GHULBUS_LOG(Trace, "Playing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePlay(m_source);
    m_userRequestedPlayState = State::Playing;
}

void QueuedSource_OAL::pause()
{
    GHULBUS_LOG(Trace, "Pausing queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourcePause(m_source);
    m_userRequestedPlayState = State::Paused;
}

void QueuedSource_OAL::stop()
{
    GHULBUS_LOG(Trace, "Stopping queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceStop(m_source);
    m_userRequestedPlayState = State::Stopped;
}

void QueuedSource_OAL::rewind()
{
    GHULBUS_LOG(Trace, "Rewinding queued source #" << m_source << ".");
    ErrorMonitor_OAL monitor;
    alSourceRewind(m_source);
}

Playable::State QueuedSource_OAL::getPlayState() const
{
    ALint state;
    alGetSourcei(m_source, AL_SOURCE_STATE, &state);
    switch(state)
    {
    case AL_PLAYING: return State::Playing;
    case AL_PAUSED:  return State::Paused;
    default:         return State::Stopped;
    }
}

void QueuedSource_OAL::loop(bool do_loop)
{
    ErrorMonitor_OAL monitor;
    alSourcei(m_source, AL_LOOPING, (do_loop) ? AL_TRUE : AL_FALSE);
}

bool QueuedSource_OAL::isLooping() const
{
    ALint ret;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_LOOPING, &ret);
    return (ret == AL_TRUE);
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer)
{
    enqueueBuffer(buffer, [](Buffer&) { return BufferAction::Drop; });
}

void QueuedSource_OAL::enqueueBuffer(Buffer& buffer, BufferProcessedCallback cb)
{
    auto& oal_buffer = dynamic_cast<Buffer_OAL&>(buffer);
    ALuint const buffer_id = oal_buffer.getBufferId_OAL();
    m_queue.emplace_back(&oal_buffer, std::move(cb));
    ErrorMonitor_OAL monitor;
    alSourceQueueBuffers(m_source, 1, &buffer_id);
    if(monitor.checkError()) {
        m_queue.pop_back();
        GHULBUS_THROW(Exceptions::OpenALError(), "Error when queuing buffers to source.");
    }
}

void QueuedSource_OAL::pump()
{
    ALint buffers_processed;
    ErrorMonitor_OAL monitor;
    alGetSourcei(m_source, AL_BUFFERS_PROCESSED, &buffers_processed);
    if(buffers_processed == 0) { return; }
    std::vector<ALuint> free_buffers(buffers_processed);
    alSourceUnqueueBuffers(m_source, buffers_processed, free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while unqueuing buffers from source.");
    }

    std::vector<ALuint> reinserted_buffers;
    reinserted_buffers.reserve(free_buffers.size());        // we assume that reinsertion is the typical case
    auto it = begin(free_buffers);
    while(it != end(free_buffers)) {
        auto const qe = m_queue.front();
        GHULBUS_ASSERT(qe.buffer->getBufferId_OAL() == *it);
        auto const buffer_action = qe.cb(*qe.buffer);
        if(buffer_action == BufferAction::Reinsert) {
            m_queue.push_back(qe);
            ++it;
        } else {
            GHULBUS_ASSERT(buffer_action == BufferAction::Drop);
            it = free_buffers.erase(it);
        }
        m_queue.pop_front();
    }

    if(!free_buffers.empty()) {
        alSourceQueueBuffers(m_source, static_cast<ALsizei>(free_buffers.size()), free_buffers.data());
        if(monitor.checkError()) {
            GHULBUS_THROW(Exceptions::OpenALError(), "Error while re-queuing buffers to source.");
        }
        // If a source stopped playing because it ran out of buffers, reinserting buffers will resume playback
        if(m_userRequestedPlayState == State::Playing && getPlayState() == State::Stopped)
        {
            alSourcePlay(m_source);
        }
    }
}

void QueuedSource_OAL::clearQueue()
{
    GHULBUS_PRECONDITION(getPlayState() == State::Stopped);
    ErrorMonitor_OAL monitor;
    std::vector<ALuint> free_buffers(m_queue.size());
    alSourceUnqueueBuffers(m_source, static_cast<ALsizei>(m_queue.size()), free_buffers.data());
    if(monitor.checkError()) {
        GHULBUS_THROW(Exceptions::OpenALError(), "Error while clearing buffer queue on source.");
    }
}

}
}
<|endoftext|>


<commit_before>/*   This file is part of the KDE project
 *
 *   Copyright (C) 2014 Dominik Haumann <dhauumann@kde.org>
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public License
 *   along with this library; see the file COPYING.LIB.  If not, write to
 *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *   Boston, MA 02110-1301, USA.
 */

#include "katetabbutton.h"

#include <KLocalizedString>

#include <QApplication>
// #include <QDebug>
#include <QDrag>
#include <QFontDatabase>
#include <QHBoxLayout>
#include <QMimeData>
#include <QMoveEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyle>
#include <QStyleOption>

#include <math.h>

TabCloseButton::TabCloseButton(QWidget * parent)
    : QAbstractButton(parent)
{
    // should never have focus
    setFocusPolicy(Qt::NoFocus);

    // closing a tab closes the document
    setToolTip(i18n("Close Document"));
}

void TabCloseButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

    // get the tab this close button belongs to
    KateTabButton *tabButton = qobject_cast<KateTabButton*>(parent());
    const bool isActive = underMouse()
        || (tabButton && tabButton->isChecked());

    // set style options depending on current state
    QStyleOption opt;
    opt.init(this);
    if (isActive && !isChecked()) {
        opt.state |= QStyle::State_Raised;
    }
    if (isChecked()) {
        opt.state |= QStyle::State_Sunken;
    }

    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this);
}

QSize TabCloseButton::sizeHint() const
{
    // make sure the widget is polished
    ensurePolished();

    // read the metrics from the style
    const int w = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this);
    const int h = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this);
    return QSize(w, h);
}

void TabCloseButton::enterEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::enterEvent(event);
}

void TabCloseButton::leaveEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::leaveEvent(event);
}

KateTabButton::KateTabButton(const QString &text, QWidget *parent)
    : QAbstractButton(parent)
    , m_geometryAnimation(0)
{
    setCheckable(true);
    setFocusPolicy(Qt::NoFocus);

    setText(text);

    // add close button
    const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, 0, this);
    m_closeButton = new TabCloseButton(this);
    QHBoxLayout * hbox = new QHBoxLayout(this);
    hbox->setSpacing(0);
    hbox->setContentsMargins(margin, 0, margin, 0);
    hbox->addStretch();
    hbox->addWidget(m_closeButton);
    setLayout(hbox);
    connect(m_closeButton, &TabCloseButton::clicked, this, &KateTabButton::closeButtonClicked);
}

void KateTabButton::closeButtonClicked()
{
    emit closeRequest(this);
}

void KateTabButton::paintEvent(QPaintEvent *ev)
{
    Q_UNUSED(ev)

    QColor barColor(palette().color(QPalette::Highlight));

    // read from the parent widget (=KateTabBar) the isActiveTabBar property
    if (!isActiveTabBar()) {
        // if inactive, convert color to gray value
        const int g = qGray(barColor.rgb());
        barColor = QColor(g, g, g);
    }

    // compute sane margins
    const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, 0, this);
    const int barMargin = margin / 2;
    const int barHeight = ceil(height() / 10.0);

    QPainter p(this);

    // paint bar if inactive but hovered
    if (!isChecked() && underMouse()) {
        barColor.setAlpha(80);
        p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor);
    }

    // paint bar
    if (isChecked()) {
        barColor.setAlpha(255);
        p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor);
    }

    // icon, if applicable
    int leftMargin = margin;
    if (! icon().isNull()) {
        const int y = (height() - 16) / 2;
        icon().paint(&p, margin, y, 16, 16);
        leftMargin += 16;
        leftMargin += margin;
    }

    // the width of the text is reduced by the close button + 2 * margin
    const int w = width() // width of widget
                - m_closeButton->width() - 2 * margin // close button
                - leftMargin; // modified button

    // draw text, we need to elide to xxx...xxx is too long
    const QString elidedText = QFontMetrics(font()).elidedText (text(), Qt::ElideMiddle, w);
    const QRect textRect(leftMargin, 0, w, height());
    const QPalette pal = QApplication::palette();
    style()->drawItemText(&p, textRect, Qt::AlignHCenter | Qt::AlignVCenter, pal, true, elidedText, QPalette::WindowText);
}

void KateTabButton::mousePressEvent(QMouseEvent *ev)
{
    ev->accept();

    // save mouse position for possible drag start event
    m_mouseDownPosition = ev->globalPos();

    // activation code
    if (ev->button() == Qt::LeftButton) {
        if (! isChecked()) {
            // make sure we stay checked
            setChecked(true);
        }

        // notify that this button was activated
        emit activated(this);
    } else {
        ev->ignore();
    }
}

void KateTabButton::mouseMoveEvent(QMouseEvent *event)
{
    // possibly start drag event
    if (QPoint(event->globalPos() - m_mouseDownPosition).manhattanLength() > QApplication::startDragDistance())
    {
        QMimeData *mimeData = new QMimeData;
        mimeData->setData(QStringLiteral("application/x-dndkatetabbutton"), QByteArray());

        auto drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setDragCursor(QPixmap(), Qt::MoveAction);
        drag->start(Qt::MoveAction);
        event->accept();
    }
    QAbstractButton::mouseMoveEvent(event);
}

void KateTabButton::mouseDoubleClickEvent(QMouseEvent *event)
{
    event->accept();
}

void KateTabButton::enterEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::enterEvent(event);
}

void KateTabButton::leaveEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::leaveEvent(event);
}

void KateTabButton::moveEvent(QMoveEvent *event)
{
    // tell the tabbar to redraw its separators. Since the separators overlap
    // the tab buttons geometry, we need to adjust the width by the separator's
    // width to avoid artifacts
    if (parentWidget()) {
        const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, 0, this);
        QRect rect = geometry();
        rect.moveLeft(event->oldPos().x());
        rect.adjust(-w, 0, w, 0);
        parentWidget()->update(rect);
    }
    QAbstractButton::moveEvent(event);
}

bool KateTabButton::isActiveTabBar() const
{
    Q_ASSERT(parentWidget());

    // read from the parent widget (=KateTabBar) the isActive property
    return parentWidget()->property("isActive").toBool();
}

void KateTabButton::setAnimatedGeometry(const QRect & startGeom,
                                        const QRect & endGeom)
{
    // stop animation in case it is running
    if (m_geometryAnimation &&
        m_geometryAnimation->state() != QAbstractAnimation::Stopped) {
        m_geometryAnimation->stop();
    }

    // already at desired position
    if (startGeom == geometry() && endGeom == startGeom) {
        return;
    }

    // if the style does not want animations, just set geometry
    if (! style()->styleHint(QStyle::SH_Widget_Animate, 0, this)
        || (isVisible() && endGeom == startGeom))
    {
        setGeometry(endGeom);
        return;
    }

    if (! m_geometryAnimation) {
        m_geometryAnimation = new QPropertyAnimation(this, "geometry", this);
        m_geometryAnimation->setDuration(100);
    }

    // finally start geometry animation
    m_geometryAnimation->setStartValue(startGeom);
    m_geometryAnimation->setEndValue(endGeom);
    m_geometryAnimation->start();
}

bool KateTabButton::geometryAnimationRunning() const
{
    return m_geometryAnimation
        && (m_geometryAnimation->state() != QAbstractAnimation::Stopped);
}
<commit_msg>TabBar: Close tab/document with middle mouse button<commit_after>/*   This file is part of the KDE project
 *
 *   Copyright (C) 2014 Dominik Haumann <dhauumann@kde.org>
 *
 *   This library is free software; you can redistribute it and/or
 *   modify it under the terms of the GNU Library General Public
 *   License as published by the Free Software Foundation; either
 *   version 2 of the License, or (at your option) any later version.
 *
 *   This library is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *   Library General Public License for more details.
 *
 *   You should have received a copy of the GNU Library General Public License
 *   along with this library; see the file COPYING.LIB.  If not, write to
 *   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 *   Boston, MA 02110-1301, USA.
 */

#include "katetabbutton.h"

#include <KLocalizedString>

#include <QApplication>
// #include <QDebug>
#include <QDrag>
#include <QFontDatabase>
#include <QHBoxLayout>
#include <QMimeData>
#include <QMoveEvent>
#include <QPainter>
#include <QPropertyAnimation>
#include <QStyle>
#include <QStyleOption>

#include <math.h>

TabCloseButton::TabCloseButton(QWidget * parent)
    : QAbstractButton(parent)
{
    // should never have focus
    setFocusPolicy(Qt::NoFocus);

    // closing a tab closes the document
    setToolTip(i18n("Close Document"));
}

void TabCloseButton::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)

    // get the tab this close button belongs to
    KateTabButton *tabButton = qobject_cast<KateTabButton*>(parent());
    const bool isActive = underMouse()
        || (tabButton && tabButton->isChecked());

    // set style options depending on current state
    QStyleOption opt;
    opt.init(this);
    if (isActive && !isChecked()) {
        opt.state |= QStyle::State_Raised;
    }
    if (isChecked()) {
        opt.state |= QStyle::State_Sunken;
    }

    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this);
}

QSize TabCloseButton::sizeHint() const
{
    // make sure the widget is polished
    ensurePolished();

    // read the metrics from the style
    const int w = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this);
    const int h = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this);
    return QSize(w, h);
}

void TabCloseButton::enterEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::enterEvent(event);
}

void TabCloseButton::leaveEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::leaveEvent(event);
}

KateTabButton::KateTabButton(const QString &text, QWidget *parent)
    : QAbstractButton(parent)
    , m_geometryAnimation(0)
{
    setCheckable(true);
    setFocusPolicy(Qt::NoFocus);

    setText(text);

    // add close button
    const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, 0, this);
    m_closeButton = new TabCloseButton(this);
    QHBoxLayout * hbox = new QHBoxLayout(this);
    hbox->setSpacing(0);
    hbox->setContentsMargins(margin, 0, margin, 0);
    hbox->addStretch();
    hbox->addWidget(m_closeButton);
    setLayout(hbox);
    connect(m_closeButton, &TabCloseButton::clicked, this, &KateTabButton::closeButtonClicked);
}

void KateTabButton::closeButtonClicked()
{
    emit closeRequest(this);
}

void KateTabButton::paintEvent(QPaintEvent *ev)
{
    Q_UNUSED(ev)

    QColor barColor(palette().color(QPalette::Highlight));

    // read from the parent widget (=KateTabBar) the isActiveTabBar property
    if (!isActiveTabBar()) {
        // if inactive, convert color to gray value
        const int g = qGray(barColor.rgb());
        barColor = QColor(g, g, g);
    }

    // compute sane margins
    const int margin = style()->pixelMetric(QStyle::PM_ButtonMargin, 0, this);
    const int barMargin = margin / 2;
    const int barHeight = ceil(height() / 10.0);

    QPainter p(this);

    // paint bar if inactive but hovered
    if (!isChecked() && underMouse()) {
        barColor.setAlpha(80);
        p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor);
    }

    // paint bar
    if (isChecked()) {
        barColor.setAlpha(255);
        p.fillRect(QRect(barMargin, height() - barHeight, width() - 2 * barMargin, barHeight), barColor);
    }

    // icon, if applicable
    int leftMargin = margin;
    if (! icon().isNull()) {
        const int y = (height() - 16) / 2;
        icon().paint(&p, margin, y, 16, 16);
        leftMargin += 16;
        leftMargin += margin;
    }

    // the width of the text is reduced by the close button + 2 * margin
    const int w = width() // width of widget
                - m_closeButton->width() - 2 * margin // close button
                - leftMargin; // modified button

    // draw text, we need to elide to xxx...xxx is too long
    const QString elidedText = QFontMetrics(font()).elidedText (text(), Qt::ElideMiddle, w);
    const QRect textRect(leftMargin, 0, w, height());
    const QPalette pal = QApplication::palette();
    style()->drawItemText(&p, textRect, Qt::AlignHCenter | Qt::AlignVCenter, pal, true, elidedText, QPalette::WindowText);
}

void KateTabButton::mousePressEvent(QMouseEvent *ev)
{
    ev->accept();

    // save mouse position for possible drag start event
    m_mouseDownPosition = ev->globalPos();

    // activation code
    if (ev->button() == Qt::LeftButton) {
        if (! isChecked()) {
            // make sure we stay checked
            setChecked(true);
        }

        // notify that this button was activated
        emit activated(this);
    } else if (ev->button() == Qt::MiddleButton) {
        emit closeRequest(this);
    } else {
        ev->ignore();
    }
}

void KateTabButton::mouseMoveEvent(QMouseEvent *event)
{
    // possibly start drag event
    if (QPoint(event->globalPos() - m_mouseDownPosition).manhattanLength() > QApplication::startDragDistance())
    {
        QMimeData *mimeData = new QMimeData;
        mimeData->setData(QStringLiteral("application/x-dndkatetabbutton"), QByteArray());

        auto drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setDragCursor(QPixmap(), Qt::MoveAction);
        drag->start(Qt::MoveAction);
        event->accept();
    }
    QAbstractButton::mouseMoveEvent(event);
}

void KateTabButton::mouseDoubleClickEvent(QMouseEvent *event)
{
    event->accept();
}

void KateTabButton::enterEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::enterEvent(event);
}

void KateTabButton::leaveEvent(QEvent *event)
{
    update(); // repaint on hover
    QAbstractButton::leaveEvent(event);
}

void KateTabButton::moveEvent(QMoveEvent *event)
{
    // tell the tabbar to redraw its separators. Since the separators overlap
    // the tab buttons geometry, we need to adjust the width by the separator's
    // width to avoid artifacts
    if (parentWidget()) {
        const int w = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, 0, this);
        QRect rect = geometry();
        rect.moveLeft(event->oldPos().x());
        rect.adjust(-w, 0, w, 0);
        parentWidget()->update(rect);
    }
    QAbstractButton::moveEvent(event);
}

bool KateTabButton::isActiveTabBar() const
{
    Q_ASSERT(parentWidget());

    // read from the parent widget (=KateTabBar) the isActive property
    return parentWidget()->property("isActive").toBool();
}

void KateTabButton::setAnimatedGeometry(const QRect & startGeom,
                                        const QRect & endGeom)
{
    // stop animation in case it is running
    if (m_geometryAnimation &&
        m_geometryAnimation->state() != QAbstractAnimation::Stopped) {
        m_geometryAnimation->stop();
    }

    // already at desired position
    if (startGeom == geometry() && endGeom == startGeom) {
        return;
    }

    // if the style does not want animations, just set geometry
    if (! style()->styleHint(QStyle::SH_Widget_Animate, 0, this)
        || (isVisible() && endGeom == startGeom))
    {
        setGeometry(endGeom);
        return;
    }

    if (! m_geometryAnimation) {
        m_geometryAnimation = new QPropertyAnimation(this, "geometry", this);
        m_geometryAnimation->setDuration(100);
    }

    // finally start geometry animation
    m_geometryAnimation->setStartValue(startGeom);
    m_geometryAnimation->setEndValue(endGeom);
    m_geometryAnimation->start();
}

bool KateTabButton::geometryAnimationRunning() const
{
    return m_geometryAnimation
        && (m_geometryAnimation->state() != QAbstractAnimation::Stopped);
}
<|endoftext|>