<commit_before>////////////////////////////////////////////////////////////////////////////////
//
//  File: ProcessVorticity.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  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.
//
//  Description: Computes Q Criterion field.
//
////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <iostream>
using namespace std;

#include "ProcessQCriterion.h"

#include <LibUtilities/BasicUtils/SharedArray.hpp>
#include <LibUtilities/BasicUtils/ParseUtils.hpp>

namespace Nektar
{
    namespace Utilities
    {
        ModuleKey ProcessQCriterion::className =
		GetModuleFactory().RegisterCreatorFunction(
												   ModuleKey(eProcessModule, "QCriterion"),
												   ProcessQCriterion::create, "Computes Q Criterion (but now it's actually just a test).");

        ProcessQCriterion::ProcessQCriterion(FieldSharedPtr f) : ProcessModule(f)
        {
        }

        ProcessQCriterion::~ProcessQCriterion()
        {
        }

        void ProcessQCriterion::Process(po::variables_map &vm)
        {
            if (m_f->m_verbose)
            {
                cout << "ProcessQCriterion: Calculating Q Criterion..." << endl;
            }

            int i, j;
            int expdim    = m_f->m_graph->GetMeshDimension();
            int spacedim  = expdim;
            if ((m_f->m_fielddef[0]->m_numHomogeneousDir) == 1 ||
                (m_f->m_fielddef[0]->m_numHomogeneousDir) == 2)
            {
                spacedim = 3;
            }
            int nfields = m_f->m_fielddef[0]->m_fields.size();
            if (spacedim == 1 || spacedim == 2)
            {
                ASSERTL0(false, "Error: ProcessQCriterion must be computed for a 3D (or quasi-3D) case.")
            }
            //int addfields = (spacedim == 2)? 1:3;
			int addfields = 1; //For calculating Q-Criterion only 1 field must be added

            int npoints = m_f->m_exp[0]->GetNpoints();

            //Array<OneD, Array<OneD, NekDouble> > grad(nfields*nfields);
            //Array<OneD, Array<OneD, NekDouble> > outfield(addfields);

			Array<OneD, Array<OneD, NekDouble> > grad(nfields * nfields);

			Array<OneD, Array<OneD, NekDouble> > omega(nfields * nfields);
			Array<OneD, Array<OneD, NekDouble> > S    (nfields * nfields);

			Array<OneD, Array<OneD, NekDouble> > outfield (addfields);
			Array<OneD, Array<OneD, NekDouble> > outfield1(addfields);
			Array<OneD, Array<OneD, NekDouble> > outfield2(addfields);
			Array<OneD, Array<OneD, NekDouble> > outfield3(addfields);

            m_f->m_exp.resize(nfields+addfields);

            for (i = 0; i < nfields*nfields; ++i)
            {
                grad[i] = Array<OneD, NekDouble>(npoints);
            }

            for (i = 0; i < addfields; ++i)
            {
                outfield[i] = Array<OneD, NekDouble>(npoints); //Will store the Q-Criterion
				outfield1[i] = Array<OneD, NekDouble>(npoints);
				outfield2[i] = Array<OneD, NekDouble>(npoints);
				outfield3[i] = Array<OneD, NekDouble>(npoints);

				omega[i] = Array<OneD, NekDouble>(npoints);
				S[i] = Array<OneD, NekDouble>(npoints);
            }

            // Calculate Gradient & Vorticity
			//            if (spacedim == 2)
			//            {
			//                cerr << "Q-Criterion calculation needs a 3D mesh." << endl;
			//            }
			for (i = 0; i < nfields; ++i)
			{

				m_f->m_exp[i]->PhysDeriv(m_f->m_exp[i]->GetPhys(),
										 grad[i*nfields],
										 grad[i*nfields+1],
										 grad[i*nfields+2]);
			}

			// W_x = Wy - Vz
			//Vmath::Vsub(npoints, grad[2*nfields+1], 1, grad[1*nfields+2], 1,
			//            outfield[0],1);
			// W_y = Uz - Wx
			//Vmath::Vsub(npoints, grad[0*nfields+2], 1, grad[2*nfields+0], 1,
			//            outfield[1], 1);
			// W_z = Vx - Uy
			//Vmath::Vsub(npoints, grad[1*nfields+0], 1, grad[0*nfields+1], 1,
			//            outfield[2], 1);

			//=================================================================
			//=================================================================
			//=================================================================

			// W_x = Wy - Vz
			Vmath::Vsub(npoints, grad[2 * nfields + 1], 1, grad[1 * nfields + 2], 1,
						outfield1[0], 1);
			// W_x^2
			Vmath::Vmul(npoints, outfield1[0], 1, outfield1[0], 1, outfield1[0], 1);

			// W_y = Uz - Wx
			Vmath::Vsub(npoints, grad[0 * nfields + 2], 1, grad[2 * nfields + 0], 1,
						outfield2[0], 1);
			// W_y^2
			Vmath::Vmul(npoints, outfield2[0], 1, outfield2[0], 1, outfield2[0], 1);

			// W_z = Vx - Uy
			Vmath::Vsub(npoints, grad[1 * nfields + 0], 1, grad[0 * nfields + 1], 1,
						outfield3[0], 1);
			// W_z^2
			Vmath::Vmul(npoints, outfield3[0], 1, outfield3[0], 1, outfield3[0], 1);

			// add fields omega = 0.5*(W_x^2 + W_y^2 + W_z^2)

			NekDouble fac = 0.5;
			Vmath::Vadd(npoints, &outfield1[0][0], 1, &outfield2[0][0], 1, &omega[0][0], 1);
			Vmath::Vadd(npoints, &omega[0][0], 1, &outfield3[0][0], 1, &omega[0][0], 1);

			for (int k = 0; k < addfields; ++k)
			{
				Vmath::Smul(npoints, fac, &omega[k][0], 1, &omega[k][0], 1);
			}

			Vmath::Zero(npoints, &outfield1[0][0], 1);
			Vmath::Zero(npoints, &outfield2[0][0], 1);
			Vmath::Zero(npoints, &outfield3[0][0], 1);

			Vmath::Vmul(npoints, grad[0 * nfields + 0], 1, grad[0 * nfields + 0], 1,
						outfield1[0], 1);
			Vmath::Vmul(npoints, grad[1 * nfields + 1], 1, grad[1 * nfields + 1], 1,
						outfield2[0], 1);
			Vmath::Vmul(npoints, grad[2 * nfields + 2], 1, grad[2 * nfields + 2], 1,
						outfield3[0], 1);

			Vmath::Vadd(npoints, &outfield1[0][0], 1, &outfield2[0][0], 1, &S[0][0], 1);
			Vmath::Vadd(npoints, &S[0][0], 1, &outfield3[0][0], 1, &S[0][0], 1);

			// W_y + V_z
			Vmath::Vadd(npoints, grad[2 * nfields + 1], 1, grad[1 * nfields + 2], 1,
						outfield1[0], 1);
			Vmath::Vmul(npoints, &outfield1[0][0], 1, &outfield1[0][0], 1,
						&outfield1[0][0], 1);

			// U_z + W_x
			Vmath::Vadd(npoints, grad[0 * nfields + 2], 1, grad[2 * nfields + 0], 1,
						outfield2[0], 1);
			Vmath::Vmul(npoints, &outfield2[0][0], 1, &outfield2[0][0], 1,
						&outfield2[0][0], 1);

			// V_x + U_y
			Vmath::Vadd(npoints, grad[1 * nfields + 0], 1, grad[0 * nfields + 1], 1,
						outfield3[0], 1);
			Vmath::Vmul(npoints, &outfield3[0][0], 1, &outfield3[0][0], 1,
						&outfield3[0][0], 1);

			Vmath::Vadd(npoints, &outfield1[0][0], 1, &outfield2[0][0], 1,
						&outfield2[0][0], 1);
			Vmath::Vadd(npoints, &outfield2[0][0], 1, &outfield3[0][0], 1,
						&outfield3[0][0], 1);

			for (int k = 0; k < addfields; ++k)
			{
				Vmath::Smul(npoints, fac, &outfield3[k][0], 1, &outfield3[k][0], 1);
			}

			Vmath::Vadd(npoints, &outfield3[0][0], 1, &S[0][0], 1, &S[0][0], 1);
			Vmath::Vsub(npoints, omega[0], 1, S[0], 1, outfield[0], 1);

			for (int k = 0; k < addfields; ++k)
			{
				Vmath::Smul(npoints, fac, &outfield[k][0], 1, &outfield[k][0], 1);
			}

			//=================================================================
			//=================================================================
			//=================================================================

            for (i = 0; i < addfields; ++i)
            {
                m_f->m_exp[nfields + i] = m_f->AppendExpList();
                m_f->m_exp[nfields + i]->UpdatePhys() = outfield[i];
                m_f->m_exp[nfields + i]->FwdTrans(outfield[i],
												  m_f->m_exp[nfields + i]->UpdateCoeffs());
            }

			//            vector<string > outname;
			//            if (addfields == 1)
			//            {
			//                outname.push_back("W_z");
			//            }
			//            else
			//            {
			//                outname.push_back("Q_x");
			//                outname.push_back("Q_y");
			//                outname.push_back("Q_z");
			//            }

			vector<string> outname;
			outname.push_back("Q");

            std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef
			= m_f->m_exp[0]->GetFieldDefinitions();
            std::vector<std::vector<NekDouble> > FieldData(FieldDef.size());

            for (j = 0; j < nfields + addfields; ++j)
            {
                for (i = 0; i < FieldDef.size(); ++i)
                {
                    if (j >= nfields)
                    {
                        FieldDef[i]->m_fields.push_back(outname[j-nfields]);
                    }
                    else
                    {
                        FieldDef[i]->m_fields.push_back(m_f->m_fielddef[0]->m_fields[j]);
                    }
                    m_f->m_exp[j]->AppendFieldData(FieldDef[i], FieldData[i]);
                }
            }

            m_f->m_fielddef = FieldDef;
            m_f->m_data     = FieldData;

        }
    }
}
<commit_msg>Code cleaned up<commit_after>////////////////////////////////////////////////////////////////////////////////
//
//  File: ProcessVorticity.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  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.
//
//  Description: Computes Q Criterion field.
//
////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <iostream>
using namespace std;

#include "ProcessQCriterion.h"

#include <LibUtilities/BasicUtils/SharedArray.hpp>
#include <LibUtilities/BasicUtils/ParseUtils.hpp>

namespace Nektar
{
    namespace Utilities
    {
        ModuleKey ProcessQCriterion::className =
		GetModuleFactory().RegisterCreatorFunction(
												   ModuleKey(eProcessModule, "QCriterion"),
												   ProcessQCriterion::create, "Computes Q-Criterion.");

        ProcessQCriterion::ProcessQCriterion(FieldSharedPtr f) : ProcessModule(f)
        {
        }

        ProcessQCriterion::~ProcessQCriterion()
        {
        }

        void ProcessQCriterion::Process(po::variables_map &vm)
        {
            if (m_f->m_verbose)
            {
                cout << "ProcessQCriterion: Calculating Q Criterion..." << endl;
            }

            int i, j;
            int expdim    = m_f->m_graph->GetMeshDimension();
            int spacedim  = expdim;
            if ((m_f->m_fielddef[0]->m_numHomogeneousDir) == 1 ||
                (m_f->m_fielddef[0]->m_numHomogeneousDir) == 2)
            {
                spacedim = 3;
            }
            int nfields = m_f->m_fielddef[0]->m_fields.size();
            if (spacedim == 1 || spacedim == 2)
            {
				cerr << "\n Error: ProcessQCriterion must be computed for a 3D (or quasi-3D) case. \n" << endl;
            }
			int addfields = 1; //For calculating Q-Criterion only 1 field must be added

            int npoints = m_f->m_exp[0]->GetNpoints();

			Array<OneD, Array<OneD, NekDouble> > grad(nfields * nfields);

			Array<OneD, Array<OneD, NekDouble> > omega(nfields * nfields);
			Array<OneD, Array<OneD, NekDouble> > S    (nfields * nfields);

			Array<OneD, Array<OneD, NekDouble> > outfield (addfields);
			Array<OneD, Array<OneD, NekDouble> > outfield1(addfields);
			Array<OneD, Array<OneD, NekDouble> > outfield2(addfields);
			Array<OneD, Array<OneD, NekDouble> > outfield3(addfields);

            m_f->m_exp.resize(nfields+addfields);

            for (i = 0; i < nfields*nfields; ++i)
            {
                grad[i] = Array<OneD, NekDouble>(npoints);
            }

            for (i = 0; i < addfields; ++i)
            {
                outfield[i] = Array<OneD, NekDouble>(npoints); //Will store the Q-Criterion
				outfield1[i] = Array<OneD, NekDouble>(npoints);
				outfield2[i] = Array<OneD, NekDouble>(npoints);
				outfield3[i] = Array<OneD, NekDouble>(npoints);

				omega[i] = Array<OneD, NekDouble>(npoints);
				S[i] = Array<OneD, NekDouble>(npoints);
            }

			for (i = 0; i < nfields; ++i)
			{

				m_f->m_exp[i]->PhysDeriv(m_f->m_exp[i]->GetPhys(),
										 grad[i*nfields],
										 grad[i*nfields+1],
										 grad[i*nfields+2]);
			}

			// W_x = Wy - Vz
			Vmath::Vsub(npoints, grad[2 * nfields + 1], 1, grad[1 * nfields + 2], 1,
						outfield1[0], 1);
			// W_x^2
			Vmath::Vmul(npoints, outfield1[0], 1, outfield1[0], 1, outfield1[0], 1);

			// W_y = Uz - Wx
			Vmath::Vsub(npoints, grad[0 * nfields + 2], 1, grad[2 * nfields + 0], 1,
						outfield2[0], 1);
			// W_y^2
			Vmath::Vmul(npoints, outfield2[0], 1, outfield2[0], 1, outfield2[0], 1);

			// W_z = Vx - Uy
			Vmath::Vsub(npoints, grad[1 * nfields + 0], 1, grad[0 * nfields + 1], 1,
						outfield3[0], 1);
			// W_z^2
			Vmath::Vmul(npoints, outfield3[0], 1, outfield3[0], 1, outfield3[0], 1);

			// add fields omega = 0.5*(W_x^2 + W_y^2 + W_z^2)

			NekDouble fac = 0.5;
			Vmath::Vadd(npoints, &outfield1[0][0], 1, &outfield2[0][0], 1, &omega[0][0], 1);
			Vmath::Vadd(npoints, &omega[0][0], 1, &outfield3[0][0], 1, &omega[0][0], 1);

			for (int k = 0; k < addfields; ++k)
			{
				Vmath::Smul(npoints, fac, &omega[k][0], 1, &omega[k][0], 1);
			}

			Vmath::Zero(npoints, &outfield1[0][0], 1);
			Vmath::Zero(npoints, &outfield2[0][0], 1);
			Vmath::Zero(npoints, &outfield3[0][0], 1);

			Vmath::Vmul(npoints, grad[0 * nfields + 0], 1, grad[0 * nfields + 0], 1,
						outfield1[0], 1);
			Vmath::Vmul(npoints, grad[1 * nfields + 1], 1, grad[1 * nfields + 1], 1,
						outfield2[0], 1);
			Vmath::Vmul(npoints, grad[2 * nfields + 2], 1, grad[2 * nfields + 2], 1,
						outfield3[0], 1);

			Vmath::Vadd(npoints, &outfield1[0][0], 1, &outfield2[0][0], 1, &S[0][0], 1);
			Vmath::Vadd(npoints, &S[0][0], 1, &outfield3[0][0], 1, &S[0][0], 1);

			// W_y + V_z
			Vmath::Vadd(npoints, grad[2 * nfields + 1], 1, grad[1 * nfields + 2], 1,
						outfield1[0], 1);
			Vmath::Vmul(npoints, &outfield1[0][0], 1, &outfield1[0][0], 1,
						&outfield1[0][0], 1);

			// U_z + W_x
			Vmath::Vadd(npoints, grad[0 * nfields + 2], 1, grad[2 * nfields + 0], 1,
						outfield2[0], 1);
			Vmath::Vmul(npoints, &outfield2[0][0], 1, &outfield2[0][0], 1,
						&outfield2[0][0], 1);

			// V_x + U_y
			Vmath::Vadd(npoints, grad[1 * nfields + 0], 1, grad[0 * nfields + 1], 1,
						outfield3[0], 1);
			Vmath::Vmul(npoints, &outfield3[0][0], 1, &outfield3[0][0], 1,
						&outfield3[0][0], 1);

			Vmath::Vadd(npoints, &outfield1[0][0], 1, &outfield2[0][0], 1,
						&outfield2[0][0], 1);
			Vmath::Vadd(npoints, &outfield2[0][0], 1, &outfield3[0][0], 1,
						&outfield3[0][0], 1);

			for (int k = 0; k < addfields; ++k)
			{
				Vmath::Smul(npoints, fac, &outfield3[k][0], 1, &outfield3[k][0], 1);
			}

			Vmath::Vadd(npoints, &outfield3[0][0], 1, &S[0][0], 1, &S[0][0], 1);
			Vmath::Vsub(npoints, omega[0], 1, S[0], 1, outfield[0], 1);

			for (int k = 0; k < addfields; ++k)
			{
				Vmath::Smul(npoints, fac, &outfield[k][0], 1, &outfield[k][0], 1);
			}

            for (i = 0; i < addfields; ++i)
            {
                m_f->m_exp[nfields + i] = m_f->AppendExpList();
                m_f->m_exp[nfields + i]->UpdatePhys() = outfield[i];
                m_f->m_exp[nfields + i]->FwdTrans(outfield[i],
												  m_f->m_exp[nfields + i]->UpdateCoeffs());
            }

			vector<string> outname;
			outname.push_back("Q");

            std::vector<LibUtilities::FieldDefinitionsSharedPtr> FieldDef
			= m_f->m_exp[0]->GetFieldDefinitions();
            std::vector<std::vector<NekDouble> > FieldData(FieldDef.size());

            for (j = 0; j < nfields + addfields; ++j)
            {
                for (i = 0; i < FieldDef.size(); ++i)
                {
                    if (j >= nfields)
                    {
                        FieldDef[i]->m_fields.push_back(outname[j-nfields]);
                    }
                    else
                    {
                        FieldDef[i]->m_fields.push_back(m_f->m_fielddef[0]->m_fields[j]);
                    }
                    m_f->m_exp[j]->AppendFieldData(FieldDef[i], FieldData[i]);
                }
            }

            m_f->m_fielddef = FieldDef;
            m_f->m_data     = FieldData;

        }
    }
}
<|endoftext|>


<commit_before>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/platform/rocm_rocdl_path.h"

#include <stdlib.h>

#include "tensorflow/core/platform/path.h"

#if !defined(PLATFORM_GOOGLE) && TENSORFLOW_USE_ROCM
#include "rocm/rocm_config.h"
#endif
#include "tensorflow/core/platform/logging.h"

namespace tensorflow {

string RocmRoot() {
#if TENSORFLOW_USE_ROCM
  VLOG(3) << "ROCM root = " << TF_ROCM_TOOLKIT_PATH;
  return TF_ROCM_TOOLKIT_PATH;
#else
  return "";
#endif
}

string RocdlRoot() {
  return tensorflow::io::JoinPath(tensorflow::RocmRoot(), "hcc/lib");
}

}  // namespace tensorflow
<commit_msg>Prepping for switch to ROCm 3.5+<commit_after>/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/platform/rocm_rocdl_path.h"

#include <stdlib.h>

#include "tensorflow/core/platform/path.h"

#if !defined(PLATFORM_GOOGLE) && TENSORFLOW_USE_ROCM
#include "rocm/rocm_config.h"
#endif
#include "tensorflow/core/platform/logging.h"

namespace tensorflow {

string RocmRoot() {
#if TENSORFLOW_USE_ROCM
  VLOG(3) << "ROCM root = " << TF_ROCM_TOOLKIT_PATH;
  return TF_ROCM_TOOLKIT_PATH;
#else
  return "";
#endif
}

string RocdlRoot() {
#if TENSORFLOW_COMPILER_IS_HIP_CLANG
  return tensorflow::io::JoinPath(tensorflow::RocmRoot(), "lib");
#else
  return tensorflow::io::JoinPath(tensorflow::RocmRoot(), "hcc/lib");
#endif
}

}  // namespace tensorflow
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file  test_async_file_logger.cpp
//----------------------------------------------------------------------------
/// \brief This is a test file for validating async_file_logger functionality.
//----------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2012-03-21
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of utxx open-source project.

Copyright (C) 2009 Serge Aleynikov <saleyn@gmail.com>

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

***** END LICENSE BLOCK *****
*/

#include <fstream>
#include <iomanip>
#include <unistd.h>

//#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <utxx/logger/async_file_logger.hpp>
#include <utxx/perf_histogram.hpp>
#include <utxx/verbosity.hpp>

const char* s_filename = "/tmp/test_async_file_logger.log";
const char* s_str1     = "This is a const char* string line:%d\n";
const char* s_str2     = "This is an stl std::string line:";
const char* s_str3     = "This is another const char* string without line\n";

static const int32_t ITERATIONS =
    getenv("ITERATIONS") ? atoi(getenv("ITERATIONS")) : 100000u;

using namespace boost::unit_test;
using namespace utxx;

struct T {
    void on_error(int, const char* s) {
        if (verbosity::level() > VERBOSE_NONE)
            std::cerr << "This error is supposed to happen: " << s << std::endl;
    }
};

void on_error(int, const char*) {}

BOOST_AUTO_TEST_CASE( test_async_logger_err_handler )
{
    text_file_logger<> l_logger;
    l_logger.on_error = &on_error;

    T t;

    l_logger.on_error = boost::bind(&T::on_error, &t, _1, _2);
    BOOST_REQUIRE_EQUAL(-2, l_logger.start("/proc/xxxx/yyyy"));
    l_logger.stop();
}

BOOST_AUTO_TEST_CASE( test_async_logger_perf )
{
    enum { ITERATIONS = 500000 };

    {
        unlink(s_filename);

        text_file_logger<> l_logger;

        int ok = l_logger.start(s_filename);

        BOOST_REQUIRE ( ok == 0 );

        perf_histogram perf("Async logger latency");

        for (int i = 0; i < ITERATIONS; i++) {
            perf.start();
            int n = l_logger.fwrite(s_str1, i);
            perf.stop();
            BOOST_REQUIRE( 0 == n );
        }

        perf.dump(std::cout);
    }
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_async_logger_append )
{
    enum { ITERATIONS = 10 };

    {
        unlink(s_filename);

        text_file_logger<> l_logger;

        for (int k=0; k < 2; k++) {

            int ok = l_logger.start(s_filename);
            BOOST_REQUIRE ( ok == 0 );

            for (int i = 0; i < ITERATIONS; i++)
                BOOST_REQUIRE( 0 == l_logger.fwrite(s_str1, i) );

            l_logger.stop();
        }

        std::ifstream file(s_filename, std::ios::in);
        for (int k = 0; k < 2; k++)
            for (int i = 0; i < ITERATIONS; i++) {
                std::string s;
                std::getline(file, s);
                BOOST_REQUIRE( ! file.fail() );

                char buf[256];
                sprintf(buf, s_str1, i);
                s += '\n';
                BOOST_REQUIRE_EQUAL( s, buf );
            }

        {
            std::string s;
            std::getline(file, s);
            BOOST_REQUIRE(file.fail());
            BOOST_REQUIRE(file.eof());
            file.close();
        }
        ::unlink(s_filename);
    }
}

class producer {
    int m_instance;
    int m_iterations;
    text_file_logger<>& m_logger;
    perf_histogram* m_histogram;
public:
    producer(text_file_logger<>& a_logger, int n, int iter, perf_histogram* h)
        : m_instance(n), m_iterations(iter), m_logger(a_logger), m_histogram(h)
    {}

    void operator() () {
        std::stringstream str;
        str << m_instance << "| " << s_str1;

        m_histogram->reset();

        for (int i = 0; i < m_iterations; i++) {
            m_histogram->start();
            if (m_logger.fwrite(str.str().c_str(), i) < 0) {
                std::cerr << "Thread " << m_instance << " iter "
                          << m_iterations << " error writing to file ("
                          << i+1 << "): " << strerror(errno) << std::endl;
                return;
            }
            m_histogram->stop();
            if (i % 4 == 0)
                ::sched_yield();
        }
    }
};

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_async_file_logger_concurrent )
{
    const int threads   = ::getenv("THREAD") ? atoi(::getenv("THREAD")) : 2;
    const int immediate = !::getenv("NO_WAKEUP");

    ::unlink(s_filename);

    text_file_logger<> l_logger;

    int ok = l_logger.start(s_filename, immediate);
    BOOST_REQUIRE ( ok == 0 );

    perf_histogram totals("Total async_file_logger performance");

    {
        boost::shared_ptr<boost::thread> l_threads[threads];
        perf_histogram                   l_histograms[threads];
        for (int i=0; i < threads; i++)
            l_threads[i] = boost::shared_ptr<boost::thread>(
                new boost::thread(producer(l_logger, i+1, ITERATIONS, &l_histograms[i])));

        for (int i=0; i < threads; i++) {
            (*l_threads)->join();
            totals += l_histograms[i];
        }
    }

    l_logger.stop();

    if (::getenv("VERBOSE"))
        totals.dump(std::cout);

    int MAX = threads;
    int cur_count[MAX];

    bzero(cur_count, sizeof(cur_count));

    std::ifstream file(s_filename, std::ios::in);
    for (int i = 0; i < ITERATIONS*MAX; i++) {
        std::string s;
        std::getline(file, s);
        BOOST_REQUIRE( ! file.fail() );

        size_t n1 = s.find_first_of('|');
        BOOST_REQUIRE( n1 != std::string::npos );

        std::string num = s.substr(0, n1);
        int thread_num = atoi(num.c_str());
        BOOST_REQUIRE( thread_num >= 1 && thread_num <= MAX );

        size_t n2 = s.find_first_of(':');
        BOOST_REQUIRE( n2 != std::string::npos );
        num = s.substr(n2+1);
        int count = atoi(num.c_str());
        BOOST_REQUIRE_EQUAL( count, cur_count[thread_num-1] );

        std::stringstream str;
        str << thread_num << "| " << s_str1;

        char buf[128];
        sprintf(buf, str.str().c_str(), cur_count[thread_num-1]);
        s += '\n';

        BOOST_REQUIRE_EQUAL( s, buf );

        cur_count[thread_num-1]++;
    }

    {
        std::string s;
        std::getline(file, s);
    }
    BOOST_REQUIRE( file.fail() );
    BOOST_REQUIRE( file.eof() );
    file.close();

    for (int i=0; i < MAX; i++)
        BOOST_REQUIRE(cur_count[i] == ITERATIONS);

    ::unlink(s_filename);
}
<commit_msg>Bug fix in logging<commit_after>//----------------------------------------------------------------------------
/// \file  test_async_file_logger.cpp
//----------------------------------------------------------------------------
/// \brief This is a test file for validating async_file_logger functionality.
//----------------------------------------------------------------------------
// Copyright (c) 2010 Serge Aleynikov <saleyn@gmail.com>
// Created: 2012-03-21
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of utxx open-source project.

Copyright (C) 2009 Serge Aleynikov <saleyn@gmail.com>

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

***** END LICENSE BLOCK *****
*/

#include <fstream>
#include <iomanip>
#include <unistd.h>

//#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <utxx/logger/async_file_logger.hpp>
#include <utxx/perf_histogram.hpp>
#include <utxx/verbosity.hpp>

const char* s_filename = "/tmp/test_async_file_logger.log";
const char* s_str1     = "This is a const char* string line:%d\n";
const char* s_str2     = "This is an stl std::string line:";
const char* s_str3     = "This is another const char* string without line\n";

static const int32_t ITERATIONS =
    getenv("ITERATIONS") ? atoi(getenv("ITERATIONS")) : 100000u;

using namespace boost::unit_test;
using namespace utxx;

struct T {
    void on_error(int, const char* s) {
        if (verbosity::level() > VERBOSE_NONE)
            std::cerr << "This error is supposed to happen: " << s << std::endl;
    }
};

void on_error(int, const char*) {}

BOOST_AUTO_TEST_CASE( test_async_logger_err_handler )
{
    text_file_logger<> l_logger;
    l_logger.on_error = &on_error;

    T t;

    l_logger.on_error = boost::bind(&T::on_error, &t, _1, _2);
    BOOST_REQUIRE_EQUAL(-2, l_logger.start("/proc/xxxx/yyyy"));
    l_logger.stop();
}

BOOST_AUTO_TEST_CASE( test_async_logger_perf )
{
    enum { ITERATIONS = 500000 };

    {
        unlink(s_filename);

        text_file_logger<> l_logger;

        int ok = l_logger.start(s_filename);

        BOOST_REQUIRE ( ok == 0 );

        perf_histogram perf("Async logger latency");

        for (int i = 0; i < ITERATIONS; i++) {
            perf.start();
            int n = l_logger.fwrite(s_str1, i);
            perf.stop();
            BOOST_REQUIRE( 0 == n );
        }

        perf.dump(std::cout);
    }
}

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_async_logger_append )
{
    enum { ITERATIONS = 10 };

    {
        unlink(s_filename);

        text_file_logger<> l_logger;

        for (int k=0; k < 2; k++) {

            int ok = l_logger.start(s_filename);
            BOOST_REQUIRE ( ok == 0 );

            for (int i = 0; i < ITERATIONS; i++)
                BOOST_REQUIRE( 0 == l_logger.fwrite(s_str1, i) );

            l_logger.stop();
        }

        std::ifstream file(s_filename, std::ios::in);
        for (int k = 0; k < 2; k++)
            for (int i = 0; i < ITERATIONS; i++) {
                std::string s;
                std::getline(file, s);
                BOOST_REQUIRE( ! file.fail() );

                char buf[256];
                sprintf(buf, s_str1, i);
                s += '\n';
                BOOST_REQUIRE_EQUAL( s, buf );
            }

        {
            std::string s;
            std::getline(file, s);
            BOOST_REQUIRE(file.fail());
            BOOST_REQUIRE(file.eof());
            file.close();
        }
        ::unlink(s_filename);
    }
}

class producer {
    int m_instance;
    int m_iterations;
    text_file_logger<>& m_logger;
    perf_histogram* m_histogram;
public:
    producer(text_file_logger<>& a_logger, int n, int iter, perf_histogram* h)
        : m_instance(n), m_iterations(iter), m_logger(a_logger), m_histogram(h)
    {}

    void operator() () {
        std::stringstream str;
        str << m_instance << "| " << s_str1;

        m_histogram->reset();

        for (int i = 0; i < m_iterations; i++) {
            m_histogram->start();
            if (m_logger.fwrite(str.str().c_str(), i) < 0) {
                std::stringstream s;
                s << "Thread " << m_instance << " iter "
                  << m_iterations << " error writing to file ("
                  << (i+1) << ", max_q_size: "
                  << m_logger.max_queue_size()
                  << "): " << strerror(errno) << std::endl;
                std::cerr << s.str();
                return;
            }
            m_histogram->stop();
            if (i % 4 == 0)
                ::sched_yield();
        }
    }
};

//-----------------------------------------------------------------------------
BOOST_AUTO_TEST_CASE( test_async_file_logger_concurrent )
{
    const int threads   = ::getenv("THREAD") ? atoi(::getenv("THREAD")) : 2;
    const int immediate = !::getenv("NO_WAKEUP");

    ::unlink(s_filename);

    text_file_logger<> l_logger;

    int ok = l_logger.start(s_filename, immediate);
    BOOST_REQUIRE ( ok == 0 );

    perf_histogram totals("Total async_file_logger performance");

    {
        boost::shared_ptr<boost::thread> l_threads[threads];
        perf_histogram                   l_histograms[threads];
        for (int i=0; i < threads; i++)
            l_threads[i] = boost::shared_ptr<boost::thread>(
                new boost::thread(producer(l_logger, i+1, ITERATIONS, &l_histograms[i])));

        for (int i=0; i < threads; i++) {
            (*l_threads)->join();
            totals += l_histograms[i];
        }
    }

    l_logger.stop();

    if (::getenv("VERBOSE"))
        totals.dump(std::cout);

    int MAX = threads;
    int cur_count[MAX];

    bzero(cur_count, sizeof(cur_count));

    std::ifstream file(s_filename, std::ios::in);
    for (int i = 0; i < ITERATIONS*MAX; i++) {
        std::string s;
        std::getline(file, s);
        BOOST_REQUIRE( ! file.fail() );

        size_t n1 = s.find_first_of('|');
        BOOST_REQUIRE( n1 != std::string::npos );

        std::string num = s.substr(0, n1);
        int thread_num = atoi(num.c_str());
        BOOST_REQUIRE( thread_num >= 1 && thread_num <= MAX );

        size_t n2 = s.find_first_of(':');
        BOOST_REQUIRE( n2 != std::string::npos );
        num = s.substr(n2+1);
        int count = atoi(num.c_str());
        BOOST_REQUIRE_EQUAL( count, cur_count[thread_num-1] );

        std::stringstream str;
        str << thread_num << "| " << s_str1;

        char buf[128];
        sprintf(buf, str.str().c_str(), cur_count[thread_num-1]);
        s += '\n';

        BOOST_REQUIRE_EQUAL( s, buf );

        cur_count[thread_num-1]++;
    }

    {
        std::string s;
        std::getline(file, s);
    }
    BOOST_REQUIRE( file.fail() );
    BOOST_REQUIRE( file.eof() );
    file.close();

    for (int i=0; i < MAX; i++)
        BOOST_REQUIRE(cur_count[i] == ITERATIONS);

    ::unlink(s_filename);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dp_gui_autoscrolledit.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: ihi $ $Date: 2006-12-20 14:21:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "svtools/svmedit2.hxx"
#include "svtools/lstner.hxx"
#include "svtools/xtextedt.hxx"
#include "vcl/scrbar.hxx"

#include "dp_gui_autoscrolledit.hxx"

namespace dp_gui {

AutoScrollEdit::AutoScrollEdit( Window* pParent, const ResId& rResId )
    : ExtMultiLineEdit( pParent, rResId )
{
    ScrollBar*  pScroll = GetVScrollBar();
    if (pScroll)
        pScroll->Hide();
//    SetLeftMargin( 0 );
    StartListening( *GetTextEngine() );
}

AutoScrollEdit::~AutoScrollEdit()
{
    EndListeningAll();
}

void AutoScrollEdit::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
    if ( rHint.IsA( TYPE(TextHint) ) )
    {
        ULONG   nId = ((const TextHint&)rHint).GetId();
        if ( nId == TEXT_HINT_VIEWSCROLLED )
        {
            ScrollBar*  pScroll = GetVScrollBar();
            if ( pScroll )
                pScroll->Show();
        }
    }
}

} // namespace dp_gui

<commit_msg>INTEGRATION: CWS changefileheader (1.2.336); FILE MERGED 2008/03/28 15:26:36 rt 1.2.336.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dp_gui_autoscrolledit.cxx,v $
 * $Revision: 1.3 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_desktop.hxx"

#include "svtools/svmedit2.hxx"
#include "svtools/lstner.hxx"
#include "svtools/xtextedt.hxx"
#include "vcl/scrbar.hxx"

#include "dp_gui_autoscrolledit.hxx"

namespace dp_gui {

AutoScrollEdit::AutoScrollEdit( Window* pParent, const ResId& rResId )
    : ExtMultiLineEdit( pParent, rResId )
{
    ScrollBar*  pScroll = GetVScrollBar();
    if (pScroll)
        pScroll->Hide();
//    SetLeftMargin( 0 );
    StartListening( *GetTextEngine() );
}

AutoScrollEdit::~AutoScrollEdit()
{
    EndListeningAll();
}

void AutoScrollEdit::Notify( SfxBroadcaster&, const SfxHint& rHint )
{
    if ( rHint.IsA( TYPE(TextHint) ) )
    {
        ULONG   nId = ((const TextHint&)rHint).GetId();
        if ( nId == TEXT_HINT_VIEWSCROLLED )
        {
            ScrollBar*  pScroll = GetVScrollBar();
            if ( pScroll )
                pScroll->Show();
        }
    }
}

} // namespace dp_gui

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2014, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "TestPlatform.h"
#include "FullIo.hpp"

#include <iostream>
#include <cstdlib>
#include <semaphore.h>
#include <string.h>
#include <unistd.h>
#include <cerrno>
#include <cassert>

using namespace std;

const int iDefaultPortNumber = 5001;

// Starts test-platform in blocking mode
static bool startBlockingTestPlatform(const char *filePath, int portNumber, string &strError)
{

    // Init semaphore
    sem_t sem;

    sem_init(&sem, false, 0);

    // Create param mgr
    CTestPlatform testPlatform(filePath, portNumber, sem);

    // Start platformmgr
    if (!testPlatform.load(strError)) {

        sem_destroy(&sem);

        return false;
    }

    // Block here
    sem_wait(&sem);

    sem_destroy(&sem);

    return true;
}

static void notifyParent(int parentFd, bool success)
{
    if (not utility::fullWrite(parentFd, &success, sizeof(success))) {
        cerr << "Unable to warn parent process of load "
             << (success ? "success" : "failure") << ": "
             << strerror(errno) << endl;
        assert(false);
    }
}

// Starts test-platform in daemon mode
static bool startDaemonTestPlatform(const char *filePath, int portNumber, string &strError)
{
    // Pipe used for communication between the child and the parent processes
    int pipefd[2];

    if (pipe(pipefd) == -1) {

        strError = "pipe failed";
        return false;
    }

    // Fork the current process:
    // - Child process is used to start test-platform
    // - Parent process is killed in order to turn its child into a daemon
    pid_t pid = fork();

    if (pid < 0) {

        strError = "fork failed!";
        return false;

    } else if (pid == 0) {

        // Child process : starts test-platform and notify the parent if it succeeds.

        // Close read side of the pipe
        close(pipefd[0]);

        // Init semaphore
        sem_t sem;

        sem_init(&sem, false, 0);

        // Create param mgr
        CTestPlatform testPlatform(filePath, portNumber, sem);

        // Message to send to parent process
        bool loadSuccess = testPlatform.load(strError);

        if (!loadSuccess) {

            cerr << strError << endl;

            // Notify parent of failure;
            notifyParent(pipefd[1], false);

        } else {

            // Notify parent of success
            notifyParent(pipefd[1], true);

            // Block here
            sem_wait(&sem);
        }
        sem_destroy(&sem);

        return loadSuccess;

    } else {

        // Parent process : need to kill it once the child notifies the successs/failure to start
        // test-platform (this status is used as exit value of the program).

        // Close write side of the pipe
        close(pipefd[1]);

        // Message received from the child process
        bool msgFromChild = false;

        if (not utility::fullRead(pipefd[0], &msgFromChild, sizeof(msgFromChild))) {
            strError = "Read pipe failed";
            return false;
        }

        // return success/failure in exit status
        return msgFromChild;
    }
}

static void showUsage()
{
    cerr << "test-platform [-dh] <file path> [port number, default "
         << iDefaultPortNumber << "]" << endl;
}

static void showInvalidUsage()
{
    cerr << "Invalid arguments: ";
    showUsage();
}

static void showHelp()
{
    showUsage();
    cerr << "<file path> must be a valid .xml file, oftenly ParameterFrameworkConfiguration.xml" << endl;
    cerr << "Arguments:" << endl
        << "    -d  starts as a deamon" << endl
        << "    -h  display this help and exit" << endl;
}

int main(int argc, char *argv[])
{
    // Option found by call to getopt()
    int opt;

    // Port number to be used by test-platform
    int portNumber;

    // Daemon flag
    bool isDaemon = false;

    // Index of the <file path> argument in the arguments list provided
    int indexFilePath = 1;

    // Handle the -d option
    while ((opt = getopt(argc, argv, "dh")) != -1) {
        switch (opt) {
        case 'd':
            isDaemon = true;
            indexFilePath = 2;
            break;
        case 'h':
            showHelp();
            return 0;
        default:
            showInvalidUsage();
            return -1;
        }
    }

    // Check the number of arguments
    if ((argc < indexFilePath + 1) || (argc > indexFilePath + 2)) {

        showInvalidUsage();
        return -1;
    }

    char *filePath = argv[indexFilePath];
    portNumber = argc > indexFilePath + 1 ? atoi(argv[indexFilePath + 1]) : iDefaultPortNumber;

    // Choose either blocking or daemon test-platform
    bool startError;
    string strError;

    if (isDaemon) {

        startError = startDaemonTestPlatform(filePath, portNumber, strError);
    } else {

        startError = startBlockingTestPlatform(filePath, portNumber, strError);
    }

    if (!startError) {

        cerr << "Test-platform error:" << strError.c_str() << endl;
        return -1;
    }
    return 0;
}
<commit_msg>Remove test-platform deamon feature<commit_after>/*
 * Copyright (c) 2011-2014, Intel Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation and/or
 * other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "TestPlatform.h"
#include "FullIo.hpp"

#include <iostream>
#include <cstdlib>
#include <semaphore.h>
#include <string.h>
#include <unistd.h>
#include <cerrno>
#include <cassert>

using namespace std;

const int iDefaultPortNumber = 5001;

// Starts test-platform in blocking mode
static bool startBlockingTestPlatform(const char *filePath, int portNumber, string &strError)
{

    // Init semaphore
    sem_t sem;

    sem_init(&sem, false, 0);

    // Create param mgr
    CTestPlatform testPlatform(filePath, portNumber, sem);

    // Start platformmgr
    if (!testPlatform.load(strError)) {

        sem_destroy(&sem);

        return false;
    }

    // Block here
    sem_wait(&sem);

    sem_destroy(&sem);

    return true;
}

static void showUsage()
{
    cerr << "test-platform [-h] <file path> [port number, default "
         << iDefaultPortNumber << "]" << endl;
}

static void showInvalidUsage()
{
    cerr << "Invalid arguments: ";
    showUsage();
}

static void showHelp()
{
    showUsage();
    cerr << "<file path> must be a valid .xml file, oftenly ParameterFrameworkConfiguration.xml" << endl;
    cerr << "Arguments:" << endl
        << "    -h  display this help and exit" << endl;
}

int main(int argc, char *argv[])
{
    // Option found by call to getopt()
    int opt;

    // Port number to be used by test-platform
    int portNumber;

    // Index of the <file path> argument in the arguments list provided
    int indexFilePath = 1;

    // Handle the -h option
    while ((opt = getopt(argc, argv, "h")) != -1) {
        switch (opt) {
        case 'h':
            showHelp();
            return 0;
        default:
            showInvalidUsage();
            return -1;
        }
    }

    // Check the number of arguments
    if ((argc < indexFilePath + 1) || (argc > indexFilePath + 2)) {

        showInvalidUsage();
        return -1;
    }

    char *filePath = argv[indexFilePath];
    portNumber = argc > indexFilePath + 1 ? atoi(argv[indexFilePath + 1]) : iDefaultPortNumber;

    string strError;
    bool startError = startBlockingTestPlatform(filePath, portNumber, strError);

    if (!startError) {

        cerr << "Test-platform error:" << strError.c_str() << endl;
        return -1;
    }
    return 0;
}
<|endoftext|>


<commit_before>// coding: utf-8
/* Copyright (c) 2014, Electronic Kiwi, daniel-k
* All Rights Reserved.
*
* The file is part of the xpcc-playground and is released under the 3-clause BSD
* license. See the file `LICENSE` for the full license governing this code.
*/

#include <xpcc/architecture.hpp>
#include <xpcc/debug/logger.hpp>
#include <nrf24.hpp>
#include "../../xpcc/examples/stm32f4_discovery/stm32f4_discovery.hpp"

xpcc::IODeviceWrapper< Usart2 > loggerDevice;
xpcc::log::Logger xpcc::log::error(loggerDevice);
xpcc::log::Logger xpcc::log::warning(loggerDevice);
xpcc::log::Logger xpcc::log::info(loggerDevice);
xpcc::log::Logger xpcc::log::debug(loggerDevice);

// Set the log level
#undef	XPCC_LOG_LEVEL
#define	XPCC_LOG_LEVEL xpcc::log::DEBUG

typedef LedBlue Led;

static constexpr bool isReceiverNotTransmitter = true;

MAIN_FUNCTION
{
	defaultSystemClock::enable();

	Led::setOutput(xpcc::Gpio::Low);

	// Initialize Usart
	GpioOutputA2::connect(Usart2::Tx);
	GpioInputA3::connect(Usart2::Rx, Gpio::InputType::PullUp);
	Usart2::initialize<defaultSystemClock, 115200>(10);

	XPCC_LOG_INFO << "Nrf24L01+ Test" << xpcc::endl;

	if(isReceiverNotTransmitter) {
	///////////// Receiver /////////////////////////////////////////////////////
		XPCC_LOG_INFO << "acting as receiver" << xpcc::endl;

		uint8_t data_array[4];
		const uint8_t tx_address[5] = {0xD7,0xD7,0xD7,0xD7,0xD7};
		const uint8_t rx_address[5] = {0xE7,0xE7,0xE7,0xE7,0xE7};

		nrf24_init();
		XPCC_LOG_DEBUG << "called nrf24_init()..." << xpcc::endl;

		nrf24_config(2,4);
		XPCC_LOG_DEBUG << "called nrf24_config(2,4)..." << xpcc::endl;

		nrf24_tx_address(tx_address);
		XPCC_LOG_DEBUG << "called nrf24_tx_address({0xD7,0xD7,0xD7,0xD7,0xD7})..." << xpcc::endl;

		nrf24_rx_address(rx_address);
		XPCC_LOG_DEBUG << "called nrf24_rx_address({0xE7,0xE7,0xE7,0xE7,0xE7})..." << xpcc::endl;

		while (1)
		{
			if(nrf24_dataReady())
			{
				nrf24_getData(data_array);
				XPCC_LOG_INFO << "Msg: 0x" << xpcc::hex
					<< data_array[0] << data_array[1] << data_array[2]
					<< data_array[3] << xpcc::endl;
			}
			Led::toggle();
			//xpcc::delay_ms(500);
		}
	} else {
	///////////// Transmitter //////////////////////////////////////////////////
		XPCC_LOG_INFO << "acting as transmitter" << xpcc::endl;
		while (1)
		{
			Led::toggle();
			xpcc::delay_ms(100);
		}
	}

}
<commit_msg>Nrf24: run with default startup clock<commit_after>// coding: utf-8
/* Copyright (c) 2014, Electronic Kiwi, daniel-k
* All Rights Reserved.
*
* The file is part of the xpcc-playground and is released under the 3-clause BSD
* license. See the file `LICENSE` for the full license governing this code.
*/

#include <xpcc/architecture.hpp>
#include <xpcc/debug/logger.hpp>
#include <nrf24.hpp>
#include "../../xpcc/examples/stm32f4_discovery/stm32f4_discovery.hpp"

xpcc::IODeviceWrapper< Usart2 > loggerDevice;
xpcc::log::Logger xpcc::log::error(loggerDevice);
xpcc::log::Logger xpcc::log::warning(loggerDevice);
xpcc::log::Logger xpcc::log::info(loggerDevice);
xpcc::log::Logger xpcc::log::debug(loggerDevice);

// Set the log level
#undef	XPCC_LOG_LEVEL
#define	XPCC_LOG_LEVEL xpcc::log::DEBUG

typedef LedBlue Led;

static constexpr bool isReceiverNotTransmitter = true;

struct
Fake8MHzSystemClock
{
	static constexpr int Usart2 = MHz16;
};

MAIN_FUNCTION
{
	//defaultSystemClock::enable();

	Led::setOutput(xpcc::Gpio::Low);

	// Initialize Usart
	GpioOutputA2::connect(Usart2::Tx);
	GpioInputA3::connect(Usart2::Rx, Gpio::InputType::PullUp);
	Usart2::initialize<Fake8MHzSystemClock, 115200>(10);

	XPCC_LOG_INFO << "Nrf24L01+ Test" << xpcc::endl;

	if(isReceiverNotTransmitter) {
	///////////// Receiver /////////////////////////////////////////////////////
		XPCC_LOG_INFO << "acting as receiver" << xpcc::endl;

		uint8_t data_array[4];
		const uint8_t tx_address[5] = {0xD7,0xD7,0xD7,0xD7,0xD7};
		const uint8_t rx_address[5] = {0xE7,0xE7,0xE7,0xE7,0xE7};

		nrf24_init();
		XPCC_LOG_DEBUG << "called nrf24_init()..." << xpcc::endl;

		nrf24_config(2,4);
		XPCC_LOG_DEBUG << "called nrf24_config(2,4)..." << xpcc::endl;

		nrf24_tx_address(tx_address);
		XPCC_LOG_DEBUG << "called nrf24_tx_address({0xD7,0xD7,0xD7,0xD7,0xD7})..." << xpcc::endl;

		nrf24_rx_address(rx_address);
		XPCC_LOG_DEBUG << "called nrf24_rx_address({0xE7,0xE7,0xE7,0xE7,0xE7})..." << xpcc::endl;

		while (1)
		{
			if(nrf24_dataReady())
			{
				nrf24_getData(data_array);
				XPCC_LOG_INFO << "Msg: 0x" << xpcc::hex
					<< data_array[0] << data_array[1] << data_array[2]
					<< data_array[3] << xpcc::endl;
			}
			Led::toggle();
			xpcc::delay_ms(100);
		}
	} else {
	///////////// Transmitter //////////////////////////////////////////////////
		XPCC_LOG_INFO << "acting as transmitter" << xpcc::endl;
		while (1)
		{
			Led::toggle();
			xpcc::delay_ms(100);
		}
	}

}
<|endoftext|>


<commit_before>#include "test_helpers.hxx"

using namespace PGSTD;
using namespace pqxx;

namespace
{
binarystring make_binarystring(transaction_base &T, string content)
{
  return binarystring(T.exec("SELECT " + T.quote_raw(content))[0][0]);
}

void test_binarystring(transaction_base &T)
{
  binarystring b = make_binarystring(T, "");
  PQXX_CHECK(b.empty(), "Empty binarystring is not empty.");
  PQXX_CHECK_EQUAL(b.str(), "", "Empty binarystring doesn't work.");
  PQXX_CHECK_EQUAL(b.size(), 0u, "Empty binarystring has nonzero size.");
  PQXX_CHECK_EQUAL(b.length(), 0u, "Length/size mismatch.");
  PQXX_CHECK(b.begin() == b.end(), "Empty binarystring iterates.");
  PQXX_CHECK(b.rbegin() == b.rend(), "Empty binarystring reverse-iterates.");
  PQXX_CHECK_THROWS(b.at(0), out_of_range, "Empty binarystring accepts at().");

  b = make_binarystring(T, "x");
  PQXX_CHECK_EQUAL(b.str(), "x", "Basic nonempty binarystring is broken.");
  PQXX_CHECK(!b.empty(), "Nonempty binarystring is empty.");
  PQXX_CHECK_EQUAL(b.size(), 1u, "Bad binarystring size.");
  PQXX_CHECK_EQUAL(b.length(), 1u, "Length/size mismatch.");
  PQXX_CHECK(b.begin() != b.end(), "Nonempty binarystring does not iterate.");
  PQXX_CHECK(
	b.rbegin() != b.rend(),
	 "Nonempty binarystring does not reverse-iterate.");
  PQXX_CHECK(b.begin() + 1 == b.end(), "Bad iteration.");
  PQXX_CHECK(b.rbegin() + 1 == b.rend(), "Bad reverse iteration.");
  PQXX_CHECK(b.front() == 'x', "Unexpected front().");
  PQXX_CHECK(b.back() == 'x', "Unexpected back().");
  PQXX_CHECK(b.at(0) == 'x', "Unexpected data at index 0.");
  PQXX_CHECK_THROWS(b.at(1), out_of_range, "Failed to catch range error.");

  const string bytes("\x01\x23\x23\xa1\x2b\x0c\xff");
  b = make_binarystring(T, bytes);
  PQXX_CHECK_EQUAL(b.str(), bytes, "Binary (un)escaping went wrong somewhere.");
  PQXX_CHECK_EQUAL(b.size(), bytes.size(), "Escaping confuses length.");

  const string bytes_escaped(T.esc_raw(bytes));
  for (string::size_type i=0; i<bytes_escaped.size(); ++i)
  {
    const unsigned char uc = static_cast<unsigned char>(bytes_escaped[i]);
    PQXX_CHECK(uc <= 127, "Non-ASCII byte in escaped string.");
  }

  PQXX_CHECK_EQUAL(
	T.quote_raw(
		reinterpret_cast<const unsigned char *>(bytes.c_str()),
		 bytes.size()),
	T.quote(b),
	"quote_raw is broken");
  PQXX_CHECK_EQUAL(T.quote(b), T.quote_raw(bytes), "Binary quoting is broken.");
  PQXX_CHECK_EQUAL(
	binarystring(T.exec("SELECT " + T.quote(b))[0][0]).str(),
	bytes,
	"Binary string is not idempotent.");

  const string nully("a\0b", 3);
  b = make_binarystring(T, nully);
  PQXX_CHECK_EQUAL(b.str(), nully, "Nul byte broke binary (un)escaping.");
  PQXX_CHECK_EQUAL(b.size(), 3u, "Nul byte broke binarystring size.");

  b = make_binarystring(T, "foo");
  PQXX_CHECK_EQUAL(string(b.get(), 3), "foo", "get() appears broken.");

  binarystring b1 = make_binarystring(T, "1"), b2 = make_binarystring(T, "2");
  PQXX_CHECK_NOT_EQUAL(b1.get(), b2.get(), "Madness rules.");
  PQXX_CHECK_NOT_EQUAL(b1.str(), b2.str(), "Logic has no more meaning.");
  b1.swap(b2);
  PQXX_CHECK_NOT_EQUAL(b1.str(), b2.str(), "swap() equalized binarystrings.");
  PQXX_CHECK_NOT_EQUAL(b1.str(), "1", "swap() did not happen.");
  PQXX_CHECK_EQUAL(b1.str(), "2", "swap() is broken.");
  PQXX_CHECK_EQUAL(b2.str(), "1", "swap() went insane.");

  b = make_binarystring(T, "bar");
  b.swap(b);
  PQXX_CHECK_EQUAL(b.str(), "bar", "Self-swap confuses binarystring.");

  b = make_binarystring(T, "\\x");
  PQXX_CHECK_EQUAL(b.str(), "\\x", "Hex-escape header confused (un)escaping.");
}
} // namespace

PQXX_REGISTER_TEST(test_binarystring)
<commit_msg>Smaller increments in difficulty.<commit_after>#include "test_helpers.hxx"

using namespace PGSTD;
using namespace pqxx;

namespace
{
binarystring make_binarystring(transaction_base &T, string content)
{
  return binarystring(T.exec("SELECT " + T.quote_raw(content))[0][0]);
}

void test_binarystring(transaction_base &T)
{
  binarystring b = make_binarystring(T, "");
  PQXX_CHECK(b.empty(), "Empty binarystring is not empty.");
  PQXX_CHECK_EQUAL(b.str(), "", "Empty binarystring doesn't work.");
  PQXX_CHECK_EQUAL(b.size(), 0u, "Empty binarystring has nonzero size.");
  PQXX_CHECK_EQUAL(b.length(), 0u, "Length/size mismatch.");
  PQXX_CHECK(b.begin() == b.end(), "Empty binarystring iterates.");
  PQXX_CHECK(b.rbegin() == b.rend(), "Empty binarystring reverse-iterates.");
  PQXX_CHECK_THROWS(b.at(0), out_of_range, "Empty binarystring accepts at().");

  b = make_binarystring(T, "z");
  PQXX_CHECK_EQUAL(b.str(), "z", "Basic nonempty binarystring is broken.");
  PQXX_CHECK(!b.empty(), "Nonempty binarystring is empty.");
  PQXX_CHECK_EQUAL(b.size(), 1u, "Bad binarystring size.");
  PQXX_CHECK_EQUAL(b.length(), 1u, "Length/size mismatch.");
  PQXX_CHECK(b.begin() != b.end(), "Nonempty binarystring does not iterate.");
  PQXX_CHECK(
	b.rbegin() != b.rend(),
	 "Nonempty binarystring does not reverse-iterate.");
  PQXX_CHECK(b.begin() + 1 == b.end(), "Bad iteration.");
  PQXX_CHECK(b.rbegin() + 1 == b.rend(), "Bad reverse iteration.");
  PQXX_CHECK(b.front() == 'z', "Unexpected front().");
  PQXX_CHECK(b.back() == 'z', "Unexpected back().");
  PQXX_CHECK(b.at(0) == 'z', "Unexpected data at index 0.");
  PQXX_CHECK_THROWS(b.at(1), out_of_range, "Failed to catch range error.");

  //const string bytes("\x01\x23\x23\xa1\x2b\x0c\xff");
  const string bytes("ab");
  b = make_binarystring(T, bytes);
  PQXX_CHECK_EQUAL(b.str(), bytes, "Binary (un)escaping went wrong somewhere.");
  PQXX_CHECK_EQUAL(b.size(), bytes.size(), "Escaping confuses length.");

  const string bytes_escaped(T.esc_raw(bytes));
  for (string::size_type i=0; i<bytes_escaped.size(); ++i)
  {
    const unsigned char uc = static_cast<unsigned char>(bytes_escaped[i]);
    PQXX_CHECK(uc <= 127, "Non-ASCII byte in escaped string.");
  }

  PQXX_CHECK_EQUAL(
	T.quote_raw(
		reinterpret_cast<const unsigned char *>(bytes.c_str()),
		 bytes.size()),
	T.quote(b),
	"quote_raw is broken");
  PQXX_CHECK_EQUAL(T.quote(b), T.quote_raw(bytes), "Binary quoting is broken.");
  PQXX_CHECK_EQUAL(
	binarystring(T.exec("SELECT " + T.quote(b))[0][0]).str(),
	bytes,
	"Binary string is not idempotent.");

  const string nully("a\0b", 3);
  b = make_binarystring(T, nully);
  PQXX_CHECK_EQUAL(b.str(), nully, "Nul byte broke binary (un)escaping.");
  PQXX_CHECK_EQUAL(b.size(), 3u, "Nul byte broke binarystring size.");

  b = make_binarystring(T, "foo");
  PQXX_CHECK_EQUAL(string(b.get(), 3), "foo", "get() appears broken.");

  binarystring b1 = make_binarystring(T, "1"), b2 = make_binarystring(T, "2");
  PQXX_CHECK_NOT_EQUAL(b1.get(), b2.get(), "Madness rules.");
  PQXX_CHECK_NOT_EQUAL(b1.str(), b2.str(), "Logic has no more meaning.");
  b1.swap(b2);
  PQXX_CHECK_NOT_EQUAL(b1.str(), b2.str(), "swap() equalized binarystrings.");
  PQXX_CHECK_NOT_EQUAL(b1.str(), "1", "swap() did not happen.");
  PQXX_CHECK_EQUAL(b1.str(), "2", "swap() is broken.");
  PQXX_CHECK_EQUAL(b2.str(), "1", "swap() went insane.");

  b = make_binarystring(T, "bar");
  b.swap(b);
  PQXX_CHECK_EQUAL(b.str(), "bar", "Self-swap confuses binarystring.");

  b = make_binarystring(T, "\\x");
  PQXX_CHECK_EQUAL(b.str(), "\\x", "Hex-escape header confused (un)escaping.");
}
} // namespace

PQXX_REGISTER_TEST(test_binarystring)
<|endoftext|>


<commit_before>/*

Copyright (c) 2007-2009, Python File Format Interface
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.

   * Neither the name of the Python File Format Interface
     project nor the names of its contributors may be used to endorse
     or promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

#include "trianglestripifier.hpp"

BOOST_AUTO_TEST_SUITE(triangle_strip_test_suite)

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_0) {
	// simple test
	Mesh m;
	MFacePtr f0 = m.add_face(0, 1, 2);
	int vertices[] = {0, 1, 2};
	BOOST_FOREACH(int pv0, vertices) {
		TriangleStrip t(pv0, pv0); // using vertex index as strip id and experiment id
		t.build(pv0, f0);
		BOOST_CHECK_EQUAL(t.reversed, false);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, pv0);
		BOOST_CHECK_EQUAL(*i++, f0->get_next_vertex(pv0));
		BOOST_CHECK_EQUAL(*i++, f0->get_next_vertex(f0->get_next_vertex(pv0)));
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK(j == t.faces.end());
	};
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_1) {
	// another simple test
	Mesh m;
	MFacePtr f0 = m.add_face(0, 1, 2);
	MFacePtr f1 = m.add_face(2, 1, 3);
	{
		TriangleStrip t(1, 1);
		t.build(0, f0);
		BOOST_CHECK_EQUAL(t.reversed, false);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK(j == t.faces.end());
	}
	{
		TriangleStrip t(2, 2);
		t.build(1, f0);
		BOOST_CHECK_EQUAL(t.reversed, true);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK(j == t.faces.end());
	}
	{
		TriangleStrip t(3, 3);
		t.build(2, f1);
		BOOST_CHECK_EQUAL(t.reversed, true);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK(j == t.faces.end());
	}
	{
		TriangleStrip t(4, 4);
		t.build(3, f1);
		BOOST_CHECK_EQUAL(t.reversed, false);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK(j == t.faces.end());
	}
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_2) {
	// checks that extra vertex is appended to fix winding
	Mesh m;
	MFacePtr f0 = m.add_face(1, 3, 2);
	MFacePtr f1 = m.add_face(2, 3, 4);
	TriangleStrip t(1, 1);
	t.build(2, f1);
	BOOST_CHECK_EQUAL(t.reversed, true);
	std::list<int>::const_iterator i = t.vertices.begin();
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 3);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK(i == t.vertices.end());
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_3) {
	// checks that strip is reversed to fix winding
	Mesh m;
	MFacePtr f0 = m.add_face(1, 3, 2);
	MFacePtr f1 = m.add_face(2, 3, 4);
	MFacePtr f2 = m.add_face(3, 5, 4);
	TriangleStrip t(1, 1);
	t.build(2, f1);
	BOOST_CHECK_EQUAL(t.reversed, true);
	std::list<int>::const_iterator i = t.vertices.begin();
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 3);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 5);
	BOOST_CHECK(i == t.vertices.end());
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_4) {
	// construct slightly more complicated mesh
	Mesh m;
	MFacePtr f0 = m.add_face(0, 1, 2);
	MFacePtr f1 = m.add_face(2, 1, 7);
	MFacePtr f2 = m.add_face(2, 7, 4);
	MFacePtr f3 = m.add_face(5, 3, 2);
	MFacePtr f4 = m.add_face(2, 1, 9);
	MFacePtr f5 = m.add_face(4, 7, 10);
	MFacePtr f6 = m.add_face(4, 10, 11);
	MFacePtr f7 = m.add_face(11, 10, 12);
	MFacePtr f8 = m.add_face(1, 0, 13);
	TriangleStrip t(1, 1);
	t.build(7, f1);
	BOOST_CHECK_EQUAL(t.reversed, false);
	std::list<int>::const_iterator i = t.vertices.begin();
	BOOST_CHECK_EQUAL(*i++, 12);
	BOOST_CHECK_EQUAL(*i++, 11);
	BOOST_CHECK_EQUAL(*i++, 10);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 7);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 0);
	BOOST_CHECK_EQUAL(*i++, 13);
	BOOST_CHECK(i == t.vertices.end());
	std::list<MFacePtr>::const_iterator j = t.faces.begin();
	BOOST_CHECK_EQUAL(*j++, f7);
	BOOST_CHECK_EQUAL(*j++, f6);
	BOOST_CHECK_EQUAL(*j++, f5);
	BOOST_CHECK_EQUAL(*j++, f2);
	BOOST_CHECK_EQUAL(*j++, f1);
	BOOST_CHECK_EQUAL(*j++, f0);
	BOOST_CHECK_EQUAL(*j++, f8);
	BOOST_CHECK(j == t.faces.end());
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Tests for get_strip().<commit_after>/*

Copyright (c) 2007-2009, Python File Format Interface
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

   * Redistributions of source code must retain the above copyright
     notice, this list of conditions and the following disclaimer.

   * Redistributions in binary form must reproduce the above
     copyright notice, this list of conditions and the following
     disclaimer in the documentation and/or other materials provided
     with the distribution.

   * Neither the name of the Python File Format Interface
     project nor the names of its contributors may be used to endorse
     or promote products derived from this software without specific
     prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>

#include "trianglestripifier.hpp"

BOOST_AUTO_TEST_SUITE(triangle_strip_test_suite)

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_0) {
	// simple test
	Mesh m;
	MFacePtr f0 = m.add_face(0, 1, 2);
	int vertices[] = {0, 1, 2};
	BOOST_FOREACH(int pv0, vertices) {
		TriangleStrip t(pv0, pv0); // using vertex index as strip id and experiment id
		t.build(pv0, f0);
		BOOST_CHECK_EQUAL(t.reversed, false);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, pv0);
		BOOST_CHECK_EQUAL(*i++, f0->get_next_vertex(pv0));
		BOOST_CHECK_EQUAL(*i++, f0->get_next_vertex(f0->get_next_vertex(pv0)));
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK(j == t.faces.end());
		// not reversed, so...
		BOOST_CHECK(t.get_strip() == t.vertices);
	};
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_1) {
	// another simple test
        // also tests get_strip on strips of length 4
	Mesh m;
	MFacePtr f0 = m.add_face(0, 1, 2);
	MFacePtr f1 = m.add_face(2, 1, 3);
	{
		TriangleStrip t(1, 1);
		t.build(0, f0);
		BOOST_CHECK_EQUAL(t.reversed, false);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK(j == t.faces.end());
		// not reversed, so...
		BOOST_CHECK(t.get_strip() == t.vertices);
	}
	{
		TriangleStrip t(2, 2);
		t.build(1, f0);
		BOOST_CHECK_EQUAL(t.reversed, true);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK(j == t.faces.end());
		std::list<int> strip = t.get_strip();
		i = strip.begin();
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK(i == strip.end());
	}
	{
		TriangleStrip t(3, 3);
		t.build(2, f1);
		BOOST_CHECK_EQUAL(t.reversed, true);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK(j == t.faces.end());
		std::list<int> strip = t.get_strip();
		i = strip.begin();
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK(i == strip.end());
	}
	{
		TriangleStrip t(4, 4);
		t.build(3, f1);
		BOOST_CHECK_EQUAL(t.reversed, false);
		std::list<int>::const_iterator i = t.vertices.begin();
		BOOST_CHECK_EQUAL(*i++, 3);
		BOOST_CHECK_EQUAL(*i++, 2);
		BOOST_CHECK_EQUAL(*i++, 1);
		BOOST_CHECK_EQUAL(*i++, 0);
		BOOST_CHECK(i == t.vertices.end());
		std::list<MFacePtr>::const_iterator j = t.faces.begin();
		BOOST_CHECK_EQUAL(*j++, f1);
		BOOST_CHECK_EQUAL(*j++, f0);
		BOOST_CHECK(j == t.faces.end());
		// not reversed, so...
		BOOST_CHECK(t.get_strip() == t.vertices);
	}
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_2) {
	// checks that extra vertex is appended to fix winding
        // 1---3---5
        //  \ / \ / \
        //   2---4---6
	Mesh m;
	MFacePtr f0 = m.add_face(1, 3, 2);
	MFacePtr f1 = m.add_face(2, 3, 4);
	MFacePtr f2 = m.add_face(4, 3, 5);
	MFacePtr f3 = m.add_face(4, 5, 6);
	TriangleStrip t(1, 1);
	t.build(2, f1);
	BOOST_CHECK_EQUAL(t.reversed, true);
	std::list<int>::const_iterator i = t.vertices.begin();
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 3);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 5);
	BOOST_CHECK_EQUAL(*i++, 6);
	BOOST_CHECK(i == t.vertices.end());
	std::list<int> strip = t.get_strip();
	i = strip.begin();
	BOOST_CHECK_EQUAL(*i++, 1); // extra vertex
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 3);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 5);
	BOOST_CHECK_EQUAL(*i++, 6);
	BOOST_CHECK(i == strip.end());
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_3) {
	// checks that strip is reversed to fix winding
	Mesh m;
	MFacePtr f0 = m.add_face(1, 3, 2);
	MFacePtr f1 = m.add_face(2, 3, 4);
	MFacePtr f2 = m.add_face(3, 5, 4);
	TriangleStrip t(1, 1);
	t.build(2, f1);
	BOOST_CHECK_EQUAL(t.reversed, true);
	std::list<int>::const_iterator i = t.vertices.begin();
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 3);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 5);
	BOOST_CHECK(i == t.vertices.end());
	std::list<int> strip = t.get_strip();
	i = strip.begin();
	BOOST_CHECK_EQUAL(*i++, 5); // reversed order
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 3);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK(i == strip.end());
}

BOOST_AUTO_TEST_CASE(triangle_strip_build_test_4) {
	// construct slightly more complicated mesh
	Mesh m;
	MFacePtr f0 = m.add_face(0, 1, 2);
	MFacePtr f1 = m.add_face(2, 1, 7);
	MFacePtr f2 = m.add_face(2, 7, 4);
	MFacePtr f3 = m.add_face(5, 3, 2);
	MFacePtr f4 = m.add_face(2, 1, 9);
	MFacePtr f5 = m.add_face(4, 7, 10);
	MFacePtr f6 = m.add_face(4, 10, 11);
	MFacePtr f7 = m.add_face(11, 10, 12);
	MFacePtr f8 = m.add_face(1, 0, 13);
	TriangleStrip t(1, 1);
	t.build(7, f1);
	BOOST_CHECK_EQUAL(t.reversed, false);
	std::list<int>::const_iterator i = t.vertices.begin();
	BOOST_CHECK_EQUAL(*i++, 12);
	BOOST_CHECK_EQUAL(*i++, 11);
	BOOST_CHECK_EQUAL(*i++, 10);
	BOOST_CHECK_EQUAL(*i++, 4);
	BOOST_CHECK_EQUAL(*i++, 7);
	BOOST_CHECK_EQUAL(*i++, 2);
	BOOST_CHECK_EQUAL(*i++, 1);
	BOOST_CHECK_EQUAL(*i++, 0);
	BOOST_CHECK_EQUAL(*i++, 13);
	BOOST_CHECK(i == t.vertices.end());
	std::list<MFacePtr>::const_iterator j = t.faces.begin();
	BOOST_CHECK_EQUAL(*j++, f7);
	BOOST_CHECK_EQUAL(*j++, f6);
	BOOST_CHECK_EQUAL(*j++, f5);
	BOOST_CHECK_EQUAL(*j++, f2);
	BOOST_CHECK_EQUAL(*j++, f1);
	BOOST_CHECK_EQUAL(*j++, f0);
	BOOST_CHECK_EQUAL(*j++, f8);
	BOOST_CHECK(j == t.faces.end());
	// not reversed, so...
	BOOST_CHECK(t.get_strip() == t.vertices);
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


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

#include "oak/server/oak_runtime.h"

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

#include "asylo/util/logging.h"
#include "asylo/util/status_macros.h"
#include "oak/common/app_config.h"
#include "oak/server/module_invocation.h"

namespace oak {

asylo::Status OakRuntime::Initialize(const ApplicationConfiguration& config) {
  LOG(INFO) << "Initializing Oak Runtime";
  if (!ValidApplicationConfig(config)) {
    return asylo::Status(asylo::error::GoogleError::INVALID_ARGUMENT, "Invalid configuration");
  }

  // Create all of the nodes.  The validity check above will ensure there is at
  // most one of each pseudo-Node type.
  for (const auto& node_config : config.nodes()) {
    const std::string& node_name = node_config.node_name();
    std::unique_ptr<OakNode> node;
    if (node_config.has_web_assembly_node()) {
      LOG(INFO) << "Create Wasm node named " << node_name;
      node =
          WasmNode::Create(node_config.node_name(), node_config.web_assembly_node().module_bytes());
    } else if (node_config.has_grpc_server_node()) {
      LOG(INFO) << "Create gRPC pseudo-Node named " << node_name;
      std::unique_ptr<OakGrpcNode> grpc_node = OakGrpcNode::Create(node_name);
      grpc_node_ = grpc_node.get();  // borrowed copy
      node = std::move(grpc_node);
    } else if (node_config.has_log_node()) {
      LOG(INFO) << "Create logging pseudo-node named " << node_name;
      node = absl::make_unique<LoggingNode>(node_name);
    } else if (node_config.has_storage_node()) {
      LOG(INFO) << "Created storage pseudo-Node named " << node_name;
      node = absl::make_unique<StorageNode>(node_name, node_config.storage_node().address());
    }
    if (node == nullptr) {
      return asylo::Status(asylo::error::GoogleError::INVALID_ARGUMENT,
                           "Failed to create Oak Node");
    }
    nodes_[node_name] = std::move(node);
  }

  // Now create channels.
  for (const auto& channel_config : config.channels()) {
    const std::string& src_name = channel_config.source_endpoint().node_name();
    const std::string& src_port = channel_config.source_endpoint().port_name();
    const std::string& dest_name = channel_config.destination_endpoint().node_name();
    const std::string& dest_port = channel_config.destination_endpoint().port_name();
    OakNode* src_node = nodes_[src_name].get();
    OakNode* dest_node = nodes_[dest_name].get();
    if (src_node == nullptr || dest_node == nullptr) {
      return asylo::Status(asylo::error::GoogleError::INVALID_ARGUMENT,
                           "Node at end of channel not found");
    }

    LOG(INFO) << "Create channel " << src_name << "." << src_port << " -> " << dest_name << "."
              << dest_port;
    auto channel = std::make_shared<MessageChannel>();

    src_node->AddNamedChannel(src_port, absl::make_unique<MessageChannelWriteHalf>(channel));
    dest_node->AddNamedChannel(dest_port, absl::make_unique<MessageChannelReadHalf>(channel));
  }

  return asylo::Status::OkStatus();
}

asylo::Status OakRuntime::Start() {
  LOG(INFO) << "Starting runtime";

  // Now all dependencies are running, start the thread for all the Wasm Nodes.
  for (auto& named_node : nodes_) {
    LOG(INFO) << "Starting node " << named_node.first;
    named_node.second->Start();
  }

  return asylo::Status::OkStatus();
}

int32_t OakRuntime::GetPort() { return grpc_node_->GetPort(); }

asylo::Status OakRuntime::Stop() {
  LOG(INFO) << "Stopping runtime...";
  grpc_node_ = nullptr;
  for (auto& named_node : nodes_) {
    LOG(INFO) << "Stopping node " << named_node.first;
    named_node.second->Stop();
  }
  nodes_.clear();

  return asylo::Status::OkStatus();
}

}  // namespace oak
<commit_msg>Treat channels to logging node specially<commit_after>/*
 * Copyright 2019 The Project Oak Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "oak/server/oak_runtime.h"

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

#include "asylo/util/logging.h"
#include "asylo/util/status_macros.h"
#include "oak/common/app_config.h"
#include "oak/server/module_invocation.h"

namespace oak {

asylo::Status OakRuntime::Initialize(const ApplicationConfiguration& config) {
  LOG(INFO) << "Initializing Oak Runtime";
  if (!ValidApplicationConfig(config)) {
    return asylo::Status(asylo::error::GoogleError::INVALID_ARGUMENT, "Invalid configuration");
  }

  // Create all of the nodes.  The validity check above will ensure there is at
  // most one of each pseudo-Node type.
  OakNode* log_node = nullptr;
  for (const auto& node_config : config.nodes()) {
    const std::string& node_name = node_config.node_name();
    std::unique_ptr<OakNode> node;
    if (node_config.has_web_assembly_node()) {
      LOG(INFO) << "Create Wasm node named " << node_name;
      node =
          WasmNode::Create(node_config.node_name(), node_config.web_assembly_node().module_bytes());
    } else if (node_config.has_grpc_server_node()) {
      LOG(INFO) << "Create gRPC pseudo-Node named " << node_name;
      std::unique_ptr<OakGrpcNode> grpc_node = OakGrpcNode::Create(node_name);
      grpc_node_ = grpc_node.get();  // borrowed copy
      node = std::move(grpc_node);
    } else if (node_config.has_log_node()) {
      LOG(INFO) << "Create logging pseudo-node named " << node_name;
      node = absl::make_unique<LoggingNode>(node_name);
      log_node = node.get();
    } else if (node_config.has_storage_node()) {
      LOG(INFO) << "Created storage pseudo-Node named " << node_name;
      node = absl::make_unique<StorageNode>(node_name, node_config.storage_node().address());
    }
    if (node == nullptr) {
      return asylo::Status(asylo::error::GoogleError::INVALID_ARGUMENT,
                           "Failed to create Oak Node");
    }
    nodes_[node_name] = std::move(node);
  }

  // Now create channels.
  std::shared_ptr<MessageChannel> logging_channel;
  for (const auto& channel_config : config.channels()) {
    const std::string& src_name = channel_config.source_endpoint().node_name();
    const std::string& src_port = channel_config.source_endpoint().port_name();
    const std::string& dest_name = channel_config.destination_endpoint().node_name();
    const std::string& dest_port = channel_config.destination_endpoint().port_name();
    OakNode* src_node = nodes_[src_name].get();
    OakNode* dest_node = nodes_[dest_name].get();
    if (src_node == nullptr || dest_node == nullptr) {
      return asylo::Status(asylo::error::GoogleError::INVALID_ARGUMENT,
                           "Node at end of channel not found");
    }

    if (dest_node == log_node && logging_channel != nullptr) {
      // Special case for all configured channels going to the logging
      // pseudo-Node: share the existing channel and hold an extra reference to
      // the write half of the channel.
      LOG(INFO) << "Re-use logging channel for " << src_name << "." << src_port << " -> "
                << dest_name << "." << dest_port;
      src_node->AddNamedChannel(src_port,
                                absl::make_unique<MessageChannelWriteHalf>(logging_channel));
    } else {
      LOG(INFO) << "Create channel " << src_name << "." << src_port << " -> " << dest_name << "."
                << dest_port;
      auto channel = std::make_shared<MessageChannel>();
      if (dest_node == log_node) {
        // Remember the logging channel for future re-use.
        logging_channel = channel;
      }

      src_node->AddNamedChannel(src_port, absl::make_unique<MessageChannelWriteHalf>(channel));
      dest_node->AddNamedChannel(dest_port, absl::make_unique<MessageChannelReadHalf>(channel));
    }
  }

  return asylo::Status::OkStatus();
}

asylo::Status OakRuntime::Start() {
  LOG(INFO) << "Starting runtime";

  // Now all dependencies are running, start the thread for all the Wasm Nodes.
  for (auto& named_node : nodes_) {
    LOG(INFO) << "Starting node " << named_node.first;
    named_node.second->Start();
  }

  return asylo::Status::OkStatus();
}

int32_t OakRuntime::GetPort() { return grpc_node_->GetPort(); }

asylo::Status OakRuntime::Stop() {
  LOG(INFO) << "Stopping runtime...";
  grpc_node_ = nullptr;
  for (auto& named_node : nodes_) {
    LOG(INFO) << "Stopping node " << named_node.first;
    named_node.second->Stop();
  }
  nodes_.clear();

  return asylo::Status::OkStatus();
}

}  // namespace oak
<|endoftext|>