<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <chrono>
#include <iostream>

#include "cuda.h"
#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "egblas.hpp"

#define cuda_check(call)                                                                                \
    {                                                                                \
        auto status = call;                                                                             \
        if (status != cudaSuccess) {                                                                    \
            std::cerr << "CUDA error: " << cudaGetErrorString(status) << " from " << #call << std::endl \
                      << "from " << __FILE__ << ":" << __LINE__ << std::endl;                           \
            exit(1);                                                                                \
        }                                                                                \
    }

namespace {

using timer = std::chrono::high_resolution_clock;
using microseconds =  std::chrono::microseconds;

float* prepare_cpu(size_t N, float s){
    float* x_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = s * (i + 1);
    }

    return x_cpu;
}

float* prepare_gpu(size_t N, float* x_cpu){
    float* x_gpu;

    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    return x_gpu;
}

void release(float* x_cpu, float* x_gpu){
    delete[] x_cpu;

    cuda_check(cudaFree(x_gpu));
}

template<typename T>
inline void report(const std::string& name, const T& t0, size_t repeat, size_t N){
    auto t1 = timer::now();
    auto us = std::chrono::duration_cast<microseconds>(t1 - t0).count();
    auto us_avg = us / double(repeat);

    std::cout << name << "(" << N << "): Tot: " << us << "us Avg: " << us_avg << "us Throughput: "
        << (1e6 / double(us_avg)) * N << "E/s" << std::endl;
}

void bench_sum(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.1f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_ssum(x_gpu, N, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_ssum(x_gpu, N, 1);
    }

    report("sum", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_sum(){
    bench_sum(100);
    bench_sum(1000);
    bench_sum(10000);
    bench_sum(100000);
    bench_sum(1000000);
    bench_sum(10000000);
    bench_sum(100000000);
    std::cout << std::endl;
}

void bench_inv_dropout(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.0f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_sinv_dropout_seed(N, 0.5f, 1.0f, x_gpu, 1, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_sinv_dropout_seed(N, 0.5f, 1.0f, x_gpu, 1, 42);
    }

    report("inv_dropout", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_inv_dropout(){
    bench_inv_dropout(100);
    bench_inv_dropout(1000);
    bench_inv_dropout(10000);
    bench_inv_dropout(100000);
    bench_inv_dropout(1000000);
    bench_inv_dropout(10000000);
    bench_inv_dropout(100000000);
    std::cout << std::endl;
}

void bench_saxpy(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.0f);
    auto* y_cpu = prepare_cpu(N, 3.0f);

    auto* x_gpu = prepare_gpu(N, x_cpu);
    auto* y_gpu = prepare_gpu(N, y_cpu);

    egblas_saxpy(N, 2.1f, x_gpu, 1, y_gpu, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_saxpy(N, 2.1f, x_gpu, 1, y_gpu, 1);
    }

    report("saxpy", t0, repeat, N);

    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_saxpy(){
    bench_saxpy(100);
    bench_saxpy(1000);
    bench_saxpy(10000);
    bench_saxpy(100000);
    bench_saxpy(1000000);
    bench_saxpy(10000000);
    bench_saxpy(100000000);
    std::cout << std::endl;
}

void bench_saxpby(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.2f);
    auto* y_cpu = prepare_cpu(N, 3.1f);

    auto* x_gpu = prepare_gpu(N, x_cpu);
    auto* y_gpu = prepare_gpu(N, y_cpu);

    egblas_saxpby(N, 2.54f, x_gpu, 1, 3.49f, y_gpu, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_saxpby(N, 2.54f, x_gpu, 1, 3.49f, y_gpu, 1);
    }

    report("saxpby", t0, repeat, N);

    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_saxpby(){
    bench_saxpby(100);
    bench_saxpby(1000);
    bench_saxpby(10000);
    bench_saxpby(100000);
    bench_saxpby(1000000);
    bench_saxpby(10000000);
    bench_saxpby(100000000);
    std::cout << std::endl;
}

void bench_shuffle(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.2f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_shuffle_seed(N, x_gpu, 4, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_shuffle_seed(N, x_gpu, 4, 42);
    }

    report("shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_shuffle(){
    bench_shuffle(100);
    bench_shuffle(1000);
    bench_shuffle(10000);
    bench_shuffle(100000);
    std::cout << std::endl;
}

void bench_par_shuffle(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.2f);
    auto* y_cpu = prepare_cpu(N, 3.1f);

    auto* x_gpu = prepare_gpu(N, x_cpu);
    auto* y_gpu = prepare_gpu(N, y_cpu);

    egblas_par_shuffle_seed(N, x_gpu, 4, y_gpu, 4, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_par_shuffle_seed(N, x_gpu, 4, y_gpu, 4, 42);
    }

    report("par_shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_par_shuffle(){
    bench_par_shuffle(100);
    bench_par_shuffle(1000);
    bench_par_shuffle(10000);
    bench_par_shuffle(100000);
    std::cout << std::endl;
}

void bench_big_shuffle(size_t N, size_t repeat = 100) {
    auto* x_cpu = prepare_cpu(N * 1024, 2.2f);
    auto* x_gpu = prepare_gpu(N * 1024, x_cpu);

    egblas_shuffle_seed(N, x_gpu, 4 * 1024, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_shuffle_seed(N, x_gpu, 4 * 1024, 42);
    }

    report("big_shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * 1024 * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_big_shuffle(){
    bench_big_shuffle(100);
    bench_big_shuffle(1000);
    bench_big_shuffle(10000);
    std::cout << std::endl;
}

void bench_par_big_shuffle(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N * 1024, 2.2f);
    auto* y_cpu = prepare_cpu(N * 1024, 3.1f);

    auto* x_gpu = prepare_gpu(N * 1024, x_cpu);
    auto* y_gpu = prepare_gpu(N * 1024, y_cpu);

    egblas_par_shuffle_seed(N, x_gpu, 4 * 1024, y_gpu, 4, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_par_shuffle_seed(N, x_gpu, 4 * 1024, y_gpu, 4, 42);
    }

    report("par_big_shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * 1024 * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * 1024 * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_par_big_shuffle(){
    bench_par_big_shuffle(100);
    bench_par_big_shuffle(1000);
    bench_par_big_shuffle(10000);
    std::cout << std::endl;
}

} // End of anonymous namespace

int main(int argc, char* argv[]){
    std::string sub = "all";

    if(argc > 1){
        sub = std::string(argv[1]);
    }

    if (sub == "sum" || sub == "all") {
        bench_sum();
    }

    if (sub == "dropout" || sub == "all") {
        bench_inv_dropout();
    }

    if (sub == "shuffle" || sub == "all") {
        bench_shuffle();
        bench_par_shuffle();
        bench_big_shuffle();
        bench_par_big_shuffle();
    }

    if (sub == "axpy" || sub == "all") {
        bench_saxpy();
        bench_saxpby();
    }
}
<commit_msg>Benchmark for stddev<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <chrono>
#include <iostream>

#include "cuda.h"
#include "cuda_runtime.h"
#include "cuda_runtime_api.h"

#include "egblas.hpp"

#define cuda_check(call)                                                                                \
    {                                                                                \
        auto status = call;                                                                             \
        if (status != cudaSuccess) {                                                                    \
            std::cerr << "CUDA error: " << cudaGetErrorString(status) << " from " << #call << std::endl \
                      << "from " << __FILE__ << ":" << __LINE__ << std::endl;                           \
            exit(1);                                                                                \
        }                                                                                \
    }

namespace {

using timer = std::chrono::high_resolution_clock;
using microseconds =  std::chrono::microseconds;

float* prepare_cpu(size_t N, float s){
    float* x_cpu = new float[N];

    for (size_t i = 0; i < N; ++i) {
        x_cpu[i] = s * (i + 1);
    }

    return x_cpu;
}

float* prepare_gpu(size_t N, float* x_cpu){
    float* x_gpu;

    cuda_check(cudaMalloc((void**)&x_gpu, N * sizeof(float)));
    cuda_check(cudaMemcpy(x_gpu, x_cpu, N * sizeof(float), cudaMemcpyHostToDevice));

    return x_gpu;
}

void release(float* x_cpu, float* x_gpu){
    delete[] x_cpu;

    cuda_check(cudaFree(x_gpu));
}

template<typename T>
inline void report(const std::string& name, const T& t0, size_t repeat, size_t N){
    auto t1 = timer::now();
    auto us = std::chrono::duration_cast<microseconds>(t1 - t0).count();
    auto us_avg = us / double(repeat);

    std::cout << name << "(" << N << "): Tot: " << us << "us Avg: " << us_avg << "us Throughput: "
        << (1e6 / double(us_avg)) * N << "E/s" << std::endl;
}

void bench_sum(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.1f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_ssum(x_gpu, N, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_ssum(x_gpu, N, 1);
    }

    report("sum", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_sum(){
    bench_sum(100);
    bench_sum(1000);
    bench_sum(10000);
    bench_sum(100000);
    bench_sum(1000000);
    bench_sum(10000000);
    bench_sum(100000000);
    std::cout << std::endl;
}

void bench_stddev(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.1f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_sstddev(x_gpu, N, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_sstddev(x_gpu, N, 1);
    }

    report("stddev", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_stddev(){
    bench_stddev(100);
    bench_stddev(1000);
    bench_stddev(10000);
    bench_stddev(100000);
    bench_stddev(1000000);
    bench_stddev(10000000);
    bench_stddev(100000000);
    std::cout << std::endl;
}

void bench_inv_dropout(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.0f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_sinv_dropout_seed(N, 0.5f, 1.0f, x_gpu, 1, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_sinv_dropout_seed(N, 0.5f, 1.0f, x_gpu, 1, 42);
    }

    report("inv_dropout", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_inv_dropout(){
    bench_inv_dropout(100);
    bench_inv_dropout(1000);
    bench_inv_dropout(10000);
    bench_inv_dropout(100000);
    bench_inv_dropout(1000000);
    bench_inv_dropout(10000000);
    bench_inv_dropout(100000000);
    std::cout << std::endl;
}

void bench_saxpy(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.0f);
    auto* y_cpu = prepare_cpu(N, 3.0f);

    auto* x_gpu = prepare_gpu(N, x_cpu);
    auto* y_gpu = prepare_gpu(N, y_cpu);

    egblas_saxpy(N, 2.1f, x_gpu, 1, y_gpu, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_saxpy(N, 2.1f, x_gpu, 1, y_gpu, 1);
    }

    report("saxpy", t0, repeat, N);

    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_saxpy(){
    bench_saxpy(100);
    bench_saxpy(1000);
    bench_saxpy(10000);
    bench_saxpy(100000);
    bench_saxpy(1000000);
    bench_saxpy(10000000);
    bench_saxpy(100000000);
    std::cout << std::endl;
}

void bench_saxpby(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.2f);
    auto* y_cpu = prepare_cpu(N, 3.1f);

    auto* x_gpu = prepare_gpu(N, x_cpu);
    auto* y_gpu = prepare_gpu(N, y_cpu);

    egblas_saxpby(N, 2.54f, x_gpu, 1, 3.49f, y_gpu, 1);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_saxpby(N, 2.54f, x_gpu, 1, 3.49f, y_gpu, 1);
    }

    report("saxpby", t0, repeat, N);

    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_saxpby(){
    bench_saxpby(100);
    bench_saxpby(1000);
    bench_saxpby(10000);
    bench_saxpby(100000);
    bench_saxpby(1000000);
    bench_saxpby(10000000);
    bench_saxpby(100000000);
    std::cout << std::endl;
}

void bench_shuffle(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.2f);
    auto* x_gpu = prepare_gpu(N, x_cpu);

    egblas_shuffle_seed(N, x_gpu, 4, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_shuffle_seed(N, x_gpu, 4, 42);
    }

    report("shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_shuffle(){
    bench_shuffle(100);
    bench_shuffle(1000);
    bench_shuffle(10000);
    bench_shuffle(100000);
    std::cout << std::endl;
}

void bench_par_shuffle(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N, 2.2f);
    auto* y_cpu = prepare_cpu(N, 3.1f);

    auto* x_gpu = prepare_gpu(N, x_cpu);
    auto* y_gpu = prepare_gpu(N, y_cpu);

    egblas_par_shuffle_seed(N, x_gpu, 4, y_gpu, 4, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_par_shuffle_seed(N, x_gpu, 4, y_gpu, 4, 42);
    }

    report("par_shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_par_shuffle(){
    bench_par_shuffle(100);
    bench_par_shuffle(1000);
    bench_par_shuffle(10000);
    bench_par_shuffle(100000);
    std::cout << std::endl;
}

void bench_big_shuffle(size_t N, size_t repeat = 100) {
    auto* x_cpu = prepare_cpu(N * 1024, 2.2f);
    auto* x_gpu = prepare_gpu(N * 1024, x_cpu);

    egblas_shuffle_seed(N, x_gpu, 4 * 1024, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_shuffle_seed(N, x_gpu, 4 * 1024, 42);
    }

    report("big_shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * 1024 * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
}

void bench_big_shuffle(){
    bench_big_shuffle(100);
    bench_big_shuffle(1000);
    bench_big_shuffle(10000);
    std::cout << std::endl;
}

void bench_par_big_shuffle(size_t N,size_t repeat = 100){
    auto* x_cpu = prepare_cpu(N * 1024, 2.2f);
    auto* y_cpu = prepare_cpu(N * 1024, 3.1f);

    auto* x_gpu = prepare_gpu(N * 1024, x_cpu);
    auto* y_gpu = prepare_gpu(N * 1024, y_cpu);

    egblas_par_shuffle_seed(N, x_gpu, 4 * 1024, y_gpu, 4, 42);

    auto t0 = timer::now();

    for(size_t i = 0; i < repeat; ++i){
        egblas_par_shuffle_seed(N, x_gpu, 4 * 1024, y_gpu, 4, 42);
    }

    report("par_big_shuffle", t0, repeat, N);

    cuda_check(cudaMemcpy(x_cpu, x_gpu, N * 1024 * sizeof(float), cudaMemcpyDeviceToHost));
    cuda_check(cudaMemcpy(y_cpu, y_gpu, N * 1024 * sizeof(float), cudaMemcpyDeviceToHost));

    release(x_cpu, x_gpu);
    release(y_cpu, y_gpu);
}

void bench_par_big_shuffle(){
    bench_par_big_shuffle(100);
    bench_par_big_shuffle(1000);
    bench_par_big_shuffle(10000);
    std::cout << std::endl;
}

} // End of anonymous namespace

int main(int argc, char* argv[]){
    std::string sub = "all";

    if(argc > 1){
        sub = std::string(argv[1]);
    }

    if (sub == "sum" || sub == "all") {
        bench_sum();
    }

    if (sub == "stddev" || sub == "all") {
        bench_stddev();
    }

    if (sub == "dropout" || sub == "all") {
        bench_inv_dropout();
    }

    if (sub == "shuffle" || sub == "all") {
        bench_shuffle();
        bench_par_shuffle();
        bench_big_shuffle();
        bench_par_big_shuffle();
    }

    if (sub == "axpy" || sub == "all") {
        bench_saxpy();
        bench_saxpby();
    }
}
<|endoftext|>


<commit_before>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "ClientRegister.h"
#include "SyncThread.h"
#include "ILoginListener.h"
#include "common/RhoConf.h"
#include "common/RhodesApp.h"
#include "System.h"

rho::String rho_sysimpl_get_phone_id();

namespace rho{
namespace sync{

using namespace rho::common;
using namespace rho::db;

static const int THREAD_WAIT_TIMEOUT = 10;

IMPLEMENT_LOGCLASS(CClientRegister,"ClientRegister");

CClientRegister* CClientRegister::m_pInstance = 0;
bool CClientRegister::s_sslVerifyPeer = true;
VectorPtr<ILoginListener*> CClientRegister::s_loginListeners;

/*static*/ CClientRegister* CClientRegister::Get()
{
    if (!m_pInstance)
    {
        m_pInstance = new CClientRegister();
    }
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create()
{
    LOG(TRACE) + "Starting ClientRegister";
    Get()->startUp();
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create(const String& devicePin)
{
    Get()->setDevicehPin(devicePin);
    return m_pInstance;
}

/*static*/ void CClientRegister::Stop()
{
    if(m_pInstance)
    {
        m_pInstance->doStop();
    }
}

/*static*/ void CClientRegister::Destroy()
{
    if ( m_pInstance )
        delete m_pInstance;

    m_pInstance = 0;
}

/*static*/ void CClientRegister::SetSslVerifyPeer(boolean b)
{
    s_sslVerifyPeer = b;
    if (m_pInstance)
        m_pInstance->m_NetRequest.setSslVerifyPeer(b);
}

bool CClientRegister::GetSslVerifyPeer()
{
    return s_sslVerifyPeer;
}

/*static*/void CClientRegister::AddLoginListener(ILoginListener* listener)
{
    s_loginListeners.addElement(listener);
}

CClientRegister::CClientRegister() : m_nPollInterval(POLL_INTERVAL_SECONDS)
{
    m_NetRequest.setSslVerifyPeer(s_sslVerifyPeer);
}

CClientRegister::~CClientRegister()
{
    doStop();
    m_pInstance = null;
}
void CClientRegister::setRhoconnectCredentials(const String& user, const String& pass, const String& session)
{
    LOG(INFO) + "New Sync credentials - user: " + user + ", sess: " + session;

    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogin(user, pass, session);
    }
    startUp();
}

void CClientRegister::dropRhoconnectCredentials(const String& session)
{
    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogout(session);
    }
}

void CClientRegister::setDevicehPin(const String& pin)
{
    m_strDevicePin = pin;

    if (pin.length() > 0)
    {
        startUp();
    } else
    {
        doStop();
    }
}

void CClientRegister::startUp()
{
    if ( RHOCONF().getString("syncserver").length() > 0 )
    {
        LOG(INFO) + "Starting ClientRegister...";

        start(epLow);
        stopWait();
    }
}

void CClientRegister::run()
{
    unsigned i = 0;
    LOG(INFO)+"ClientRegister is started";
	while(!isStopping())
	{
        i++;
        LOG(INFO)+"Try to register: " + i;
        if ( CSyncThread::getInstance() != null )
		{
			if ( doRegister(CSyncThread::getSyncEngine()) )
			{
			    LOG(INFO)+"Registered: " + i;
				break;
			}
		} else
		    LOG(INFO)+"SyncThread is not ready";

		LOG(INFO)+"Waiting for "+ m_nPollInterval+ " sec to try again to register client";
		wait(m_nPollInterval*1000);
	}
    LOG(INFO)+"ClientRegister thread shutdown";
}

String CClientRegister::getRegisterBody(const String& strClientID)
{
	IRhoPushClient* pushClient = RHODESAPP().getDefaultPushClient();
	int port = RHOCONF().getInt("push_port");

	String body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
		port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho::System::getPhoneId(),
        /*device_push_type*/ (0 != pushClient) ? pushClient->getType() : "" /*it means native push type*/);

	LOG(INFO)+"getRegisterBody() BODY is: " + body;
	return body;

	/*
    if(m_isAns)
		body = CSyncThread::getSyncEngine().getProtocol().getClientAnsRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	else
		body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	*/

}

boolean CClientRegister::doRegister(CSyncEngine& oSync)
{
    String session = oSync.loadSession();
    if ( session.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Session is empty, do register later";
        return false;
    }

    Get()->setRhoconnectCredentials("", "", session);

    if ( m_strDevicePin.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Device PUSH pin is empty, do register later";
        return false;
    }
    m_nPollInterval = POLL_INTERVAL_SECONDS;

	String client_id = oSync.loadClientID();
	if ( client_id.length() == 0 )
	{
        LOG(WARNING)+"Sync client_id is empty, do register later";
		return false;
	}

    IDBResult res = CDBAdapter::getUserDB().executeSQL("SELECT token,token_sent from client_info");
    if ( !res.isEnd() ) {
		String token = res.getStringByIdx(0);
		int token_sent = res.getIntByIdx(1) && !RHOCONF().getBool("register_push_at_startup");
		if ( m_strDevicePin.compare(token) == 0 && token_sent > 0 )
		{
			//token in db same as new one and it was already send to the server
			//so we do nothing
			return true;
		}
    }
	String strBody = getRegisterBody(client_id);
    NetResponse resp = getNet().pushData( oSync.getProtocol().getClientRegisterUrl(client_id), strBody, &oSync );
	if( resp.isOK() )
    {
//				try {
			CDBAdapter::getUserDB().executeSQL("UPDATE client_info SET token_sent=?, token=?", 1, m_strDevicePin );
//				} catch(Exception ex) {
//					LOG.ERROR("Error saving token_sent to the DB...");
//				}
		LOG(INFO)+"Registered client sucessfully...";
		return true;
	}

	LOG(WARNING)+"Network error: "+ resp.getRespCode();
	return false;
}

void CClientRegister::doStop()
{
    LOG(INFO) + "Stopping ClientRegister...";

    m_NetRequest.cancel();
    stop(WAIT_BEFOREKILL_SECONDS);
}

}
}
<commit_msg>fixed ClientRegister infinite thread resume<commit_after>/*------------------------------------------------------------------------
* (The MIT License)
*
* Copyright (c) 2008-2011 Rhomobile, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* http://rhomobile.com
*------------------------------------------------------------------------*/

#include "ClientRegister.h"
#include "SyncThread.h"
#include "ILoginListener.h"
#include "common/RhoConf.h"
#include "common/RhodesApp.h"
#include "System.h"

rho::String rho_sysimpl_get_phone_id();

namespace rho{
namespace sync{

using namespace rho::common;
using namespace rho::db;

static const int THREAD_WAIT_TIMEOUT = 10;

IMPLEMENT_LOGCLASS(CClientRegister,"ClientRegister");

CClientRegister* CClientRegister::m_pInstance = 0;
bool CClientRegister::s_sslVerifyPeer = true;
VectorPtr<ILoginListener*> CClientRegister::s_loginListeners;

/*static*/ CClientRegister* CClientRegister::Get()
{
    if (!m_pInstance)
    {
        m_pInstance = new CClientRegister();
    }
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create()
{
    LOG(TRACE) + "Starting ClientRegister";
    Get()->startUp();
    return m_pInstance;
}

/*static*/ CClientRegister* CClientRegister::Create(const String& devicePin)
{
    Get()->setDevicehPin(devicePin);
    return m_pInstance;
}

/*static*/ void CClientRegister::Stop()
{
    if(m_pInstance)
    {
        m_pInstance->doStop();
    }
}

/*static*/ void CClientRegister::Destroy()
{
    if ( m_pInstance )
        delete m_pInstance;

    m_pInstance = 0;
}

/*static*/ void CClientRegister::SetSslVerifyPeer(boolean b)
{
    s_sslVerifyPeer = b;
    if (m_pInstance)
        m_pInstance->m_NetRequest.setSslVerifyPeer(b);
}

bool CClientRegister::GetSslVerifyPeer()
{
    return s_sslVerifyPeer;
}

/*static*/void CClientRegister::AddLoginListener(ILoginListener* listener)
{
    s_loginListeners.addElement(listener);
}

CClientRegister::CClientRegister() : m_nPollInterval(POLL_INTERVAL_SECONDS)
{
    m_NetRequest.setSslVerifyPeer(s_sslVerifyPeer);
}

CClientRegister::~CClientRegister()
{
    doStop();
    m_pInstance = null;
}
void CClientRegister::setRhoconnectCredentials(const String& user, const String& pass, const String& session)
{
    LOG(INFO) + "New Sync credentials - user: " + user + ", sess: " + session;

    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogin(user, pass, session);
    }

    if (!isAlive()) {
        startUp();
    }
}

void CClientRegister::dropRhoconnectCredentials(const String& session)
{
    for(VectorPtr<ILoginListener*>::iterator I = s_loginListeners.begin(); I != s_loginListeners.end(); ++I)
    {
        (*I)->onLogout(session);
    }
}

void CClientRegister::setDevicehPin(const String& pin)
{
    m_strDevicePin = pin;

    if (pin.length() > 0)
    {
        startUp();
    } else
    {
        doStop();
    }
}

void CClientRegister::startUp()
{
    if ( RHOCONF().getString("syncserver").length() > 0 )
    {
        LOG(INFO) + "Starting ClientRegister...";

        start(epLow);
        stopWait();
    }
}

void CClientRegister::run()
{
    unsigned i = 0;
    LOG(INFO)+"ClientRegister is started";
	while(!isStopping())
	{
        i++;
        LOG(INFO)+"Try to register: " + i;
        if ( CSyncThread::getInstance() != null )
		{
			if ( doRegister(CSyncThread::getSyncEngine()) )
			{
			    LOG(INFO)+"Registered: " + i;
				break;
			}
		} else
		    LOG(INFO)+"SyncThread is not ready";

		LOG(INFO)+"Waiting for "+ m_nPollInterval+ " sec to try again to register client";
		wait(m_nPollInterval*1000);
	}
    LOG(INFO)+"ClientRegister thread shutdown";
}

String CClientRegister::getRegisterBody(const String& strClientID)
{
	IRhoPushClient* pushClient = RHODESAPP().getDefaultPushClient();
	int port = RHOCONF().getInt("push_port");

	String body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
		port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho::System::getPhoneId(),
        /*device_push_type*/ (0 != pushClient) ? pushClient->getType() : "" /*it means native push type*/);

	LOG(INFO)+"getRegisterBody() BODY is: " + body;
	return body;

	/*
    if(m_isAns)
		body = CSyncThread::getSyncEngine().getProtocol().getClientAnsRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	else
		body = CSyncThread::getSyncEngine().getProtocol().getClientRegisterBody( strClientID, m_strDevicePin,
			port > 0 ? port : DEFAULT_PUSH_PORT, rho_rhodesapp_getplatform(), rho_sysimpl_get_phone_id() );
	*/

}

boolean CClientRegister::doRegister(CSyncEngine& oSync)
{
    String session = oSync.loadSession();
    if ( session.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Session is empty, do register later";
        return false;
    }

    if ( m_strDevicePin.length() == 0 )
    {
        m_nPollInterval = POLL_INTERVAL_INFINITE;
        LOG(INFO)+"Device PUSH pin is empty, do register later";
        return false;
    }
    m_nPollInterval = POLL_INTERVAL_SECONDS;

	String client_id = oSync.loadClientID();
	if ( client_id.length() == 0 )
	{
        LOG(WARNING)+"Sync client_id is empty, do register later";
		return false;
	}

    IDBResult res = CDBAdapter::getUserDB().executeSQL("SELECT token,token_sent from client_info");
    if ( !res.isEnd() ) {
		String token = res.getStringByIdx(0);
		int token_sent = res.getIntByIdx(1) && !RHOCONF().getBool("register_push_at_startup");
		if ( m_strDevicePin.compare(token) == 0 && token_sent > 0 )
		{
			//token in db same as new one and it was already send to the server
			//so we do nothing
            setRhoconnectCredentials("","",session);

			return true;
		}
    }
	String strBody = getRegisterBody(client_id);
    NetResponse resp = getNet().pushData( oSync.getProtocol().getClientRegisterUrl(client_id), strBody, &oSync );
	if( resp.isOK() )
    {
//				try {
			CDBAdapter::getUserDB().executeSQL("UPDATE client_info SET token_sent=?, token=?", 1, m_strDevicePin );
//				} catch(Exception ex) {
//					LOG.ERROR("Error saving token_sent to the DB...");
//				}
		LOG(INFO)+"Registered client sucessfully...";

        setRhoconnectCredentials("","",session);
        return true;

    }

	LOG(WARNING)+"Network error: "+ resp.getRespCode();
	return false;
}

void CClientRegister::doStop()
{
    LOG(INFO) + "Stopping ClientRegister...";

    m_NetRequest.cancel();
    stop(WAIT_BEFOREKILL_SECONDS);
}

}
}
<|endoftext|>


<commit_before>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "driver.hh"
#include "bsemain.hh"
#include "internal.hh"
#include "bsesequencer.hh"

#define DDEBUG(...)     Bse::debug ("driver", __VA_ARGS__)

namespace Bse {

// == Driver ==
Driver::Driver (const String &devid) :
  devid_ (devid)
{}

Driver::~Driver ()
{}

// == RegisteredDriver ==
template<typename DriverP>
struct RegisteredDriver {
  const String                            driver_id_;
  std::function<DriverP (const String&)>  create_;
  std::function<void (Driver::EntryVec&)> list_;
  using RegisteredDriverVector = std::vector<RegisteredDriver>;
  static RegisteredDriverVector&
  registered_driver_vector()
  {
    static RegisteredDriverVector registered_driver_vector_;
    return registered_driver_vector_;
  }
  static DriverP
  open (const String &devid, Driver::IODir iodir, Error *ep,
        const std::function<Error (DriverP, Driver::IODir)> &opener)
  {
    std::function<DriverP (const String&)> create;
    const String driverid = kvpair_key (devid);
    for (const auto &driver : registered_driver_vector())
      if (driver.driver_id_ == driverid)
        {
          create = driver.create_;
          break;
        }
    Error error = Error::DEVICE_NOT_AVAILABLE;
    DriverP driver = create ? create (kvpair_value (devid)) : NULL;
    if (driver)
      {
        error = opener (driver, iodir);
        if (ep)
          *ep = error;
        if (error == Error::NONE)
          {
            assert_return (driver->opened() == true, nullptr);
            assert_return (!(iodir & Driver::READONLY) || driver->readable(), nullptr);
            assert_return (!(iodir & Driver::WRITEONLY) || driver->writable(), nullptr);
          }
        else
          driver = nullptr;
      }
    else if (ep)
      *ep = error;
    return driver;
  }
  static String
  register_driver (const String &driverid,
                   const std::function<DriverP (const String&)> &create,
                   const std::function<void (Driver::EntryVec&)> &list)
  {
    auto &vec = registered_driver_vector();
    RegisteredDriver rd = { driverid, create, list, };
    vec.push_back (rd);
    return driverid;
  }
  static Driver::EntryVec
  list_drivers (const Driver::EntryVec &pseudos)
  {
    Driver::EntryVec entries;
    std::copy (pseudos.begin(), pseudos.end(), std::back_inserter (entries));
    auto &vec = registered_driver_vector();
    for (const auto &rd : vec)
      {
        Driver::EntryVec dentries;
        rd.list_ (dentries);
        for (auto &entry : dentries)
          entry.devid = entry.devid.empty() ? rd.driver_id_ : rd.driver_id_ + "=" + entry.devid;
        entries.insert (entries.end(), std::make_move_iterator (dentries.begin()), std::make_move_iterator (dentries.end()));
      }
    std::sort (entries.begin(), entries.end(), [] (const Driver::Entry &a, const Driver::Entry &b) {
        return a.priority < b.priority;
      });
    return entries;
  }
};

// == PcmDriver ==
PcmDriver::PcmDriver (const String &devid) :
  Driver (devid)
{}

PcmDriverP
PcmDriver::open (const String &devid, IODir desired, IODir required, const PcmDriverConfig &config, Error *ep)
{
  auto opener =  [&config] (PcmDriverP d, IODir iodir) {
    return d->open (iodir, config);
  };
  if (devid == "auto")
    {
      for (const auto &entry : list_drivers())
        if (entry.priority < PSEUDO &&          // ignore pseudo devices during auto-selection
            !(entry.priority & 0x0000ffff))     // ignore secondary devices during auto-selection
          {
            PcmDriverP pcm_driver = RegisteredDriver<PcmDriverP>::open (entry.devid, desired, ep, opener);
            if (!pcm_driver && required && desired != required)
              pcm_driver = RegisteredDriver<PcmDriverP>::open (entry.devid, required, ep, opener);
            if (pcm_driver)
              return pcm_driver;
          }
    }
  else
    {
      PcmDriverP pcm_driver = RegisteredDriver<PcmDriverP>::open (devid, desired, ep, opener);
      if (!pcm_driver && required && desired != required)
        pcm_driver = RegisteredDriver<PcmDriverP>::open (devid, required, ep, opener);
      if (pcm_driver)
        return pcm_driver;
    }
  return nullptr;
}

String
PcmDriver::register_driver (const String &driverid,
                            const std::function<PcmDriverP (const String&)> &create,
                            const std::function<void (EntryVec&)> &list)
{
  return RegisteredDriver<PcmDriverP>::register_driver (driverid, create, list);
}

Driver::EntryVec
PcmDriver::list_drivers ()
{
  Driver::Entry entry;
  entry.devid = "auto";
  entry.device_name = _("Automatic driver selection");
  entry.device_info = _("Select the first available PCM card or server");
  entry.readonly = false;
  entry.writeonly = false;
  entry.priority = Driver::PAUTO;
  Driver::EntryVec pseudos;
  pseudos.push_back (entry);
  return RegisteredDriver<PcmDriverP>::list_drivers (pseudos);
}

// == MidiDriver ==
MidiDriver::MidiDriver (const String &devid) :
  Driver (devid)
{}

MidiDriverP
MidiDriver::open (const String &devid, IODir iodir, Error *ep)
{
  auto opener = [] (MidiDriverP d, IODir iodir) {
    return d->open (iodir);
  };
  if (devid == "auto")
    {
      for (const auto &entry : list_drivers())
        if (entry.priority < PSEUDO)    // ignore pseudo devices during auto-selection
          {
            MidiDriverP midi_driver = RegisteredDriver<MidiDriverP>::open (entry.devid, iodir, ep, opener);
            if (midi_driver)
              return midi_driver;
          }
    }
  else
    {
      MidiDriverP midi_driver = RegisteredDriver<MidiDriverP>::open (devid, iodir, ep, opener);
      if (midi_driver)
        return midi_driver;
    }
  return nullptr;
}

String
MidiDriver::register_driver (const String &driverid,
                             const std::function<MidiDriverP (const String&)> &create,
                             const std::function<void (EntryVec&)> &list)
{
  return RegisteredDriver<MidiDriverP>::register_driver (driverid, create, list);
}

Driver::EntryVec
MidiDriver::list_drivers ()
{
  Driver::Entry entry;
  entry.devid = "auto";
  entry.device_name = _("Automatic MIDI driver selection");
  entry.device_info = _("Select the first available MIDI device");
  entry.readonly = false;
  entry.writeonly = false;
  entry.priority = Driver::PAUTO;
  Driver::EntryVec pseudos;
  pseudos.push_back (entry);
  return RegisteredDriver<MidiDriverP>::list_drivers (pseudos);
}

// == NullPcmDriver ==
class NullPcmDriver : public PcmDriver {
  uint          n_channels_ = 0;
  uint          mix_freq_ = 0;
  uint          busy_us_ = 0;
  uint          sleep_us_ = 0;
public:
  explicit      NullPcmDriver (const String &devid) : PcmDriver (devid) {}
  static PcmDriverP
  create (const String &devid)
  {
    auto pdriverp = std::make_shared<NullPcmDriver> (devid);
    return pdriverp;
  }
  virtual float
  pcm_frequency () const override
  {
    return mix_freq_;
  }
  virtual void
  close () override
  {
    assert_return (opened());
    flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
  }
  virtual Error
  open (IODir iodir, const PcmDriverConfig &config) override
  {
    assert_return (!opened(), Error::INTERNAL);
    // setup request
    const bool nosleep = true;
    const bool require_readable = iodir == READONLY || iodir == READWRITE;
    const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
    flags_ |= Flags::READABLE * require_readable;
    flags_ |= Flags::WRITABLE * require_writable;
    n_channels_ = config.n_channels;
    mix_freq_ = config.mix_freq;
    busy_us_ = 0;
    sleep_us_ = nosleep ? 0 : 10 * 1000;
    flags_ |= Flags::OPENED;
    DDEBUG ("NULL-PCM: opening with freq=%f channels=%d: %s", mix_freq_, n_channels_, bse_error_blurb (Error::NONE));
    return Error::NONE;
  }
  virtual bool
  pcm_check_io (long *timeoutp) override
  {
    // keep the sequencer busy or we will constantly timeout
    Sequencer::instance().wakeup();
    *timeoutp = 1;
    // ensure sequencer fairness
    return !Sequencer::instance().thread_lagging (2);
  }
  virtual void
  pcm_latency (uint *rlatency, uint *wlatency) const override
  {
    *rlatency = mix_freq_ / 10;
    *wlatency = mix_freq_ / 10;
  }
  virtual size_t
  pcm_read (size_t n, float *values) override
  {
    memset (values, 0, sizeof (values[0]) * n);
    return n;
  }
  virtual void
  pcm_write (size_t n, const float *values) override
  {
    busy_us_ += n * 1000000 / mix_freq_;
    if (busy_us_ >= 100 * 1000)
      {
        busy_us_ = 0;
        // give cpu to other applications (we might run at nice level -20)
        if (sleep_us_)
          g_usleep (sleep_us_);
      }
  }
  static void
  list_drivers (Driver::EntryVec &entries)
  {
    Driver::Entry entry;
    entry.devid = ""; // "null"
    entry.device_name = "Null PCM Driver";
    entry.device_info = _("Discard all PCM output and provide zeros as PCM input");
    entry.readonly = false;
    entry.writeonly = false;
    entry.priority = Driver::PNULL;
    entries.push_back (entry);
  }
};

static const String null_pcm_driverid = PcmDriver::register_driver ("null", NullPcmDriver::create, NullPcmDriver::list_drivers);

// == NullMidiDriver ==
class NullMidiDriver : public MidiDriver {
public:
  explicit      NullMidiDriver (const String &devid) : MidiDriver (devid) {}
  static MidiDriverP
  create (const String &devid)
  {
    auto pdriverp = std::make_shared<NullMidiDriver> (devid);
    return pdriverp;
  }
  virtual void
  close () override
  {
    assert_return (opened());
    flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
  }
  virtual Error
  open (IODir iodir) override
  {
    assert_return (!opened(), Error::INTERNAL);
    // setup request
    const bool require_readable = iodir == READONLY || iodir == READWRITE;
    const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
    flags_ |= Flags::READABLE * require_readable;
    flags_ |= Flags::WRITABLE * require_writable;
    flags_ |= Flags::OPENED;
    DDEBUG ("NULL-MIDI: opening: %s", bse_error_blurb (Error::NONE));
    return Error::NONE;
  }
  static void
  list_drivers (Driver::EntryVec &entries)
  {
    Driver::Entry entry;
    entry.devid = ""; // "null"
    entry.device_name = "Null MIDI Driver";
    entry.device_info = _("Discard all MIDI events");
    entry.readonly = false;
    entry.writeonly = false;
    entry.priority = Driver::PNULL;
    entries.push_back (entry);
  }
};

static const String null_midi_driverid = MidiDriver::register_driver ("null", NullMidiDriver::create, NullMidiDriver::list_drivers);

} // Bse

// == libbsejack.so ==
#include <gmodule.h>

static Bse::Error
try_load_libbsejack ()
{
  using namespace Bse;
  const std::string libbsejack = string_format ("%s/lib/libbse-jack-%u.%u.%u.so", runpath (RPath::INSTALLDIR),
                                                BSE_MAJOR_VERSION, BSE_MINOR_VERSION, BSE_MICRO_VERSION);
  Error error = Error::FILE_NOT_FOUND;
  String errmsg;
  if (Path::check (libbsejack, "fr"))
    {
      GModule *gmodule = g_module_open (libbsejack.c_str(), G_MODULE_BIND_LOCAL); // no API import
      if (gmodule)
        error = Error::NONE;
      else
        {
          errmsg = g_module_error();
          error = Error::FILE_OPEN_FAILED;
        }
    }
  DDEBUG ("loading \"%s\": %s%s", libbsejack, bse_error_blurb (error), errmsg.empty() ? "" : ": " + errmsg);
  return error;
}

static bool *bsejack_loaded = Bse::register_driver_loader ("bsejack", try_load_libbsejack);
<commit_msg>BSE: driver.cc: be silent about libbse-jack loading errors<commit_after>// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
#include "driver.hh"
#include "bsemain.hh"
#include "internal.hh"
#include "bsesequencer.hh"

#define DDEBUG(...)     Bse::debug ("driver", __VA_ARGS__)

namespace Bse {

// == Driver ==
Driver::Driver (const String &devid) :
  devid_ (devid)
{}

Driver::~Driver ()
{}

// == RegisteredDriver ==
template<typename DriverP>
struct RegisteredDriver {
  const String                            driver_id_;
  std::function<DriverP (const String&)>  create_;
  std::function<void (Driver::EntryVec&)> list_;
  using RegisteredDriverVector = std::vector<RegisteredDriver>;
  static RegisteredDriverVector&
  registered_driver_vector()
  {
    static RegisteredDriverVector registered_driver_vector_;
    return registered_driver_vector_;
  }
  static DriverP
  open (const String &devid, Driver::IODir iodir, Error *ep,
        const std::function<Error (DriverP, Driver::IODir)> &opener)
  {
    std::function<DriverP (const String&)> create;
    const String driverid = kvpair_key (devid);
    for (const auto &driver : registered_driver_vector())
      if (driver.driver_id_ == driverid)
        {
          create = driver.create_;
          break;
        }
    Error error = Error::DEVICE_NOT_AVAILABLE;
    DriverP driver = create ? create (kvpair_value (devid)) : NULL;
    if (driver)
      {
        error = opener (driver, iodir);
        if (ep)
          *ep = error;
        if (error == Error::NONE)
          {
            assert_return (driver->opened() == true, nullptr);
            assert_return (!(iodir & Driver::READONLY) || driver->readable(), nullptr);
            assert_return (!(iodir & Driver::WRITEONLY) || driver->writable(), nullptr);
          }
        else
          driver = nullptr;
      }
    else if (ep)
      *ep = error;
    return driver;
  }
  static String
  register_driver (const String &driverid,
                   const std::function<DriverP (const String&)> &create,
                   const std::function<void (Driver::EntryVec&)> &list)
  {
    auto &vec = registered_driver_vector();
    RegisteredDriver rd = { driverid, create, list, };
    vec.push_back (rd);
    return driverid;
  }
  static Driver::EntryVec
  list_drivers (const Driver::EntryVec &pseudos)
  {
    Driver::EntryVec entries;
    std::copy (pseudos.begin(), pseudos.end(), std::back_inserter (entries));
    auto &vec = registered_driver_vector();
    for (const auto &rd : vec)
      {
        Driver::EntryVec dentries;
        rd.list_ (dentries);
        for (auto &entry : dentries)
          entry.devid = entry.devid.empty() ? rd.driver_id_ : rd.driver_id_ + "=" + entry.devid;
        entries.insert (entries.end(), std::make_move_iterator (dentries.begin()), std::make_move_iterator (dentries.end()));
      }
    std::sort (entries.begin(), entries.end(), [] (const Driver::Entry &a, const Driver::Entry &b) {
        return a.priority < b.priority;
      });
    return entries;
  }
};

// == PcmDriver ==
PcmDriver::PcmDriver (const String &devid) :
  Driver (devid)
{}

PcmDriverP
PcmDriver::open (const String &devid, IODir desired, IODir required, const PcmDriverConfig &config, Error *ep)
{
  auto opener =  [&config] (PcmDriverP d, IODir iodir) {
    return d->open (iodir, config);
  };
  if (devid == "auto")
    {
      for (const auto &entry : list_drivers())
        if (entry.priority < PSEUDO &&          // ignore pseudo devices during auto-selection
            !(entry.priority & 0x0000ffff))     // ignore secondary devices during auto-selection
          {
            PcmDriverP pcm_driver = RegisteredDriver<PcmDriverP>::open (entry.devid, desired, ep, opener);
            if (!pcm_driver && required && desired != required)
              pcm_driver = RegisteredDriver<PcmDriverP>::open (entry.devid, required, ep, opener);
            if (pcm_driver)
              return pcm_driver;
          }
    }
  else
    {
      PcmDriverP pcm_driver = RegisteredDriver<PcmDriverP>::open (devid, desired, ep, opener);
      if (!pcm_driver && required && desired != required)
        pcm_driver = RegisteredDriver<PcmDriverP>::open (devid, required, ep, opener);
      if (pcm_driver)
        return pcm_driver;
    }
  return nullptr;
}

String
PcmDriver::register_driver (const String &driverid,
                            const std::function<PcmDriverP (const String&)> &create,
                            const std::function<void (EntryVec&)> &list)
{
  return RegisteredDriver<PcmDriverP>::register_driver (driverid, create, list);
}

Driver::EntryVec
PcmDriver::list_drivers ()
{
  Driver::Entry entry;
  entry.devid = "auto";
  entry.device_name = _("Automatic driver selection");
  entry.device_info = _("Select the first available PCM card or server");
  entry.readonly = false;
  entry.writeonly = false;
  entry.priority = Driver::PAUTO;
  Driver::EntryVec pseudos;
  pseudos.push_back (entry);
  return RegisteredDriver<PcmDriverP>::list_drivers (pseudos);
}

// == MidiDriver ==
MidiDriver::MidiDriver (const String &devid) :
  Driver (devid)
{}

MidiDriverP
MidiDriver::open (const String &devid, IODir iodir, Error *ep)
{
  auto opener = [] (MidiDriverP d, IODir iodir) {
    return d->open (iodir);
  };
  if (devid == "auto")
    {
      for (const auto &entry : list_drivers())
        if (entry.priority < PSEUDO)    // ignore pseudo devices during auto-selection
          {
            MidiDriverP midi_driver = RegisteredDriver<MidiDriverP>::open (entry.devid, iodir, ep, opener);
            if (midi_driver)
              return midi_driver;
          }
    }
  else
    {
      MidiDriverP midi_driver = RegisteredDriver<MidiDriverP>::open (devid, iodir, ep, opener);
      if (midi_driver)
        return midi_driver;
    }
  return nullptr;
}

String
MidiDriver::register_driver (const String &driverid,
                             const std::function<MidiDriverP (const String&)> &create,
                             const std::function<void (EntryVec&)> &list)
{
  return RegisteredDriver<MidiDriverP>::register_driver (driverid, create, list);
}

Driver::EntryVec
MidiDriver::list_drivers ()
{
  Driver::Entry entry;
  entry.devid = "auto";
  entry.device_name = _("Automatic MIDI driver selection");
  entry.device_info = _("Select the first available MIDI device");
  entry.readonly = false;
  entry.writeonly = false;
  entry.priority = Driver::PAUTO;
  Driver::EntryVec pseudos;
  pseudos.push_back (entry);
  return RegisteredDriver<MidiDriverP>::list_drivers (pseudos);
}

// == NullPcmDriver ==
class NullPcmDriver : public PcmDriver {
  uint          n_channels_ = 0;
  uint          mix_freq_ = 0;
  uint          busy_us_ = 0;
  uint          sleep_us_ = 0;
public:
  explicit      NullPcmDriver (const String &devid) : PcmDriver (devid) {}
  static PcmDriverP
  create (const String &devid)
  {
    auto pdriverp = std::make_shared<NullPcmDriver> (devid);
    return pdriverp;
  }
  virtual float
  pcm_frequency () const override
  {
    return mix_freq_;
  }
  virtual void
  close () override
  {
    assert_return (opened());
    flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
  }
  virtual Error
  open (IODir iodir, const PcmDriverConfig &config) override
  {
    assert_return (!opened(), Error::INTERNAL);
    // setup request
    const bool nosleep = true;
    const bool require_readable = iodir == READONLY || iodir == READWRITE;
    const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
    flags_ |= Flags::READABLE * require_readable;
    flags_ |= Flags::WRITABLE * require_writable;
    n_channels_ = config.n_channels;
    mix_freq_ = config.mix_freq;
    busy_us_ = 0;
    sleep_us_ = nosleep ? 0 : 10 * 1000;
    flags_ |= Flags::OPENED;
    DDEBUG ("NULL-PCM: opening with freq=%f channels=%d: %s", mix_freq_, n_channels_, bse_error_blurb (Error::NONE));
    return Error::NONE;
  }
  virtual bool
  pcm_check_io (long *timeoutp) override
  {
    // keep the sequencer busy or we will constantly timeout
    Sequencer::instance().wakeup();
    *timeoutp = 1;
    // ensure sequencer fairness
    return !Sequencer::instance().thread_lagging (2);
  }
  virtual void
  pcm_latency (uint *rlatency, uint *wlatency) const override
  {
    *rlatency = mix_freq_ / 10;
    *wlatency = mix_freq_ / 10;
  }
  virtual size_t
  pcm_read (size_t n, float *values) override
  {
    memset (values, 0, sizeof (values[0]) * n);
    return n;
  }
  virtual void
  pcm_write (size_t n, const float *values) override
  {
    busy_us_ += n * 1000000 / mix_freq_;
    if (busy_us_ >= 100 * 1000)
      {
        busy_us_ = 0;
        // give cpu to other applications (we might run at nice level -20)
        if (sleep_us_)
          g_usleep (sleep_us_);
      }
  }
  static void
  list_drivers (Driver::EntryVec &entries)
  {
    Driver::Entry entry;
    entry.devid = ""; // "null"
    entry.device_name = "Null PCM Driver";
    entry.device_info = _("Discard all PCM output and provide zeros as PCM input");
    entry.readonly = false;
    entry.writeonly = false;
    entry.priority = Driver::PNULL;
    entries.push_back (entry);
  }
};

static const String null_pcm_driverid = PcmDriver::register_driver ("null", NullPcmDriver::create, NullPcmDriver::list_drivers);

// == NullMidiDriver ==
class NullMidiDriver : public MidiDriver {
public:
  explicit      NullMidiDriver (const String &devid) : MidiDriver (devid) {}
  static MidiDriverP
  create (const String &devid)
  {
    auto pdriverp = std::make_shared<NullMidiDriver> (devid);
    return pdriverp;
  }
  virtual void
  close () override
  {
    assert_return (opened());
    flags_ &= ~size_t (Flags::OPENED | Flags::READABLE | Flags::WRITABLE);
  }
  virtual Error
  open (IODir iodir) override
  {
    assert_return (!opened(), Error::INTERNAL);
    // setup request
    const bool require_readable = iodir == READONLY || iodir == READWRITE;
    const bool require_writable = iodir == WRITEONLY || iodir == READWRITE;
    flags_ |= Flags::READABLE * require_readable;
    flags_ |= Flags::WRITABLE * require_writable;
    flags_ |= Flags::OPENED;
    DDEBUG ("NULL-MIDI: opening: %s", bse_error_blurb (Error::NONE));
    return Error::NONE;
  }
  static void
  list_drivers (Driver::EntryVec &entries)
  {
    Driver::Entry entry;
    entry.devid = ""; // "null"
    entry.device_name = "Null MIDI Driver";
    entry.device_info = _("Discard all MIDI events");
    entry.readonly = false;
    entry.writeonly = false;
    entry.priority = Driver::PNULL;
    entries.push_back (entry);
  }
};

static const String null_midi_driverid = MidiDriver::register_driver ("null", NullMidiDriver::create, NullMidiDriver::list_drivers);

} // Bse

// == libbsejack.so ==
#include <gmodule.h>

static Bse::Error
try_load_libbsejack ()
{
  using namespace Bse;
  const std::string libbsejack = string_format ("%s/lib/libbse-jack-%u.%u.%u.so", runpath (RPath::INSTALLDIR),
                                                BSE_MAJOR_VERSION, BSE_MINOR_VERSION, BSE_MICRO_VERSION);
  if (Path::check (libbsejack, "fr"))
    {
      GModule *gmodule = g_module_open (libbsejack.c_str(), G_MODULE_BIND_LOCAL); // no API import
      if (!gmodule)
        DDEBUG ("loading \"%s\" failed: %s", libbsejack, g_module_error());
    }
  return Error::NONE;
}

static bool *bsejack_loaded = Bse::register_driver_loader ("bsejack", try_load_libbsejack);
<|endoftext|>


<commit_before>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

// (c) COPRIGHT URI/MIT 1996,1998,1999
// Please first read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
//	jhrg,jimg	James Gallagher <jgallagher@gso.uri.edu>

// Implementation for the CE Clause class.

#include "config.h"

#include <assert.h>

#include <algorithm>

#include "expr.h"
#include "DDS.h"
#include "Clause.h"

using std::cerr;
using std::endl;

Clause::Clause(const int oper, rvalue *a1, rvalue_list *rv)
    : _op(oper), _b_func(0), _bt_func(0), _arg1(a1), _args(rv)
{
    assert(OK());
}

Clause::Clause(bool_func func, rvalue_list *rv)
    : _op(0), _b_func(func), _bt_func(0), _arg1(0), _args(rv)
{
    assert(OK());

    if (_args)			// account for null arg list
	_argc = _args->size();
    else
	_argc = 0;
}

Clause::Clause(btp_func func, rvalue_list *rv)
    : _op(0), _b_func(0), _bt_func(func), _arg1(0), _args(rv)
{
    assert(OK());

    if (_args)
	_argc = _args->size();
    else
	_argc = 0;
}

Clause::Clause() : _op(0), _b_func(0), _bt_func(0), _arg1(0), _args(0)
{
}

static inline void
delete_rvalue(rvalue *rv)
{
    delete rv; rv = 0;
}

Clause::~Clause()
{
    if (_arg1) {
	delete _arg1; _arg1 = 0;
    }

    if (_args) {
	// _args is a pointer to a vector<rvalue*> and we must must delete
	// each rvalue pointer here explicitly. 02/03/04 jhrg
	for_each(_args->begin(), _args->end(), delete_rvalue);
	delete _args; _args = 0;
    }
}

/** @brief Checks the "representation invariant" of a clause. */
bool
Clause::OK()
{
    // Each clause object can contain one of: a relational clause, a boolean
    // function clause or a BaseType pointer function clause. It must have a
    // valid argument list.
    //
    // But, a valid arg list might contain zero arguments! 10/16/98 jhrg
    bool relational = (_op && !_b_func && !_bt_func);
    bool boolean = (!_op && _b_func && !_bt_func);
    bool basetype = (!_op && !_b_func && _bt_func);

    if (relational)
	return _arg1 && _args;
    else if (boolean || basetype)
	return true;		// Until we check arguments...10/16/98 jhrg
    else
	return false;
}

/** @brief Return true if the clause returns a boolean value. */
bool
Clause::boolean_clause()
{
    assert(OK());

    return _op || _b_func;
}

/** @brief Return true if the clause returns a value in a BaseType pointer. */
bool
Clause::value_clause()
{
    assert(OK());

    return (_bt_func != 0);
}

/** @brief Evaluate a clause which returns a boolean value
    This method must only be evaluated for clauses with relational
    expressions or boolean functions.
    @param dataset This is passed to the rvalue::bvalue() method.
    @param dds Use variables from this DDS when evaluating the
    expression
    @return True if the clause is true, false otherwise.
    @exception InternalErr if called for a clause that returns a
    BaseType pointer. */
bool
Clause::value(const string &dataset, DDS &dds)
{
    assert(OK());
    assert(_op || _b_func);

    if (_op) {			// Is it a relational clause?
	// rvalue::bvalue(...) returns the rvalue encapsulated in a
	// BaseType *.
	BaseType *btp = _arg1->bvalue(dataset, dds);
	// The list of rvalues is an implicit logical OR, so assume
	// FALSE and return TRUE for the first TRUE subclause.
	bool result = false;
	for (rvalue_list_iter i = _args->begin();
	     i != _args->end() && !result;
	     i++)
	{
	    result = result || btp->ops((*i)->bvalue(dataset, dds),
					_op, dataset);
	}

	return result;
    }
    else if (_b_func) {		// ...A bool function?
	BaseType **argv = build_btp_args(_args, dds, dataset);

	bool result = (*_b_func)(_argc, argv, dds);
	delete[] argv;		// Cache me!
	argv = 0;

	return result;
    }
    else {
	throw InternalErr(__FILE__, __LINE__,
                "A selection expression must contain only boolean clauses.");
    }
}

/** @brief Evaluate a clause that returns a value via a BaseType
    pointer.
    This method must only be evaluated for clauses with relational
    expressions or boolean functions.
    @param dataset This is passed to the function.
    @param dds Use variables from this DDS when evaluating the
    expression
    @param value A value-result parameter
    @return True if the the BaseType pointer is not null, false otherwise.
    @exception InternalErr if called for a clause that returns a
    boolean value. Not that this method itself \e does return a
    boolean value. */
bool
Clause::value(const string &dataset, DDS &dds, BaseType **value)
{
    assert(OK());
    assert(_bt_func);

    if (_bt_func) {
        // build_btp_args() is a function defined in RValue.cc. It no longer
        // reads the values as it builds the arguments, that is now left up
        // to the functions themselves. 9/25/06 jhrg
	BaseType **argv = build_btp_args(_args, dds, dataset);

	*value = (*_bt_func)(_argc, argv, dds, dataset);
	delete[] argv;		// Cache me!
	argv = 0;

	if (*value) {
	    (*value)->set_send_p(true);
	    return true;
	}
	else {
	    return false;
	}
    }
    else {
	throw InternalErr(__FILE__, __LINE__,
                "Claue::value() was called in a context expecting a BaseType pointer return, but the Clause was boolean-valued instead.");
    }
}

<commit_msg>Clause.cc: Added a call to set_read_p(true) in Clause::value so that handlers' read() methods will not try to 'read over' the values inserted to the variables by a CE function.<commit_after>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of libdap, A C++ implementation of the OPeNDAP Data
// Access Protocol.

// Copyright (c) 2002,2003 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

// (c) COPRIGHT URI/MIT 1996,1998,1999
// Please first read the full copyright statement in the file COPYRIGHT_URI.
//
// Authors:
//	jhrg,jimg	James Gallagher <jgallagher@gso.uri.edu>

// Implementation for the CE Clause class.

#include "config.h"

#include <assert.h>

#include <algorithm>

#include "expr.h"
#include "DDS.h"
#include "Clause.h"

using std::cerr;
using std::endl;

Clause::Clause(const int oper, rvalue *a1, rvalue_list *rv)
    : _op(oper), _b_func(0), _bt_func(0), _arg1(a1), _args(rv)
{
    assert(OK());
}

Clause::Clause(bool_func func, rvalue_list *rv)
    : _op(0), _b_func(func), _bt_func(0), _arg1(0), _args(rv)
{
    assert(OK());

    if (_args)			// account for null arg list
	_argc = _args->size();
    else
	_argc = 0;
}

Clause::Clause(btp_func func, rvalue_list *rv)
    : _op(0), _b_func(0), _bt_func(func), _arg1(0), _args(rv)
{
    assert(OK());

    if (_args)
	_argc = _args->size();
    else
	_argc = 0;
}

Clause::Clause() : _op(0), _b_func(0), _bt_func(0), _arg1(0), _args(0)
{
}

static inline void
delete_rvalue(rvalue *rv)
{
    delete rv; rv = 0;
}

Clause::~Clause()
{
    if (_arg1) {
	delete _arg1; _arg1 = 0;
    }

    if (_args) {
	// _args is a pointer to a vector<rvalue*> and we must must delete
	// each rvalue pointer here explicitly. 02/03/04 jhrg
	for_each(_args->begin(), _args->end(), delete_rvalue);
	delete _args; _args = 0;
    }
}

/** @brief Checks the "representation invariant" of a clause. */
bool
Clause::OK()
{
    // Each clause object can contain one of: a relational clause, a boolean
    // function clause or a BaseType pointer function clause. It must have a
    // valid argument list.
    //
    // But, a valid arg list might contain zero arguments! 10/16/98 jhrg
    bool relational = (_op && !_b_func && !_bt_func);
    bool boolean = (!_op && _b_func && !_bt_func);
    bool basetype = (!_op && !_b_func && _bt_func);

    if (relational)
	return _arg1 && _args;
    else if (boolean || basetype)
	return true;		// Until we check arguments...10/16/98 jhrg
    else
	return false;
}

/** @brief Return true if the clause returns a boolean value. */
bool
Clause::boolean_clause()
{
    assert(OK());

    return _op || _b_func;
}

/** @brief Return true if the clause returns a value in a BaseType pointer. */
bool
Clause::value_clause()
{
    assert(OK());

    return (_bt_func != 0);
}

/** @brief Evaluate a clause which returns a boolean value
    This method must only be evaluated for clauses with relational
    expressions or boolean functions.
    @param dataset This is passed to the rvalue::bvalue() method.
    @param dds Use variables from this DDS when evaluating the
    expression
    @return True if the clause is true, false otherwise.
    @exception InternalErr if called for a clause that returns a
    BaseType pointer. */
bool
Clause::value(const string &dataset, DDS &dds)
{
    assert(OK());
    assert(_op || _b_func);

    if (_op) {			// Is it a relational clause?
	// rvalue::bvalue(...) returns the rvalue encapsulated in a
	// BaseType *.
	BaseType *btp = _arg1->bvalue(dataset, dds);
	// The list of rvalues is an implicit logical OR, so assume
	// FALSE and return TRUE for the first TRUE subclause.
	bool result = false;
	for (rvalue_list_iter i = _args->begin();
	     i != _args->end() && !result;
	     i++)
	{
	    result = result || btp->ops((*i)->bvalue(dataset, dds),
					_op, dataset);
	}

	return result;
    }
    else if (_b_func) {		// ...A bool function?
	BaseType **argv = build_btp_args(_args, dds, dataset);

	bool result = (*_b_func)(_argc, argv, dds);
	delete[] argv;		// Cache me!
	argv = 0;

	return result;
    }
    else {
	throw InternalErr(__FILE__, __LINE__,
                "A selection expression must contain only boolean clauses.");
    }
}

/** @brief Evaluate a clause that returns a value via a BaseType
    pointer.
    This method must only be evaluated for clauses with relational
    expressions or boolean functions.
    @param dataset This is passed to the function.
    @param dds Use variables from this DDS when evaluating the
    expression
    @param value A value-result parameter
    @return True if the the BaseType pointer is not null, false otherwise.
    @exception InternalErr if called for a clause that returns a
    boolean value. Not that this method itself \e does return a
    boolean value. */
bool
Clause::value(const string &dataset, DDS &dds, BaseType **value)
{
    assert(OK());
    assert(_bt_func);

    if (_bt_func) {
        // build_btp_args() is a function defined in RValue.cc. It no longer
        // reads the values as it builds the arguments, that is now left up
        // to the functions themselves. 9/25/06 jhrg
	BaseType **argv = build_btp_args(_args, dds, dataset);

	*value = (*_bt_func)(_argc, argv, dds, dataset);
	delete[] argv;		// Cache me!
	argv = 0;

	if (*value) {
	    (*value)->set_send_p(true);
        (*value)->set_read_p(true);
	    return true;
	}
	else {
	    return false;
	}
    }
    else {
	throw InternalErr(__FILE__, __LINE__,
                "Claue::value() was called in a context expecting a BaseType pointer return, but the Clause was boolean-valued instead.");
    }
}

<|endoftext|>


<commit_before>/** @file
    @brief Implementation of the "multiserver" plugin that offers the stock VRPN
   devices.

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>
*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include "VRPNMultiserver.h"
#include "DevicesWithParameters.h"
#include <osvr/PluginKit/PluginKit.h>
#include <osvr/Util/UniquePtr.h>
#include <osvr/VRPNServer/VRPNDeviceRegistration.h>

// Library/third-party includes
#include "hidapi/hidapi.h"
#include "vrpn_Connection.h"
#include "vrpn_Tracker_RazerHydra.h"
#include "vrpn_Tracker_Filter.h"
#include <boost/noncopyable.hpp>

// Standard includes
#include <iostream>
#include <map>
#include <string>
#include <sstream>

class VRPNHardwareDetect : boost::noncopyable {
  public:
    VRPNHardwareDetect(VRPNMultiserverData &data) : m_data(data) {}
    OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx) {
        struct hid_device_info *enumData = hid_enumerate(0, 0);
        for (struct hid_device_info *dev = enumData; dev != nullptr;
             dev = dev->next) {
            if (dev->vendor_id == 0x1532 && dev->product_id == 0x0300) {
                /// Decorated name for Hydra
                std::string name;
                {
                    // Razer Hydra
                    osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                    name = reg.useDecoratedName(m_data.getName("RazerHydra"));
                    reg.registerDevice(new vrpn_Tracker_RazerHydra(
                        name.c_str(), reg.getVRPNConnection()));
                }
                std::string localName = "*" + name;

                {
                    // Corresponding filter
                    osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                    reg.registerDevice(new vrpn_Tracker_FilterOneEuro(
                        reg.useDecoratedName(m_data.getName("OneEuroFilter"))
                            .c_str(),
                        reg.getVRPNConnection(), localName.c_str(), 2, 1.15,
                        1.0, 1.2, 1.5, 5.0, 1.2));
                }
                break;
            }
        }
        hid_free_enumeration(enumData);
        return OSVR_RETURN_SUCCESS;
    }

  private:
    VRPNMultiserverData &m_data;
};

OSVR_PLUGIN(org_opengoggles_bundled_Multiserver) {
    osvr::pluginkit::PluginContext context(ctx);

    VRPNMultiserverData &data =
        *context.registerObjectForDeletion(new VRPNMultiserverData);
    context.registerHardwareDetectCallback(new VRPNHardwareDetect(data));

    osvrRegisterDriverInstantiationCallback(
        ctx, "YEI_3Space_Sensor", &wrappedConstructor<&createYEI>, &data);

    return OSVR_RETURN_SUCCESS;
}
<commit_msg>Avoid trying to connect to the same hydra more than once.<commit_after>/** @file
    @brief Implementation of the "multiserver" plugin that offers the stock VRPN
   devices.

    @date 2014

    @author
    Ryan Pavlik
    <ryan@sensics.com>
    <http://sensics.com>
*/

// Copyright 2014 Sensics, Inc.
//
// All rights reserved.
//
// (Final version intended to be licensed under
// the Apache License, Version 2.0)

// Internal Includes
#include "VRPNMultiserver.h"
#include "DevicesWithParameters.h"
#include <osvr/PluginKit/PluginKit.h>
#include <osvr/Util/UniquePtr.h>
#include <osvr/VRPNServer/VRPNDeviceRegistration.h>

// Library/third-party includes
#include "hidapi/hidapi.h"
#include "vrpn_Connection.h"
#include "vrpn_Tracker_RazerHydra.h"
#include "vrpn_Tracker_Filter.h"
#include <boost/noncopyable.hpp>

// Standard includes
#include <iostream>
#include <map>
#include <string>
#include <sstream>
#include <vector>

class VRPNHardwareDetect : boost::noncopyable {
  public:
    VRPNHardwareDetect(VRPNMultiserverData &data) : m_data(data) {}
    OSVR_ReturnCode operator()(OSVR_PluginRegContext ctx) {
        struct hid_device_info *enumData = hid_enumerate(0, 0);
        for (struct hid_device_info *dev = enumData; dev != nullptr;
             dev = dev->next) {
            if (dev->vendor_id == 0x1532 && dev->product_id == 0x0300 &&
                !m_isPathHandled(dev->path)) {
                m_handlePath(dev->path);
                /// Decorated name for Hydra
                std::string name;
                {
                    // Razer Hydra
                    osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                    name = reg.useDecoratedName(m_data.getName("RazerHydra"));
                    reg.registerDevice(new vrpn_Tracker_RazerHydra(
                        name.c_str(), reg.getVRPNConnection()));
                }
                std::string localName = "*" + name;

                {
                    // Corresponding filter
                    osvr::vrpnserver::VRPNDeviceRegistration reg(ctx);
                    reg.registerDevice(new vrpn_Tracker_FilterOneEuro(
                        reg.useDecoratedName(m_data.getName("OneEuroFilter"))
                            .c_str(),
                        reg.getVRPNConnection(), localName.c_str(), 2, 1.15,
                        1.0, 1.2, 1.5, 5.0, 1.2));
                }
                break;
            }
        }
        hid_free_enumeration(enumData);
        return OSVR_RETURN_SUCCESS;
    }

  private:
    bool m_isPathHandled(const char *path) {
        return std::find(begin(m_handledPaths), end(m_handledPaths),
                         std::string(path)) != end(m_handledPaths);
    }
    void m_handlePath(const char *path) {
        m_handledPaths.push_back(std::string(path));
    }
    VRPNMultiserverData &m_data;
    std::vector<std::string> m_handledPaths;
};

OSVR_PLUGIN(org_opengoggles_bundled_Multiserver) {
    osvr::pluginkit::PluginContext context(ctx);

    VRPNMultiserverData &data =
        *context.registerObjectForDeletion(new VRPNMultiserverData);
    context.registerHardwareDetectCallback(new VRPNHardwareDetect(data));

    osvrRegisterDriverInstantiationCallback(
        ctx, "YEI_3Space_Sensor", &wrappedConstructor<&createYEI>, &data);

    return OSVR_RETURN_SUCCESS;
}
<|endoftext|>


<commit_before>template <typename T>
inline double evaluatePartitions(data_t* data, struct Density* density,
                                 struct Splitter<T>* splitter, size_t k) {
    size_t i = splitter->feature_id;
    size_t n_features = splitter->n_features;
    data_t data_point;
    target_t target_value;
    size_t id = splitter->node->id;
    memset((void*) density->counters_left, 0x00, splitter->n_classes * sizeof(size_t));
    memset((void*) density->counters_right, 0x00, splitter->n_classes * sizeof(size_t));
    memset((void*) density->counters_nan, 0x00, splitter->n_classes * sizeof(size_t));
    density->split_value = splitter->partition_values[k];
    for (uint j = 0; j < splitter->n_instances; j++) {
        if (splitter->belongs_to[j] == id) {
            target_value = splitter->targets[j];
            data_point = data[j * n_features + i];
            if (data_point == splitter->nan_value) {
                density->counters_nan[target_value]++;
            }
            else if (data_point >= density->split_value) {
                density->counters_right[target_value]++;
            }
            else {
                density->counters_left[target_value]++;
            }
        }
    }
    return getFeatureCost(density, splitter->n_classes);
}

template <typename T>
inline double evaluatePartitionsWithRegression(data_t* data, struct Density* density,
                                 struct Splitter<T>* splitter, size_t k) {

    size_t i = splitter->feature_id;
    size_t n_features = splitter->n_features;
    data_t data_point;
    T y;
    size_t id = splitter->node->id;
    size_t n_left = 0, n_right = 0;
    density->split_value = splitter->partition_values[k];
    data_t split_value = density->split_value;
    T mean_left = 0, mean_right = 0;
    double cost = 0.0;
    for (uint j = 0; j < splitter->n_instances; j++) {
        if (splitter->belongs_to[j] == id) {
            data_point = data[j * n_features + i];
            y = splitter->targets[j];
            if (data_point == splitter->nan_value) {}
            else if (data_point >= split_value) {
                mean_right += y;
                n_right++;
            }
            else {
                mean_left += y;
                n_left++;
            }
        }
    }
    if ((n_left == 0) or (n_right == 0)) { return INFINITY; }
    mean_left /= n_left;
    mean_right /= n_right;
    for (uint j = 0; j < splitter->n_instances; j++) {
        if (splitter->belongs_to[j] == id) {
            data_point = data[j * n_features + i];
            y = splitter->targets[j];
            if (data_point == splitter->nan_value) {}
            else if (data_point >= split_value) {
                cost += std::abs(mean_right - y); // TODO : use squared error ?
            }
            else {
                cost += std::abs(mean_right - y); // TODO : use squared error ?
            }
        }
    }
    return cost;
}

template <typename T>
double evaluateByThreshold(struct Splitter<T>* splitter, struct Density* density,
                           data_t* const data, int partition_value_type) {
    size_t best_split_id = 0;
    double lowest_cost = INFINITY;
    double cost;
    size_t n_partition_values;
    switch(partition_value_type) {
        case gbdf_part::QUARTILE_PARTITIONING:
            splitter->partition_values = density->quartiles;
            n_partition_values = 4;
            break;
        case gbdf_part::DECILE_PARTITIONING:
            splitter->partition_values = density->deciles;
            n_partition_values = 10;
            break;
        case gbdf_part::PERCENTILE_PARTITIONING:
            splitter->partition_values = density->percentiles;
            n_partition_values = 100;
            break;
        default:
            splitter->partition_values = density->percentiles;
            n_partition_values = 100;
    }
    for (uint k = 1; k < n_partition_values - 1; k++) {
        if (splitter->task == gbdf_task::CLASSIFICATION_TASK) {
            cost = evaluatePartitions(data, density, splitter, k);
        }
        else {
            cost = evaluatePartitionsWithRegression(data, density, splitter, k);
        }
        if (cost < lowest_cost) {
            lowest_cost = cost;
            best_split_id = k;
        }
    }
    if (splitter->task == gbdf_task::CLASSIFICATION_TASK) {
        evaluatePartitions(data, density, splitter, best_split_id);
    }
    else {
        evaluatePartitionsWithRegression(data, density, splitter, best_split_id);
    }
    return lowest_cost;
}
<commit_msg>Use static_cast rather than C-style cast<commit_after>template <typename T>
inline double evaluatePartitions(data_t* data, struct Density* density,
                                 struct Splitter<T>* splitter, size_t k) {
    size_t i = splitter->feature_id;
    size_t n_features = splitter->n_features;
    data_t data_point;
    target_t target_value;
    size_t id = splitter->node->id;
    memset(static_cast<void*>(density->counters_left), 0x00, splitter->n_classes * sizeof(size_t));
    memset(static_cast<void*>(density->counters_right), 0x00, splitter->n_classes * sizeof(size_t));
    memset(static_cast<void*>(density->counters_nan), 0x00, splitter->n_classes * sizeof(size_t));
    density->split_value = splitter->partition_values[k];
    for (uint j = 0; j < splitter->n_instances; j++) {
        if (splitter->belongs_to[j] == id) {
            target_value = splitter->targets[j];
            data_point = data[j * n_features + i];
            if (data_point == splitter->nan_value) {
                density->counters_nan[target_value]++;
            }
            else if (data_point >= density->split_value) {
                density->counters_right[target_value]++;
            }
            else {
                density->counters_left[target_value]++;
            }
        }
    }
    return getFeatureCost(density, splitter->n_classes);
}

template <typename T>
inline double evaluatePartitionsWithRegression(data_t* data, struct Density* density,
                                 struct Splitter<T>* splitter, size_t k) {

    size_t i = splitter->feature_id;
    size_t n_features = splitter->n_features;
    data_t data_point;
    T y;
    size_t id = splitter->node->id;
    size_t n_left = 0, n_right = 0;
    density->split_value = splitter->partition_values[k];
    data_t split_value = density->split_value;
    T mean_left = 0, mean_right = 0;
    double cost = 0.0;
    for (uint j = 0; j < splitter->n_instances; j++) {
        if (splitter->belongs_to[j] == id) {
            data_point = data[j * n_features + i];
            y = splitter->targets[j];
            if (data_point == splitter->nan_value) {}
            else if (data_point >= split_value) {
                mean_right += y;
                n_right++;
            }
            else {
                mean_left += y;
                n_left++;
            }
        }
    }
    if ((n_left == 0) or (n_right == 0)) { return INFINITY; }
    mean_left /= n_left;
    mean_right /= n_right;
    for (uint j = 0; j < splitter->n_instances; j++) {
        if (splitter->belongs_to[j] == id) {
            data_point = data[j * n_features + i];
            y = splitter->targets[j];
            if (data_point == splitter->nan_value) {}
            else if (data_point >= split_value) {
                cost += std::abs(mean_right - y); // TODO : use squared error ?
            }
            else {
                cost += std::abs(mean_right - y); // TODO : use squared error ?
            }
        }
    }
    return cost;
}

template <typename T>
double evaluateByThreshold(struct Splitter<T>* splitter, struct Density* density,
                           data_t* const data, int partition_value_type) {
    size_t best_split_id = 0;
    double lowest_cost = INFINITY;
    double cost;
    size_t n_partition_values;
    switch(partition_value_type) {
        case gbdf_part::QUARTILE_PARTITIONING:
            splitter->partition_values = density->quartiles;
            n_partition_values = 4;
            break;
        case gbdf_part::DECILE_PARTITIONING:
            splitter->partition_values = density->deciles;
            n_partition_values = 10;
            break;
        case gbdf_part::PERCENTILE_PARTITIONING:
            splitter->partition_values = density->percentiles;
            n_partition_values = 100;
            break;
        default:
            splitter->partition_values = density->percentiles;
            n_partition_values = 100;
    }
    for (uint k = 1; k < n_partition_values - 1; k++) {
        if (splitter->task == gbdf_task::CLASSIFICATION_TASK) {
            cost = evaluatePartitions(data, density, splitter, k);
        }
        else {
            cost = evaluatePartitionsWithRegression(data, density, splitter, k);
        }
        if (cost < lowest_cost) {
            lowest_cost = cost;
            best_split_id = k;
        }
    }
    if (splitter->task == gbdf_task::CLASSIFICATION_TASK) {
        evaluatePartitions(data, density, splitter, best_split_id);
    }
    else {
        evaluatePartitionsWithRegression(data, density, splitter, best_split_id);
    }
    return lowest_cost;
}
<|endoftext|>