<commit_before>#ifndef __MONOMIO_HPP__
#define __MONOMIO_HPP__
#include <iostream>
#include <cmath>
#include "monomiointerfaz.hpp"

using std::cout;
using std::cin;
using std::endl;
using std::ostream;
using std::istream;

class Monomio:public ed::MonomioInterfaz{
    private:
        double coeficiente_;
        int grado_;
    public:
        Monomio(double coeficiente = 1, int grado = 1){ //Constructor inicializado
            setGrado(grado);
            setCoeficiente(coeficiente);
        }

        Monomio(const Monomio &m){
            setGrado(m.grado_);
            setCoeficiente(m.coeficiente_);
        }

        int getGrado() const{
            return grado_;
        }

        double getCoeficiente() const{
            return coeficiente_;
        }
        void setGrado(int grado){
            grado_ = grado;
        }

        void setCoeficiente(double coeficiente){
            coeficiente_ = coeficiente;
        }

        void escribirMonomio(){
            cout << getCoeficiente() << "x^" << getGrado();
        }

        void leerMonomio(){
            int grado;
            double coeficiente;

            cout << "Introduzca el coeficiente del monomio..: " << endl;
            cin >> coeficiente;
            cout << "Introduzca el grado del monomio..: " << endl;
            cin >> grado;
            setGrado(grado);
            setCoeficiente(coeficiente);
        }

        Monomio &operator= (const Monomio &recibido){
            this->setGrado(recibido.getGrado());
            this->setCoeficiente(recibido.getCoeficiente());

            return *this;
        }

        Monomio &operator+ (const Monomio &recibido){
            if(this->getGrado() == recibido.getGrado()){
                this->setCoeficiente(this->getCoeficiente() + recibido.getCoeficiente());
                return *this;
            }
            cout << "La suma no se ha podido realizar porque los grados de los monomios no son iguales" << endl;
            return *this;
        }

        bool operator== (Monomio &aux){
            return this->getGrado() == aux.getGrado() && this->getCoeficiente() == aux.getCoeficiente();
        }

        Monomio operator* (const Monomio &m2){
            Monomio resultado(1,0);

            resultado.setGrado(this->getGrado() + m2.getGrado());
            resultado.setCoeficiente(this->getCoeficiente() * m2.getCoeficiente());

            return resultado;
        }

        double resuelveMonomio(double valorX){
            double resultado;
            resultado = pow(valorX * getCoeficiente(), getGrado());

            return resultado;
        }

        //friend istream &operator>>(istream &stream, Monomio &m);
        //friend ostream &operator<<(ostream &stream, Monomio const &m);
        friend ostream &operator<< (ostream &salida, const Monomio &m){
            if(m.getCoeficiente() == 1 || m.getCoeficiente() == -1){
                if(m.getGrado() == 1 && m.getCoeficiente() == 1)
                    salida << "x";
                else if(m.getGrado() == 1 && m.getCoeficiente() == -1)
                    salida << "-x";
                else
                    salida << "x^" << m.getGrado();
            }
            else{
                if(m.getGrado() == 1)
                    salida << m.getCoeficiente() << "x^";
                else
                    salida << m.getCoeficiente() << "x^" << m.getGrado();
            }
            return salida;
        }
};

void cabeceraEjercicios(){
    system("clear");
    system("tput bold");
    system("tput setab 12");
    cout << "+-------------------------------------------------------+" << endl;
    cout << "| Teófilo Rojas Mata, Práctica 1 de Estructura de Datos |" << endl;
    cout << "+-------------------------------------------------------+" << endl;
    system("tput sgr0");
    cout << endl;
}

int menu(){
    int opcion = -1;

    do{
        cabeceraEjercicios();
        cout << "1.- Obtener el valor de un monomio para un dato concreto de X." << endl;
        cout << "2.- Obtener la multiplicación de dos monomios para almacenar el resultado en un tercero." << endl;
        cout << "0.- Salir sin hacer nada." << endl;
        cout << endl;

        cout << ">> Introduzca la opción deseada..: ";
        cin >> opcion;
        if(opcion == 0)
            cout << "Saliendo..." << endl;
        if(opcion < 0 || opcion > 2){
            system("tput setaf 1");
            cout << "Error de opcion." << endl;
            system("tput sgr0");
            cout << "Presione intro para continuar..." << endl;
            cin.ignore();
            cin.get();
        }
    }while(opcion < 0 || opcion > 2);

    return opcion;
}

#endif
<commit_msg>Modificado bool operator==<commit_after>#ifndef __MONOMIO_HPP__
#define __MONOMIO_HPP__
#include <iostream>
#include <cmath>
#include <cstdlib> // Para los systems del menú en linux
#include "monomiointerfaz.hpp"

using std::cout;
using std::cin;
using std::endl;
using std::ostream;
using std::istream;

class Monomio:public ed::MonomioInterfaz{
    private:
        double coeficiente_;
        int grado_;
    public:
        Monomio(double coeficiente = 1, int grado = 1){ //Constructor inicializado
            setGrado(grado);
            setCoeficiente(coeficiente);
        }

        Monomio(const Monomio &m){
            setGrado(m.grado_);
            setCoeficiente(m.coeficiente_);
        }

        int getGrado() const{
            return grado_;
        }

        double getCoeficiente() const{
            return coeficiente_;
        }
        void setGrado(int grado){
            grado_ = grado;
        }

        void setCoeficiente(double coeficiente){
            coeficiente_ = coeficiente;
        }

        void escribirMonomio(){
            cout << getCoeficiente() << "x^" << getGrado();
        }

        void leerMonomio(){
            int grado;
            double coeficiente;

            cout << "Introduzca el coeficiente del monomio..: " << endl;
            cin >> coeficiente;
            cout << "Introduzca el grado del monomio..: " << endl;
            cin >> grado;
            setGrado(grado);
            setCoeficiente(coeficiente);
        }

        Monomio &operator= (const Monomio &recibido){
            this->setGrado(recibido.getGrado());
            this->setCoeficiente(recibido.getCoeficiente());

            return *this;
        }

        Monomio &operator+ (const Monomio &recibido){
            if(this->getGrado() == recibido.getGrado()){
                this->setCoeficiente(this->getCoeficiente() + recibido.getCoeficiente());
                return *this;
            }
            cout << "La suma no se ha podido realizar porque los grados de los monomios no son iguales" << endl;
            return *this;
        }

        bool operator== (Monomio &aux){
        	return (this->getGrado()==aux.getGrado()) &&
        		   (this->getCoeficiente()==aux.getCoeficiente());
        }

        Monomio operator* (const Monomio &m2){
            Monomio resultado(1,0);

            resultado.setGrado(this->getGrado() + m2.getGrado());
            resultado.setCoeficiente(this->getCoeficiente() * m2.getCoeficiente());

            return resultado;
        }

        double resuelveMonomio(double valorX){
            double resultado;
            resultado = pow(valorX * getCoeficiente(), getGrado());

            return resultado;
        }

        //friend istream &operator>>(istream &stream, Monomio &m);
        //friend ostream &operator<<(ostream &stream, Monomio const &m);
        friend ostream &operator<< (ostream &salida, const Monomio &m){
            if(m.getCoeficiente() == 1 || m.getCoeficiente() == -1){
                if(m.getGrado() == 1 && m.getCoeficiente() == 1)
                    salida << "x";
                else if(m.getGrado() == 1 && m.getCoeficiente() == -1)
                    salida << "-x";
                else
                    salida << "x^" << m.getGrado();
            }
            else{
                if(m.getGrado() == 1)
                    salida << m.getCoeficiente() << "x^";
                else
                    salida << m.getCoeficiente() << "x^" << m.getGrado();
            }
            return salida;
        }
};

void cabeceraEjercicios(){
    system("clear");
    system("tput bold");
    system("tput setab 12");
    cout << "+-------------------------------------------------------+" << endl;
    cout << "| Teófilo Rojas Mata, Práctica 1 de Estructura de Datos |" << endl;
    cout << "+-------------------------------------------------------+" << endl;
    system("tput sgr0");
    cout << endl;
}

int menu(){
    int opcion = -1;

    do{
        cabeceraEjercicios();
        cout << "1.- Obtener el valor de un monomio para un dato concreto de X." << endl;
        cout << "2.- Obtener la multiplicación de dos monomios para almacenar el resultado en un tercero." << endl;
        cout << "0.- Salir sin hacer nada." << endl;
        cout << endl;

        cout << ">> Introduzca la opción deseada..: ";
        cin >> opcion;
        if(opcion == 0)
            cout << "Saliendo..." << endl;
        if(opcion < 0 || opcion > 2){
            system("tput setaf 1");
            cout << "Error de opcion." << endl;
            system("tput sgr0");
            cout << "Presione intro para continuar..." << endl;
            cin.ignore();
            cin.get();
        }
    }while(opcion < 0 || opcion > 2);

    return opcion;
}

#endif
<|endoftext|>


<commit_before>#include "inc/cLang.h"

LangCompiler::LangCompiler(int ID){
	thID = ID;
	timeOut = 2000/1000;
}

LangCompiler::~LangCompiler(){

}

string LangCompiler::compile(string code, bool show, compilerFlag flags)
{
	string res;
	warning_err.clear();
	result.clear();
	cout.flush();

	if(!generetionSample(code, flags))
	{
		ERROR("Canot open file with generation source code, maybe permission denied	");
		return "Canot open file with generation source code, maybe permission denied";
	}
	//l12("11111111111111111111111");
	//l12(code);
	cout.flush();
	cout.flush();
	string code_file_name;

	string build_str ;
	string prog_name;
	string run_str ;
	switch(flags){
	case Flag_CPP:  //  &> results.txt
		code_file_name = "prog" + to_string(thID) + ".out";
		//build_str = "cd src; clang++ -Wall -stdlib=libc++ code" + to_string(thID) + ".cpp -o ../prog" + to_string(thID) + ".out";
		build_str = "g++ -Wno-deprecated -W ./src/code" + to_string(thID) + ".cpp -o prog" + to_string(thID) +
				".out  2>&1 ;rm ./src/code" + to_string(thID) + ".cpp";  // 2>&1 | tee -a cout.txt
		//".out 2>&1	";
		run_str = " ./prog" + to_string(thID) + ".out 2>&1 ;  rm prog" + to_string(thID) + ".out";
		prog_name = code_file_name;
		break;
	case Flag_Java:
		code_file_name = "Main" + to_string(thID) + ".class";
		build_str = "cd src; javac Main" + to_string(thID) + ".java -d ../ 2>&1";
		run_str = " java Main" + to_string(thID) + " 2>&1 ;  rm Main" + to_string(thID)+".class";
		prog_name = "Main"+to_string(thID)+".class";
		break;
	case Flag_JS:
		code_file_name = "Main" + to_string(thID) + ".js";
		build_str = "cd src; nodejs Main" + to_string(thID) + ".js ../ 2>&1";
		run_str = " node Main" + to_string(thID) + " 2>&1 ;  rm Main" + to_string(thID)+".js";
		prog_name = "Main"+to_string(thID)+".js";
		break;
	case Flag_PHP:
		code_file_name = "./src/Main" + to_string(thID) + ".php";
		build_str = "";
		run_str = "php ./src/Main" + to_string(thID) + ".php 2>&1 ;  ";
		prog_name = code_file_name;
		break;
	case Flag_CS:
		code_file_name = "./src/Main" + to_string(thID) + ".exe";
		build_str = "dmcs ./src/Main" + to_string(thID) + ".cs 2>&1";
		run_str = " mono ./src/Main" + to_string(thID) + ".exe 2>&1 " + "; rm ./src/Main" + to_string(thID) + ".exe";
		prog_name = code_file_name;
		break;
	}//java -jar js.jar myscript.js

	/*
	 * BETA // don't delete
	 *
	in.append("cd /var/www/fcgi/srs/; clang++ -Wall -stdlib=libc++ code$1.cpp -o prog$1.out; if [ -f /var/www/fcgi/srs/prog$1.out ]; then  ./prog$1.out;  rm prog$1.out; fi");
	in.append("cd /var/www/fcgi/srs/;");
	in.append("clang++ -Wall -stdlib=libc++ code" + to_string(thID) + ".cpp -o prog" + to_string(thID) + ".out;");
	in.append("if [ -f /var/www/fcgi/srs/" + code_file_name + " ]; then ./" + code_file_name) + ";";
	in.append("rm prog.out;");
	in.append("fi;");*/
	long double  comp_time;
	string warning = getStdoutFromCommand(build_str, 0, &comp_time);

	//cout << "\n\n\n" << warning;
	//l12("2222222222222222222");
	//l12(warning);
	if (flags == Flag_JS)
	{
		if (warning.find("project/src/Main") != string::npos)
		{
			//warning.erase(0, warning.find("\n") + 1);
			warning.erase(0, warning.find(".js:") + 4);

			string line = warning;
			line.erase(line.find("\n"), line.size() - 1);
			std::string::size_type sz;
			int error_line = std::stoi( line, &sz );
			error_line -= 12;
			warning.erase(0, warning.find("\n"));
			warning = "error in:" + to_string(error_line) + warning;
		}
	}

	warning_err.append(warning);

	//INFO("build time: " + to_string(comp_time) + warning_err);
	cout.flush();
	if(fileExist(prog_name))
	{
		string std_out_string = getStdoutFromCommand(run_str, 0, &comp_time);
		result.append(std_out_string);
		//l12("333333333333333333");
		//l12(std_out_string);

		//INFO("compute time: " + to_string(comp_time));
	}
	else
	{
		ERROR("cLang colpilation: file not exist");
	}
	cout.flush();
	/*
	 * parse error and result if not found err
	 */
	if(flags == Flag_JS)
	{
		if(std::size_t pos = warning_err.find("/var/www/fcgi/src/") != -1)      // position of "live" in str
		{
			warning_err = warning_err.substr (pos + 18); // 18 - Length of @/var/www/fcgi/src/@
			result = " ";
		}
		else
		{
			result = warning_err;
			warning_err = "";
		}

	}
	if(show)
	{
		//res.append(in);
		res.append("<form><textarea style=\"width: 100%; height: 400px;\">");
		if(result.size() <= 1 && warning_err.size() <= 1)
			res.append("=======OK=======");
		else
			res.append(warning_err + result);
		res.append("</textarea></form>");
		return res;
	}
	else
		res.append(warning_err + result);
	cout.flush();
	return res;

	/*cout << "Content-type: text/html\r\n"
						 << "\r\n"
						 << "\n"
						 << "  \n"
						 << "    <title>Result!</title>\n"
						 << "  \n"
						 << "  \n";*/
	//cout << "<form><textarea style=\"width: 100%; height: 400px;\">"  << k<< "</textarea></form>";
	/*cout << "  \n"
						 << "\n";*/
}

bool LangCompiler::generetionSample(string code, compilerFlag flags)
{
	std::ofstream cout("cout.txt", std::ios::out);
	// in the future
	cout.flush();
	ofstream file;
	char str[50];
	switch (flags)
	{
	case Flag_CPP:
		sprintf(str, "src/code%d.cpp\0", thID);
		//INFO(str);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;

		break;
	case Flag_Java:
		replaceAll(code,"{{thId}}",to_string(thID));
		sprintf(str, "src/Main%d.java\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;
	case Flag_PHP:
		sprintf(str, "src/Main%d.php\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;
	case Flag_CS:
		sprintf(str, "src/Main%d.cs\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;
	case Flag_JS:
		sprintf(str, "src/Main%d.js\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;

	}
	cout.flush();
	file << code;
	file.close();
	cout.flush();

	return true;
}

char* LangCompiler::getSystemOutput(char* cmd){
	int buff_size = 32;
	char buff[buff_size+1]; memset((char*)&buff, 0, buff_size+1);

	char* ret = NULL;
	string str = "";

	int fd[2];
	int old_fd[3];
	pipe(fd);

	old_fd[0] = !STDIN_FILENO;
	old_fd[1] = !STDOUT_FILENO;
	old_fd[2] = !STDERR_FILENO;

	old_fd[0] = dup(STDIN_FILENO);
	old_fd[1] = dup(STDOUT_FILENO);
	old_fd[2] = dup(STDERR_FILENO);

	int pid = fork();
	switch(pid){
	case 0:
		close(fd[0]);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);
		dup2(fd[1], STDOUT_FILENO);
		dup2(fd[1], STDERR_FILENO);
		system(cmd);
		close (fd[1]);
		exit(1);
		break;
	case -1:
		cerr << "GetSystemOutput/fork() error\n" << endl;
		exit(1);
	default:
		close(fd[1]);
		dup2(fd[0], STDIN_FILENO);

		while (read(fd[0], buff, buff_size)){
			str.append(buff);
			memset(buff, 0, buff_size);
		}

		ret = new char (strlen((char*)str.c_str()));

		strcpy(ret, (char*)str.c_str());

		waitpid(pid, NULL, 0);
		close(fd[0]);
	}

	dup2(STDIN_FILENO, old_fd[0]);
	dup2(STDOUT_FILENO, old_fd[1]);
	dup2(STDERR_FILENO, old_fd[2]);

	return ret;
}

string LangCompiler::getStdoutFromCommand(string cmd, int mTimeOut, long double *executionTime)
{
	string data="";
	FILE * stream;
	std::clock_t    start;
	start = std::clock();
	// your test
	//     std::cout << "Time: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;
	const int max_buffer = 256;
	char buffer[max_buffer];

	//cmd.append(" 2>&1 ");//>/dev/null
	const long double sysTime = time(0) *1000;
	//printf("%lf", sysTime);
	//  const long double sysTimeMS = sysTime*1000;
	//stream =

	stream = popen(cmd.c_str(), "r");

	if (stream) {
		while (!feof(stream))
		{
			if (fgets(buffer, max_buffer, stream) != NULL)
				data.append(buffer);
			if (mTimeOut != 0 && (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) > mTimeOut)
			{
				data = "timeout";
				break;
			}
		}
		if(executionTime != 0)
			executionTime[0] = (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000);
		//INFO(to_string(time(0)));
		pclose(stream);
	}

	/*std::ifstream in ;
	in << popen(cmd.c_str(), "r");
	std::string contents((std::istreambuf_iterator<char>(in)),
	    std::istreambuf_iterator<char>());
	data = contents;*/
	return data;
	/*std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
	    if (!pipe) return "ERROR";
	    char buffer[128];
	    std::string result = "";
	    while (!feof(pipe.get())) {
	        if (fgets(buffer, 128, pipe.get()) != NULL)
	            result += buffer;
	    }
	    return result;*/
}

long double LangCompiler::getTimeOut() const{
	return timeOut*1000;
}

void LangCompiler::setTimeOut(long double timeOut) {
	this->timeOut = timeOut/1000;
}

bool LangCompiler::fileExist( string name )
{
	FILE *file;
	if (file = fopen(name.c_str(), "r"))
	{
		fclose(file);
		return 1;
	}
	return 0;
	/*if( access( name.c_str(), F_OK ) != -1 ) {
	    return 1;
	} else {
		return 0;
	}*/
}

bool LangCompiler::fileRemove ( string name )
{
	remove(name.c_str() );
}

const string& LangCompiler::getResult() const {
	return result;
}

int LangCompiler::getThId() const {
	return thID;
}

const string& LangCompiler::getWarningErr() const {
	return warning_err;
}
LangCompiler::compilerFlag LangCompiler::convertFromName(string lang)
{
	if (lang == "c++" || lang == "C++")
		return LangCompiler::Flag_CPP;
	else if (lang == "Java" || lang == "java")
		return LangCompiler::Flag_Java;
	else if (lang == "JS" || lang == "js")
		return LangCompiler::Flag_JS;
	else if (lang == "PHP" || lang == "php")
		return LangCompiler::Flag_PHP;
	else if (lang == "C#" || lang == "c#" || lang == "CS" || lang == "cs" )
		return LangCompiler::Flag_CS;
	else
		return LangCompiler::Flag_CPP;
}

<commit_msg>cout in file<commit_after>#include "inc/cLang.h"

LangCompiler::LangCompiler(int ID){
	thID = ID;
	timeOut = 2000/1000;
}

LangCompiler::~LangCompiler(){

}

string LangCompiler::compile(string code, bool show, compilerFlag flags)
{
	string res;
	warning_err.clear();
	result.clear();
	cout.flush();

	if(!generetionSample(code, flags))
	{
		ERROR("Canot open file with generation source code, maybe permission denied	");
		return "Canot open file with generation source code, maybe permission denied";
	}
	//l12("11111111111111111111111");
	//l12(code);
	cout.flush();
	cout.flush();
	string code_file_name;

	string build_str ;
	string prog_name;
	string run_str ;
	switch(flags){
	case Flag_CPP:  //  &> results.txt
		code_file_name = "prog" + to_string(thID) + ".out";
		//build_str = "cd src; clang++ -Wall -stdlib=libc++ code" + to_string(thID) + ".cpp -o ../prog" + to_string(thID) + ".out";
		build_str = "g++ -Wno-deprecated -W ./src/code" + to_string(thID) + ".cpp -o prog" + to_string(thID) +
				".out  2>&1 | tee -a cout.txt;rm ./src/code" + to_string(thID) + ".cpp";  // 2>&1 | tee -a cout.txt
		//".out 2>&1	";
		run_str = " ./prog" + to_string(thID) + ".out 2>&1 | tee -a cout.txt;  rm prog" + to_string(thID) + ".out";
		prog_name = code_file_name;
		break;
	case Flag_Java:
		code_file_name = "Main" + to_string(thID) + ".class";
		build_str = "cd src; javac Main" + to_string(thID) + ".java -d ../ 2>&1 |  tee -a cout.txt";
		run_str = " java Main" + to_string(thID) + " 2>&1 |  tee -a cout.txt ;  rm Main" + to_string(thID)+".class";
		prog_name = "Main"+to_string(thID)+".class";
		break;
	case Flag_JS:
		code_file_name = "Main" + to_string(thID) + ".js";
		build_str = "cd src; nodejs Main" + to_string(thID) + ".js ../ 2>&1 |  tee -a cout.txt";
		run_str = " node Main" + to_string(thID) + " 2>&1 |  tee -a cout.txt ;  rm Main" + to_string(thID)+".js";
		prog_name = "Main"+to_string(thID)+".js";
		break;
	case Flag_PHP:
		code_file_name = "./src/Main" + to_string(thID) + ".php";
		build_str = "";
		run_str = "php ./src/Main" + to_string(thID) + ".php 2>&1 |  tee -a cout.txt ;  ";
		prog_name = code_file_name;
		break;
	case Flag_CS:
		code_file_name = "./src/Main" + to_string(thID) + ".exe";
		build_str = "dmcs ./src/Main" + to_string(thID) + ".cs 2>&1 |  tee -a cout.txt";
		run_str = " mono ./src/Main" + to_string(thID) + ".exe 2>&1 |  tee -a cout.txt " + "; rm ./src/Main" + to_string(thID) + ".exe";
		prog_name = code_file_name;
		break;
	}//java -jar js.jar myscript.js

	/*
	 * BETA // don't delete
	 *
	in.append("cd /var/www/fcgi/srs/; clang++ -Wall -stdlib=libc++ code$1.cpp -o prog$1.out; if [ -f /var/www/fcgi/srs/prog$1.out ]; then  ./prog$1.out;  rm prog$1.out; fi");
	in.append("cd /var/www/fcgi/srs/;");
	in.append("clang++ -Wall -stdlib=libc++ code" + to_string(thID) + ".cpp -o prog" + to_string(thID) + ".out;");
	in.append("if [ -f /var/www/fcgi/srs/" + code_file_name + " ]; then ./" + code_file_name) + ";";
	in.append("rm prog.out;");
	in.append("fi;");*/
	long double  comp_time;
	string warning = getStdoutFromCommand(build_str, 0, &comp_time);

	//cout << "\n\n\n" << warning;
	//l12("2222222222222222222");
	//l12(warning);
	if (flags == Flag_JS)
	{
		if (warning.find("project/src/Main") != string::npos)
		{
			//warning.erase(0, warning.find("\n") + 1);
			warning.erase(0, warning.find(".js:") + 4);

			string line = warning;
			line.erase(line.find("\n"), line.size() - 1);
			std::string::size_type sz;
			int error_line = std::stoi( line, &sz );
			error_line -= 12;
			warning.erase(0, warning.find("\n"));
			warning = "error in:" + to_string(error_line) + warning;
		}
	}

	warning_err.append(warning);

	//INFO("build time: " + to_string(comp_time) + warning_err);
	cout.flush();
	if(fileExist(prog_name))
	{
		string std_out_string = getStdoutFromCommand(run_str, 0, &comp_time);
		result.append(std_out_string);
		//l12("333333333333333333");
		//l12(std_out_string);

		//INFO("compute time: " + to_string(comp_time));
	}
	else
	{
		ERROR("cLang colpilation: file not exist");
	}
	cout.flush();
	/*
	 * parse error and result if not found err
	 */
	if(flags == Flag_JS)
	{
		if(std::size_t pos = warning_err.find("/var/www/fcgi/src/") != -1)      // position of "live" in str
		{
			warning_err = warning_err.substr (pos + 18); // 18 - Length of @/var/www/fcgi/src/@
			result = " ";
		}
		else
		{
			result = warning_err;
			warning_err = "";
		}

	}
	if(show)
	{
		//res.append(in);
		res.append("<form><textarea style=\"width: 100%; height: 400px;\">");
		if(result.size() <= 1 && warning_err.size() <= 1)
			res.append("=======OK=======");
		else
			res.append(warning_err + result);
		res.append("</textarea></form>");
		return res;
	}
	else
		res.append(warning_err + result);
	cout.flush();
	return res;

	/*cout << "Content-type: text/html\r\n"
						 << "\r\n"
						 << "\n"
						 << "  \n"
						 << "    <title>Result!</title>\n"
						 << "  \n"
						 << "  \n";*/
	//cout << "<form><textarea style=\"width: 100%; height: 400px;\">"  << k<< "</textarea></form>";
	/*cout << "  \n"
						 << "\n";*/
}

bool LangCompiler::generetionSample(string code, compilerFlag flags)
{
	std::ofstream cout("cout.txt", std::ios::out);
	// in the future
	cout.flush();
	ofstream file;
	char str[50];
	switch (flags)
	{
	case Flag_CPP:
		sprintf(str, "src/code%d.cpp\0", thID);
		//INFO(str);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;

		break;
	case Flag_Java:
		replaceAll(code,"{{thId}}",to_string(thID));
		sprintf(str, "src/Main%d.java\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;
	case Flag_PHP:
		sprintf(str, "src/Main%d.php\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;
	case Flag_CS:
		sprintf(str, "src/Main%d.cs\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;
	case Flag_JS:
		sprintf(str, "src/Main%d.js\0", thID);
		file.open(str, fstream::out);
		if(!file.is_open())
			return false;
		break;

	}
	cout.flush();
	file << code;
	file.close();
	cout.flush();

	return true;
}

char* LangCompiler::getSystemOutput(char* cmd){
	int buff_size = 32;
	char buff[buff_size+1]; memset((char*)&buff, 0, buff_size+1);

	char* ret = NULL;
	string str = "";

	int fd[2];
	int old_fd[3];
	pipe(fd);

	old_fd[0] = !STDIN_FILENO;
	old_fd[1] = !STDOUT_FILENO;
	old_fd[2] = !STDERR_FILENO;

	old_fd[0] = dup(STDIN_FILENO);
	old_fd[1] = dup(STDOUT_FILENO);
	old_fd[2] = dup(STDERR_FILENO);

	int pid = fork();
	switch(pid){
	case 0:
		close(fd[0]);
		close(STDOUT_FILENO);
		close(STDERR_FILENO);
		dup2(fd[1], STDOUT_FILENO);
		dup2(fd[1], STDERR_FILENO);
		system(cmd);
		close (fd[1]);
		exit(1);
		break;
	case -1:
		cerr << "GetSystemOutput/fork() error\n" << endl;
		exit(1);
	default:
		close(fd[1]);
		dup2(fd[0], STDIN_FILENO);

		while (read(fd[0], buff, buff_size)){
			str.append(buff);
			memset(buff, 0, buff_size);
		}

		ret = new char (strlen((char*)str.c_str()));

		strcpy(ret, (char*)str.c_str());

		waitpid(pid, NULL, 0);
		close(fd[0]);
	}

	dup2(STDIN_FILENO, old_fd[0]);
	dup2(STDOUT_FILENO, old_fd[1]);
	dup2(STDERR_FILENO, old_fd[2]);

	return ret;
}

string LangCompiler::getStdoutFromCommand(string cmd, int mTimeOut, long double *executionTime)
{
	string data="";
	FILE * stream;
	std::clock_t    start;
	start = std::clock();
	// your test
	//     std::cout << "Time: " << (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) << " ms" << std::endl;
	const int max_buffer = 256;
	char buffer[max_buffer];

	//cmd.append(" 2>&1 ");//>/dev/null
	const long double sysTime = time(0) *1000;
	//printf("%lf", sysTime);
	//  const long double sysTimeMS = sysTime*1000;
	//stream =

	stream = popen(cmd.c_str(), "r");

	if (stream) {
		while (!feof(stream))
		{
			if (fgets(buffer, max_buffer, stream) != NULL)
				data.append(buffer);
			if (mTimeOut != 0 && (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000) > mTimeOut)
			{
				data = "timeout";
				break;
			}
		}
		if(executionTime != 0)
			executionTime[0] = (std::clock() - start) / (double)(CLOCKS_PER_SEC / 1000);
		//INFO(to_string(time(0)));
		pclose(stream);
	}

	/*std::ifstream in ;
	in << popen(cmd.c_str(), "r");
	std::string contents((std::istreambuf_iterator<char>(in)),
	    std::istreambuf_iterator<char>());
	data = contents;*/
	return data;
	/*std::shared_ptr<FILE> pipe(popen(cmd.c_str(), "r"), pclose);
	    if (!pipe) return "ERROR";
	    char buffer[128];
	    std::string result = "";
	    while (!feof(pipe.get())) {
	        if (fgets(buffer, 128, pipe.get()) != NULL)
	            result += buffer;
	    }
	    return result;*/
}

long double LangCompiler::getTimeOut() const{
	return timeOut*1000;
}

void LangCompiler::setTimeOut(long double timeOut) {
	this->timeOut = timeOut/1000;
}

bool LangCompiler::fileExist( string name )
{
	FILE *file;
	if (file = fopen(name.c_str(), "r"))
	{
		fclose(file);
		return 1;
	}
	return 0;
	/*if( access( name.c_str(), F_OK ) != -1 ) {
	    return 1;
	} else {
		return 0;
	}*/
}

bool LangCompiler::fileRemove ( string name )
{
	remove(name.c_str() );
}

const string& LangCompiler::getResult() const {
	return result;
}

int LangCompiler::getThId() const {
	return thID;
}

const string& LangCompiler::getWarningErr() const {
	return warning_err;
}
LangCompiler::compilerFlag LangCompiler::convertFromName(string lang)
{
	if (lang == "c++" || lang == "C++")
		return LangCompiler::Flag_CPP;
	else if (lang == "Java" || lang == "java")
		return LangCompiler::Flag_Java;
	else if (lang == "JS" || lang == "js")
		return LangCompiler::Flag_JS;
	else if (lang == "PHP" || lang == "php")
		return LangCompiler::Flag_PHP;
	else if (lang == "C#" || lang == "c#" || lang == "CS" || lang == "cs" )
		return LangCompiler::Flag_CS;
	else
		return LangCompiler::Flag_CPP;
}

<|endoftext|>


<commit_before>#ifndef MUNCHAR
#define MUNCHAR

#include <cstddef>

namespace Munchar {

  // Unconditional success

  struct Success {
    const char* operator()(const char* b, const char* e) const {
      return b;
    }
  };

  // Unconditional failure

  struct Failure {
    const char* operator()(const char* b, const char* e) const {
      return nullptr;
    }
  };

  // Arbitrary character

  struct Any_Char {
    const char* operator()(const char* b, const char* e) const {
      return b != e ? b+1 : nullptr;
    }
  };

  // Character constant

  class Char {
    const char c_;
  public:
    constexpr Char(const char c) : c_(c) { }
    const char* operator()(const char* b, const char* e) const {
      return b != e && *b == c_ ? b+1 : nullptr;
    }
  };

  constexpr Char operator"" _lit(const char c) {
    return Char { c };
  }

  // String constant

  template<typename Ptr = const char*>
  class Str {
    Ptr s_;
    size_t len_;
  public:
    constexpr Str(Ptr s, size_t len) : s_(s), len_(len) { }
    const char* operator()(const char* b, const char* e) const {
      Ptr s = s_;
      for (size_t i = 0; i < len_; ++i, ++b, ++s) {
        if ((b == e) || (*s_ != *b)) return nullptr;
      }
      return b;
    }
  };

  constexpr Str<> operator"" _lit(const char* c, size_t len) {
    return Str<> { c, len };
  }

  // Character class

  template<typename Ptr = const char*>
  class Char_Class {
    Ptr s_;
    size_t len_;
  public:
    constexpr Char_Class(Ptr s, size_t len) : s_(s), len_(len) { }
    const char* operator()(const char* b, const char* e) const {
      if (b == e) return nullptr;
      Ptr s = s_;
      for (size_t i = 0; i < len_; ++i, ++s) if (*s == *b) return b+1;
      return nullptr;
    }
  };

  constexpr Char_Class<> operator"" _cls(const char* c, size_t len) {
    return Char_Class<> { c, len };
  }

  // Base class for unary combinators

  template<typename M>
  class Unary {
  protected:
    const M m_;
  public:
    constexpr Unary(const M& m) : m_(m) { }
  };

  // Base class for binary combinators

  template<typename L, typename R>
  class Binary {
  protected:
    const L l_;
    const R r_;
  public:
    constexpr Binary(const L& l, const R& r) : l_(l), r_(r) { }
  };

  // Sequencing

  template<typename L, typename R>
  class Sequence : public Binary<L, R> {
  public:
    using Binary<L, R>::Binary;
    const char* operator()(const char* b, const char* e) const {
      return (b = this->l_(b, e)) ? this->r_(b, e) : nullptr;
    }
  };

  template<typename L, typename R>
  constexpr Sequence<L, R> operator^(const L& l, const R& r) {
    return Sequence<L, R> { l, r };
  }

  // Alternation

  template<typename L, typename R>
  class Alternation : public Binary<L, R> {
  public:
    using Binary<L, R>::Binary;
    const char* operator()(const char* b, const char* e) const {
      return (b = this->l_(b, e)) ? b : this->r_(b, e);
    }
  };

  template<typename L, typename R>
  constexpr Alternation<L, R> operator|(const L& l, const R& r) {
    return Alternation<L, R> { l, r };
  }

  // Option

  template<typename M>
  constexpr auto operator~(const M& m)
  -> decltype(m | Success { }) {
    return m | Success { };
  }

  // Repetition

  template<typename M>
  class Zero_Or_More : public Unary<M> {
  public:
    using Unary<M>::Unary;
    const char* operator()(const char* b, const char* e) const {
      for (const char* p = b; (p = this->m_(b, e)); b = p) ;
      return b;
    }
  };

  template<typename M>
  constexpr Zero_Or_More<M> operator*(const M& m) {
    return Zero_Or_More<M> { m };
  }

  template<typename M>
  constexpr auto operator+(const M& m)
  -> decltype(m ^ *m) {
    return m ^ *m;
  }

  // Bounded repetition

  template<typename M>
  class Exactly_N_Times : public Unary<M> {
    size_t n_;
  public:
    constexpr Exactly_N_Times(const M& m, size_t n) : Unary<M> { m }, n_(n) { }
    const char* operator()(const char* b, const char* e) const {
      size_t i;
      for (i = 0; i < n_ && (b = this->m_(b, e)); ++i) ;
      return i == n_ ? b : nullptr;
    }
  };

  template<typename M>
  constexpr Exactly_N_Times<M> operator==(const M& m,  size_t n) {
    return Exactly_N_Times<M> { m, n };
  }

  template<typename M>
  constexpr auto operator>(const M& m,  size_t n)
  -> decltype((m == n) ^ +m) {
    return (m == n) ^ +m;
  }

  template<typename M>
  constexpr auto operator>=(const M& m,  size_t n)
  -> decltype((m == n) ^ *m) {
    return (m == n) ^ *m;
  }

  template<typename M>
  constexpr auto operator<(const M& m,  size_t n)
  -> decltype((m == n-1) | *m) {
    return (m == n-1) | *m;
  }

  template<typename M>
  constexpr auto operator<=(const M& m,  size_t n)
  -> decltype((m == n) | *m) {
    return (m == n) | *m;
  }

  template<typename M>
  constexpr auto between(size_t a, size_t b, const M& m)
  -> decltype((m == a) ^ (m <= b)) {
    return (m == a) ^ (m <= b);
  }

  // Negation

  template<typename M>
  class Negation : Unary<M> {
  public:
    using Unary<M>::Unary;
    const char* operator()(const char* b, const char* e) const {
      return this->m_(b, e) ? nullptr : b;
    }
  };

  template<typename M>
  constexpr Negation<M> operator!(const M& m) {
    return Negation<M> { m };
  }

  // Lookahead

  template<typename M>
  class Lookahead : Unary<M> {
  public:
    using Unary<M>::Unary;
    const char* operator()(const char* b, const char* e) const {
      return this->m_(b, e) ? b : nullptr;
    }
  };

  template<typename M>
  constexpr Lookahead<M> operator&(const M& m) {
    return Lookahead<M> { m };
  }

  // Predicate

  template<typename P>
  class Predicate {
    const P p_;
  public:
    constexpr Predicate(const P& p) : p_(p) { }
    const char* operator()(const char* b, const char* e) const {
      return (b != e) && p_(*b) ? b+1 : nullptr;
    }
  };

  template<typename I, typename O>
  class Predicate<O (*)(I)> {
    O (*const p_)(I);
  public:
    constexpr Predicate(O (*const p)(I)) : p_(p) { }
    const char* operator()(const char* b, const char* e) const {
      return (b != e) && p_(*b) ? b+1 : nullptr;
    }
  };

  template<typename PT>
  constexpr Predicate<PT> P(const PT& p) {
    return Predicate<PT> { p };
  }

  template<typename I, typename O>
  constexpr Predicate<O (*)(I)> P(O (*const p)(I)) {
    return Predicate<O (*)(I)> { p };
  }

}

#endif<commit_msg>adding a class for lifting plain functions<commit_after>#ifndef MUNCHAR
#define MUNCHAR

#include <cstddef>

namespace Munchar {

  // Unconditional success

  struct Success {
    const char* operator()(const char* b, const char* e) const {
      return b;
    }
  };

  // Unconditional failure

  struct Failure {
    const char* operator()(const char* b, const char* e) const {
      return nullptr;
    }
  };

  // Arbitrary character

  struct Any_Char {
    const char* operator()(const char* b, const char* e) const {
      return b != e ? b+1 : nullptr;
    }
  };

  // Character constant

  class Char {
    const char c_;
  public:
    constexpr Char(const char c) : c_(c) { }
    const char* operator()(const char* b, const char* e) const {
      return b != e && *b == c_ ? b+1 : nullptr;
    }
  };

  constexpr Char operator"" _lit(const char c) {
    return Char { c };
  }

  // String constant

  template<typename Ptr = const char*>
  class Str {
    Ptr s_;
    size_t len_;
  public:
    constexpr Str(Ptr s, size_t len) : s_(s), len_(len) { }
    const char* operator()(const char* b, const char* e) const {
      Ptr s = s_;
      for (size_t i = 0; i < len_; ++i, ++b, ++s) {
        if ((b == e) || (*s_ != *b)) return nullptr;
      }
      return b;
    }
  };

  constexpr Str<> operator"" _lit(const char* c, size_t len) {
    return Str<> { c, len };
  }

  // Character class

  template<typename Ptr = const char*>
  class Char_Class {
    Ptr s_;
    size_t len_;
  public:
    constexpr Char_Class(Ptr s, size_t len) : s_(s), len_(len) { }
    const char* operator()(const char* b, const char* e) const {
      if (b == e) return nullptr;
      Ptr s = s_;
      for (size_t i = 0; i < len_; ++i, ++s) if (*s == *b) return b+1;
      return nullptr;
    }
  };

  constexpr Char_Class<> operator"" _cls(const char* c, size_t len) {
    return Char_Class<> { c, len };
  }

  // Predicate

  template<typename P>
  class Predicate {
    const P p_;
  public:
    constexpr Predicate(const P& p) : p_(p) { }
    const char* operator()(const char* b, const char* e) const {
      return (b != e) && p_(*b) ? b+1 : nullptr;
    }
  };

  template<typename I, typename O>
  class Predicate<O (*)(I)> {
    O (*const p_)(I);
  public:
    constexpr Predicate(O (*const p)(I)) : p_(p) { }
    const char* operator()(const char* b, const char* e) const {
      return (b != e) && p_(*b) ? b+1 : nullptr;
    }
  };

  template<typename PT>
  constexpr Predicate<PT> P(const PT& p) {
    return Predicate<PT> { p };
  }

  template<typename I, typename O>
  constexpr Predicate<O (*)(I)> P(O (*const p)(I)) {
    return Predicate<O (*)(I)> { p };
  }

  // Function

  class Function {
    const char* (*f_)(const char*, const char*);
  public:
    constexpr Function(const char* (*f)(const char*, const char*)) : f_(f) { }
    const char* operator()(const char* b, const char* e) const {
      return f_(b, e);
    }
  };

  constexpr Function F(const char* (*f)(const char*, const char*)) {
    return Function { f };
  }

  // Base class for unary combinators

  template<typename M>
  class Unary {
  protected:
    const M m_;
  public:
    constexpr Unary(const M& m) : m_(m) { }
  };

  // Base class for binary combinators

  template<typename L, typename R>
  class Binary {
  protected:
    const L l_;
    const R r_;
  public:
    constexpr Binary(const L& l, const R& r) : l_(l), r_(r) { }
  };

  // Sequencing

  template<typename L, typename R>
  class Sequence : public Binary<L, R> {
  public:
    using Binary<L, R>::Binary;
    const char* operator()(const char* b, const char* e) const {
      return (b = this->l_(b, e)) ? this->r_(b, e) : nullptr;
    }
  };

  template<typename L, typename R>
  constexpr Sequence<L, R> operator^(const L& l, const R& r) {
    return Sequence<L, R> { l, r };
  }

  // Alternation

  template<typename L, typename R>
  class Alternation : public Binary<L, R> {
  public:
    using Binary<L, R>::Binary;
    const char* operator()(const char* b, const char* e) const {
      return (b = this->l_(b, e)) ? b : this->r_(b, e);
    }
  };

  template<typename L, typename R>
  constexpr Alternation<L, R> operator|(const L& l, const R& r) {
    return Alternation<L, R> { l, r };
  }

  // Option

  template<typename M>
  constexpr auto operator~(const M& m)
  -> decltype(m | Success { }) {
    return m | Success { };
  }

  // Repetition

  template<typename M>
  class Zero_Or_More : public Unary<M> {
  public:
    using Unary<M>::Unary;
    const char* operator()(const char* b, const char* e) const {
      for (const char* p = b; (p = this->m_(b, e)); b = p) ;
      return b;
    }
  };

  template<typename M>
  constexpr Zero_Or_More<M> operator*(const M& m) {
    return Zero_Or_More<M> { m };
  }

  template<typename M>
  constexpr auto operator+(const M& m)
  -> decltype(m ^ *m) {
    return m ^ *m;
  }

  // Bounded repetition

  template<typename M>
  class Exactly_N_Times : public Unary<M> {
    size_t n_;
  public:
    constexpr Exactly_N_Times(const M& m, size_t n) : Unary<M> { m }, n_(n) { }
    const char* operator()(const char* b, const char* e) const {
      size_t i;
      for (i = 0; i < n_ && (b = this->m_(b, e)); ++i) ;
      return i == n_ ? b : nullptr;
    }
  };

  template<typename M>
  constexpr Exactly_N_Times<M> operator==(const M& m,  size_t n) {
    return Exactly_N_Times<M> { m, n };
  }

  template<typename M>
  constexpr auto operator>(const M& m,  size_t n)
  -> decltype((m == n) ^ +m) {
    return (m == n) ^ +m;
  }

  template<typename M>
  constexpr auto operator>=(const M& m,  size_t n)
  -> decltype((m == n) ^ *m) {
    return (m == n) ^ *m;
  }

  template<typename M>
  constexpr auto operator<(const M& m,  size_t n)
  -> decltype((m == n-1) | *m) {
    return (m == n-1) | *m;
  }

  template<typename M>
  constexpr auto operator<=(const M& m,  size_t n)
  -> decltype((m == n) | *m) {
    return (m == n) | *m;
  }

  template<typename M>
  constexpr auto between(size_t a, size_t b, const M& m)
  -> decltype((m == a) ^ (m <= b)) {
    return (m == a) ^ (m <= b);
  }

  // Negation

  template<typename M>
  class Negation : Unary<M> {
  public:
    using Unary<M>::Unary;
    const char* operator()(const char* b, const char* e) const {
      return this->m_(b, e) ? nullptr : b;
    }
  };

  template<typename M>
  constexpr Negation<M> operator!(const M& m) {
    return Negation<M> { m };
  }

  // Lookahead

  template<typename M>
  class Lookahead : Unary<M> {
  public:
    using Unary<M>::Unary;
    const char* operator()(const char* b, const char* e) const {
      return this->m_(b, e) ? b : nullptr;
    }
  };

  template<typename M>
  constexpr Lookahead<M> operator&(const M& m) {
    return Lookahead<M> { m };
  }

}

#endif<|endoftext|>


<commit_before>/* Copyright (c) 2017-2018 ARM Limited
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.
 */

#if !defined(COMPONENT_PSA_SRV_IPC)
#error [NOT_SUPPORTED] Test supported only on PSA targets
#endif

#if (defined( __CC_ARM ) || defined(__ARMCC_VERSION) || defined( __ICCARM__ ))
#error [NOT_SUPPORTED] this test is supported on GCC only
#endif

#if defined(TARGET_FUTURE_SEQUANA_PSA)
#error [NOT_SUPPORTED] Disable this Test until FUTURE_SEQUANA_PSA enables Memory protection
#endif

#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "cmsis.h"
#include "spm_api.h"
#include <stdlib.h>
#include "fault_functions.h"

using namespace utest::v1;

#define HARDFAULT_IRQn   ((IRQn_Type)-13)
#define EXC_RETURN_RETURN_STACK_MSK ((uint32_t)(0x00000004))
#define PC_INDEX_IN_STACK_FRAME 6

volatile uint32_t fault_occurred;
uint32_t real_hard_fault_handler;

__STATIC_FORCEINLINE uint32_t __get_LR(void)
{
    uint32_t result;

    __ASM volatile("MOV %0, lr" : "=r"(result));
    return (result);
}

void do_nothing(void)
{
    __NOP();
}

static void hard_fault_handler_test()
{
    fault_occurred++;
    // LR is set EXC_RETURN
    // lowest bits identify PSP vs MSP stack used for stacking
    uint32_t lr = __get_LR();
    uint32_t sp;

    if (lr & EXC_RETURN_RETURN_STACK_MSK) {
        sp = __get_PSP();
    } else {
        sp = __get_MSP();
    }

    // Overwrite return address.
    // Fake return to a our special function since current
    // instruction under test will always fail due to memory protection
    ((uint32_t *)sp)[PC_INDEX_IN_STACK_FRAME] = (uint32_t)do_nothing;
}

__attribute__((naked)) void call_mem(uint32_t addr)
{
    // Only first instruction will be executed in positive flow,
    // since exception will be generated for invalid memory access.
    // Other instructions are for calling do_nothing function according to AAPCS.
    __ASM(
        "LDR     r1, [r0]\n"
        "BX      lr\n"
    );
}

static void test_memory(uint32_t addr, uint32_t expected_fatal_count)
{
    call_mem(addr);
    // Although call_mem is a "naked" function, it is called using AAPCS.
    // Thus we can assume LR will point to next instruction, and caller save registers are backed up
    TEST_ASSERT_EQUAL(expected_fatal_count, fault_occurred);
}

static void secure_ram_fault_test(void)
{
    test_memory(PSA_SECURE_RAM_START, 1);
}

static void secure_flash_fault_test(void)
{
    test_memory(PSA_SECURE_ROM_START, 1);
}

static void non_secure_ram_fault_test(void)
{
    test_memory(PSA_NON_SECURE_RAM_START, 0);
}

static void non_secure_flash_fault_test(void)
{
    test_memory(PSA_NON_SECURE_ROM_START, 0);
}

utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case)
{
    // Save old hard fault handler and replace it with a new one
    // NOTE: only works when VTOR is set to RAM
    real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn);
    NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
    fault_occurred = 0;

    return greentea_case_setup_handler(source, index_of_case);
}

utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed,
                                            const failure_t reason)
{
    // Restore real hard fault handler
    NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler);

    return greentea_case_teardown_handler(source, passed, failed, reason);
}

Case cases[] = {
    Case("SPM - Access secure RAM",       fault_override_setup, secure_ram_fault_test, fault_override_teardown),
    Case("SPM - Access secure Flash",     fault_override_setup, secure_flash_fault_test, fault_override_teardown),
    Case("SPM - Access non-secure RAM",   fault_override_setup, non_secure_ram_fault_test, fault_override_teardown),
    Case("SPM - Access non-secure Flash", fault_override_setup, non_secure_flash_fault_test, fault_override_teardown),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
#ifndef NO_GREENTEA
    GREENTEA_SETUP(20, "default_auto");
#endif
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    Harness::run(specification);
}
<commit_msg>Fix SPM HAL test<commit_after>/* Copyright (c) 2017-2018 ARM Limited
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * 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.
 */

#if !defined(COMPONENT_PSA_SRV_IPC)
#error [NOT_SUPPORTED] Test supported only on PSA targets
#endif

#if (defined( __CC_ARM ) || defined(__ARMCC_VERSION) || defined( __ICCARM__ ))
#error [NOT_SUPPORTED] this test is supported on GCC only
#endif

#if defined(TARGET_FUTURE_SEQUANA_PSA)
#error [NOT_SUPPORTED] Disable this Test until FUTURE_SEQUANA_PSA enables Memory protection
#endif

#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "cmsis.h"
#include "spm_api.h"
#include <stdlib.h>
#include "fault_functions.h"

using namespace utest::v1;

#define HARDFAULT_IRQn   ((IRQn_Type)-13)
#define EXC_RETURN_RETURN_STACK_MSK ((uint32_t)(0x00000004))
#define PC_INDEX_IN_STACK_FRAME 6

volatile uint32_t fault_occurred;
uint32_t real_hard_fault_handler;

__STATIC_FORCEINLINE uint32_t __get_LR(void)
{
    uint32_t result;

    __ASM volatile("MOV %0, lr" : "=r"(result));
    return (result);
}

void do_nothing(void)
{
    __NOP();
}

static void hard_fault_handler_test()
{
    fault_occurred++;
    // LR is set EXC_RETURN
    // lowest bits identify PSP vs MSP stack used for stacking
    uint32_t lr = __get_LR();
    uint32_t sp;

    if (lr & EXC_RETURN_RETURN_STACK_MSK) {
        sp = __get_PSP();
    } else {
        sp = __get_MSP();
    }

    // Overwrite return address.
    // Fake return to a our special function since current
    // instruction under test will always fail due to memory protection
    ((uint32_t *)sp)[PC_INDEX_IN_STACK_FRAME] = (uint32_t)do_nothing;
}

__attribute__((naked)) void call_mem(uint32_t addr)
{
    // Only first instruction will be executed in positive flow,
    // since exception will be generated for invalid memory access.
    // Other instructions are for calling do_nothing function according to AAPCS.
    __ASM(
        "LDR     r4, [r0]\n"
        "BX      lr\n"
    );
}

static void test_memory(uint32_t addr, uint32_t expected_fatal_count)
{
    call_mem(addr);
    // Although call_mem is a "naked" function, it is called using AAPCS.
    // Thus we can assume LR will point to next instruction, and caller save registers are backed up
    TEST_ASSERT_EQUAL(expected_fatal_count, fault_occurred);
}

static void secure_ram_fault_test(void)
{
    test_memory(PSA_SECURE_RAM_START, 1);
}

static void secure_flash_fault_test(void)
{
    test_memory(PSA_SECURE_ROM_START, 1);
}

static void non_secure_ram_fault_test(void)
{
    test_memory(PSA_NON_SECURE_RAM_START, 0);
}

static void non_secure_flash_fault_test(void)
{
    test_memory(PSA_NON_SECURE_ROM_START, 0);
}

utest::v1::status_t fault_override_setup(const Case *const source, const size_t index_of_case)
{
    // Save old hard fault handler and replace it with a new one
    // NOTE: only works when VTOR is set to RAM
    real_hard_fault_handler = NVIC_GetVector(HARDFAULT_IRQn);
    NVIC_SetVector(HARDFAULT_IRQn, (uint32_t)&hard_fault_handler_test);
    fault_occurred = 0;

    return greentea_case_setup_handler(source, index_of_case);
}

utest::v1::status_t fault_override_teardown(const Case *const source, const size_t passed, const size_t failed,
                                            const failure_t reason)
{
    // Restore real hard fault handler
    NVIC_SetVector(HARDFAULT_IRQn, real_hard_fault_handler);

    return greentea_case_teardown_handler(source, passed, failed, reason);
}

Case cases[] = {
    Case("SPM - Access secure RAM",       fault_override_setup, secure_ram_fault_test, fault_override_teardown),
    Case("SPM - Access secure Flash",     fault_override_setup, secure_flash_fault_test, fault_override_teardown),
    Case("SPM - Access non-secure RAM",   fault_override_setup, non_secure_ram_fault_test, fault_override_teardown),
    Case("SPM - Access non-secure Flash", fault_override_setup, non_secure_flash_fault_test, fault_override_teardown),
};

utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
#ifndef NO_GREENTEA
    GREENTEA_SETUP(20, "default_auto");
#endif
    return greentea_test_setup_handler(number_of_cases);
}

Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

int main()
{
    Harness::run(specification);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <folly/executors/CPUThreadPoolExecutor.h>
#include <folly/portability/GTest.h>
#include <folly/synchronization/Baton.h>
#include <folly/synchronization/Latch.h>
#include <thrift/lib/cpp2/server/ParallelConcurrencyController.h>
#include <thrift/lib/cpp2/server/RoundRobinRequestPile.h>

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::concurrency;

using Func = std::function<void(
    ServerRequest&&, const AsyncProcessorFactory::MethodMetadata&)>;

class MockAsyncProcessor : public AsyncProcessor {
 public:
  void processSerializedRequest(
      ResponseChannelRequest::UniquePtr,
      SerializedRequest&&,
      protocol::PROTOCOL_TYPES,
      Cpp2RequestContext*,
      folly::EventBase*,
      concurrency::ThreadManager*) override {}

  void executeRequest(
      ServerRequest&& request,
      const AsyncProcessorFactory::MethodMetadata& methodMetadata) override {
    if (executeRequestFunc_) {
      executeRequestFunc_(std::move(request), methodMetadata);
    } else {
      LOG(FATAL) << "Unimplemented executeRequest called";
    }
  }

  void setFunc(Func func) { executeRequestFunc_ = std::move(func); }

 private:
  Func executeRequestFunc_;
};

class FIFORequestPile : public RequestPileInterface {
 public:
  std::optional<ServerRequestRejection> enqueue(
      ServerRequest&& request) override {
    queue_.enqueue(std::move(request));
    return std::nullopt;
  }

  std::pair<std::optional<ServerRequest>, std::optional<intptr_t>> dequeue()
      override {
    if (auto res = queue_.try_dequeue()) {
      return std::make_pair(std::move(*res), std::nullopt);
    } else {
      return std::make_pair(std::nullopt, std::nullopt);
    }
  }

  void onRequestFinished(intptr_t /* userData */) override {}

  uint64_t requestCount() const override { return queue_.size(); }

 private:
  using Queue = folly::UMPMCQueue<
      ServerRequest,
      /* MayBlock */ false,
      /* LgSegmentSize  */ 5>;

  Queue queue_;
};

class ResourcePool {
 public:
  ResourcePool(FIFORequestPile* pile, ParallelConcurrencyController* controller)
      : pile_(pile), controller_(controller) {}

  void enqueue(ServerRequest&& request) {
    pile_->enqueue(std::move(request));
    controller_->onEnqueued();
  }

 private:
  FIFORequestPile* pile_;
  ParallelConcurrencyController* controller_;
};

class MockResponseChannelRequest : public ResponseChannelRequest {
 public:
  bool isActive() const override { return true; }

  bool isOneway() const override { return false; }

  bool includeEnvelope() const override { return false; }

  void sendReply(
      ResponsePayload&&,
      MessageChannel::SendCallback*,
      folly::Optional<uint32_t>) override {}

  void sendErrorWrapped(folly::exception_wrapper, std::string) override {}

  bool tryStartProcessing() override { return true; }
};

namespace {

ServerRequest getRequest(AsyncProcessor* ap, folly::EventBase* eb) {
  ServerRequest req(
      ResponseChannelRequest::UniquePtr(new MockResponseChannelRequest),
      SerializedCompressedRequest(std::unique_ptr<folly::IOBuf>{}),
      eb,
      nullptr, /* ctx  */
      static_cast<protocol::PROTOCOL_TYPES>(0),
      nullptr, /* requestContext  */
      ap,
      nullptr, /* methodMetadata  */
      nullptr /* serviceRequestInfo */);
  return req;
}

Func blockingTaskGen(
    folly::Baton<>& baton, ParallelConcurrencyController& controller) {
  Func waitingTask = [&](ServerRequest&& /* request */,
                         const AsyncProcessorFactory::MethodMetadata&) {
    baton.wait();
    controller.onRequestFinished(0);
  };

  return waitingTask;
}

Func endingTaskGen(
    folly::Baton<>& baton, ParallelConcurrencyController& controller) {
  Func waitingTask = [&](ServerRequest&& /* request */,
                         const AsyncProcessorFactory::MethodMetadata&) {
    controller.onRequestFinished(0);
    baton.post();
  };

  return waitingTask;
}

std::unique_ptr<AsyncProcessor> makeAP(Func func) {
  auto mockAP = std::make_unique<MockAsyncProcessor>();
  mockAP->setFunc(func);
  std::unique_ptr<AsyncProcessor> endingAP(std::move(mockAP));
  return endingAP;
}

} // namespace

// This test just tests the normal case where we have 2 tasks that sit in
// the Executor, the count should return 2.
// When the tasks all finish, the count should return 0
TEST(ParallelConcurrencyControllerTest, NormalCases) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(1);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);

  folly::Baton baton1;
  folly::Baton baton2;

  auto blockingAP = makeAP(blockingTaskGen(baton1, controller));

  auto endingAP = makeAP(endingTaskGen(baton2, controller));

  ResourcePool pool(&pile, &controller);

  pool.enqueue(getRequest(blockingAP.get(), &eb));
  pool.enqueue(getRequest(endingAP.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);
  baton1.post();

  baton2.wait();
  EXPECT_EQ(controller.requestCount(), 0);
}

// This tests when the concurrency limit is set to 2
// In this case only 2 tasks can run concurrently
TEST(ParallelConcurrencyControllerTest, LimitedTasks) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(1);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);

  controller.setExecutionLimitRequests(2);

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;

  auto staringBlockingAP = makeAP(blockingTaskGen(baton1, controller));

  auto blockingAP = makeAP(blockingTaskGen(baton2, controller));

  auto endingAP = makeAP(endingTaskGen(baton3, controller));

  ResourcePool pool(&pile, &controller);

  pool.enqueue(getRequest(blockingAP.get(), &eb));
  pool.enqueue(getRequest(blockingAP.get(), &eb));
  pool.enqueue(getRequest(endingAP.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);

  baton1.post();
  baton2.post();

  baton3.wait();
  EXPECT_EQ(controller.requestCount(), 0);
}

Func edgeTaskGen(
    folly::Latch& latch,
    folly::Baton<>& baton,
    ParallelConcurrencyController& controller) {
  Func waitingTask = [&](ServerRequest&& /* request */,
                         const AsyncProcessorFactory::MethodMetadata&) {
    baton.wait();
    controller.onRequestFinished(0);

    latch.count_down();
  };

  return waitingTask;
}

std::unique_ptr<AsyncProcessor> getEdgeTaskAP(
    folly::Latch& latch,
    folly::Baton<>& baton,
    ParallelConcurrencyController& controller) {
  auto mockAP = new MockAsyncProcessor;
  mockAP->setFunc(edgeTaskGen(latch, baton, controller));
  std::unique_ptr<AsyncProcessor> endingAP(mockAP);
  return endingAP;
}

TEST(ParallelConcurrencyControllerTest, DifferentOrdering1) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(2);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);
  controller.setExecutionLimitRequests(2);

  ResourcePool pool(&pile, &controller);

  folly::Latch latch(3);

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;

  auto mockAP1 = getEdgeTaskAP(latch, baton1, controller);
  auto mockAP2 = getEdgeTaskAP(latch, baton2, controller);
  auto mockAP3 = getEdgeTaskAP(latch, baton3, controller);

  // one scenario is right after one task finishes
  // we push another task into the queue
  pool.enqueue(getRequest(mockAP1.get(), &eb));
  pool.enqueue(getRequest(mockAP2.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);

  // one task will finish immediately and another task is pushed
  // This shouldn't be causing any idle thread
  baton1.post();
  pool.enqueue(getRequest(mockAP3.get(), &eb));

  baton2.post();
  baton3.post();

  latch.wait();
  EXPECT_EQ(controller.requestCount(), 0);
  EXPECT_EQ(pile.requestCount(), 0);
}

TEST(ParallelConcurrencyControllerTest, DifferentOrdering2) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(2);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);
  controller.setExecutionLimitRequests(2);

  ResourcePool pool(&pile, &controller);

  folly::Latch latch(3);

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;

  auto mockAP1 = getEdgeTaskAP(latch, baton1, controller);
  auto mockAP2 = getEdgeTaskAP(latch, baton2, controller);
  auto mockAP3 = getEdgeTaskAP(latch, baton3, controller);

  // another scenario is right before one task finishes
  // we push another task into the queue
  pool.enqueue(getRequest(mockAP1.get(), &eb));
  pool.enqueue(getRequest(mockAP2.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);

  // one task will finish immediately and another task is pushed
  pool.enqueue(getRequest(mockAP3.get(), &eb));
  baton1.post();
  baton2.post();
  baton3.post();

  latch.wait();
  EXPECT_EQ(controller.requestCount(), 0);
  EXPECT_EQ(pile.requestCount(), 0);
}

// This test verifies that tasks added through the underlying executor
// of the ConcurrencyController will get higher priority than the task
// added through ConcurrencyController
// This is mimicing the scenario where one request may spawn other tasks
// in their handler code and we should execute those first
TEST(ParallelConcurrencyControllerTest, ExistingTasksHaveHigherPriority) {
  folly::EventBase eb;

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;
  folly::Baton baton4;

  std::atomic<size_t> counter{0};

  Func task1 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    baton1.wait();
    ++counter;
    EXPECT_EQ(counter, 1);
  };
  Func task2 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    baton2.wait();
    ++counter;
    EXPECT_EQ(counter, 3);
  };
  Func task3 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    baton3.wait();
    ++counter;
    EXPECT_EQ(counter, 4);
  };
  auto task4 = [&] {
    baton4.wait();
    ++counter;
    EXPECT_EQ(counter, 2);
  };

  folly::Baton baton5;
  folly::Baton baton6;
  folly::Baton baton7;

  Func task5 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    baton5.wait();
    ++counter;
    EXPECT_EQ(counter, 5);
  };
  Func task6 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    baton6.wait();
    ++counter;
    EXPECT_EQ(counter, 6);
  };
  Func task7 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    baton7.wait();
    ++counter;
    EXPECT_EQ(counter, 7);
  };

  auto ap1 = std::make_unique<MockAsyncProcessor>();
  ap1->setFunc(task1);
  auto ap2 = std::make_unique<MockAsyncProcessor>();
  ap2->setFunc(task2);
  auto ap3 = std::make_unique<MockAsyncProcessor>();
  ap3->setFunc(task3);

  auto ap5 = std::make_unique<MockAsyncProcessor>();
  ap5->setFunc(task5);
  auto ap6 = std::make_unique<MockAsyncProcessor>();
  ap6->setFunc(task6);
  auto ap7 = std::make_unique<MockAsyncProcessor>();
  ap7->setFunc(task7);

  folly::CPUThreadPoolExecutor ex(1);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);

  ResourcePool pool(&pile, &controller);

  // This block is verifying that when a task is added through
  // underlying executor, it will get higher priority
  {
    // task1 is pushed by ConcurrencyController
    // and gets blocked
    // This is executed first so counter == 1
    pool.enqueue(getRequest(ap1.get(), &eb));
    // task2 is pushed
    // This is executed last so counter == 3
    pool.enqueue(getRequest(ap2.get(), &eb));
    // task2 is pushed
    // This is executed last so counter == 4
    pool.enqueue(getRequest(ap3.get(), &eb));
    // task3 is pushed through executor which should
    // get higher priority than task2
    // This is executed before task2 so counter == 2
    ex.add(task4);
  }

  // This block is verifying the normal behavior that
  // tasks added through ConcurrencyController are
  // executed in order
  {
    // task5 is pushed by ConcurrencyController
    // and gets blocked
    // This is executed first so counter == 5
    pool.enqueue(getRequest(ap5.get(), &eb));
    // task6 is pushed
    // This is executed last so counter == 6
    pool.enqueue(getRequest(ap6.get(), &eb));
    // task7 is pushed
    // This is executed last so counter == 6
    pool.enqueue(getRequest(ap7.get(), &eb));
  }

  baton1.post();
  baton2.post();
  baton3.post();
  baton4.post();

  baton5.post();
  baton6.post();
  baton7.post();
}
<commit_msg>fix a flaky test<commit_after>/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * 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 <folly/executors/CPUThreadPoolExecutor.h>
#include <folly/portability/GTest.h>
#include <folly/synchronization/Baton.h>
#include <folly/synchronization/Latch.h>
#include <thrift/lib/cpp2/server/ParallelConcurrencyController.h>
#include <thrift/lib/cpp2/server/RoundRobinRequestPile.h>

using namespace std;
using namespace apache::thrift;
using namespace apache::thrift::transport;
using namespace apache::thrift::concurrency;

using Func = std::function<void(
    ServerRequest&&, const AsyncProcessorFactory::MethodMetadata&)>;

class MockAsyncProcessor : public AsyncProcessor {
 public:
  void processSerializedRequest(
      ResponseChannelRequest::UniquePtr,
      SerializedRequest&&,
      protocol::PROTOCOL_TYPES,
      Cpp2RequestContext*,
      folly::EventBase*,
      concurrency::ThreadManager*) override {}

  void executeRequest(
      ServerRequest&& request,
      const AsyncProcessorFactory::MethodMetadata& methodMetadata) override {
    if (executeRequestFunc_) {
      executeRequestFunc_(std::move(request), methodMetadata);
    } else {
      LOG(FATAL) << "Unimplemented executeRequest called";
    }
  }

  void setFunc(Func func) { executeRequestFunc_ = std::move(func); }

 private:
  Func executeRequestFunc_;
};

class FIFORequestPile : public RequestPileInterface {
 public:
  std::optional<ServerRequestRejection> enqueue(
      ServerRequest&& request) override {
    queue_.enqueue(std::move(request));
    return std::nullopt;
  }

  std::pair<std::optional<ServerRequest>, std::optional<intptr_t>> dequeue()
      override {
    if (auto res = queue_.try_dequeue()) {
      return std::make_pair(std::move(*res), std::nullopt);
    } else {
      return std::make_pair(std::nullopt, std::nullopt);
    }
  }

  void onRequestFinished(intptr_t /* userData */) override {}

  uint64_t requestCount() const override { return queue_.size(); }

 private:
  using Queue = folly::UMPMCQueue<
      ServerRequest,
      /* MayBlock */ false,
      /* LgSegmentSize  */ 5>;

  Queue queue_;
};

class ResourcePool {
 public:
  ResourcePool(FIFORequestPile* pile, ParallelConcurrencyController* controller)
      : pile_(pile), controller_(controller) {}

  void enqueue(ServerRequest&& request) {
    pile_->enqueue(std::move(request));
    controller_->onEnqueued();
  }

 private:
  FIFORequestPile* pile_;
  ParallelConcurrencyController* controller_;
};

class MockResponseChannelRequest : public ResponseChannelRequest {
 public:
  bool isActive() const override { return true; }

  bool isOneway() const override { return false; }

  bool includeEnvelope() const override { return false; }

  void sendReply(
      ResponsePayload&&,
      MessageChannel::SendCallback*,
      folly::Optional<uint32_t>) override {}

  void sendErrorWrapped(folly::exception_wrapper, std::string) override {}

  bool tryStartProcessing() override { return true; }
};

namespace {

ServerRequest getRequest(AsyncProcessor* ap, folly::EventBase* eb) {
  ServerRequest req(
      ResponseChannelRequest::UniquePtr(new MockResponseChannelRequest),
      SerializedCompressedRequest(std::unique_ptr<folly::IOBuf>{}),
      eb,
      nullptr, /* ctx  */
      static_cast<protocol::PROTOCOL_TYPES>(0),
      nullptr, /* requestContext  */
      ap,
      nullptr, /* methodMetadata  */
      nullptr /* serviceRequestInfo */);
  return req;
}

Func blockingTaskGen(
    folly::Baton<>& baton, ParallelConcurrencyController& controller) {
  Func waitingTask = [&](ServerRequest&& /* request */,
                         const AsyncProcessorFactory::MethodMetadata&) {
    baton.wait();
    controller.onRequestFinished(0);
  };

  return waitingTask;
}

Func endingTaskGen(
    folly::Baton<>& baton, ParallelConcurrencyController& controller) {
  Func waitingTask = [&](ServerRequest&& /* request */,
                         const AsyncProcessorFactory::MethodMetadata&) {
    controller.onRequestFinished(0);
    baton.post();
  };

  return waitingTask;
}

std::unique_ptr<AsyncProcessor> makeAP(Func func) {
  auto mockAP = std::make_unique<MockAsyncProcessor>();
  mockAP->setFunc(func);
  std::unique_ptr<AsyncProcessor> endingAP(std::move(mockAP));
  return endingAP;
}

} // namespace

// This test just tests the normal case where we have 2 tasks that sit in
// the Executor, the count should return 2.
// When the tasks all finish, the count should return 0
TEST(ParallelConcurrencyControllerTest, NormalCases) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(1);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);

  folly::Baton baton1;
  folly::Baton baton2;

  auto blockingAP = makeAP(blockingTaskGen(baton1, controller));

  auto endingAP = makeAP(endingTaskGen(baton2, controller));

  ResourcePool pool(&pile, &controller);

  pool.enqueue(getRequest(blockingAP.get(), &eb));
  pool.enqueue(getRequest(endingAP.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);
  baton1.post();

  baton2.wait();
  EXPECT_EQ(controller.requestCount(), 0);
}

// This tests when the concurrency limit is set to 2
// In this case only 2 tasks can run concurrently
TEST(ParallelConcurrencyControllerTest, LimitedTasks) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(1);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);

  controller.setExecutionLimitRequests(2);

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;

  auto staringBlockingAP = makeAP(blockingTaskGen(baton1, controller));

  auto blockingAP = makeAP(blockingTaskGen(baton2, controller));

  auto endingAP = makeAP(endingTaskGen(baton3, controller));

  ResourcePool pool(&pile, &controller);

  pool.enqueue(getRequest(blockingAP.get(), &eb));
  pool.enqueue(getRequest(blockingAP.get(), &eb));
  pool.enqueue(getRequest(endingAP.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);

  baton1.post();
  baton2.post();

  baton3.wait();
  EXPECT_EQ(controller.requestCount(), 0);
}

Func edgeTaskGen(
    folly::Latch& latch,
    folly::Baton<>& baton,
    ParallelConcurrencyController& controller) {
  Func waitingTask = [&](ServerRequest&& /* request */,
                         const AsyncProcessorFactory::MethodMetadata&) {
    baton.wait();
    controller.onRequestFinished(0);

    latch.count_down();
  };

  return waitingTask;
}

std::unique_ptr<AsyncProcessor> getEdgeTaskAP(
    folly::Latch& latch,
    folly::Baton<>& baton,
    ParallelConcurrencyController& controller) {
  auto mockAP = new MockAsyncProcessor;
  mockAP->setFunc(edgeTaskGen(latch, baton, controller));
  std::unique_ptr<AsyncProcessor> endingAP(mockAP);
  return endingAP;
}

TEST(ParallelConcurrencyControllerTest, DifferentOrdering1) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(2);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);
  controller.setExecutionLimitRequests(2);

  ResourcePool pool(&pile, &controller);

  folly::Latch latch(3);

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;

  auto mockAP1 = getEdgeTaskAP(latch, baton1, controller);
  auto mockAP2 = getEdgeTaskAP(latch, baton2, controller);
  auto mockAP3 = getEdgeTaskAP(latch, baton3, controller);

  // one scenario is right after one task finishes
  // we push another task into the queue
  pool.enqueue(getRequest(mockAP1.get(), &eb));
  pool.enqueue(getRequest(mockAP2.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);

  // one task will finish immediately and another task is pushed
  // This shouldn't be causing any idle thread
  baton1.post();
  pool.enqueue(getRequest(mockAP3.get(), &eb));

  baton2.post();
  baton3.post();

  latch.wait();
  EXPECT_EQ(controller.requestCount(), 0);
  EXPECT_EQ(pile.requestCount(), 0);
}

TEST(ParallelConcurrencyControllerTest, DifferentOrdering2) {
  folly::EventBase eb;

  folly::CPUThreadPoolExecutor ex(2);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);
  controller.setExecutionLimitRequests(2);

  ResourcePool pool(&pile, &controller);

  folly::Latch latch(3);

  folly::Baton baton1;
  folly::Baton baton2;
  folly::Baton baton3;

  auto mockAP1 = getEdgeTaskAP(latch, baton1, controller);
  auto mockAP2 = getEdgeTaskAP(latch, baton2, controller);
  auto mockAP3 = getEdgeTaskAP(latch, baton3, controller);

  // another scenario is right before one task finishes
  // we push another task into the queue
  pool.enqueue(getRequest(mockAP1.get(), &eb));
  pool.enqueue(getRequest(mockAP2.get(), &eb));

  EXPECT_EQ(controller.requestCount(), 2);

  // one task will finish immediately and another task is pushed
  pool.enqueue(getRequest(mockAP3.get(), &eb));
  baton1.post();
  baton2.post();
  baton3.post();

  latch.wait();
  EXPECT_EQ(controller.requestCount(), 0);
  EXPECT_EQ(pile.requestCount(), 0);
}

// This test verifies that tasks added through the underlying executor
// of the ConcurrencyController will get higher priority than the task
// added through ConcurrencyController
// This is mimicing the scenario where one request may spawn other tasks
// in their handler code and we should execute those first
TEST(ParallelConcurrencyControllerTest, ExistingTasksHaveHigherPriority) {
  folly::EventBase eb;

  std::atomic<size_t> counter{0};

  Func task1 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    ++counter;
    EXPECT_EQ(counter, 1);
  };
  Func task2 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    ++counter;
    EXPECT_EQ(counter, 3);
  };
  Func task3 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    ++counter;
    EXPECT_EQ(counter, 4);
  };
  auto task4 = [&] {
    ++counter;
    EXPECT_EQ(counter, 2);
  };

  Func task5 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    ++counter;
    EXPECT_EQ(counter, 5);
  };
  Func task6 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    ++counter;
    EXPECT_EQ(counter, 6);
  };
  Func task7 = [&](ServerRequest&& /* request */,
                   const AsyncProcessorFactory::MethodMetadata&) {
    ++counter;
    EXPECT_EQ(counter, 7);
  };

  auto ap1 = std::make_unique<MockAsyncProcessor>();
  ap1->setFunc(task1);
  auto ap2 = std::make_unique<MockAsyncProcessor>();
  ap2->setFunc(task2);
  auto ap3 = std::make_unique<MockAsyncProcessor>();
  ap3->setFunc(task3);

  auto ap5 = std::make_unique<MockAsyncProcessor>();
  ap5->setFunc(task5);
  auto ap6 = std::make_unique<MockAsyncProcessor>();
  ap6->setFunc(task6);
  auto ap7 = std::make_unique<MockAsyncProcessor>();
  ap7->setFunc(task7);

  folly::Baton baton;

  folly::CPUThreadPoolExecutor ex(1);
  FIFORequestPile pile;
  ParallelConcurrencyController controller(pile, ex);

  ResourcePool pool(&pile, &controller);

  ex.add([&] { baton.wait(); });

  // This block is verifying that when a task is added through
  // underlying executor, it will get higher priority
  {
    // task1 is pushed by ConcurrencyController
    // and gets blocked
    // This is executed first so counter == 1
    pool.enqueue(getRequest(ap1.get(), &eb));
    // task2 is pushed
    // This is executed last so counter == 3
    pool.enqueue(getRequest(ap2.get(), &eb));
    // task2 is pushed
    // This is executed last so counter == 4
    pool.enqueue(getRequest(ap3.get(), &eb));
    // task3 is pushed through executor which should
    // get higher priority than task2
    // This is executed before task2 so counter == 2
    ex.add(task4);
  }

  // This block is verifying the normal behavior that
  // tasks added through ConcurrencyController are
  // executed in order
  {
    // task5 is pushed by ConcurrencyController
    // and gets blocked
    // This is executed first so counter == 5
    pool.enqueue(getRequest(ap5.get(), &eb));
    // task6 is pushed
    // This is executed last so counter == 6
    pool.enqueue(getRequest(ap6.get(), &eb));
    // task7 is pushed
    // This is executed last so counter == 6
    pool.enqueue(getRequest(ap7.get(), &eb));
  }

  baton.post();
}
<|endoftext|>


<commit_before>
#include "AConfig.h"
#if(HAS_STD_PILOT)
#include "Device.h"
#include "Pin.h"
#include "Pilot.h"
#include "Timer.h"

Timer pilotTimer;
Timer deadmanSwitchTimer;
Timer blinklightTimer;
bool _headingHoldEnabled = false;
int  _headingHoldTarget = 0;
int hdg = 0;
int hdg_Error;
int raw_Left, raw_Right;
int left, right;  // motor outputs in microseconds, +/-500
int loop_Gain = 1;
int integral_Divisor = 100;
long hdg_Error_Integral = 0;
int tgt_Hdg = 0;
bool _depthHoldEnabled = false;
int _depthHoldTarget = 0;
int depth = 0;
int depth_Error = 0;
int raw_lift =0;
int lift = 0;
int target_depth;
int raw_yaw, yaw;
bool _deadmanSwitchEnabled = false;
bool blinkstate = false;

void Pilot::device_setup(){
  pilotTimer.reset();
  deadmanSwitchTimer.reset();
  blinklightTimer.reset();
  Serial.println(F("log:pilot setup complete;"));
}

void Pilot::device_loop(Command command){
//intended to respond to fly by wire commands: MaintainHeading(); TurnTo(compassheading); DiveTo(depth);

    if( command.cmp("ping")){
      deadmanSwitchTimer.reset();
      _deadmanSwitchEnabled = false;
      Serial.print(F("pong:")); Serial.print(command.args[0]); Serial.print(","); Serial.print(millis()); Serial.print(";");
    }

    if (deadmanSwitchTimer.elapsed (2000)) {
      _depthHoldEnabled = false;
      _headingHoldEnabled = false;
      int argsToSend[] = {0};
      command.pushCommand("stop",argsToSend);
      _deadmanSwitchEnabled = true;

    }

    if (_deadmanSwitchEnabled && blinklightTimer.elapsed(500)){
      int argsToSend[] = {1,255};
      if (blinkstate){
        argsToSend[1] = 0;
      }
      command.pushCommand("ligt",argsToSend);
      blinkstate = !blinkstate;
    }

    if( command.cmp("holdHeading_toggle")){
      if (_headingHoldEnabled) {
        _headingHoldEnabled = false;
        raw_Left = 0;
        raw_Right = 0;
        hdg_Error_Integral = 0;  // Reset error integrator
        tgt_Hdg = -500;  // -500 = system not in hdg hold

        int argsToSend[] = {1,00}; //include number of parms as last parm
        command.pushCommand("yaw",argsToSend);
        Serial.println(F("log:heading_hold_disabled;"));

      } else {
        _headingHoldEnabled = true;
        if(command.args[0]==0){
          _headingHoldTarget = navdata::HDGD;
        } else {
          _headingHoldTarget = command.args[1];
        }
        tgt_Hdg = _headingHoldTarget;
        Serial.print(F("log:heading_hold_enabled on="));
        Serial.print(tgt_Hdg);
        Serial.println(';');
      }
      Serial.print(F("targetHeading:"));
      if (_headingHoldEnabled) {
        Serial.print(tgt_Hdg);
      } else {
        Serial.print(DISABLED);
      }
      Serial.println(';');
    }

    if( command.cmp("holdDepth_toggle")){
      if (_depthHoldEnabled) {
        _depthHoldEnabled = false;
        raw_lift = 0;
        target_depth = 0;

        int argsToSend[] = {1,0}; //include number of parms as last parm
        command.pushCommand("lift",argsToSend);
        Serial.println(F("log:depth_hold_disabled;"));

      } else {
        _depthHoldEnabled = true;
        if(command.args[0]==0){
          _depthHoldTarget = navdata::DEAP*100;  //casting to cm
        } else {
          _depthHoldTarget = command.args[1];
        }
        target_depth = _depthHoldTarget;
        Serial.print(F("log:depth_hold_enabled on="));
        Serial.print(target_depth);
        Serial.println(';');
      }
      Serial.print(F("targetDepth:"));
      if (_depthHoldEnabled) {
        Serial.print(target_depth);
      } else {
        Serial.print(DISABLED);
      }
      Serial.println(';');
    }

    if (pilotTimer.elapsed (50)) {

      // Autopilot Test #3 6 Jan 2014
      // Hold vehicle at arbitrary heading
      // Integer math; proportional control plus basic integrator
      // No hysteresis around 180 degree error

      // Check whether hold mode is on

      if (_depthHoldEnabled)
      {
        depth = navdata::DEAP*100;
        depth_Error = target_depth-depth;  //positive error = positive lift = go deaper.

        raw_lift = depth_Error * loop_Gain;
        lift = constrain(raw_lift, -50, 50);

        Serial.println(F("log:dhold pushing command;"));
        Serial.print(F("dp_er:"));
        Serial.print(depth_Error);
        Serial.println(';');
        int argsToSend[] = {1,lift}; //include number of parms as last parm
        command.pushCommand("lift",argsToSend);

      }

      if (_headingHoldEnabled)
      {

        // Code for hold mode here
        hdg = navdata::HDGD;

        // Calculate heading error

        hdg_Error = hdg - tgt_Hdg;

        if (hdg_Error > 180)
        {
        hdg_Error = hdg_Error - 360;
        }

        if (hdg_Error < -179)
        {
        hdg_Error = hdg_Error + 360;
        }

        // Run error accumulator (integrator)
        hdg_Error_Integral = hdg_Error_Integral + hdg_Error;

        // Calculator motor outputs
        raw_yaw = -1 * hdg_Error * loop_Gain;

        // raw_Left = raw_Left - (hdg_Error_Integral / integral_Divisor);
        // raw_Right = raw_Right + (hdg_Error_Integral / integral_Divisor);

        // Constrain and output to motors

        yaw = constrain(raw_yaw, -50, 50);
        Serial.println(F("log:hold pushing command;"));
        Serial.print(F("p_er:"));
        Serial.print(hdg_Error);
        Serial.println(';');

        int argsToSend[] = {1,yaw}; //include number of parms as last parm
        command.pushCommand("yaw",argsToSend);
      }

    }
}
#endif
<commit_msg>Reduced the brightness of the no signal lights<commit_after>
#include "AConfig.h"
#if(HAS_STD_PILOT)
#include "Device.h"
#include "Pin.h"
#include "Pilot.h"
#include "Timer.h"

Timer pilotTimer;
Timer deadmanSwitchTimer;
Timer blinklightTimer;
bool _headingHoldEnabled = false;
int  _headingHoldTarget = 0;
int hdg = 0;
int hdg_Error;
int raw_Left, raw_Right;
int left, right;  // motor outputs in microseconds, +/-500
int loop_Gain = 1;
int integral_Divisor = 100;
long hdg_Error_Integral = 0;
int tgt_Hdg = 0;
bool _depthHoldEnabled = false;
int _depthHoldTarget = 0;
int depth = 0;
int depth_Error = 0;
int raw_lift =0;
int lift = 0;
int target_depth;
int raw_yaw, yaw;
bool _deadmanSwitchEnabled = false;
bool blinkstate = false;

void Pilot::device_setup(){
  pilotTimer.reset();
  deadmanSwitchTimer.reset();
  blinklightTimer.reset();
  Serial.println(F("log:pilot setup complete;"));
}

void Pilot::device_loop(Command command){
//intended to respond to fly by wire commands: MaintainHeading(); TurnTo(compassheading); DiveTo(depth);

    if( command.cmp("ping")){
      deadmanSwitchTimer.reset();
      _deadmanSwitchEnabled = false;
      Serial.print(F("pong:")); Serial.print(command.args[0]); Serial.print(","); Serial.print(millis()); Serial.print(";");
    }

    if (deadmanSwitchTimer.elapsed (2000)) {
      _depthHoldEnabled = false;
      _headingHoldEnabled = false;
      int argsToSend[] = {0};
      command.pushCommand("stop",argsToSend);
      _deadmanSwitchEnabled = true;

    }

    if (_deadmanSwitchEnabled && blinklightTimer.elapsed(500)){
      int argsToSend[] = {1,50};
      if (blinkstate){
        argsToSend[1] = 0;
      }
      command.pushCommand("ligt",argsToSend);
      blinkstate = !blinkstate;
    }

    if( command.cmp("holdHeading_toggle")){
      if (_headingHoldEnabled) {
        _headingHoldEnabled = false;
        raw_Left = 0;
        raw_Right = 0;
        hdg_Error_Integral = 0;  // Reset error integrator
        tgt_Hdg = -500;  // -500 = system not in hdg hold

        int argsToSend[] = {1,00}; //include number of parms as last parm
        command.pushCommand("yaw",argsToSend);
        Serial.println(F("log:heading_hold_disabled;"));

      } else {
        _headingHoldEnabled = true;
        if(command.args[0]==0){
          _headingHoldTarget = navdata::HDGD;
        } else {
          _headingHoldTarget = command.args[1];
        }
        tgt_Hdg = _headingHoldTarget;
        Serial.print(F("log:heading_hold_enabled on="));
        Serial.print(tgt_Hdg);
        Serial.println(';');
      }
      Serial.print(F("targetHeading:"));
      if (_headingHoldEnabled) {
        Serial.print(tgt_Hdg);
      } else {
        Serial.print(DISABLED);
      }
      Serial.println(';');
    }

    if( command.cmp("holdDepth_toggle")){
      if (_depthHoldEnabled) {
        _depthHoldEnabled = false;
        raw_lift = 0;
        target_depth = 0;

        int argsToSend[] = {1,0}; //include number of parms as last parm
        command.pushCommand("lift",argsToSend);
        Serial.println(F("log:depth_hold_disabled;"));

      } else {
        _depthHoldEnabled = true;
        if(command.args[0]==0){
          _depthHoldTarget = navdata::DEAP*100;  //casting to cm
        } else {
          _depthHoldTarget = command.args[1];
        }
        target_depth = _depthHoldTarget;
        Serial.print(F("log:depth_hold_enabled on="));
        Serial.print(target_depth);
        Serial.println(';');
      }
      Serial.print(F("targetDepth:"));
      if (_depthHoldEnabled) {
        Serial.print(target_depth);
      } else {
        Serial.print(DISABLED);
      }
      Serial.println(';');
    }

    if (pilotTimer.elapsed (50)) {

      // Autopilot Test #3 6 Jan 2014
      // Hold vehicle at arbitrary heading
      // Integer math; proportional control plus basic integrator
      // No hysteresis around 180 degree error

      // Check whether hold mode is on

      if (_depthHoldEnabled)
      {
        depth = navdata::DEAP*100;
        depth_Error = target_depth-depth;  //positive error = positive lift = go deaper.

        raw_lift = depth_Error * loop_Gain;
        lift = constrain(raw_lift, -50, 50);

        Serial.println(F("log:dhold pushing command;"));
        Serial.print(F("dp_er:"));
        Serial.print(depth_Error);
        Serial.println(';');
        int argsToSend[] = {1,lift}; //include number of parms as last parm
        command.pushCommand("lift",argsToSend);

      }

      if (_headingHoldEnabled)
      {

        // Code for hold mode here
        hdg = navdata::HDGD;

        // Calculate heading error

        hdg_Error = hdg - tgt_Hdg;

        if (hdg_Error > 180)
        {
        hdg_Error = hdg_Error - 360;
        }

        if (hdg_Error < -179)
        {
        hdg_Error = hdg_Error + 360;
        }

        // Run error accumulator (integrator)
        hdg_Error_Integral = hdg_Error_Integral + hdg_Error;

        // Calculator motor outputs
        raw_yaw = -1 * hdg_Error * loop_Gain;

        // raw_Left = raw_Left - (hdg_Error_Integral / integral_Divisor);
        // raw_Right = raw_Right + (hdg_Error_Integral / integral_Divisor);

        // Constrain and output to motors

        yaw = constrain(raw_yaw, -50, 50);
        Serial.println(F("log:hold pushing command;"));
        Serial.print(F("p_er:"));
        Serial.print(hdg_Error);
        Serial.println(';');

        int argsToSend[] = {1,yaw}; //include number of parms as last parm
        command.pushCommand("yaw",argsToSend);
      }

    }
}
#endif
<|endoftext|>


<commit_before>
#include <unistd.h>
#include <cctype>
#include <iostream>
#include <future>
#include <stdexcept>

#include "engine.h"
#include "collector.h"
#include "directory.h"
#include "settings.h"
#include "plugin_loader.h"

engine::engine (const std::string& tmpdir,
		const std::string& subdir,
		const int parallel,
		const int bytes_buffer,
		const int max_open_files)
    : _tmpdir (subdir.empty() ? tmpdir : (tmpdir + "/" + subdir)),
      _is_subdir (subdir.size()),
      _parallel (parallel),
      _bytes_buffer (bytes_buffer),
      _max_files (max_open_files)
{
    if (access(tmpdir.c_str(), R_OK|W_OK|X_OK) != 0)
    {
	throw std::runtime_error (tmpdir + " needs to be a writable directory");
    }
}

engine::~engine()
{}

void
engine::enable_sorters (const mapredo::base::keytype type, const bool reverse)
{
    if (_is_subdir)
    {
	if (!directory::exists(_tmpdir)) directory::create (_tmpdir);
    }

    for (size_t i = 0; i < _parallel; i++)
    {
	_sorters.push_back (sorter(_tmpdir, i, _bytes_buffer/_parallel,
				   type, reverse));
    }
    _unprepared = false;
}

void
engine::flush()
{
    for (auto& sorter: _sorters) sorter.flush();

    for (auto& sorter: _sorters)
    {
	sorter.wait_flushed();
	sorter.grab_tmpfiles();
    }
}

void
engine::flush (mapredo::base& mapreducer, plugin_loader& loader)
{
    for (auto& sorter: _sorters) sorter.flush();

    for (auto& sorter: _sorters)
    {
	sorter.wait_flushed();
	std::list<std::string> tmpfiles (sorter.grab_tmpfiles());

	if (tmpfiles.size() == 1)
	{
	    _files_final_merge.push_back (tmpfiles.front());
	}
	else if (tmpfiles.size())
	{
	    _mergers.push_back
		(file_merger(loader.get(),
			     static_cast<std::list<std::string>&&>(tmpfiles),
			     _tmpdir, _unique_id++, 0x20000,
			     _max_files/_parallel));
	}
    }
    _sorters.clear();

    merge (mapreducer);
}

void
engine::reduce (mapredo::base& mapreducer, plugin_loader& loader)
{
    if (!_is_subdir)
    {
	throw std::logic_error
	    ("Subdir need to be set for reduce only processing");
    }

    try
    {
	std::vector<std::list<std::string>> lists;
	directory dir (_tmpdir);

	lists.resize (_parallel);

	for (const auto& file: dir)
	{
	    const char *period = strchr (file, '.');

	    if (!period || !isdigit(period[1]))
	    {
		throw std::runtime_error (std::string("Invalid tmpfile name ")
					  + file);
	    }
	    lists[atoi(period+1)%_parallel].push_back (_tmpdir + "/" + file);
	}

	for (auto& tmpfiles: lists)
	{
	    if (tmpfiles.size() == 1)
	    {
		_files_final_merge.push_back (tmpfiles.front());
	    }
	    else if (tmpfiles.size())
	    {
		_mergers.push_back
		    (file_merger
		     (loader.get(),
		      static_cast<std::list<std::string>&&>(tmpfiles),
		      _tmpdir, _unique_id++, 0x20000, _max_files/_parallel));
	    }
	}

	merge (mapreducer);
    }
    catch (...)
    {
	if (!settings::instance().keep_tmpfiles())
	{
	    directory::remove(_tmpdir, true);
	}
	throw;
    }

    if (!settings::instance().keep_tmpfiles())
    {
	directory::remove(_tmpdir);
    }
}

void
engine::merge (mapredo::base& mapreducer)
{
    std::vector<std::future<std::string>> results;
    results.resize (_mergers.size());
    auto iter = _mergers.begin();
    auto riter = results.begin();

    if (_files_final_merge.empty())
    {
	if (_mergers.empty()) return;
	if (_mergers.size() == 1)
	{
	    iter->merge();
	    return;
	}
    }

    for (; iter != _mergers.end(); iter++, riter++)
    {
	auto& merger (*iter);

	*riter = std::async (std::launch::async,
			     &file_merger::merge_to_file,
			     &merger);
    }

    for (iter = _mergers.begin(), riter = results.begin();
	 iter != _mergers.end(); iter++, riter++)
    {
	if (iter->exception_ptr())
	{
	    std::rethrow_exception(iter->exception_ptr());
	}
	_files_final_merge.push_back (riter->get());
    }
    _mergers.clear();

    file_merger merger
	(mapreducer,
	 static_cast<std::list<std::string>&&>(_files_final_merge),
	 _tmpdir, _unique_id, 0x10000, _max_files);
    merger.merge();

    _files_final_merge.clear();
}

static unsigned int hash(const char* str, int siz)
{
    unsigned int result = 0x55555555;
    int i;

    for (i = 0; i < siz && str[i] != '\t'; i++)
    {
	result ^= str[i];
	result = ((result << 5) | (result >> 27));
    }
    return result;
}

void
engine::collect (const char* inbuffer, const int insize)
{
    if (_unprepared)
    {
	throw std::runtime_error ("engine::enable_sorters() needs to be called"
				  " before any mapping is done");
    }

    if (_parallel > 1)
    {
	int value = hash(inbuffer, insize);
	_sorters[value % _parallel].add (inbuffer, insize);
    }
    else _sorters[0].add (inbuffer, insize);
}
<commit_msg>int -> auto (inline call)<commit_after>
#include <unistd.h>
#include <cctype>
#include <iostream>
#include <future>
#include <stdexcept>

#include "engine.h"
#include "collector.h"
#include "directory.h"
#include "settings.h"
#include "plugin_loader.h"

engine::engine (const std::string& tmpdir,
		const std::string& subdir,
		const int parallel,
		const int bytes_buffer,
		const int max_open_files)
    : _tmpdir (subdir.empty() ? tmpdir : (tmpdir + "/" + subdir)),
      _is_subdir (subdir.size()),
      _parallel (parallel),
      _bytes_buffer (bytes_buffer),
      _max_files (max_open_files)
{
    if (access(tmpdir.c_str(), R_OK|W_OK|X_OK) != 0)
    {
	throw std::runtime_error (tmpdir + " needs to be a writable directory");
    }
}

engine::~engine()
{}

void
engine::enable_sorters (const mapredo::base::keytype type, const bool reverse)
{
    if (_is_subdir)
    {
	if (!directory::exists(_tmpdir)) directory::create (_tmpdir);
    }

    for (size_t i = 0; i < _parallel; i++)
    {
	_sorters.push_back (sorter(_tmpdir, i, _bytes_buffer/_parallel,
				   type, reverse));
    }
    _unprepared = false;
}

void
engine::flush()
{
    for (auto& sorter: _sorters) sorter.flush();

    for (auto& sorter: _sorters)
    {
	sorter.wait_flushed();
	sorter.grab_tmpfiles();
    }
}

void
engine::flush (mapredo::base& mapreducer, plugin_loader& loader)
{
    for (auto& sorter: _sorters) sorter.flush();

    for (auto& sorter: _sorters)
    {
	sorter.wait_flushed();
	std::list<std::string> tmpfiles (sorter.grab_tmpfiles());

	if (tmpfiles.size() == 1)
	{
	    _files_final_merge.push_back (tmpfiles.front());
	}
	else if (tmpfiles.size())
	{
	    _mergers.push_back
		(file_merger(loader.get(),
			     static_cast<std::list<std::string>&&>(tmpfiles),
			     _tmpdir, _unique_id++, 0x20000,
			     _max_files/_parallel));
	}
    }
    _sorters.clear();

    merge (mapreducer);
}

void
engine::reduce (mapredo::base& mapreducer, plugin_loader& loader)
{
    if (!_is_subdir)
    {
	throw std::logic_error
	    ("Subdir need to be set for reduce only processing");
    }

    try
    {
	std::vector<std::list<std::string>> lists;
	directory dir (_tmpdir);

	lists.resize (_parallel);

	for (const auto& file: dir)
	{
	    const char *period = strchr (file, '.');

	    if (!period || !isdigit(period[1]))
	    {
		throw std::runtime_error (std::string("Invalid tmpfile name ")
					  + file);
	    }
	    lists[atoi(period+1)%_parallel].push_back (_tmpdir + "/" + file);
	}

	for (auto& tmpfiles: lists)
	{
	    if (tmpfiles.size() == 1)
	    {
		_files_final_merge.push_back (tmpfiles.front());
	    }
	    else if (tmpfiles.size())
	    {
		_mergers.push_back
		    (file_merger
		     (loader.get(),
		      static_cast<std::list<std::string>&&>(tmpfiles),
		      _tmpdir, _unique_id++, 0x20000, _max_files/_parallel));
	    }
	}

	merge (mapreducer);
    }
    catch (...)
    {
	if (!settings::instance().keep_tmpfiles())
	{
	    directory::remove(_tmpdir, true);
	}
	throw;
    }

    if (!settings::instance().keep_tmpfiles())
    {
	directory::remove(_tmpdir);
    }
}

void
engine::merge (mapredo::base& mapreducer)
{
    std::vector<std::future<std::string>> results;
    results.resize (_mergers.size());
    auto iter = _mergers.begin();
    auto riter = results.begin();

    if (_files_final_merge.empty())
    {
	if (_mergers.empty()) return;
	if (_mergers.size() == 1)
	{
	    iter->merge();
	    return;
	}
    }

    for (; iter != _mergers.end(); iter++, riter++)
    {
	auto& merger (*iter);

	*riter = std::async (std::launch::async,
			     &file_merger::merge_to_file,
			     &merger);
    }

    for (iter = _mergers.begin(), riter = results.begin();
	 iter != _mergers.end(); iter++, riter++)
    {
	if (iter->exception_ptr())
	{
	    std::rethrow_exception(iter->exception_ptr());
	}
	_files_final_merge.push_back (riter->get());
    }
    _mergers.clear();

    file_merger merger
	(mapreducer,
	 static_cast<std::list<std::string>&&>(_files_final_merge),
	 _tmpdir, _unique_id, 0x10000, _max_files);
    merger.merge();

    _files_final_merge.clear();
}

static unsigned int hash(const char* str, int siz)
{
    unsigned int result = 0x55555555;
    int i;

    for (i = 0; i < siz && str[i] != '\t'; i++)
    {
	result ^= str[i];
	result = ((result << 5) | (result >> 27));
    }
    return result;
}

void
engine::collect (const char* inbuffer, const int insize)
{
    if (_unprepared)
    {
	throw std::runtime_error ("engine::enable_sorters() needs to be called"
				  " before any mapping is done");
    }

    if (_parallel > 1)
    {
	_sorters[hash(inbuffer, insize) % _parallel].add (inbuffer, insize);
    }
    else _sorters[0].add (inbuffer, insize);
}
<|endoftext|>