<commit_before>#include "ExponentialRand.h"
#include "UniformRand.h"
#include "../BasicRandGenerator.h"

double ExponentialRand::stairWidth[257] = {0};
double ExponentialRand::stairHeight[256] = {0};
bool ExponentialRand::dummy = ExponentialRand::setupTables();

ExponentialRand::ExponentialRand(double rate)
{
    setRate(rate);
}

std::string ExponentialRand::name()
{
    return "Exponential(" + toStringWithPrecision(getRate()) + ")";
}

bool ExponentialRand::setupTables()
{
    /// Set up ziggurat tables
    static constexpr long double A = 3.9496598225815571993e-3l; /// area under rectangle

    /// coordinates of the implicit rectangle in base layer
    stairHeight[0] = std::exp(-x1);
    stairWidth[0] = A / stairHeight[0];
    /// implicit value for the top layer
    stairWidth[256] = 0;

    for (unsigned i = 1; i <= 255; ++i)
    {
        /// such y_i that f(x_{i+1}) = y_i
        stairWidth[i] = -std::log(stairHeight[i - 1]);
        stairHeight[i] = stairHeight[i - 1] + A / stairWidth[i];
    }
    return true;
}

void ExponentialRand::setRate(double rate)
{
    lambda = rate;
    if (lambda <= 0)
        lambda = 1.0;
    beta = 1.0 / lambda;
}

double ExponentialRand::f(double x) const
{
    return (x > 0) ? lambda * std::exp(-lambda * x) : 0;
}

double ExponentialRand::F(double x) const
{
    return (x > 0) ? 1 - std::exp(-lambda * x) : 0;
}

double ExponentialRand::variate() const
{
    return beta * standardVariate();
}

double ExponentialRand::variate(double rate)
{
    return standardVariate() / rate;
}

double ExponentialRand::standardVariate()
{
    /// Ziggurat algorithm
    int iter = 0;
    do {
        int stairId = RandGenerator::variate() & 255;
        double x = UniformRand::standardVariate() * stairWidth[stairId]; /// get horizontal coordinate

        if (x < stairWidth[stairId + 1]) /// if we are under the upper stair - accept
            return x;

        if (stairId == 0) /// if we catch the tail
            return x1 + standardVariate();

        if (UniformRand::variate(stairHeight[stairId - 1], stairHeight[stairId]) < std::exp(-x)) /// if we are under the curve - accept
            return x;

        /// rejection - go back

    } while (++iter <= 1e9); /// one billion should be enough to be sure there is a bug
    return NAN; /// fail due to some error
}

std::complex<double> ExponentialRand::CF(double t) const
{
    double rate2 = lambda * lambda;
    double denominator = rate2 + t * t;
    return std::complex<double>(rate2 / denominator, lambda * t / denominator);
}

double ExponentialRand::Quantile(double p) const
{
    if (p < 0 || p > 1)
        return NAN;
    if (p == 1)
        return INFINITY;
    return -beta * std::log(1.0 - p);
}

double ExponentialRand::Median() const
{
    return beta * M_LN2;
}

double ExponentialRand::Mode() const
{
    return 0.0;
}

double ExponentialRand::Skewness() const
{
    return 2.0;
}

double ExponentialRand::ExcessKurtosis() const
{
    return 6.0;
}

double ExponentialRand::Entropy() const
{
    return 1 - std::log(lambda);
}

double ExponentialRand::Moment(int n) const
{
    if (n < 0)
        return 0;
    if (n == 0)
        return 1;
    return RandMath::factorial(n) / std::pow(lambda, n);
}

bool ExponentialRand::fit_MLE(const QVector<double> &sample)
{
    double N = sample.size();
    if (N <= 0)
        return false;

    long double sum = 0.0L;
    for (double var : sample) {
        if (var < 0)
            return false;
        sum += var;
    }
    if (sum <= 0)
        return false;

    setRate(N / sum);
    return true;
}
<commit_msg>Update ExponentialRand.cpp<commit_after>#include "ExponentialRand.h"
#include "UniformRand.h"
#include "../BasicRandGenerator.h"

double ExponentialRand::stairWidth[257] = {0};
double ExponentialRand::stairHeight[256] = {0};
bool ExponentialRand::dummy = ExponentialRand::setupTables();

ExponentialRand::ExponentialRand(double rate)
{
    setRate(rate);
}

std::string ExponentialRand::name()
{
    return "Exponential(" + toStringWithPrecision(getRate()) + ")";
}

bool ExponentialRand::setupTables()
{
    /// Set up ziggurat tables
    static constexpr long double A = 3.9496598225815571993e-3l; /// area under rectangle

    /// coordinates of the implicit rectangle in base layer
    stairHeight[0] = std::exp(-x1);
    stairWidth[0] = A / stairHeight[0];
    /// implicit value for the top layer
    stairWidth[256] = 0;

    for (unsigned i = 1; i <= 255; ++i)
    {
        /// such y_i that f(x_{i+1}) = y_i
        stairWidth[i] = -std::log(stairHeight[i - 1]);
        stairHeight[i] = stairHeight[i - 1] + A / stairWidth[i];
    }
    return true;
}

void ExponentialRand::setRate(double rate)
{
    lambda = rate;
    if (lambda <= 0)
        lambda = 1.0;
    beta = 1.0 / lambda;
}

double ExponentialRand::f(double x) const
{
    return (x > 0) ? lambda * std::exp(-lambda * x) : 0;
}

double ExponentialRand::F(double x) const
{
    return (x > 0) ? 1 - std::exp(-lambda * x) : 0;
}

double ExponentialRand::variate() const
{
    return beta * standardVariate();
}

double ExponentialRand::variate(double rate)
{
    return standardVariate() / rate;
}

double ExponentialRand::standardVariate()
{
    /// Ziggurat algorithm
    int iter = 0;
    do {
        int stairId = RandGenerator::variate() & 255;
        double x = UniformRand::standardVariate() * stairWidth[stairId]; /// get horizontal coordinate

        if (x < stairWidth[stairId + 1]) /// if we are under the upper stair - accept
            return x;

        if (stairId == 0) /// if we catch the tail
            return x1 + standardVariate();

        if (UniformRand::variate(stairHeight[stairId - 1], stairHeight[stairId]) < std::exp(-x)) /// if we are under the curve - accept
            return x;

        /// rejection - go back

    } while (++iter <= 1e9); /// one billion should be enough to be sure there is a bug
    return NAN; /// fail due to some error
}

std::complex<double> ExponentialRand::CF(double t) const
{
    double rate2 = lambda * lambda;
    double denominator = rate2 + t * t;
    return std::complex<double>(rate2 / denominator, lambda * t / denominator);
}

double ExponentialRand::Quantile(double p) const
{
    if (p < 0 || p > 1)
        return NAN;
    if (p == 1)
        return INFINITY;
    return -beta * std::log(1.0 - p);
}

double ExponentialRand::Median() const
{
    return beta * M_LN2;
}

double ExponentialRand::Mode() const
{
    return 0.0;
}

double ExponentialRand::Skewness() const
{
    return 2.0;
}

double ExponentialRand::ExcessKurtosis() const
{
    return 6.0;
}

double ExponentialRand::Entropy() const
{
    return 1 - std::log(lambda);
}

double ExponentialRand::Moment(int n) const
{
    if (n < 0)
        return 0;
    if (n == 0)
        return 1;
    return RandMath::factorial(n) / std::pow(lambda, n);
}

bool ExponentialRand::fit_MLE(const QVector<double> &sample)
{
    double n = sample.size();
    if (n <= 0)
        return false;

    long double sum = 0.0L;
    for (double var : sample) {
        if (var < 0)
            return false;
        sum += var;
    }
    if (sum <= 0)
        return false;

    setRate(n / sum);
    return true;
}
<|endoftext|>


<commit_before>// -*- C++ -*-
// matrixMultiplication.cc
// a huge comparison of doing naive and tiled matrix multiplication using many
//  different methods and technologies

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <array>
#include <string>
#include <chrono>
#include <algorithm>

// yucky, but for asking the system how many cores we have
#include <unistd.h>

// header file for openmp
#include <omp.h>

// header files for tbb
#include <tbb/blocked_range.h>
#include <tbb/parallel_reduce.h>
#include <tbb/parallel_for.h>
#include <tbb/task_scheduler_init.h>

// header files for cuda implementation
#include "MatrixMultiplication_cuda.cuh"

// header files for eigen
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <Eigen/Core>
#pragma GCC diagnostic pop

// header files for kokkos
#include <Kokkos_Core.hpp>
#include "Teuchos_Array.hpp"
#include "Intrepid_ArrayTools.hpp"
#include "Intrepid_FieldContainer.hpp"

using std::string;
using std::vector;
using std::array;
using std::chrono::high_resolution_clock;
using std::chrono::duration;
using std::chrono::duration_cast;
using Intrepid::FieldContainer;

/*
template<class Scalar, class LeftViewType, class RightViewType, class OutputViewType>
struct ContractFieldFieldTensorFunctor {
  LeftViewType _leftFields;
  RightViewType _rightFields;
  OutputViewType _outputFields;
  int _numLeftFields;
  int _numRightFields;
  int _numPoints;
  int _dim1Tensor;
  int _dim2Tensor;
  bool _sumInto;

  ContractFieldFieldTensorFunctor(
				  LeftViewType leftFields,
				  RightViewType rightFields,
				  OutputViewType outputFields,
				  int numLeftFields,
				  int numRightFields,
				  int numPoints,
				  int dim1Tensor,
				  int dim2Tensor,
				  bool sumInto) :
    _leftFields(leftFields),
    _rightFields(rightFields),
    _outputFields(outputFields),
    _numLeftFields(numLeftFields),
    _numRightFields(numRightFields),
    _numPoints(numPoints),
    _dim1Tensor(dim1Tensor),
    _dim2Tensor(dim2Tensor),
    _sumInto(sumInto)
  {
    // Nothing to do
  }

  KOKKOS_INLINE_FUNCTION
  void operator()(const unsigned int elementIndex) const {
    if (_sumInto) {
      for (int lbf = 0; lbf < _numLeftFields; lbf++) {
        for (int rbf = 0; rbf < _numRightFields; rbf++) {
          Scalar tmpVal(0);
          for (int qp = 0; qp < _numPoints; qp++) {
            for (int iTens1 = 0; iTens1 < _dim1Tensor; iTens1++) {
              for (int iTens2 = 0; iTens2 < _dim2Tensor; iTens2++) {
                tmpVal += _leftFields(elementIndex, lbf, qp, iTens1, iTens2)*_rightFields(elementIndex, rbf, qp, iTens1, iTens2);
	      } // D2-loop
            } // D1-loop
          } // P-loop
          _outputFields(elementIndex, lbf, rbf) += tmpVal;
        } // R-loop
      } // L-loop
    }
    else {
      for (int lbf = 0; lbf < _numLeftFields; lbf++) {
        for (int rbf = 0; rbf < _numRightFields; rbf++) {
          Scalar tmpVal(0);
          for (int qp = 0; qp < _numPoints; qp++) {
            for (int iTens1 = 0; iTens1 < _dim1Tensor; iTens1++) {
              for (int iTens2 = 0; iTens2 < _dim2Tensor; iTens2++) {
                tmpVal += _leftFields(elementIndex, lbf, qp, iTens1, iTens2)*_rightFields(elementIndex, rbf, qp, iTens1, iTens2);
              } // D2-loop
            } // D1-loop
          } // P-loop
          _outputFields(elementIndex, lbf, rbf) = tmpVal;
        } // R-loop
      } // L-loop
    }
  }
};
*/
void ArrayTools::contractFieldFieldTensor(FieldContainer &            outputFields,
                                          const FieldContainer &   leftFields,
                                          const FieldContainer &  rightFields,
                                          const int           compEngine) {

  // get sizes
  int numCells        = leftFields.dimension(0);
  int numLeftFields   = leftFields.dimension(1);
  int numRightFields  = rightFields.dimension(1);
  int numPoints       = leftFields.dimension(2);
  int dim1Tensor      = leftFields.dimension(3);
  int dim2Tensor      = leftFields.dimension(4);

  switch(compEngine) {
    case 0: {
        for (int cl = 0; cl < numCells; cl++) {
	        for (int lbf = 0; lbf < numLeftFields; lbf++) {
	          for (int rbf = 0; rbf < numRightFields; rbf++) {
	          Scalar tmpVal(0);
	            for (int qp = 0; qp < numPoints; qp++) {
	              for (int iTens1 = 0; iTens1 < dim1Tensor; iTens1++) {
		              for (int iTens2 = 0; iTens2 < dim2Tensor; iTens2++) {

                    tmpVal += leftFields(cl, lbf, qp, iTens1, iTens2) *
                              rightFields(cl, rbf, qp, iTens1, iTens2);
		              } // D2-loop
	              } // D1-loop
	            } // P-loop
	            outputFields(cl, lbf, rbf) = tmpVal;
	          } // R-loop
	        } // L-loop
        } // C-loop
      }
    break;

  case 1: {
    /*
    typedef Kokkos::View<Scalar*****> input_view_t;
    typedef Kokkos::View<Scalar***> output_view_t;

    typedef typename input_view_t::HostMirror input_host_t;
    typedef typename output_view_t::HostMirror output_host_t;

    Kokkos::initialize();

    input_view_t kokkosLeft("left_input", numCells, numLeftFields, numPoints, dim1Tensor, dim2Tensor);
    input_view_t kokkosRight("right_input", numCells, numRightFields, numPoints, dim1Tensor, dim2Tensor);
    output_view_t kokkosOut("output", numCells, numLeftFields, numRightFields);

    input_host_t hostLeft = Kokkos::create_mirror_view(kokkosLeft);
    input_host_t hostRight = Kokkos::create_mirror_view(kokkosRight);
    output_host_t hostOut = Kokkos::create_mirror_view(kokkosOut);

    // Copy everything
    for (int cl = 0; cl < numCells; ++cl) {
      for (int lbf = 0; lbf < numLeftFields; ++lbf) {
	      for (int qp = 0; qp < numPoints; ++qp) {
	        for (int iTens1 = 0; iTens1 < dim1Tensor; ++iTens1) {
	          for (int iTens2 = 0; iTens2 < dim2Tensor; ++iTens2) {
	            hostLeft(cl, lbf, qp, iTens1, iTens2) = leftFields(cl, lbf, qp, iTens1, iTens2);
	          }
	        }
	      }
      }

      for (int rbf = 0; rbf < numRightFields; ++rbf) {
	      for (int qp = 0; qp < numPoints; ++qp) {
	        for (int iTens1 = 0; iTens1 < dim1Tensor; ++iTens1) {
	          for (int iTens2 = 0; iTens2 < dim2Tensor; ++iTens2) {
	            hostRight(cl, rbf, qp, iTens1, iTens2) = rightFields(cl, rbf, qp, iTens1, iTens2);
	          }
	        }
	      }
      }

      for (int lbf = 0; lbf < numLeftFields; ++lbf) {
	      for (int rbf = 0; rbf < numRightFields; ++rbf) {
	        hostOut(cl, lbf, rbf) = outputFields(cl, lbf, rbf);
	      }
      }
    }

    Kokkos::deep_copy(kokkosLeft, hostLeft);
    Kokkos::deep_copy(kokkosRight, hostRight);
    Kokkos::deep_copy(kokkosOut, hostOut);

    ContractFieldFieldTensorFunctor<Scalar, input_view_t, input_view_t, output_view_t>
      kokkosFunctor(kokkosLeft, kokkosRight, kokkosOut,
		    numLeftFields, numRightFields, numPoints,
		    dim1Tensor, dim2Tensor, sumInto);
    Kokkos::parallel_for(numCells, kokkosFunctor);

    Kokkos::fence();

    Kokkos::deep_copy(hostOut, kokkosOut);

    for (int cl = 0; cl < numCells; ++cl) {
      for (int lbf = 0; lbf < numLeftFields; ++lbf) {
	      for (int rbf = 0; rbf < numRightFields; ++rbf) {
	        outputFields(cl, lbf, rbf) = hostOut(cl, lbf, rbf);
	      }
      }
    }
    Kokkos::finalize();
    */
  }
} // end contractFieldFieldTensor

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

  // ===============================================================
  // ********************** < do kokkos> ***************************
  // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  int c=5, p=9, l=3, r=7, d1=13, d2=5;

  FieldContainer<double> in_c_l_p_d_d(c, l, p, d1, d2);
  FieldContainer<double> in_c_r_p_d_d(c, r, p, d1, d2);
  FieldContainer<double> out1_c_l_r(c, l, r);
  FieldContainer<double> out2_c_l_r(c, l, r);

  // fill with random numbers
  for (int i=0; i<in_c_l_p_d_d.size(); i++) {
    in_c_l_p_d_d[i] = Teuchos::ScalarTraits<double>::random();
  }
  for (int i=0; i<in_c_r_p_d_d.size(); i++) {
    in_c_r_p_d_d[i] = Teuchos::ScalarTraits<double>::random();
  }
  contractFieldFieldTensor<double>(out1_c_l_r, in_c_l_p_d_d, in_c_r_p_d_d, 0);
  //contractFieldFieldTensor<double>(out2_c_l_r, in_c_l_p_d_d, in_c_r_p_d_d, COMP_BLAS);

  /*
  Kokkos::initialize();

  //printf("kokkos is running on %s\n", typeid(Kokkos::DefaultExecutionSpace).name());
  matrixView_type left("left", matrixSize*matrixSize);
  matrixView_type right("right", matrixSize*matrixSize);
  matrixView_type result("result", matrixSize*matrixSize);

  host_matrix h_left = Kokkos::create_mirror_view(left);
  host_matrix h_right = Kokkos::create_mirror_view(right);
  host_matrix h_result = Kokkos::create_mirror_view(result);

  for(unsigned index = 0; index < matrixSize*matrixSize; ++index) {
    h_left(index) = leftMatrix(index);
    h_right(index) = rightMatrixRow(index);
    h_result(index) = 0;
  }

  Kokkos::deep_copy(left, h_left);
  Kokkos::deep_copy(right, h_right);
  Kokkos::deep_copy(result, h_result);

  KokkosFunctor kokkosFunctor(matrixSize, left, right, result);
  // start timing
  tic = high_resolution_clock::now();
  matrixView_type finalResults;
  for (unsigned int repeatIndex = 0;
       repeatIndex < numberOfRepeats; ++repeatIndex) {

    Kokkos::parallel_for(matrixSize*matrixSize, kokkosFunctor);
    Kokkos::fence();

  }
  // stop timing
  toc = high_resolution_clock::now();
  const double kokkosElapsedTime =
    duration_cast<duration<double> >(toc - tic).count();

  Kokkos::deep_copy(h_result, result);

  for(unsigned index = 0; index < matrixSize * matrixSize; ++index){
    resultMatrix(index) = h_result(index);
  }
  // check the answer
  double kokkosCheckSum = 0;
  for (unsigned int row = 0; row < matrixSize; ++row) {
    for (unsigned int col = 0; col < matrixSize; ++col) {
      kokkosCheckSum += resultMatrix(row*matrixSize + col);
    }
  }
  sprintf(methodName, "naive kokkos");
  if (std::abs(cacheUnfriendlyCheckSum - kokkosCheckSum) / cacheUnfriendlyCheckSum < 1e-3) {
    printf("%-38s : time %6.2f speedup w.r.t. unfriendly %6.2f, w.r.t. friendly %6.2f\n",
           methodName,
           kokkosElapsedTime,
           cacheUnfriendlyElapsedTime / kokkosElapsedTime,
           cacheFriendlyElapsedTime / kokkosElapsedTime);
  } else {
    printf("%-38s : incorrect checksum %lf instead of %lf\n",
           methodName, kokkosCheckSum, cacheUnfriendlyCheckSum);
  }

  Kokkos::finalize();
  */
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // ********************** </do kokkos> ***************************
  // ===============================================================

  return 0;
}
<commit_msg>the function seems to be running correctly in serial mode, going to try to add blas to this file so I can make sure my answers are right. After that on to kokkos<commit_after>// -*- C++ -*-
// matrixMultiplication.cc
// a huge comparison of doing naive and tiled matrix multiplication using many
//  different methods and technologies

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <array>
#include <string>
#include <chrono>
#include <algorithm>

// yucky, but for asking the system how many cores we have
#include <unistd.h>

// header file for openmp
#include <omp.h>

// header files for tbb
#include <tbb/blocked_range.h>
#include <tbb/parallel_reduce.h>
#include <tbb/parallel_for.h>
#include <tbb/task_scheduler_init.h>

// header files for cuda implementation
#include "MatrixMultiplication_cuda.cuh"

// header files for eigen
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#include <Eigen/Core>
#pragma GCC diagnostic pop

// header files for kokkos
#include <Kokkos_Core.hpp>
#include "Teuchos_Array.hpp"
#include "Intrepid_ArrayTools.hpp"
#include "Intrepid_FieldContainer.hpp"
#include "Intrepid_RealSpaceTools.hpp"
#include "Teuchos_oblackholestream.hpp"
#include "Teuchos_RCP.hpp"
#include "Teuchos_ScalarTraits.hpp"
#include "Teuchos_GlobalMPISession.hpp"

using std::string;
using std::vector;
using std::array;
using std::chrono::high_resolution_clock;
using std::chrono::duration;
using std::chrono::duration_cast;
using Intrepid::FieldContainer;

/*
template<class Scalar, class LeftViewType, class RightViewType, class OutputViewType>
struct ContractFieldFieldTensorFunctor {
  LeftViewType _leftFields;
  RightViewType _rightFields;
  OutputViewType _outputFields;
  int _numLeftFields;
  int _numRightFields;
  int _numPoints;
  int _dim1Tensor;
  int _dim2Tensor;
  bool _sumInto;

  ContractFieldFieldTensorFunctor(
				  LeftViewType leftFields,
				  RightViewType rightFields,
				  OutputViewType outputFields,
				  int numLeftFields,
				  int numRightFields,
				  int numPoints,
				  int dim1Tensor,
				  int dim2Tensor,
				  bool sumInto) :
    _leftFields(leftFields),
    _rightFields(rightFields),
    _outputFields(outputFields),
    _numLeftFields(numLeftFields),
    _numRightFields(numRightFields),
    _numPoints(numPoints),
    _dim1Tensor(dim1Tensor),
    _dim2Tensor(dim2Tensor),
    _sumInto(sumInto)
  {
    // Nothing to do
  }

  KOKKOS_INLINE_FUNCTION
  void operator()(const unsigned int elementIndex) const {
    if (_sumInto) {
      for (int lbf = 0; lbf < _numLeftFields; lbf++) {
        for (int rbf = 0; rbf < _numRightFields; rbf++) {
          Scalar tmpVal(0);
          for (int qp = 0; qp < _numPoints; qp++) {
            for (int iTens1 = 0; iTens1 < _dim1Tensor; iTens1++) {
              for (int iTens2 = 0; iTens2 < _dim2Tensor; iTens2++) {
                tmpVal += _leftFields(elementIndex, lbf, qp, iTens1, iTens2)*_rightFields(elementIndex, rbf, qp, iTens1, iTens2);
	      } // D2-loop
            } // D1-loop
          } // P-loop
          _outputFields(elementIndex, lbf, rbf) += tmpVal;
        } // R-loop
      } // L-loop
    }
    else {
      for (int lbf = 0; lbf < _numLeftFields; lbf++) {
        for (int rbf = 0; rbf < _numRightFields; rbf++) {
          Scalar tmpVal(0);
          for (int qp = 0; qp < _numPoints; qp++) {
            for (int iTens1 = 0; iTens1 < _dim1Tensor; iTens1++) {
              for (int iTens2 = 0; iTens2 < _dim2Tensor; iTens2++) {
                tmpVal += _leftFields(elementIndex, lbf, qp, iTens1, iTens2)*_rightFields(elementIndex, rbf, qp, iTens1, iTens2);
              } // D2-loop
            } // D1-loop
          } // P-loop
          _outputFields(elementIndex, lbf, rbf) = tmpVal;
        } // R-loop
      } // L-loop
    }
  }
};
*/

void contractFieldFieldTensor(FieldContainer<double> & outputFields,
			      const FieldContainer<double> &   leftFields,
			      const FieldContainer<double> &  rightFields,
                              const int compEngine) {

  // get sizes
  int numCells        = leftFields.dimension(0);
  int numLeftFields   = leftFields.dimension(1);
  int numRightFields  = rightFields.dimension(1);
  int numPoints       = leftFields.dimension(2);
  int dim1Tensor      = leftFields.dimension(3);
  int dim2Tensor      = leftFields.dimension(4);

  switch(compEngine) {
    case 0: {
        for (int cl = 0; cl < numCells; cl++) {
	        for (int lbf = 0; lbf < numLeftFields; lbf++) {
	          for (int rbf = 0; rbf < numRightFields; rbf++) {
	          double tmpVal = 0;
	            for (int qp = 0; qp < numPoints; qp++) {
	              for (int iTens1 = 0; iTens1 < dim1Tensor; iTens1++) {
		              for (int iTens2 = 0; iTens2 < dim2Tensor; iTens2++) {

                    tmpVal += leftFields(cl, lbf, qp, iTens1, iTens2) *
                              rightFields(cl, rbf, qp, iTens1, iTens2);
		              } // D2-loop
	              } // D1-loop
	            } // P-loop
	            outputFields(cl, lbf, rbf) = tmpVal;
	          } // R-loop
	        } // L-loop
        } // C-loop
      }
    break;

  case 1: {
    /*
    typedef Kokkos::View<Scalar*****> input_view_t;
    typedef Kokkos::View<Scalar***> output_view_t;

    typedef typename input_view_t::HostMirror input_host_t;
    typedef typename output_view_t::HostMirror output_host_t;

    Kokkos::initialize();

    input_view_t kokkosLeft("left_input", numCells, numLeftFields, numPoints, dim1Tensor, dim2Tensor);
    input_view_t kokkosRight("right_input", numCells, numRightFields, numPoints, dim1Tensor, dim2Tensor);
    output_view_t kokkosOut("output", numCells, numLeftFields, numRightFields);

    input_host_t hostLeft = Kokkos::create_mirror_view(kokkosLeft);
    input_host_t hostRight = Kokkos::create_mirror_view(kokkosRight);
    output_host_t hostOut = Kokkos::create_mirror_view(kokkosOut);

    // Copy everything
    for (int cl = 0; cl < numCells; ++cl) {
      for (int lbf = 0; lbf < numLeftFields; ++lbf) {
	      for (int qp = 0; qp < numPoints; ++qp) {
	        for (int iTens1 = 0; iTens1 < dim1Tensor; ++iTens1) {
	          for (int iTens2 = 0; iTens2 < dim2Tensor; ++iTens2) {
	            hostLeft(cl, lbf, qp, iTens1, iTens2) = leftFields(cl, lbf, qp, iTens1, iTens2);
	          }
	        }
	      }
      }

      for (int rbf = 0; rbf < numRightFields; ++rbf) {
	      for (int qp = 0; qp < numPoints; ++qp) {
	        for (int iTens1 = 0; iTens1 < dim1Tensor; ++iTens1) {
	          for (int iTens2 = 0; iTens2 < dim2Tensor; ++iTens2) {
	            hostRight(cl, rbf, qp, iTens1, iTens2) = rightFields(cl, rbf, qp, iTens1, iTens2);
	          }
	        }
	      }
      }

      for (int lbf = 0; lbf < numLeftFields; ++lbf) {
	      for (int rbf = 0; rbf < numRightFields; ++rbf) {
	        hostOut(cl, lbf, rbf) = outputFields(cl, lbf, rbf);
	      }
      }
    }

    Kokkos::deep_copy(kokkosLeft, hostLeft);
    Kokkos::deep_copy(kokkosRight, hostRight);
    Kokkos::deep_copy(kokkosOut, hostOut);

    ContractFieldFieldTensorFunctor<Scalar, input_view_t, input_view_t, output_view_t>
      kokkosFunctor(kokkosLeft, kokkosRight, kokkosOut,
		    numLeftFields, numRightFields, numPoints,
		    dim1Tensor, dim2Tensor, sumInto);
    Kokkos::parallel_for(numCells, kokkosFunctor);

    Kokkos::fence();

    Kokkos::deep_copy(hostOut, kokkosOut);

    for (int cl = 0; cl < numCells; ++cl) {
      for (int lbf = 0; lbf < numLeftFields; ++lbf) {
	      for (int rbf = 0; rbf < numRightFields; ++rbf) {
	        outputFields(cl, lbf, rbf) = hostOut(cl, lbf, rbf);
	      }
      }
    }
    Kokkos::finalize();
    */
  }
  }
}

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

  // ===============================================================
  // ********************** < do kokkos> ***************************
  // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
  int c=5, p=9, l=3, r=7, d1=13, d2=5;

  FieldContainer<double> in_c_l_p_d_d(c, l, p, d1, d2);
  FieldContainer<double> in_c_r_p_d_d(c, r, p, d1, d2);
  FieldContainer<double> out1_c_l_r(c, l, r);
  FieldContainer<double> out2_c_l_r(c, l, r);

  // fill with random numbers
  for (int i=0; i<in_c_l_p_d_d.size(); i++) {
    in_c_l_p_d_d[i] = Teuchos::ScalarTraits<double>::random();
  }
  for (int i=0; i<in_c_r_p_d_d.size(); i++) {
    in_c_r_p_d_d[i] = Teuchos::ScalarTraits<double>::random();
  }
  contractFieldFieldTensor(out1_c_l_r, in_c_l_p_d_d, in_c_r_p_d_d, 0);
  //contractFieldFieldTensor<double>(out2_c_l_r, in_c_l_p_d_d, in_c_r_p_d_d, COMP_BLAS);

  /*
  Kokkos::initialize();

  //printf("kokkos is running on %s\n", typeid(Kokkos::DefaultExecutionSpace).name());
  matrixView_type left("left", matrixSize*matrixSize);
  matrixView_type right("right", matrixSize*matrixSize);
  matrixView_type result("result", matrixSize*matrixSize);

  host_matrix h_left = Kokkos::create_mirror_view(left);
  host_matrix h_right = Kokkos::create_mirror_view(right);
  host_matrix h_result = Kokkos::create_mirror_view(result);

  for(unsigned index = 0; index < matrixSize*matrixSize; ++index) {
    h_left(index) = leftMatrix(index);
    h_right(index) = rightMatrixRow(index);
    h_result(index) = 0;
  }

  Kokkos::deep_copy(left, h_left);
  Kokkos::deep_copy(right, h_right);
  Kokkos::deep_copy(result, h_result);

  KokkosFunctor kokkosFunctor(matrixSize, left, right, result);
  // start timing
  tic = high_resolution_clock::now();
  matrixView_type finalResults;
  for (unsigned int repeatIndex = 0;
       repeatIndex < numberOfRepeats; ++repeatIndex) {

    Kokkos::parallel_for(matrixSize*matrixSize, kokkosFunctor);
    Kokkos::fence();

  }
  // stop timing
  toc = high_resolution_clock::now();
  const double kokkosElapsedTime =
    duration_cast<duration<double> >(toc - tic).count();

  Kokkos::deep_copy(h_result, result);

  for(unsigned index = 0; index < matrixSize * matrixSize; ++index){
    resultMatrix(index) = h_result(index);
  }
  // check the answer
  double kokkosCheckSum = 0;
  for (unsigned int row = 0; row < matrixSize; ++row) {
    for (unsigned int col = 0; col < matrixSize; ++col) {
      kokkosCheckSum += resultMatrix(row*matrixSize + col);
    }
  }
  sprintf(methodName, "naive kokkos");
  if (std::abs(cacheUnfriendlyCheckSum - kokkosCheckSum) / cacheUnfriendlyCheckSum < 1e-3) {
    printf("%-38s : time %6.2f speedup w.r.t. unfriendly %6.2f, w.r.t. friendly %6.2f\n",
           methodName,
           kokkosElapsedTime,
           cacheUnfriendlyElapsedTime / kokkosElapsedTime,
           cacheFriendlyElapsedTime / kokkosElapsedTime);
  } else {
    printf("%-38s : incorrect checksum %lf instead of %lf\n",
           methodName, kokkosCheckSum, cacheUnfriendlyCheckSum);
  }

  Kokkos::finalize();
  */
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // ********************** </do kokkos> ***************************
  // ===============================================================

  return 0;
}
<|endoftext|>


<commit_before>
#define INF 0x7fffffffffffffffLL
#define MAXN 2222
#define MAXM 22222

int h[MAXN],p[MAXN];
int u[MAXM],v[MAXM],next[MAXM];
int flow[MAXM],c;
int d[MAXN],cst[MAXM];

int e,n;

void add(int u_, int v_, ll cst_, ll w_){
    u[e]=u_;      v[e]=v_;
    flow[e]=w_;     cst[e]=cst_;
    next[e]=h[u_];    h[u_]=e;
    e++;
}

void Bellman_Ford(int s){ // Dijkstra, na verdade
    int inq[MAXN];
    queue<int> q;
    memset(inq, 0,sizeof(inq));

    for(int i=0; i<=n; i++) {
        d[i]=INF;
        d[s]=0;
    }
    q.push(s);
    inq[s]=1;

    while(!q.empty()){
        int u_ = q.front(); q.pop();
        inq[u_]=0;
        for(int x=h[u_]; x!=-1; x=next[x])
          if(flow[x] && d[u_]+cst[x]<d[v[x]]){
            d[v[x]] = d[u_] + cst[x];
            p[v[x]]=x;
            if(!inq[v[x]]){
                q.push(v[x]);
                inq[v[x]]=1;
            }
          }
    }
}

// Retorna o flow maximo, se quiser o cost, basta pegar var global c
int mcmf(int s, int t){
    int f=0;     c=0;
    p[s]=-1;
    while(true){
        Bellman_Ford(s);

        if(d[t] == INF) break;
        ll a=INF;
        for(int x=p[t]; x!=-1; x=p[u[x]])
            a=min(a,flow[x]);
        for(int x=p[t]; x!=-1; x=p[u[x]]){
            flow[x]-=a;
            flow[x^1]+=a;
        }
        c+=d[t]*a;
        f+=a;
    }
    return f;
}

// Exemplo de utilizacao
memset(h,-1,sizeof h);
e = 0;

// Para cada edge no grafo, adiciona-se a edge inversa logo apos, com o
// peso negativo e capacidade nula
add(u,v, w, cap);
add(v,u, -w, 0);
<commit_msg>colocando func de reset<commit_after>
#define INF 0x7fffffffffffffffLL
#define MAXN 2222
#define MAXM 22222

int h[MAXN],p[MAXN];
int u[MAXM],v[MAXM],next[MAXM];
int flow[MAXM],c;
int d[MAXN],cst[MAXM];

int e,n;

void reset(){
    memset(h,-1,sizeof h);
    e = 0;
}

void add(int u_, int v_, ll cst_, ll w_){
    u[e]=u_;      v[e]=v_;
    flow[e]=w_;     cst[e]=cst_;
    next[e]=h[u_];    h[u_]=e;
    e++;
}

void Bellman_Ford(int s){ // Dijkstra, na verdade
    int inq[MAXN];
    queue<int> q;
    memset(inq, 0,sizeof(inq));

    for(int i=0; i<=n; i++) {
        d[i]=INF;
        d[s]=0;
    }
    q.push(s);
    inq[s]=1;

    while(!q.empty()){
        int u_ = q.front(); q.pop();
        inq[u_]=0;
        for(int x=h[u_]; x!=-1; x=next[x])
          if(flow[x] && d[u_]+cst[x]<d[v[x]]){
            d[v[x]] = d[u_] + cst[x];
            p[v[x]]=x;
            if(!inq[v[x]]){
                q.push(v[x]);
                inq[v[x]]=1;
            }
          }
    }
}

// Retorna o flow maximo, se quiser o cost, basta pegar var global c
int mcmf(int s, int t){
    int f=0;     c=0;
    p[s]=-1;
    while(true){
        Bellman_Ford(s);

        if(d[t] == INF) break;
        ll a=INF;
        for(int x=p[t]; x!=-1; x=p[u[x]])
            a=min(a,flow[x]);
        for(int x=p[t]; x!=-1; x=p[u[x]]){
            flow[x]-=a;
            flow[x^1]+=a;
        }
        c+=d[t]*a;
        f+=a;
    }
    return f;
}

// Exemplo de utilizacao:
// Para cada edge no grafo, adiciona-se a edge inversa logo apos, com o
// peso negativo e capacidade nula
add(u,v, w, cap);
add(v,u, -w, 0);
<|endoftext|>


<commit_before>/*  \brief Utility Functions for Lobid API (HBZ) to get title data, norm data (GND) and organisational data
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "LobidUtil.h"
#include <unordered_map>
#include "Downloader.h"
#include "JSON.h"
#include "UrlUtil.h"
#include "util.h"

namespace LobidUtil {

std::unordered_map<std::string, const std::shared_ptr<const JSON::ObjectNode>> url_to_lookup_result_cache;

static std::string BASE_URL_GND = "http://lobid.org/gnd/search?format=json";
static std::string BASE_URL_ORGANISATIONS = "http://lobid.org/organisations/search?format=json";
static std::string BASE_URL_RESOURCES = "http://lobid.org/resources/search?format=json";

void AddUrlParams(std::string * const url, const std::string &key, const std::unordered_map<std::string, std::string> &params) {
    unsigned i(0);
    for (const auto &key_and_value : params) {
        if (i == 0)
            *url += "&" + key + "=";
        else
            *url += UrlUtil::UrlEncode(" AND ");
        *url += UrlUtil::UrlEncode(key_and_value.first + ":" + key_and_value.second);
        ++i;
    }
}

const std::string BuildUrl(const std::string &base_url, const std::unordered_map<std::string, std::string> &query_params,
                           const std::unordered_map<std::string, std::string> &filter_params,
                           const std::string &additional_query_params)
{
    std::string url(base_url);
    AddUrlParams(&url, "q", query_params);
    if (not additional_query_params.empty())
        url += UrlUtil::UrlEncode(" AND " + additional_query_params);
    AddUrlParams(&url, "filter", filter_params);
    return url;
}

const std::shared_ptr<const JSON::ObjectNode> Query(const std::string &url, const bool allow_multiple_results) {
    LOG_DEBUG(url);
    const auto url_and_lookup_result(url_to_lookup_result_cache.find(url));
    if (url_and_lookup_result != url_to_lookup_result_cache.end())
        return url_and_lookup_result->second;

    Downloader downloader(url);
    if (downloader.anErrorOccurred())
        LOG_ERROR(downloader.getLastErrorMessage());

    JSON::Parser json_parser(downloader.getMessageBody());
    std::shared_ptr<JSON::JSONNode> root_node;
    if (not (json_parser.parse(&root_node)))
        LOG_ERROR("failed to parse returned JSON: " + json_parser.getErrorMessage() + "(input was: "
                  + downloader.getMessageBody() + ")");

    const std::shared_ptr<const JSON::ObjectNode> root_object(JSON::JSONNode::CastToObjectNodeOrDie("root", root_node));
    url_to_lookup_result_cache.emplace(url, root_object);

    const unsigned total_items(root_object->getIntegerValue("totalItems"));
    if (total_items == 0) {
        LOG_WARNING("empty result for query: " + url);
        return nullptr;
    } else if (not allow_multiple_results and total_items > 1) {
        LOG_WARNING("multiple results for query: " + url);
        return nullptr;
    }

    return root_object;
}

const std::string QueryAndLookupString(const std::string &url, const std::string &path, const bool allow_multiple_results) {
    const auto root_object(Query(url, allow_multiple_results));
    if (root_object == nullptr)
        return "";

    return JSON::LookupString(path, root_object, "");
}

const std::vector<std::string> QueryAndLookupStrings(const std::string &url, const std::string &path, const bool allow_multiple_results) {
    const auto root_object(Query(url, allow_multiple_results));
    if (root_object == nullptr)
        return std::vector<std::string>{};

    return JSON::LookupStrings(path, root_object);
}

std::string GetAuthorGNDNumber(const std::string &author, const std::string &additional_query_params) {
    return QueryAndLookupString(BuildUrl(BASE_URL_GND, { { "preferredName", author } }, { { "type", "DifferentiatedPerson" } }, additional_query_params),
                                "/member/0/gndIdentifier", /* allow_multiple_results */ false);
}

std::vector<std::string> GetAuthorProfessions(const std::string &author, const std::string &additional_query_params) {
    return QueryAndLookupStrings(BuildUrl(BASE_URL_GND, { { "preferredName", author } }, { { "type", "DifferentiatedPerson" } }, additional_query_params),
                                 "/member/*/professionOrOccupation/*/label", /* allow_multiple_results */ false);
}

std::string GetOrganisationISIL(const std::string &organisation, const std::string &additional_query_params) {
    return QueryAndLookupString(BuildUrl(BASE_URL_ORGANISATIONS, { { "name", organisation } }, std::unordered_map<std::string, std::string>(),  additional_query_params),
                                "/member/0/isil", /* allow_multiple_results */ false);
}

std::string GetTitleDOI(const std::string &title, const std::string &additional_query_params) {
    return QueryAndLookupString(BuildUrl(BASE_URL_RESOURCES, { { "title", "\"" + title + "\"" } }, std::unordered_map<std::string, std::string>(), additional_query_params),
                                "/member/0/doi/0", /* allow_multiple_results */ false);
}

} // namespace LobidUtil
<commit_msg>whitespace<commit_after>/*  \brief Utility Functions for Lobid API (HBZ) to get title data, norm data (GND) and organisational data
 *  \copyright 2018 Universitätsbibliothek Tübingen.  All rights reserved.
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program 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 Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "LobidUtil.h"
#include <unordered_map>
#include "Downloader.h"
#include "JSON.h"
#include "UrlUtil.h"
#include "util.h"

namespace LobidUtil {

std::unordered_map<std::string, const std::shared_ptr<const JSON::ObjectNode>> url_to_lookup_result_cache;

static std::string BASE_URL_GND = "http://lobid.org/gnd/search?format=json";
static std::string BASE_URL_ORGANISATIONS = "http://lobid.org/organisations/search?format=json";
static std::string BASE_URL_RESOURCES = "http://lobid.org/resources/search?format=json";

void AddUrlParams(std::string * const url, const std::string &key, const std::unordered_map<std::string, std::string> &params) {
    unsigned i(0);
    for (const auto &key_and_value : params) {
        if (i == 0)
            *url += "&" + key + "=";
        else
            *url += UrlUtil::UrlEncode(" AND ");
        *url += UrlUtil::UrlEncode(key_and_value.first + ":" + key_and_value.second);
        ++i;
    }
}

const std::string BuildUrl(const std::string &base_url, const std::unordered_map<std::string, std::string> &query_params,
                           const std::unordered_map<std::string, std::string> &filter_params,
                           const std::string &additional_query_params)
{
    std::string url(base_url);
    AddUrlParams(&url, "q", query_params);
    if (not additional_query_params.empty())
        url += UrlUtil::UrlEncode(" AND " + additional_query_params);
    AddUrlParams(&url, "filter", filter_params);
    return url;
}

const std::shared_ptr<const JSON::ObjectNode> Query(const std::string &url, const bool allow_multiple_results) {
    LOG_DEBUG(url);
    const auto url_and_lookup_result(url_to_lookup_result_cache.find(url));
    if (url_and_lookup_result != url_to_lookup_result_cache.end())
        return url_and_lookup_result->second;

    Downloader downloader(url);
    if (downloader.anErrorOccurred())
        LOG_ERROR(downloader.getLastErrorMessage());

    JSON::Parser json_parser(downloader.getMessageBody());
    std::shared_ptr<JSON::JSONNode> root_node;
    if (not (json_parser.parse(&root_node)))
        LOG_ERROR("failed to parse returned JSON: " + json_parser.getErrorMessage() + "(input was: "
                  + downloader.getMessageBody() + ")");

    const std::shared_ptr<const JSON::ObjectNode> root_object(JSON::JSONNode::CastToObjectNodeOrDie("root", root_node));
    url_to_lookup_result_cache.emplace(url, root_object);

    const unsigned total_items(root_object->getIntegerValue("totalItems"));
    if (total_items == 0) {
        LOG_WARNING("empty result for query: " + url);
        return nullptr;
    } else if (not allow_multiple_results and total_items > 1) {
        LOG_WARNING("multiple results for query: " + url);
        return nullptr;
    }

    return root_object;
}

const std::string QueryAndLookupString(const std::string &url, const std::string &path, const bool allow_multiple_results) {
    const auto root_object(Query(url, allow_multiple_results));
    if (root_object == nullptr)
        return "";

    return JSON::LookupString(path, root_object, "");
}

const std::vector<std::string> QueryAndLookupStrings(const std::string &url, const std::string &path, const bool allow_multiple_results) {
    const auto root_object(Query(url, allow_multiple_results));
    if (root_object == nullptr)
        return std::vector<std::string>{};

    return JSON::LookupStrings(path, root_object);
}

std::string GetAuthorGNDNumber(const std::string &author, const std::string &additional_query_params) {
    return QueryAndLookupString(BuildUrl(BASE_URL_GND, { { "preferredName", author } }, { { "type", "DifferentiatedPerson" } }, additional_query_params),
                                "/member/0/gndIdentifier", /* allow_multiple_results */ false);
}

std::vector<std::string> GetAuthorProfessions(const std::string &author, const std::string &additional_query_params) {
    return QueryAndLookupStrings(BuildUrl(BASE_URL_GND, { { "preferredName", author } }, { { "type", "DifferentiatedPerson" } }, additional_query_params),
                                 "/member/*/professionOrOccupation/*/label", /* allow_multiple_results */ false);
}

std::string GetOrganisationISIL(const std::string &organisation, const std::string &additional_query_params) {
    return QueryAndLookupString(BuildUrl(BASE_URL_ORGANISATIONS, { { "name", organisation } }, std::unordered_map<std::string, std::string>(), additional_query_params),
                                "/member/0/isil", /* allow_multiple_results */ false);
}

std::string GetTitleDOI(const std::string &title, const std::string &additional_query_params) {
    return QueryAndLookupString(BuildUrl(BASE_URL_RESOURCES, { { "title", "\"" + title + "\"" } }, std::unordered_map<std::string, std::string>(), additional_query_params),
                                "/member/0/doi/0", /* allow_multiple_results */ false);
}

} // namespace LobidUtil
<|endoftext|>


<commit_before>/*
 ============================================================================
 Name		: ConnectionManager.cpp
 Author	  : Anton Antonov
 Version	 : 1.0
 Copyright   :   Copyright (C) 2008 Rhomobile. All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 Description : CConnectionManager implementation
 ============================================================================
 */

#include "ConnectionManager.h"
#include <centralrepository.h>
#include <ProfileEngineSDKCRKeys.h>

#include <ApEngineConsts.h>
#include <es_enum.h>
#include <activeapdb.h>
#include <apsettingshandlerui.h>
#include <badesca.h>
#include <stringloader.h>
#include <aknquerydialog.h>
#include <CommDbConnPref.h>

#include <httpstringconstants.h>

#include <stdio.h>
#include <string.h>

#include <aknlists.h>		// CAknSinglePopupMenuStyleListBox
#include <CommDb.h>

extern TUint32 gSelectedConnectionId;

namespace EConnectionStatus
	{
	TInt Disconnected = 5;
	}

class TIapData
{
public:
	TBuf<128> iName;
	TUint32 iIap;

};

CConnectionManager::CConnectionManager()
	{
	// No implementation required
	}

CConnectionManager::~CConnectionManager()
	{
	}

TInt CConnectionManager::SelectIAP()
{
	CArrayFixFlat<TIapData>* iEApList=new (ELeave) CArrayFixFlat<TIapData>(2) ;
	TInt stack=0;
	// Make listitems. and PUSH it
	CAknSinglePopupMenuStyleListBox* list = new(ELeave) CAknSinglePopupMenuStyleListBox;
	CleanupStack::PushL(list);
	stack++;

	// Create popup list and PUSH it.
	CAknPopupList* popupList = CAknPopupList::NewL(list,
		R_AVKON_SOFTKEYS_OK_CANCEL, AknPopupLayouts::EMenuWindow);
	CleanupStack::PushL(popupList);stack++;

	CDesCArrayFlat* items = new (ELeave) CDesCArrayFlat(5);
	CleanupStack::PushL(items);stack++;
	// initialize listbox.
	list->ConstructL(popupList, CEikListBox::ELeftDownInViewRect);
	list->CreateScrollBarFrameL(ETrue);
	list->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff,
		CEikScrollBarFrame::EAuto);

	TBuf<52> iapfromtable;
	TInt err = KErrNone;

	CCommsDatabase* iCommsDB=CCommsDatabase::NewL(EDatabaseTypeIAP);
	CleanupStack::PushL(iCommsDB);stack++;
#ifdef __SERIES60_3X__
	CCommsDbTableView* gprsTable = iCommsDB->OpenIAPTableViewMatchingBearerSetLC(
			iBearerFilter == EApBearerTypeWLAN
				? ECommDbBearerWLAN
				: ECommDbBearerGPRS|ECommDbBearerWLAN|ECommDbBearerVirtual,
		ECommDbConnectionDirectionOutgoing);
#else
	CCommsDbTableView* gprsTable = iCommsDB->OpenIAPTableViewMatchingBearerSetLC(
		ECommDbBearerGPRS|ECommDbBearerVirtual,
		ECommDbConnectionDirectionOutgoing);
#endif
	User::LeaveIfError(gprsTable->GotoFirstRecord());
	TInt i=0;
	TUint32 id;
	TIapData eap;

	TInt cur =0; //current value
	do
	{
		gprsTable->ReadTextL(TPtrC(COMMDB_NAME), iapfromtable);
		gprsTable->ReadUintL(TPtrC(COMMDB_ID), id);
		items->AppendL(iapfromtable);
		eap.iIap = id;
		eap.iName.Copy(iapfromtable);
		iEApList->AppendL(eap);

		err = gprsTable->GotoNextRecord();
		i++;
	}
	while (err == KErrNone);
	CleanupStack::PopAndDestroy(2); stack--;

	// Set listitems.
	CTextListBoxModel* model = list->Model();
	model->SetItemTextArray(items);
	model->SetOwnershipType(ELbmOwnsItemArray);
	CleanupStack::Pop();

	popupList->SetTitleL(_L("Access Point"));
	list->SetListBoxObserver(popupList);
	TInt popupOk = popupList->ExecuteLD();
	CleanupStack::Pop();
	TInt iap=0;
	if (popupOk)
	{
		TInt index = list->CurrentItemIndex();
		iap=(*iEApList)[index].iIap;

	}
	CleanupStack::PopAndDestroy();
	iEApList->Reset();
	delete iEApList;
	return iap;
}

CConnectionManager* CConnectionManager::NewLC()
	{
	CConnectionManager* self = new (ELeave)CConnectionManager();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CConnectionManager* CConnectionManager::NewL()
	{
	CConnectionManager* self=CConnectionManager::NewLC();
	CleanupStack::Pop(); // self;
	return self;
	}

void CConnectionManager::ConstructL()
	{
		iRepository            = CRepository::NewL(KCRUidProfileEngine);
	    iPreviousProfileId     = -1;
	    iSelectedConnectionId  = 0u-1;

	    iConnectionSetup  = EFalse;
	    iNewConnection = ETrue;
	}

void CConnectionManager::Release()
	{
	    if (iRepository)
	        delete iRepository;

	    iConnection.Close();
	    iSessionHttp.Close();
	    iServerSocket.Close();
	}

TBool  CConnectionManager::IsOfflineMode()
	{
		return (iPreviousProfileId == EConnectionStatus::Disconnected) ? ETrue : EFalse;
	}

TBool CConnectionManager::SetupConnection()
	{
		TInt iCurrentProfileId;
		iBearerFilter = EApBearerTypeAllBearers;

		ASSERT(iRepository);

		// Check whether we are offline or online
		iRepository->Get(KProEngActiveProfile, iCurrentProfileId);

	    // Close the connection only if
	    // a) this is not the first time and
	    // b) the profile has changed and
	    // c) either the previous or the current profile is Offline (5 = Offline)
	    if (iPreviousProfileId != -1 && iPreviousProfileId != iCurrentProfileId &&
	            (iPreviousProfileId == EConnectionStatus::Disconnected || iCurrentProfileId == EConnectionStatus::Disconnected))
	    {
	        // Close and uninitialize
	        iConnectionSetup = EFalse;
	        iSessionHttp .Close();
	        iConnection  .Close();
	        iServerSocket.Close();
	    }

	    // Save current profile id
	    iPreviousProfileId = iCurrentProfileId;

	    // Try to find an existing connection. If connection has not been set up,
	    // iConnection is not initialized and FindExistingConnection() fails.
	    // Thus, in that case, finding must not be carried out.
	    if (iConnectionSetup && !FindExistingConnection())
	    {
	        iConnectionSetup = EFalse;
	    }

	    if (iConnectionSetup)
	    {
	        // Connection setup is done
	    	iNewConnection = EFalse;
	        return ETrue;
	    }

	    // Open RHTTPSession with default protocol ("HTTP/TCP")
	    iSessionHttp.OpenL();

	    // Install this class as the callback for authentication requests. When
	    // page requires authentication the framework calls GetCredentialsL to get
	    // user name and password.
	    InstallAuthenticationL(iSessionHttp);

	    // In offline, only WLAN connections are available
	    if (iCurrentProfileId == EConnectionStatus::Disconnected)
	    {
	        iBearerFilter = EApBearerTypeWLAN;
	    }

#ifdef __WINSCW__
	    gSelectedConnectionId = 3; //SYM emulator: should not ask about access point
#endif

	    // Show IAP selection dialog
	    if ( gSelectedConnectionId == -1 )
	    	gSelectedConnectionId = SelectIAP();

	    iSelectedConnectionId =  gSelectedConnectionId;

    	iNewConnection = ETrue;

        // IAP Selected
        // Open socket server and start the connection
        User::LeaveIfError(iServerSocket.Connect(KESockDefaultMessageSlots));
        User::LeaveIfError(iConnection.Open(iServerSocket, KConnectionTypeDefault));
        // Now we have the iap Id. Use it to connect for the connection
        TCommDbConnPref connectPref;
		// Setup preferences
		connectPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);

		// Sets the CommDb ID of the IAP to use for this connection
        connectPref.SetIapId(iSelectedConnectionId);
        // Sets direction
        connectPref.SetDirection(ECommDbConnectionDirectionOutgoing);

        connectPref.SetBearerSet(iBearerFilter);

        // Start connection
        User::LeaveIfError(iConnection.Start(connectPref));

        //TInt retval = iConnection.Start();
        //User::LeaveIfError(retval);

        // Set the sessions connection info...
        RStringPool strPool = iSessionHttp.StringPool();
        RHTTPConnectionInfo connInfo = iSessionHttp.ConnectionInfo();
        // ...to use our socket server and connection
        connInfo.SetPropertyL(strPool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable()), THTTPHdrVal (iServerSocket.Handle()));
        // ...to use our connection
        connInfo.SetPropertyL(strPool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable()), THTTPHdrVal (REINTERPRET_CAST(TInt, &(iConnection))));

        iConnectionSetup = ETrue;

	    return ETrue;
}

TBool CConnectionManager::FindExistingConnection()
{
    TUint uiNbConnections;

    if (iConnection.EnumerateConnections(uiNbConnections) != KErrNone)
    {
        return EFalse;
    }

    TConnectionInfoBuf connInfo;

    for (TUint uiConnection = 1; uiConnection <= uiNbConnections; ++uiConnection)
    {
        // Note: GetConnectionInfo expects 1-based index.
        if (iConnection.GetConnectionInfo(uiConnection, connInfo) == KErrNone)
        {
            if (connInfo().iIapId == iSelectedConnectionId)
            {
                return ETrue;
            }
        }
    }

    return EFalse;
}

TBool CConnectionManager::GetCredentialsL(const TUriC8& /*aURI*/, RString /*aRealm*/,
		RStringF /*aAuthenticationType*/, RString& /*aUsername*/, RString& /*aPassword*/)
{

    //// Return ETrue if user has given credentials (username and password),
    //// otherwise EFlase
    return EFalse;
}
<commit_msg>fixed SYMBIAN FP2 specific issue with access point id<commit_after>/*
 ============================================================================
 Name		: ConnectionManager.cpp
 Author	  : Anton Antonov
 Version	 : 1.0
 Copyright   :   Copyright (C) 2008 Rhomobile. All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 Description : CConnectionManager implementation
 ============================================================================
 */

#include "ConnectionManager.h"
#include <centralrepository.h>
#include <ProfileEngineSDKCRKeys.h>

#include <ApEngineConsts.h>
#include <es_enum.h>
#include <activeapdb.h>
#include <apsettingshandlerui.h>
#include <badesca.h>
#include <stringloader.h>
#include <aknquerydialog.h>
#include <CommDbConnPref.h>

#include <httpstringconstants.h>

#include <stdio.h>
#include <string.h>

#include <aknlists.h>		// CAknSinglePopupMenuStyleListBox
#include <CommDb.h>

extern TUint32 gSelectedConnectionId;

namespace EConnectionStatus
	{
	TInt Disconnected = 5;
	}

class TIapData
{
public:
	TBuf<128> iName;
	TUint32 iIap;

};

CConnectionManager::CConnectionManager()
	{
	// No implementation required
	}

CConnectionManager::~CConnectionManager()
	{
	}

TInt CConnectionManager::SelectIAP()
{
	CArrayFixFlat<TIapData>* iEApList=new (ELeave) CArrayFixFlat<TIapData>(2) ;
	TInt stack=0;
	// Make listitems. and PUSH it
	CAknSinglePopupMenuStyleListBox* list = new(ELeave) CAknSinglePopupMenuStyleListBox;
	CleanupStack::PushL(list);
	stack++;

	// Create popup list and PUSH it.
	CAknPopupList* popupList = CAknPopupList::NewL(list,
		R_AVKON_SOFTKEYS_OK_CANCEL, AknPopupLayouts::EMenuWindow);
	CleanupStack::PushL(popupList);stack++;

	CDesCArrayFlat* items = new (ELeave) CDesCArrayFlat(5);
	CleanupStack::PushL(items);stack++;
	// initialize listbox.
	list->ConstructL(popupList, CEikListBox::ELeftDownInViewRect);
	list->CreateScrollBarFrameL(ETrue);
	list->ScrollBarFrame()->SetScrollBarVisibilityL(CEikScrollBarFrame::EOff,
		CEikScrollBarFrame::EAuto);

	TBuf<52> iapfromtable;
	TInt err = KErrNone;

	CCommsDatabase* iCommsDB=CCommsDatabase::NewL(EDatabaseTypeIAP);
	CleanupStack::PushL(iCommsDB);stack++;
#ifdef __SERIES60_3X__
	CCommsDbTableView* gprsTable = iCommsDB->OpenIAPTableViewMatchingBearerSetLC(
			iBearerFilter == EApBearerTypeWLAN
				? ECommDbBearerWLAN
				: ECommDbBearerGPRS|ECommDbBearerWLAN|ECommDbBearerVirtual,
		ECommDbConnectionDirectionOutgoing);
#else
	CCommsDbTableView* gprsTable = iCommsDB->OpenIAPTableViewMatchingBearerSetLC(
		ECommDbBearerGPRS|ECommDbBearerVirtual,
		ECommDbConnectionDirectionOutgoing);
#endif
	User::LeaveIfError(gprsTable->GotoFirstRecord());
	TInt i=0;
	TUint32 id;
	TIapData eap;

	TInt cur =0; //current value
	do
	{
		gprsTable->ReadTextL(TPtrC(COMMDB_NAME), iapfromtable);
		gprsTable->ReadUintL(TPtrC(COMMDB_ID), id);
		items->AppendL(iapfromtable);
		eap.iIap = id;
		eap.iName.Copy(iapfromtable);
		iEApList->AppendL(eap);

		err = gprsTable->GotoNextRecord();
		i++;
	}
	while (err == KErrNone);
	CleanupStack::PopAndDestroy(2); stack--;

	// Set listitems.
	CTextListBoxModel* model = list->Model();
	model->SetItemTextArray(items);
	model->SetOwnershipType(ELbmOwnsItemArray);
	CleanupStack::Pop();

	popupList->SetTitleL(_L("Access Point"));
	list->SetListBoxObserver(popupList);
	TInt popupOk = popupList->ExecuteLD();
	CleanupStack::Pop();
	TInt iap=0;
	if (popupOk)
	{
		TInt index = list->CurrentItemIndex();
		iap=(*iEApList)[index].iIap;

	}
	CleanupStack::PopAndDestroy();
	iEApList->Reset();
	delete iEApList;
	return iap;
}

CConnectionManager* CConnectionManager::NewLC()
	{
	CConnectionManager* self = new (ELeave)CConnectionManager();
	CleanupStack::PushL(self);
	self->ConstructL();
	return self;
	}

CConnectionManager* CConnectionManager::NewL()
	{
	CConnectionManager* self=CConnectionManager::NewLC();
	CleanupStack::Pop(); // self;
	return self;
	}

void CConnectionManager::ConstructL()
	{
		iRepository            = CRepository::NewL(KCRUidProfileEngine);
	    iPreviousProfileId     = -1;
	    iSelectedConnectionId  = 0u-1;

	    iConnectionSetup  = EFalse;
	    iNewConnection = ETrue;
	}

void CConnectionManager::Release()
	{
	    if (iRepository)
	        delete iRepository;

	    iConnection.Close();
	    iSessionHttp.Close();
	    iServerSocket.Close();
	}

TBool  CConnectionManager::IsOfflineMode()
	{
		return (iPreviousProfileId == EConnectionStatus::Disconnected) ? ETrue : EFalse;
	}

TBool CConnectionManager::SetupConnection()
	{
		TInt iCurrentProfileId;
		iBearerFilter = EApBearerTypeAllBearers;

		ASSERT(iRepository);

		// Check whether we are offline or online
		iRepository->Get(KProEngActiveProfile, iCurrentProfileId);

	    // Close the connection only if
	    // a) this is not the first time and
	    // b) the profile has changed and
	    // c) either the previous or the current profile is Offline (5 = Offline)
	    if (iPreviousProfileId != -1 && iPreviousProfileId != iCurrentProfileId &&
	            (iPreviousProfileId == EConnectionStatus::Disconnected || iCurrentProfileId == EConnectionStatus::Disconnected))
	    {
	        // Close and uninitialize
	        iConnectionSetup = EFalse;
	        iSessionHttp .Close();
	        iConnection  .Close();
	        iServerSocket.Close();
	    }

	    // Save current profile id
	    iPreviousProfileId = iCurrentProfileId;

	    // Try to find an existing connection. If connection has not been set up,
	    // iConnection is not initialized and FindExistingConnection() fails.
	    // Thus, in that case, finding must not be carried out.
	    if (iConnectionSetup && !FindExistingConnection())
	    {
	        iConnectionSetup = EFalse;
	    }

	    if (iConnectionSetup)
	    {
	        // Connection setup is done
	    	iNewConnection = EFalse;
	        return ETrue;
	    }

	    // Open RHTTPSession with default protocol ("HTTP/TCP")
	    iSessionHttp.OpenL();

	    // Install this class as the callback for authentication requests. When
	    // page requires authentication the framework calls GetCredentialsL to get
	    // user name and password.
	    InstallAuthenticationL(iSessionHttp);

	    // In offline, only WLAN connections are available
	    if (iCurrentProfileId == EConnectionStatus::Disconnected)
	    {
	        iBearerFilter = EApBearerTypeWLAN;
	    }

#ifdef __WINSCW__
//SYM emulator: should not ask about access point
#ifdef __S60_32__
	    gSelectedConnectionId = 1; //FP2
#else
	    gSelectedConnectionId = 3; //FP1
#endif

#endif

	    // Show IAP selection dialog
	    if ( gSelectedConnectionId == -1 )
	    	gSelectedConnectionId = SelectIAP();

	    iSelectedConnectionId =  gSelectedConnectionId;

    	iNewConnection = ETrue;

        // IAP Selected
        // Open socket server and start the connection
        User::LeaveIfError(iServerSocket.Connect(KESockDefaultMessageSlots));
        User::LeaveIfError(iConnection.Open(iServerSocket, KConnectionTypeDefault));
        // Now we have the iap Id. Use it to connect for the connection
        TCommDbConnPref connectPref;
		// Setup preferences
		connectPref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);

		// Sets the CommDb ID of the IAP to use for this connection
        connectPref.SetIapId(iSelectedConnectionId);
        // Sets direction
        connectPref.SetDirection(ECommDbConnectionDirectionOutgoing);

        connectPref.SetBearerSet(iBearerFilter);

        // Start connection
        User::LeaveIfError(iConnection.Start(connectPref));

        //TInt retval = iConnection.Start();
        //User::LeaveIfError(retval);

        // Set the sessions connection info...
        RStringPool strPool = iSessionHttp.StringPool();
        RHTTPConnectionInfo connInfo = iSessionHttp.ConnectionInfo();
        // ...to use our socket server and connection
        connInfo.SetPropertyL(strPool.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable()), THTTPHdrVal (iServerSocket.Handle()));
        // ...to use our connection
        connInfo.SetPropertyL(strPool.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable()), THTTPHdrVal (REINTERPRET_CAST(TInt, &(iConnection))));

        iConnectionSetup = ETrue;

	    return ETrue;
}

TBool CConnectionManager::FindExistingConnection()
{
    TUint uiNbConnections;

    if (iConnection.EnumerateConnections(uiNbConnections) != KErrNone)
    {
        return EFalse;
    }

    TConnectionInfoBuf connInfo;

    for (TUint uiConnection = 1; uiConnection <= uiNbConnections; ++uiConnection)
    {
        // Note: GetConnectionInfo expects 1-based index.
        if (iConnection.GetConnectionInfo(uiConnection, connInfo) == KErrNone)
        {
            if (connInfo().iIapId == iSelectedConnectionId)
            {
                return ETrue;
            }
        }
    }

    return EFalse;
}

TBool CConnectionManager::GetCredentialsL(const TUriC8& /*aURI*/, RString /*aRealm*/,
		RStringF /*aAuthenticationType*/, RString& /*aUsername*/, RString& /*aPassword*/)
{

    //// Return ETrue if user has given credentials (username and password),
    //// otherwise EFlase
    return EFalse;
}
<|endoftext|>


<commit_before>// Copyright (C) 2017 Rob Caelers <rob.caelers@gmail.com>
//
// 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.

#include "loopp/core/MainLoop.hpp"

#include <string>
#include <system_error>
#include <algorithm>
#include <cstring>

#include "lwip/sockets.h"
#include "lwip/sys.h"

#include "esp_log.h"

#include "loopp/net/NetworkErrors.hpp"

#include "loopp/utils/hexdump.hpp"

static const char tag[] = "MAINLOOP";

using namespace loopp;
using namespace loopp::core;

MainLoop::~MainLoop()
{
  get_thread_local().remove();
}

void
MainLoop::invoke_func(std::function<void()> func)
{
  ScopedLock l(queue_mutex);
  queue.push(func);
  trigger.signal();
}

void
MainLoop::terminate()
{
  terminate_loop = true;
  trigger.signal();
}

std::shared_ptr<MainLoop>
MainLoop::current()
{
  return get_thread_local().get();
}

ThreadLocal<std::shared_ptr<MainLoop>> &
MainLoop::get_thread_local()
{
  static ThreadLocal<std::shared_ptr<MainLoop>> local;
  return local;
}

void
MainLoop::notify_read(int fd, io_callback cb, std::chrono::milliseconds timeout_duration)
{
  notify(fd, IoType::Read, cb, timeout_duration);
}

void
MainLoop::notify_write(int fd, io_callback cb, std::chrono::milliseconds timeout_duration)
{
  notify(fd, IoType::Write, cb, timeout_duration);
}

void
MainLoop::unnotify_read(int fd)
{
  unnotify(fd, IoType::Read);
}

void
MainLoop::unnotify_write(int fd)
{
  unnotify(fd, IoType::Write);
}

void
MainLoop::unnotify(int fd)
{
  unnotify(fd, IoType::Read);
  unnotify(fd, IoType::Write);
}

void
MainLoop::cancel(int fd)
{
  cancel(fd, IoType::Read);
  cancel(fd, IoType::Write);
}

MainLoop::poll_list_type::iterator
MainLoop::find(int fd, IoType type)
{
  return std::find_if(poll_list.begin(), poll_list.end(), [fd, type](PollData pd) { return pd.fd == fd && pd.type == type; });
}

void
MainLoop::notify(int fd, IoType type, io_callback cb, std::chrono::milliseconds timeout_duration)
{
  ScopedLock l(poll_list_mutex);
  auto iter = find(fd, type);

  if (iter != poll_list.end())
    {
      iter->callback = cb;
      iter->start_time = std::chrono::system_clock::now();
      iter->timeout_duration = timeout_duration;
    }
  else
    {
      PollData pd;
      pd.fd = fd;
      pd.type = type;
      pd.cancelled = false;
      pd.callback = cb;
      pd.start_time = std::chrono::system_clock::now();
      pd.timeout_duration = timeout_duration;
      poll_list.push_back(pd);
    }
  trigger.signal();
}

void
MainLoop::unnotify(int fd, IoType type)
{
  ScopedLock l(poll_list_mutex);
  auto iter = find(fd, type);

  if (iter != poll_list.end())
    {
      poll_list.erase(iter);
      trigger.signal();
    }
}

void
MainLoop::cancel(int fd, IoType type)
{
  ScopedLock l(poll_list_mutex);
  auto iter = find(fd, type);

  if (iter != poll_list.end())
    {
      iter->cancelled = true;
      trigger.signal();
    }
}

MainLoop::timer_id
MainLoop::add_timer(std::chrono::milliseconds duration, timer_callback callback)
{
  ScopedLock l(timer_list_mutex);
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

  TimerData data;
  data.id = next_timer_id++;
  data.expire_time = now + duration;
  data.period = std::chrono::milliseconds::max();
  data.callback = callback;

  timers.push_back(data);
  trigger.signal();

  return data.id;
}

MainLoop::timer_id
MainLoop::add_periodic_timer(std::chrono::milliseconds period, timer_callback callback)
{
  ScopedLock l(timer_list_mutex);
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

  TimerData data;
  data.id = next_timer_id++;
  data.expire_time = now + period;
  data.period = period;
  data.callback = callback;

  timers.push_back(data);
  trigger.signal();

  return data.id;
}

void
MainLoop::cancel_timer(timer_id id)
{
  ScopedLock l(timer_list_mutex);
  auto iter = std::find_if(timers.begin(), timers.end(), [id](TimerData t) { return t.id = id; });
  if (iter != timers.end())
    {
      timers.erase(iter);
    }
  trigger.signal();
}

MainLoop::timer_list_type::iterator
MainLoop::get_first_expiring_timer()
{
  auto iter = std::min_element(timers.begin(), timers.end(), [](TimerData &a, TimerData &b) { return a.expire_time < b.expire_time; });

  return iter;
}

std::chrono::milliseconds
MainLoop::get_first_expiring_timer_duration()
{
  ScopedLock l(timer_list_mutex);

  auto iter = get_first_expiring_timer();
  if (iter != timers.end())
    {
      return std::chrono::duration_cast<std::chrono::milliseconds>(iter->expire_time - std::chrono::system_clock::now());
    }
  else
    {
      return std::chrono::milliseconds::max();
    }
}

int
MainLoop::do_select(poll_list_type &poll_list_copy)
{
  FD_ZERO(&read_set);
  FD_ZERO(&write_set);

  int trigger_fd = trigger.get_poll_fd();
  int max_fd = trigger_fd;
  FD_SET(trigger_fd, &read_set);

  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  std::chrono::milliseconds timeout = get_first_expiring_timer_duration();

  for (auto &pd : poll_list_copy)
    {
      max_fd = std::max(max_fd, pd.fd);

      if (pd.timeout_duration != std::chrono::milliseconds::max())
        {
          auto t = std::chrono::duration_cast<std::chrono::milliseconds>(pd.start_time - now + pd.timeout_duration);
          timeout = std::max(std::chrono::milliseconds(0), std::min(timeout, t));
        }

      if (!pd.cancelled)
        {
          switch (pd.type)
            {
              case IoType::Read:
                FD_SET(pd.fd, &read_set);
                break;
              case IoType::Write:
                FD_SET(pd.fd, &write_set);
                break;
            }
        }
    }

  int r = 0;

#if DEBUG_SELECT
  hexdump(tag, "IN r: ", reinterpret_cast<uint8_t *>(&read_set), sizeof(read_set));
  hexdump(tag, "IN w: ", reinterpret_cast<uint8_t *>(&write_set), sizeof(write_set));
#endif

  if (timeout != std::chrono::milliseconds::max())
    {
      timeval tv;
      tv.tv_sec = timeout.count() / 1000;
      tv.tv_usec = (timeout.count() % 1000) * 1000;
#if DEBUG_SELECT
      ESP_LOGD(tag, "Select timeout %d %d:", static_cast<int>(tv.tv_sec), static_cast<int>(tv.tv_usec / 1000));
#endif
      r = select(max_fd + 1, &read_set, &write_set, nullptr, &tv);
    }
  else
    {
      r = select(max_fd + 1, &read_set, &write_set, nullptr, nullptr);
    }

#if DEBUG_SELECT
  ESP_LOGD(tag, "Select ret = %d:", r);
  hexdump(tag, "OUT r: ", reinterpret_cast<uint8_t *>(&read_set), sizeof(read_set));
  hexdump(tag, "OUT w: ", reinterpret_cast<uint8_t *>(&write_set), sizeof(write_set));
#endif

  return r;
}

MainLoop::poll_list_type
MainLoop::get_poll_list() const
{
  ScopedLock l(poll_list_mutex);
  return poll_list;
}

void
MainLoop::run()
{
  get_thread_local().set(shared_from_this());

  while (true)
    {
      poll_list_type poll_list_copy = get_poll_list();

      int r = do_select(poll_list_copy);

      if (r == -1)
        {
          const char *error = strerror(errno);
          ESP_LOGE(tag, "Error during select: %s", error);
        }
      else if (r == 0)
        {
          handle_timeout(poll_list_copy);
          handle_timers();
        }
      else if (r > 0)
        {
          if (FD_ISSET(trigger.get_poll_fd(), &read_set))
            {
              handle_queue();
            }

          handle_io(poll_list_copy);
          handle_timers();
        }
    }
}

void
MainLoop::handle_timeout(poll_list_type &poll_list_copy)
{
  std::error_code ec;
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

  for (auto &pd : poll_list_copy)
    {
      if (pd.timeout_duration != std::chrono::milliseconds::max() && now > pd.start_time + pd.timeout_duration)
        {
          unnotify(pd.fd, pd.type);
          try
            {
              pd.callback(loopp::net::NetworkErrc::Timeout);
            }
          catch (const std::system_error &ex)
            {
              ESP_LOGE(tag,
                       "System error while handling timeout %d/%d %d %s",
                       pd.fd,
                       static_cast<std::underlying_type<IoType>::type>(pd.type),
                       ex.code().value(),
                       ex.what());
            }
          catch (const std::exception &ex)
            {
              ESP_LOGE(tag, "Exception while handling timeout %d/%d %s", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type), ex.what());
            }
          catch (...)
            {
              ESP_LOGE(tag, "Exception while handling timeout %d/%d", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type));
            }
        }
    }
}

void
MainLoop::handle_io(poll_list_type &poll_list_copy)
{
  std::error_code ec;
  for (auto &pd : poll_list_copy)
    {
      if ((pd.type == IoType::Read && FD_ISSET(pd.fd, &read_set)) || (pd.type == IoType::Write && FD_ISSET(pd.fd, &write_set)) || pd.cancelled)
        {
          unnotify(pd.fd, pd.type);
          try
            {
              if (pd.cancelled)
                {
                  ec = loopp::net::NetworkErrc::Cancelled;
                }
              pd.callback(ec);
            }
          catch (const std::system_error &ex)
            {
              ESP_LOGE(tag,
                       "System error while handling %d/%d %d %s",
                       pd.fd,
                       static_cast<std::underlying_type<IoType>::type>(pd.type),
                       ex.code().value(),
                       ex.what());
            }
          catch (const std::exception &ex)
            {
              ESP_LOGE(tag, "Exception while handling %d/%d %s", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type), ex.what());
            }
          catch (...)
            {
              ESP_LOGE(tag, "Exception while handling %d/%d", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type));
            }
        }
    }
}

void
MainLoop::handle_timers()
{
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  timer_list_type notify_list;

  timer_list_mutex.lock();
  auto first = get_first_expiring_timer();
  while (first != timers.end() && now >= first->expire_time)
    {
      notify_list.push_back(*first);
      if (first->period != std::chrono::milliseconds::max())
        {
          first->expire_time += first->period;
        }
      else
        {
          timers.erase(first);
        }
      first = get_first_expiring_timer();
    }
  timer_list_mutex.unlock();

  for (auto t : notify_list)
    {
      t.callback();
    }
}

void
MainLoop::handle_queue()
{
  int size = 0;

  {
    ScopedLock l(queue_mutex);
    size = queue.size();
    trigger.confirm();
  }

  for (int i = 0; i < size; i++)
    {
      nonstd::optional<deferred_func> obj(queue.pop_for(std::chrono::milliseconds(0)));
      if (obj)
        {
          deferred_func func = *obj;
          try
            {
              func();
            }
          catch (const std::system_error &ex)
            {
              ESP_LOGE(tag, "System error while handling invoked function%d %s", ex.code().value(), ex.what());
            }
          catch (const std::exception &ex)
            {
              ESP_LOGE(tag, "Exception while handling invoked function: %s", ex.what());
            }
          catch (...)
            {
              ESP_LOGE(tag, "Exception while handling invoked function");
            }
        }
    }
}
<commit_msg>Fix timer cancel bug<commit_after>// Copyright (C) 2017 Rob Caelers <rob.caelers@gmail.com>
//
// 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.

#include "loopp/core/MainLoop.hpp"

#include <string>
#include <system_error>
#include <algorithm>
#include <cstring>

#include "lwip/sockets.h"
#include "lwip/sys.h"

#include "esp_log.h"

#include "loopp/net/NetworkErrors.hpp"

#include "loopp/utils/hexdump.hpp"

static const char tag[] = "MAINLOOP";

using namespace loopp;
using namespace loopp::core;

MainLoop::~MainLoop()
{
  get_thread_local().remove();
}

void
MainLoop::invoke_func(std::function<void()> func)
{
  ScopedLock l(queue_mutex);
  queue.push(func);
  trigger.signal();
}

void
MainLoop::terminate()
{
  terminate_loop = true;
  trigger.signal();
}

std::shared_ptr<MainLoop>
MainLoop::current()
{
  return get_thread_local().get();
}

ThreadLocal<std::shared_ptr<MainLoop>> &
MainLoop::get_thread_local()
{
  static ThreadLocal<std::shared_ptr<MainLoop>> local;
  return local;
}

void
MainLoop::notify_read(int fd, io_callback cb, std::chrono::milliseconds timeout_duration)
{
  notify(fd, IoType::Read, cb, timeout_duration);
}

void
MainLoop::notify_write(int fd, io_callback cb, std::chrono::milliseconds timeout_duration)
{
  notify(fd, IoType::Write, cb, timeout_duration);
}

void
MainLoop::unnotify_read(int fd)
{
  unnotify(fd, IoType::Read);
}

void
MainLoop::unnotify_write(int fd)
{
  unnotify(fd, IoType::Write);
}

void
MainLoop::unnotify(int fd)
{
  unnotify(fd, IoType::Read);
  unnotify(fd, IoType::Write);
}

void
MainLoop::cancel(int fd)
{
  cancel(fd, IoType::Read);
  cancel(fd, IoType::Write);
}

MainLoop::poll_list_type::iterator
MainLoop::find(int fd, IoType type)
{
  return std::find_if(poll_list.begin(), poll_list.end(), [fd, type](PollData pd) { return pd.fd == fd && pd.type == type; });
}

void
MainLoop::notify(int fd, IoType type, io_callback cb, std::chrono::milliseconds timeout_duration)
{
  ScopedLock l(poll_list_mutex);
  auto iter = find(fd, type);

  if (iter != poll_list.end())
    {
      iter->callback = cb;
      iter->start_time = std::chrono::system_clock::now();
      iter->timeout_duration = timeout_duration;
    }
  else
    {
      PollData pd;
      pd.fd = fd;
      pd.type = type;
      pd.cancelled = false;
      pd.callback = cb;
      pd.start_time = std::chrono::system_clock::now();
      pd.timeout_duration = timeout_duration;
      poll_list.push_back(pd);
    }
  trigger.signal();
}

void
MainLoop::unnotify(int fd, IoType type)
{
  ScopedLock l(poll_list_mutex);
  auto iter = find(fd, type);

  if (iter != poll_list.end())
    {
      poll_list.erase(iter);
      trigger.signal();
    }
}

void
MainLoop::cancel(int fd, IoType type)
{
  ScopedLock l(poll_list_mutex);
  auto iter = find(fd, type);

  if (iter != poll_list.end())
    {
      iter->cancelled = true;
      trigger.signal();
    }
}

MainLoop::timer_id
MainLoop::add_timer(std::chrono::milliseconds duration, timer_callback callback)
{
  ScopedLock l(timer_list_mutex);
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

  TimerData data;
  data.id = next_timer_id++;
  data.expire_time = now + duration;
  data.period = std::chrono::milliseconds::max();
  data.callback = callback;

  timers.push_back(data);
  trigger.signal();

  return data.id;
}

MainLoop::timer_id
MainLoop::add_periodic_timer(std::chrono::milliseconds period, timer_callback callback)
{
  ScopedLock l(timer_list_mutex);
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

  TimerData data;
  data.id = next_timer_id++;
  data.expire_time = now + period;
  data.period = period;
  data.callback = callback;

  timers.push_back(data);
  trigger.signal();

  return data.id;
}

void
MainLoop::cancel_timer(timer_id id)
{
  ScopedLock l(timer_list_mutex);
  auto iter = std::find_if(timers.begin(), timers.end(), [id](const TimerData &t) { return t.id == id; });
  if (iter != timers.end())
    {
      timers.erase(iter);
    }
  trigger.signal();
}

MainLoop::timer_list_type::iterator
MainLoop::get_first_expiring_timer()
{
  auto iter = std::min_element(timers.begin(), timers.end(), [](TimerData &a, TimerData &b) { return a.expire_time < b.expire_time; });

  return iter;
}

std::chrono::milliseconds
MainLoop::get_first_expiring_timer_duration()
{
  ScopedLock l(timer_list_mutex);

  auto iter = get_first_expiring_timer();
  if (iter != timers.end())
    {
      return std::chrono::duration_cast<std::chrono::milliseconds>(iter->expire_time - std::chrono::system_clock::now());
    }
  else
    {
      return std::chrono::milliseconds::max();
    }
}

int
MainLoop::do_select(poll_list_type &poll_list_copy)
{
  FD_ZERO(&read_set);
  FD_ZERO(&write_set);

  int trigger_fd = trigger.get_poll_fd();
  int max_fd = trigger_fd;
  FD_SET(trigger_fd, &read_set);

  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  std::chrono::milliseconds timeout = get_first_expiring_timer_duration();

  for (auto &pd : poll_list_copy)
    {
      max_fd = std::max(max_fd, pd.fd);

      if (pd.timeout_duration != std::chrono::milliseconds::max())
        {
          auto t = std::chrono::duration_cast<std::chrono::milliseconds>(pd.start_time - now + pd.timeout_duration);
          timeout = std::max(std::chrono::milliseconds(0), std::min(timeout, t));
        }

      if (!pd.cancelled)
        {
          switch (pd.type)
            {
              case IoType::Read:
                FD_SET(pd.fd, &read_set);
                break;
              case IoType::Write:
                FD_SET(pd.fd, &write_set);
                break;
            }
        }
    }

  int r = 0;

#if DEBUG_SELECT
  hexdump(tag, "IN r: ", reinterpret_cast<uint8_t *>(&read_set), sizeof(read_set));
  hexdump(tag, "IN w: ", reinterpret_cast<uint8_t *>(&write_set), sizeof(write_set));
#endif

  if (timeout != std::chrono::milliseconds::max())
    {
      timeval tv;
      tv.tv_sec = timeout.count() / 1000;
      tv.tv_usec = (timeout.count() % 1000) * 1000;
#if DEBUG_SELECT
      ESP_LOGD(tag, "Select timeout %d %d:", static_cast<int>(tv.tv_sec), static_cast<int>(tv.tv_usec / 1000));
#endif
      r = select(max_fd + 1, &read_set, &write_set, nullptr, &tv);
    }
  else
    {
      r = select(max_fd + 1, &read_set, &write_set, nullptr, nullptr);
    }

#if DEBUG_SELECT
  ESP_LOGD(tag, "Select ret = %d:", r);
  hexdump(tag, "OUT r: ", reinterpret_cast<uint8_t *>(&read_set), sizeof(read_set));
  hexdump(tag, "OUT w: ", reinterpret_cast<uint8_t *>(&write_set), sizeof(write_set));
#endif

  return r;
}

MainLoop::poll_list_type
MainLoop::get_poll_list() const
{
  ScopedLock l(poll_list_mutex);
  return poll_list;
}

void
MainLoop::run()
{
  get_thread_local().set(shared_from_this());

  while (true)
    {
      poll_list_type poll_list_copy = get_poll_list();

      int r = do_select(poll_list_copy);

      if (r == -1)
        {
          const char *error = strerror(errno);
          ESP_LOGE(tag, "Error during select: %s", error);
        }
      else if (r == 0)
        {
          handle_timeout(poll_list_copy);
          handle_timers();
        }
      else if (r > 0)
        {
          if (FD_ISSET(trigger.get_poll_fd(), &read_set))
            {
              handle_queue();
            }

          handle_io(poll_list_copy);
          handle_timers();
        }
    }
}

void
MainLoop::handle_timeout(poll_list_type &poll_list_copy)
{
  std::error_code ec;
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();

  for (auto &pd : poll_list_copy)
    {
      if (pd.timeout_duration != std::chrono::milliseconds::max() && now > pd.start_time + pd.timeout_duration)
        {
          unnotify(pd.fd, pd.type);
          try
            {
              pd.callback(loopp::net::NetworkErrc::Timeout);
            }
          catch (const std::system_error &ex)
            {
              ESP_LOGE(tag,
                       "System error while handling timeout %d/%d %d %s",
                       pd.fd,
                       static_cast<std::underlying_type<IoType>::type>(pd.type),
                       ex.code().value(),
                       ex.what());
            }
          catch (const std::exception &ex)
            {
              ESP_LOGE(tag, "Exception while handling timeout %d/%d %s", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type), ex.what());
            }
          catch (...)
            {
              ESP_LOGE(tag, "Exception while handling timeout %d/%d", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type));
            }
        }
    }
}

void
MainLoop::handle_io(poll_list_type &poll_list_copy)
{
  std::error_code ec;
  for (auto &pd : poll_list_copy)
    {
      if ((pd.type == IoType::Read && FD_ISSET(pd.fd, &read_set)) || (pd.type == IoType::Write && FD_ISSET(pd.fd, &write_set)) || pd.cancelled)
        {
          unnotify(pd.fd, pd.type);
          try
            {
              if (pd.cancelled)
                {
                  ec = loopp::net::NetworkErrc::Cancelled;
                }
              pd.callback(ec);
            }
          catch (const std::system_error &ex)
            {
              ESP_LOGE(tag,
                       "System error while handling %d/%d %d %s",
                       pd.fd,
                       static_cast<std::underlying_type<IoType>::type>(pd.type),
                       ex.code().value(),
                       ex.what());
            }
          catch (const std::exception &ex)
            {
              ESP_LOGE(tag, "Exception while handling %d/%d %s", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type), ex.what());
            }
          catch (...)
            {
              ESP_LOGE(tag, "Exception while handling %d/%d", pd.fd, static_cast<std::underlying_type<IoType>::type>(pd.type));
            }
        }
    }
}

void
MainLoop::handle_timers()
{
  std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
  timer_list_type notify_list;

  timer_list_mutex.lock();
  auto first = get_first_expiring_timer();
  while (first != timers.end() && now >= first->expire_time)
    {
      notify_list.push_back(*first);
      if (first->period != std::chrono::milliseconds::max())
        {
          first->expire_time += first->period;
        }
      else
        {
          timers.erase(first);
        }
      first = get_first_expiring_timer();
    }
  timer_list_mutex.unlock();

  for (auto t : notify_list)
    {
      t.callback();
    }
}

void
MainLoop::handle_queue()
{
  int size = 0;

  {
    ScopedLock l(queue_mutex);
    size = queue.size();
    trigger.confirm();
  }

  for (int i = 0; i < size; i++)
    {
      nonstd::optional<deferred_func> obj(queue.pop_for(std::chrono::milliseconds(0)));
      if (obj)
        {
          deferred_func func = *obj;
          try
            {
              func();
            }
          catch (const std::system_error &ex)
            {
              ESP_LOGE(tag, "System error while handling invoked function%d %s", ex.code().value(), ex.what());
            }
          catch (const std::exception &ex)
            {
              ESP_LOGE(tag, "Exception while handling invoked function: %s", ex.what());
            }
          catch (...)
            {
              ESP_LOGE(tag, "Exception while handling invoked function");
            }
        }
    }
}
<|endoftext|>


<commit_before>//===-- debug.cpp ---------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Debug logging implementation.
//
//===----------------------------------------------------------------------===//

#include "debug.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>

static int mypid = 0;
static FILE *logfp = NULL;

FILE *getlogfp() {

  int newmypid = getpid();
  if (mypid == newmypid) {
    return logfp;
  }

#if 0
  // Simply log to stderr unless it's not a tty
  if (isatty(2)) {
    assert(fileno(stderr) == 2);
    return stderr;
  }
#endif

  // TODO: Definitely not thread-safe O:)

  if (logfp) {
    fclose(logfp);
    logfp = NULL;
  }

  const char *pid_template = "/tmp/ipcd.%d.log";
  char buf[100];

  sprintf(buf, pid_template, newmypid);

  logfp = fopen(buf, "w");
  assert(logfp);

  mypid = newmypid;

  return logfp;
}

extern "C" void __assert_fail(const char *assertion, const char *file,
                              unsigned int line, const char *function) {
  ipclog("Assertion '%s' failed at %s:%d in %s\n", assertion, file, line,
         function);
  abort();
}
<commit_msg>libipc: If unable to open log, attempt to log error and abort.<commit_after>//===-- debug.cpp ---------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Debug logging implementation.
//
//===----------------------------------------------------------------------===//

#include "debug.h"

#include <assert.h>
#include <stdlib.h>
#include <unistd.h>

static int mypid = 0;
static FILE *logfp = NULL;

FILE *getlogfp() {

  int newmypid = getpid();
  if (mypid == newmypid) {
    return logfp;
  }

#if 0
  // Simply log to stderr unless it's not a tty
  if (isatty(2)) {
    assert(fileno(stderr) == 2);
    return stderr;
  }
#endif

  // TODO: Definitely not thread-safe O:)

  if (logfp) {
    fclose(logfp);
    logfp = NULL;
  }

  const char *pid_template = "/tmp/ipcd.%d.log";
  char buf[100];

  sprintf(buf, pid_template, newmypid);

  logfp = fopen(buf, "w");

  // If unable to open log, attempt to print to stderr and bail
  if (!logfp) {
    fprintf(stderr, "Error opening log file!");
    abort();
  }

  mypid = newmypid;

  return logfp;
}

extern "C" void __assert_fail(const char *assertion, const char *file,
                              unsigned int line, const char *function) {
  ipclog("Assertion '%s' failed at %s:%d in %s\n", assertion, file, line,
         function);
  abort();
}
<|endoftext|>