<commit_before>//
//  main_image.c
//  climso-auto
//
//  Created by Maël Valais on 21/04/2014.
//  Copyright (c) 2014 Maël Valais. All rights reserved.
//

#define IMPULSION_PIXEL_H	25 //ms
#define IMPULSION_PIXEL_V	25 //ms
#define PIN_NORD			12
#define	PIN_SUD				11
#define	PIN_EST				10
#define PIN_OUEST			9

#define ARDUINO_DEV_LIST "/dev/ttyACM0 /dev/ttyACM1 /dev/ttyACM2 /dev/tty.usbmodemfa131 /dev/tty.usbmodemfd111"

#include <iostream>
#include <iomanip> // Pour cout << setprecision(4)
#include <csignal> // Pour éviter de ctrl+C sans supprimer les objets en mémoire
using namespace std;

#include "image.h"
#include "cmd_arduino.h"

void boucleDeGuidage(); // Prototype fonction
int main(int argc, char **argv) {
	boucleDeGuidage();
	return 0;
}

int main2(int argc, char **argv) {
	string empl = "images-de-correlation/test-correl-mv/\0";
	Image* obj = Image::depuisTiff(empl+"obj.tif");
	Image* ref = Image::tracerFormeSoleil(221);
	ref->versTiff(empl+"ref.tif");

	Image* obj_lapl = obj->convoluer(NOYAU_LAPLACIEN_TAB,NOYAU_LAPLACIEN_TAILLE);
	Image* ref_lapl = ref->convoluer(NOYAU_LAPLACIEN_TAB,NOYAU_LAPLACIEN_TAILLE);

	Image* correl = obj_lapl->correlation_rapide(*ref_lapl,0.9);
	correl->versTiff(empl+"correl.tif");
	double l_max, c_max;
	correl->maxParInterpolation(&l_max, &c_max);
	cout << "Max : (x=" << c_max << ",y=" << l_max << ")" <<endl;

	cout << "Hauteur relative : " << correl->calculerHauteurRelativeAutour(l_max,c_max) << endl;
	delete correl;
	delete obj; delete ref;
	delete obj_lapl; delete ref_lapl;
}

CSBIGCam* initialiserCamera() {
	CSBIGCam *cam = NULL;
	PAR_ERROR err;
	int num_essai = 0;
	do {
		if (num_essai > 0) {
			sleep(5);
			cout << "Essai de connexion à la caméra numéro " << num_essai << ":"<< endl;
		}
		if(cam != NULL)
			delete cam;
		cam = new CSBIGCam(DEV_USB); // Création du device USB
		if ((err = cam->GetError()) != CE_NO_ERROR) {
			cerr << "Erreur avec la camera lors de la création de l'objet caméra : " << cam->GetErrorString() << endl;
		}
		else if ((err=cam->EstablishLink()) != CE_NO_ERROR) { // Connexion à la caméra
			cerr << "Erreur avec la camera lors de l'établissement du lien: " << cam->GetErrorString() << endl;
		}
		else {
			// Ajustement du mode de lecture en binning 8x8 (cf "start exposure 2 parameters" dans la doc)
			// Pbms rencontrés : le readout-mode "RM_NXN" ne semblait pas fonctionner : il a fallu corriger
			// le mode numéro 10 dans csbigcam.cpp. Je suspecte que cette fonctionnalité n'a pas été implémentée
			// dans csbigcam.cpp.
			cam->SetReadoutMode(RM_3X3); // Binning 3x3 matériel
		}
		num_essai++;
	}
	while(err != CE_NO_ERROR);
	return cam;
}
int initialiserArduino() {
	int num_essai = 0;
	int fd_arduino;
	do {
		if (num_essai > 0) {
			sleep(5);
			cout << "Essai de connexion à l'arduino numéro " << num_essai << endl;
		}
		if((fd_arduino=arduinoInitialiserCom(ARDUINO_DEV_LIST)) == ARDUINO_ERR) {
			cerr << "Erreur de communication avec Arduino" << endl;
			char rep[300];
			arduinoRecevoirReponse(fd_arduino,rep);
			printf("%s",rep);
		}
		num_essai++;
	}
	while(fd_arduino == ARDUINO_ERR);
	return fd_arduino;
}

void signalHandler(int signum)
{
    cout << "Interruption " << signum << " recue\n";
    exit(signum);
}

void boucleDeGuidage() {
	// Emplacement des images debug
	string emplacement = "images-de-correlation/test-sbig/\0";

	signal(SIGINT, signalHandler);
    signal(SIGABRT, signalHandler);

	int fd_arduino = initialiserArduino();

	//
	// Création de l'image ayant la forme du soleil puis laplacien
	//
	Image *ref = Image::tracerFormeSoleil(221);
	//Image *ref_lapl = ref->convoluer(NOYAU_LAPLACIEN_TAB, NOYAU_LAPLACIEN_TAILLE);
	Image *ref_lapl = ref->convoluerParDerivee();
	int larg_img_cam, haut_img_cam;
	double l_max_initial,c_max_initial;
	double l_max, c_max;

	//
	// Connexion à la caméra
	//
	CSBIGImg *obj_sbig = new CSBIGImg;
	CSBIGCam *cam = initialiserCamera();

	//
	// Prise de vue, corrélation et interpolation pour trouver le centre du Soleil
	//
	while (cam->GrabImage(obj_sbig, SBDF_DARK_ALSO) != CE_NO_ERROR) {
        cerr << "Erreur avec la camera lors de la capture d'une image : " << cam->GetErrorString() << endl;
        delete cam; cam = initialiserCamera();
    }
	obj_sbig->AutoBackgroundAndRange();
    Image *obj_no_bin = Image::depuisSBIGImg(*obj_sbig);
    //obj_no_bin->versTiff(emplacement+"obj_initial");
    //obj_no_bin = Image::depuisTiff(emplacement+"obj_initial.tif");
	Image *obj = obj_no_bin->reduire(2);
    Image *obj_lapl = obj->convoluerParDerivee();//convoluer(NOYAU_LAPLACIEN_TAB, NOYAU_LAPLACIEN_TAILLE);
    Image *correl = obj_lapl->correlation_rapide(*ref_lapl, 0.70);
	correl->maxParInterpolation(&l_max_initial, &c_max_initial);

#if DEBUG
    obj->versTiff(emplacement+"t0_obj.tif");
	correl->versTiff(emplacement+"t0_correl.tif");
	obj_lapl->versTiff(emplacement+"t0_obj_lapl.tif");
    ref_lapl->versTiff(emplacement+"t0_ref_lapl.tif");
	ref->versTiff(emplacement+"t0_ref.tif");
#endif

    delete obj_sbig;
    delete obj;
	delete correl;
	delete obj_lapl;
	delete obj_no_bin;

	cout << fixed << showpoint << setprecision(2);
	cout << "La première prise de vue indique le Soleil à la position (x= "
			<<c_max_initial<< ", y=" <<l_max_initial<<")" << endl;

	do {

		sleep(5); // attendre N secondes

		obj_sbig = new CSBIGImg();
		while (cam->GrabImage(obj_sbig, SBDF_DARK_ALSO) != CE_NO_ERROR) {
			cerr << "Erreur avec la camera lors de la capture d'une image : " << cam->GetErrorString() << endl;
	        delete cam; cam = initialiserCamera();
		}
		obj_sbig->AutoBackgroundAndRange();
		obj_no_bin = Image::depuisSBIGImg(*obj_sbig);
	    //obj_no_bin = Image::depuisTiff(emplacement+"obj_initial.tif");
		obj = obj_no_bin->reduire(2); // Binning 2x2 logiciel
	    obj_lapl = obj->convoluerParDerivee();//convoluer(NOYAU_LAPLACIEN_TAB, NOYAU_LAPLACIEN_TAILLE);
		correl = obj_lapl->correlation_rapide(*ref_lapl, 0.70);
		correl->maxParInterpolation(&l_max, &c_max);
		double ratio = correl->calculerHauteurRelativeAutour(l_max,c_max);

#if DEBUG
		obj->versTiff(emplacement+"t_obj.tif");
		correl->versTiff(emplacement+"t_correl.tif");
		obj_lapl->versTiff(emplacement+"t_obj_lapl.tif");
#endif

		delete obj_sbig; 	// On devrait éviter de créer autant d'objet à chaque itération
		delete obj;			// Mais bon, re-coder tout est pénible
		delete correl;
		delete obj_lapl;
		delete obj_no_bin;
		//
		// Calcul du décalage x,y entre la position initiale
		//
		double l_decal = l_max - l_max_initial;
		double c_decal = c_max - c_max_initial;

		cout << "La prise de vue indique le Soleil à la position (x= "
				<< c_max << ", y=" <<l_max<<")" << endl;
		cout << "Le décalage avec l'image d'origine est de (x= "
				<< c_decal << ", y=" <<l_decal<<")" << endl;
		cout << "Ratio moyenne_autour_pix/valeur_pix : " << ratio << endl;

		while(arduinoEnvoyerCmd((l_decal<0)?PIN_SUD:PIN_NORD,
				((l_decal<0)?l_decal*(-1):l_decal)*IMPULSION_PIXEL_V,
				fd_arduino) == ARDUINO_ERR) {
			cerr << "Erreur de communication avec Arduino" << endl;
			fd_arduino = initialiserArduino();
		}
		while(arduinoEnvoyerCmd((c_decal<0)?PIN_OUEST:PIN_EST,
				((c_decal<0)?c_decal*(-1):c_decal)*IMPULSION_PIXEL_H,
				fd_arduino) == ARDUINO_ERR) {
			cerr << "Erreur de communication avec Arduino" << endl;
			fd_arduino = initialiserArduino();
		}
	} while(true);

	// Extinction du lien avec la caméra
	if (cam->CloseDevice() != CE_NO_ERROR) {
        cerr << "Erreur avec la camera : " << cam->GetErrorString() << endl;
        exit(1);
    }
}
<commit_msg>Divers<commit_after>//
//  main_image.c
//  climso-auto
//
//  Created by Maël Valais on 21/04/2014.
//  Copyright (c) 2014 Maël Valais. All rights reserved.
//

#define IMPULSION_PIXEL_H	25 //ms
#define IMPULSION_PIXEL_V	25 //ms
#define PIN_NORD			12
#define	PIN_SUD				11
#define	PIN_EST				10
#define PIN_OUEST			9

#define ARDUINO_DEV_LIST "/dev/ttyACM0 /dev/ttyACM1 /dev/ttyACM2 /dev/tty.usbmodemfa131 /dev/tty.usbmodemfd111"

#include <iostream>
#include <iomanip> // Pour cout << setprecision(4)
#include <csignal> // Pour éviter de ctrl+C sans supprimer les objets en mémoire
using namespace std;

#include "image.h"
#include "cmd_arduino.h"

void boucleDeGuidage(); // Prototype fonction
int main(int argc, char **argv) {
	boucleDeGuidage();
	return 0;
}

int main2(int argc, char **argv) {
	string empl = "images-de-correlation/test-correl-mv/\0";
	Image* obj = Image::depuisTiff(empl+"obj.tif");
	Image* ref = Image::tracerFormeSoleil(221);
	ref->versTiff(empl+"ref.tif");

	Image* obj_lapl = obj->convoluer(NOYAU_LAPLACIEN_TAB,NOYAU_LAPLACIEN_TAILLE);
	Image* ref_lapl = ref->convoluer(NOYAU_LAPLACIEN_TAB,NOYAU_LAPLACIEN_TAILLE);

	Image* correl = obj_lapl->correlation_rapide(*ref_lapl,0.9);
	correl->versTiff(empl+"correl.tif");
	double l_max, c_max;
	correl->maxParInterpolation(&l_max, &c_max);
	cout << "Max : (x=" << c_max << ",y=" << l_max << ")" <<endl;

	cout << "Hauteur relative : " << correl->calculerHauteurRelativeAutour(l_max,c_max) << endl;
	delete correl;
	delete obj; delete ref;
	delete obj_lapl; delete ref_lapl;
}

CSBIGCam* initialiserCamera() {
	CSBIGCam *cam = NULL;
	PAR_ERROR err;
	int num_essai = 0;
	do {
		if (num_essai > 0) {
			sleep(5);
			cout << "Essai de connexion à la caméra numéro " << num_essai << ":"<< endl;
		}
		if(cam != NULL)
			delete cam;
		cam = new CSBIGCam(DEV_USB); // Création du device USB
		if ((err = cam->GetError()) != CE_NO_ERROR) {
			cerr << "Erreur avec la camera lors de la création de l'objet caméra : " << cam->GetErrorString() << endl;
		}
		else if ((err=cam->EstablishLink()) != CE_NO_ERROR) { // Connexion à la caméra
			cerr << "Erreur avec la camera lors de l'établissement du lien: " << cam->GetErrorString() << endl;
		}
		else {
			// Ajustement du mode de lecture en binning 8x8 (cf "start exposure 2 parameters" dans la doc)
			// Pbms rencontrés : le readout-mode "RM_NXN" ne semblait pas fonctionner : il a fallu corriger
			// le mode numéro 10 dans csbigcam.cpp. Je suspecte que cette fonctionnalité n'a pas été implémentée
			// dans csbigcam.cpp.
			cam->SetReadoutMode(RM_3X3); // Binning 3x3 matériel
		}
		num_essai++;
	}
	while(err != CE_NO_ERROR);
	return cam;
}
int initialiserArduino() {
	int num_essai = 0;
	int fd_arduino;
	do {
		if (num_essai > 0) {
			sleep(5);
			cout << "Essai de connexion à l'arduino numéro " << num_essai << endl;
		}
		if((fd_arduino=arduinoInitialiserCom(ARDUINO_DEV_LIST)) == ARDUINO_ERR) {
			cerr << "Erreur de communication avec Arduino" << endl;
			char rep[300];
			arduinoRecevoirReponse(fd_arduino,rep);
			printf("%s",rep);
		}
		num_essai++;
	}
	while(fd_arduino == ARDUINO_ERR);
	return fd_arduino;
}

void signalHandler(int signum)
{
    cout << "Interruption " << signum << " recue\n";
    exit(signum);
}

void boucleDeGuidage() {
	// Emplacement des images debug
	string emplacement = "images-de-correlation/test-sbig/\0";

	signal(SIGINT, signalHandler);
    signal(SIGABRT, signalHandler);

	int fd_arduino = initialiserArduino();

	//
	// Création de l'image ayant la forme du soleil puis laplacien
	//
	Image *ref = Image::tracerFormeSoleil(228);
	//Image *ref_lapl = ref->convoluer(NOYAU_LAPLACIEN_TAB, NOYAU_LAPLACIEN_TAILLE);
	Image *ref_lapl = ref->convoluerParDerivee();
	int larg_img_cam, haut_img_cam;
	double l_max_initial,c_max_initial;
	double l_max, c_max;

	//
	// Connexion à la caméra
	//
	CSBIGImg *obj_sbig = new CSBIGImg;
	CSBIGCam *cam = initialiserCamera();

	//
	// Prise de vue, corrélation et interpolation pour trouver le centre du Soleil
	//
	while (cam->GrabImage(obj_sbig, SBDF_DARK_ALSO) != CE_NO_ERROR) {
        cerr << "Erreur avec la camera lors de la capture d'une image : " << cam->GetErrorString() << endl;
        delete cam; cam = initialiserCamera();
    }
	obj_sbig->AutoBackgroundAndRange();
    Image *obj_no_bin = Image::depuisSBIGImg(*obj_sbig);
    //obj_no_bin->versTiff(emplacement+"obj_initial");
    //obj_no_bin = Image::depuisTiff(emplacement+"obj_initial.tif");
	Image *obj = obj_no_bin->reduire(2);
    Image *obj_lapl = obj->convoluerParDerivee();//convoluer(NOYAU_LAPLACIEN_TAB, NOYAU_LAPLACIEN_TAILLE);
    Image *correl = obj_lapl->correlation_rapide(*ref_lapl, 0.70);
	correl->maxParInterpolation(&l_max_initial, &c_max_initial);

#if DEBUG
    obj->versTiff(emplacement+"t0_obj.tif");
	correl->versTiff(emplacement+"t0_correl.tif");
	obj_lapl->versTiff(emplacement+"t0_obj_lapl.tif");
    ref_lapl->versTiff(emplacement+"t0_ref_lapl.tif");
	ref->versTiff(emplacement+"t0_ref.tif");
#endif

    delete obj_sbig;
    delete obj;
	delete correl;
	delete obj_lapl;
	delete obj_no_bin;

	cout << fixed << showpoint << setprecision(2);
	cout << "La première prise de vue indique le Soleil à la position (x= "
			<<c_max_initial<< ", y=" <<l_max_initial<<")" << endl;

	do {

		sleep(5); // attendre N secondes

		obj_sbig = new CSBIGImg();
		while (cam->GrabImage(obj_sbig, SBDF_DARK_ALSO) != CE_NO_ERROR) {
			cerr << "Erreur avec la camera lors de la capture d'une image : " << cam->GetErrorString() << endl;
	        delete cam; cam = initialiserCamera();
		}
		obj_sbig->AutoBackgroundAndRange();
		obj_no_bin = Image::depuisSBIGImg(*obj_sbig);
	    //obj_no_bin = Image::depuisTiff(emplacement+"obj_initial.tif");
		obj = obj_no_bin->reduire(2); // Binning 2x2 logiciel
	    obj_lapl = obj->convoluerParDerivee();//convoluer(NOYAU_LAPLACIEN_TAB, NOYAU_LAPLACIEN_TAILLE);
		correl = obj_lapl->correlation_rapide(*ref_lapl, 0.70);
		correl->maxParInterpolation(&l_max, &c_max);
		double ratio = correl->calculerHauteurRelativeAutour(l_max,c_max);

#if DEBUG
		obj->versTiff(emplacement+"t_obj.tif");
		correl->versTiff(emplacement+"t_correl.tif");
		obj_lapl->versTiff(emplacement+"t_obj_lapl.tif");
#endif

		delete obj_sbig; 	// On devrait éviter de créer autant d'objet à chaque itération
		delete obj;			// Mais bon, re-coder tout est pénible
		delete correl;
		delete obj_lapl;
		delete obj_no_bin;
		//
		// Calcul du décalage x,y entre la position initiale
		//
		double l_decal = l_max - l_max_initial;
		double c_decal = c_max - c_max_initial;

		cout << "La prise de vue indique le Soleil à la position (x= "
				<< c_max << ", y=" <<l_max<<")" << endl;
		cout << "Le décalage avec l'image d'origine est de (x= "
				<< c_decal << ", y=" <<l_decal<<")" << endl;
		cout << "Ratio moyenne_autour_pix/valeur_pix : " << ratio << endl;

		while(arduinoEnvoyerCmd((l_decal<0)?PIN_SUD:PIN_NORD,
				((l_decal<0)?l_decal*(-1):l_decal)*IMPULSION_PIXEL_V,
				fd_arduino) == ARDUINO_ERR) {
			cerr << "Erreur de communication avec Arduino" << endl;
			fd_arduino = initialiserArduino();
		}
		while(arduinoEnvoyerCmd((c_decal<0)?PIN_OUEST:PIN_EST,
				((c_decal<0)?c_decal*(-1):c_decal)*IMPULSION_PIXEL_H,
				fd_arduino) == ARDUINO_ERR) {
			cerr << "Erreur de communication avec Arduino" << endl;
			fd_arduino = initialiserArduino();
		}
	} while(true);

	// Extinction du lien avec la caméra
	if (cam->CloseDevice() != CE_NO_ERROR) {
        cerr << "Erreur avec la camera : " << cam->GetErrorString() << endl;
        exit(1);
    }
}
<|endoftext|>


<commit_before>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file IfCan.hxx
 *
 * Asynchronous NMRAnet interface implementation for CANbus.
 *
 * @author Balazs Racz
 * @date 3 Dec 2013
 */

#ifndef _NMRANET_IFCAN_HXX_
#define _NMRANET_IFCAN_HXX_

#include <memory>

#include "executor/StateFlow.hxx"
#include "nmranet/If.hxx"
#include "nmranet/AliasCache.hxx"
#include "nmranet/Defs.hxx"
#include "utils/CanIf.hxx"

namespace nmranet
{

class IfCan;

/** Counts the number of alias conflicts that we see for aliases that we
 * already reserved. */
extern size_t g_alias_use_conflicts;

class AliasAllocator;
class IfCan;

/// Implementation of the OpenLCB interface abstraction for the CAN-bus
/// interface standard. This contains the parsers for CAN frames, dispatcher
/// for the different frame types, the alias mapping tables (both local and
/// remote nodes), and the flows responsible for sending outgoing
/// messages. Inherits handling of the MTI-indexed messages from the base class
/// @ref If.
class IfCan : public If, public CanIf
{
public:
    /**
     * Creates a CAN interface.
     *
     * @param executor will be used to process incoming (and outgoing) messages.
     *
     * @param device is a CanHub. The interface will add a member to this pipe
     * to handle incoming and outgoing traffic. The caller should add the
     * necessary hardware device, GridConnect bridge or mock interface to this
     * pipe (before this constructor or else outgoing packets might be lost).
     *
     * @param local_alias_cache_size tells the number of aliases to keep track
     * of for nocal virtual nodes and proxied nodes.
     *
     * @param remote_alias_cache_size tells the number of aliases to keep track
     * of for remote nodes on the bus.
     *
     * @param local_nodes_count is the maximum number of virtual nodes that
     * this interface will support. */
    IfCan(ExecutorBase *executor, CanHubFlow *device,
          int local_alias_cache_size, int remote_alias_cache_size,
          int local_nodes_count);

    ~IfCan();

    /** Adds support to this interface for addressed NMRAnet messages (both
     * sending and receiving). */
    void add_addressed_message_support();

    /// @returns the alias cache for local nodes (vnodes and proxies)
    AliasCache *local_aliases()
    {
        return &localAliases_;
    }

    /// @returns the alias cache for remote nodes on this IF
    AliasCache *remote_aliases()
    {
        return &remoteAliases_;
    }

    /// @returns the alias cache for remote nodes on this IF
    AliasAllocator *alias_allocator()
    {
        return aliasAllocator_.get();
    }

    /// Sets the alias allocator for this If. Takes ownership of pointer.
    void set_alias_allocator(AliasAllocator *a);

    void add_owned_flow(Executable *e) OVERRIDE;

    bool matching_node(NodeHandle expected, NodeHandle actual) OVERRIDE;

    void delete_local_node(Node *node) override;

private:
    void canonicalize_handle(NodeHandle* h);

    friend class CanFrameWriteFlow; // accesses the device and the hubport.

    /** Aliases we know are owned by local (virtual or proxied) nodes.
     *
     *  This member must only be accessed from the If's executor.
     */
    AliasCache localAliases_;
    /** Aliases we know are owned by remote nodes on this If.
     *
     *  This member must only be accessed from the If's executor.
     */
    AliasCache remoteAliases_;

    /// Various implementation control flows that this interface owns.
    std::vector<std::unique_ptr<Executable>> ownedFlows_;

    /// Owns the alias allocator module.
    std::unique_ptr<AliasAllocator> aliasAllocator_;

    DISALLOW_COPY_AND_ASSIGN(IfCan);
};

/** Base class for incoming CAN frame handlers. */
class CanFrameStateFlow : public StateFlow<Buffer<CanMessageData>, QList<1>>
{
public:
    CanFrameStateFlow(IfCan *service)
        : StateFlow<Buffer<CanMessageData>, QList<1>>(service)
    {
    }

    IfCan *if_can()
    {
        return static_cast<IfCan *>(service());
    }
};

} // namespace nmranet

#endif // _NMRANET_IFCAN_HXX_
<commit_msg>Adds a flow for translating an alias to a node id.<commit_after>/** \copyright
 * Copyright (c) 2013, Balazs Racz
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  - Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 *  - Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * \file IfCan.hxx
 *
 * Asynchronous NMRAnet interface implementation for CANbus.
 *
 * @author Balazs Racz
 * @date 3 Dec 2013
 */

#ifndef _NMRANET_IFCAN_HXX_
#define _NMRANET_IFCAN_HXX_

#include <memory>

#include "executor/StateFlow.hxx"
#include "nmranet/If.hxx"
#include "nmranet/AliasCache.hxx"
#include "nmranet/Defs.hxx"
#include "utils/CanIf.hxx"

namespace nmranet
{

class IfCan;

/** Counts the number of alias conflicts that we see for aliases that we
 * already reserved. */
extern size_t g_alias_use_conflicts;

class AliasAllocator;
class IfCan;

/// Implementation of the OpenLCB interface abstraction for the CAN-bus
/// interface standard. This contains the parsers for CAN frames, dispatcher
/// for the different frame types, the alias mapping tables (both local and
/// remote nodes), and the flows responsible for sending outgoing
/// messages. Inherits handling of the MTI-indexed messages from the base class
/// @ref If.
class IfCan : public If, public CanIf
{
public:
    /**
     * Creates a CAN interface.
     *
     * @param executor will be used to process incoming (and outgoing) messages.
     *
     * @param device is a CanHub. The interface will add a member to this pipe
     * to handle incoming and outgoing traffic. The caller should add the
     * necessary hardware device, GridConnect bridge or mock interface to this
     * pipe (before this constructor or else outgoing packets might be lost).
     *
     * @param local_alias_cache_size tells the number of aliases to keep track
     * of for nocal virtual nodes and proxied nodes.
     *
     * @param remote_alias_cache_size tells the number of aliases to keep track
     * of for remote nodes on the bus.
     *
     * @param local_nodes_count is the maximum number of virtual nodes that
     * this interface will support. */
    IfCan(ExecutorBase *executor, CanHubFlow *device,
          int local_alias_cache_size, int remote_alias_cache_size,
          int local_nodes_count);

    ~IfCan();

    /** Adds support to this interface for addressed NMRAnet messages (both
     * sending and receiving). */
    void add_addressed_message_support();

    /// @returns the alias cache for local nodes (vnodes and proxies)
    AliasCache *local_aliases()
    {
        return &localAliases_;
    }

    /// @returns the alias cache for remote nodes on this IF
    AliasCache *remote_aliases()
    {
        return &remoteAliases_;
    }

    /// @returns the alias cache for remote nodes on this IF
    AliasAllocator *alias_allocator()
    {
        return aliasAllocator_.get();
    }

    /// Sets the alias allocator for this If. Takes ownership of pointer.
    void set_alias_allocator(AliasAllocator *a);

    void add_owned_flow(Executable *e) OVERRIDE;

    bool matching_node(NodeHandle expected, NodeHandle actual) OVERRIDE;

    void delete_local_node(Node *node) override;

private:
    void canonicalize_handle(NodeHandle* h);

    friend class CanFrameWriteFlow; // accesses the device and the hubport.

    /** Aliases we know are owned by local (virtual or proxied) nodes.
     *
     *  This member must only be accessed from the If's executor.
     */
    AliasCache localAliases_;
    /** Aliases we know are owned by remote nodes on this If.
     *
     *  This member must only be accessed from the If's executor.
     */
    AliasCache remoteAliases_;

    /// Various implementation control flows that this interface owns.
    std::vector<std::unique_ptr<Executable>> ownedFlows_;

    /// Owns the alias allocator module.
    std::unique_ptr<AliasAllocator> aliasAllocator_;

    DISALLOW_COPY_AND_ASSIGN(IfCan);
};

/** Base class for incoming CAN frame handlers. */
class CanFrameStateFlow : public StateFlow<Buffer<CanMessageData>, QList<1>>
{
public:
    CanFrameStateFlow(IfCan *service)
        : StateFlow<Buffer<CanMessageData>, QList<1>>(service)
    {
    }

    IfCan *if_can()
    {
        return static_cast<IfCan *>(service());
    }
};

struct NodeCanonicalizeRequest
{
    /** Requests a NodeHandle to be canonicalized, i.e. look up node ID from
     * alias. */
    void reset(Node* node, NodeHandle handle)
    {
        srcNode = node;
        this->handle = handle;
        resultCode = 0;
    }

    Node* srcNode;
    NodeHandle handle;

    BarrierNotifiable done;
    int resultCode;
};

class NodeIdLookupFlow
    : public StateFlow<Buffer<NodeCanonicalizeRequest>, QList<1>>
{
public:
    NodeIdLookupFlow(IfCan *iface)
        : StateFlow<Buffer<NodeCanonicalizeRequest>, QList<1>>(iface)
    {
    }

    Action entry() override
    {
        if (input()->handle.id != 0)
        {
            return return_ok();
        }
        if (input()->handle.alias == 0)
        {
            // This is an empty handle, say that's OK.
            return return_ok();
        }
        NodeID id = iface()->remote_aliases()->lookup(input()->handle.alias);
        if (!id)
        {
            id = iface()->local_aliases()->lookup(input()->handle.alias);
        }
        if (id)
        {
            input()->handle.id = id;
            return return_ok();
        }
        return allocate_and_call(
            iface()->addressed_message_write_flow(), STATE(send_request));
    }

private:
    Action send_request()
    {
        auto *b =
            get_allocation_result(iface()->addressed_message_write_flow());
        b->data()->reset(Defs::MTI_VERIFY_NODE_ID_ADDRESSED,
            input()->srcNode->node_id(), input()->handle, EMPTY_PAYLOAD);
        replyHandler_.set_alias_waiting(input()->handle.alias);
        iface()->addressed_message_write_flow()->send(b);

        return sleep_and_call(&timer_, MSEC_TO_NSEC(700), STATE(reply_timeout));
    }

    Action reply_timeout()
    {
        replyHandler_.set_alias_waiting(0);
        if (!timer_.is_triggered())
        {
            return return_with_error(Defs::ERROR_OPENLCB_TIMEOUT);
        }
        if (!input()->handle.id)
        {
            return return_with_error(Defs::ERROR_OPENMRN_NOT_FOUND);
        }
        return return_ok();
    }

    class ReplyHandler : public MessageHandler
    {
    public:
        ReplyHandler(NodeIdLookupFlow *parent)
            : parent_(parent)
        {
            parent_->iface()->dispatcher()->register_handler(
                this, Defs::MTI_VERIFIED_NODE_ID_NUMBER, Defs::MTI_EXACT);
        }

        ~ReplyHandler()
        {
            parent_->iface()->dispatcher()->unregister_handler(
                this, Defs::MTI_VERIFIED_NODE_ID_NUMBER, Defs::MTI_EXACT);
        }

        /// Handler callback for incoming messages.
        void send(Buffer<NMRAnetMessage> *message, unsigned priority) OVERRIDE
        {
            AutoReleaseBuffer<NMRAnetMessage> ab(message);
            if (aliasWaiting_ == 0)
                return;

            NMRAnetMessage *msg = message->data();
            if (msg->src.alias != aliasWaiting_)
                return;

            if (msg->src.id != 0)
            {
                parent_->input()->handle.id = msg->src.id;
            }
            else if (msg->payload.size() == 6)
            {
                parent_->input()->handle.id =
                    data_to_node_id(msg->payload.data());
            }
            else
            {
                // Node ID verified with no source data. Problem.
            }
            set_alias_waiting(0);
            parent_->timer_.trigger();
        }

        void set_alias_waiting(NodeAlias a)
        {
            aliasWaiting_ = a;
        }

    private:
        enum
        {
            // AMD frames
            CAN_FILTER1 = CanMessageData::CAN_EXT_FRAME_FILTER | 0x10701000,
            CAN_MASK1 = CanMessageData::CAN_EXT_FRAME_MASK | 0x1FFFF000,
        };

        NodeAlias aliasWaiting_{0};
        NodeIdLookupFlow *parent_;
    } replyHandler_{this};

    friend class ReplyHandler;

    Action return_ok()
    {
        return return_with_error(0);
    }

    Action return_with_error(int error)
    {
        input()->resultCode = error;
        return_buffer();
        return exit();
    }

    NodeCanonicalizeRequest *input()
    {
        return message()->data();
    }

    IfCan *iface()
    {
        return static_cast<IfCan *>(service());
    }

    BarrierNotifiable bn_;
    StateFlowTimer timer_{this};
};

} // namespace nmranet

#endif // _NMRANET_IFCAN_HXX_
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/session_change_processor.h"

#include <sstream>
#include <string>
#include <vector>

#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "chrome/browser/extensions/extension_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/internal_api/read_node.h"
#include "chrome/browser/sync/internal_api/sync_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_details.h"
#include "content/common/notification_service.h"
#include "content/common/notification_source.h"

namespace browser_sync {

SessionChangeProcessor::SessionChangeProcessor(
    UnrecoverableErrorHandler* error_handler,
    SessionModelAssociator* session_model_associator)
    : ChangeProcessor(error_handler),
      session_model_associator_(session_model_associator),
      profile_(NULL),
      setup_for_test_(false) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(error_handler);
  DCHECK(session_model_associator_);
}

SessionChangeProcessor::SessionChangeProcessor(
    UnrecoverableErrorHandler* error_handler,
    SessionModelAssociator* session_model_associator,
    bool setup_for_test)
    : ChangeProcessor(error_handler),
      session_model_associator_(session_model_associator),
      profile_(NULL),
      setup_for_test_(setup_for_test) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(error_handler);
  DCHECK(session_model_associator_);
}

SessionChangeProcessor::~SessionChangeProcessor() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void SessionChangeProcessor::Observe(int type,
                                     const NotificationSource& source,
                                     const NotificationDetails& details) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(running());
  DCHECK(profile_);

  // Track which windows and/or tabs are modified.
  std::vector<SyncedTabDelegate*> modified_tabs;
  switch (type) {
    case chrome::NOTIFICATION_BROWSER_OPENED: {
      Browser* browser = Source<Browser>(source).ptr();
      if (browser->profile() != profile_) {
        return;
      }
      VLOG(1) << "Received BROWSER_OPENED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_TAB_PARENTED: {
      SyncedTabDelegate* tab = Source<SyncedTabDelegate>(source).ptr();
      if (tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received TAB_PARENTED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
      SyncedTabDelegate* tab =
          TabContentsWrapper::GetCurrentWrapperForContents(
              Source<TabContents>(source).ptr())->synced_tab_delegate();
      if (tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received LOAD_COMPLETED_MAIN_FRAME for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_TAB_CLOSED: {
      SyncedTabDelegate* tab =
          TabContentsWrapper::GetCurrentWrapperForContents(
              Source<NavigationController>(source).ptr()->tab_contents())->
              synced_tab_delegate();
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received TAB_CLOSED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_NAV_LIST_PRUNED: {
      SyncedTabDelegate* tab =
          TabContentsWrapper::GetCurrentWrapperForContents(
              Source<NavigationController>(source).ptr()->tab_contents())->
              synced_tab_delegate();
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received NAV_LIST_PRUNED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_NAV_ENTRY_CHANGED: {
      SyncedTabDelegate* tab =
          TabContentsWrapper::GetCurrentWrapperForContents(
              Source<NavigationController>(source).ptr()->tab_contents())->
              synced_tab_delegate();
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received NAV_ENTRY_CHANGED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
      SyncedTabDelegate* tab =
          TabContentsWrapper::GetCurrentWrapperForContents(
              Source<NavigationController>(source).ptr()->tab_contents())->
              synced_tab_delegate();
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received NAV_ENTRY_COMMITTED for profile " << profile_;
      break;
    }

    case chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: {
      ExtensionTabHelper* extension_tab_helper =
          Source<ExtensionTabHelper>(source).ptr();
      if (extension_tab_helper->tab_contents()->browser_context() != profile_) {
        return;
      }
      if (extension_tab_helper->extension_app()) {
        modified_tabs.push_back(extension_tab_helper->tab_contents_wrapper()->
            synced_tab_delegate());
      }
      VLOG(1) << "Received TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED "
              << "for profile " << profile_;
      break;
    }

    default:
      LOG(ERROR) << "Received unexpected notification of type "
                  << type;
      break;
  }

  // Associate tabs first so the synced session tracker is aware of them.
  if (!modified_tabs.empty())
    session_model_associator_->ReassociateTabs(modified_tabs);
  // Note, we always reassociate windows because it's possible a tab became
  // "interesting" by going to a valid URL, in which case it needs to be added
  // to the window's tab information.
  session_model_associator_->ReassociateWindows(false);
}

void SessionChangeProcessor::ApplyChangesFromSyncModel(
    const sync_api::BaseTransaction* trans,
    const sync_api::SyncManager::ChangeRecord* changes,
    int change_count) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!running()) {
    return;
  }

  StopObserving();

  sync_api::ReadNode root(trans);
  if (!root.InitByTagLookup(kSessionsTag)) {
    error_handler()->OnUnrecoverableError(FROM_HERE,
        "Sessions root node lookup failed.");
    return;
  }

  for (int i = 0; i < change_count; ++i) {
    const sync_api::SyncManager::ChangeRecord& change = changes[i];
    sync_api::SyncManager::ChangeRecord::Action action(change.action);
    if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == action) {
      // Deletions should only be for a foreign client itself, and hence affect
      // the header node, never a tab node.
      sync_api::ReadNode node(trans);
      if (!node.InitByIdLookup(change.id)) {
        error_handler()->OnUnrecoverableError(FROM_HERE,
                                              "Session node lookup failed.");
        return;
      }
      DCHECK_EQ(node.GetModelType(), syncable::SESSIONS);
      const sync_pb::SessionSpecifics& specifics = node.GetSessionSpecifics();
      session_model_associator_->DisassociateForeignSession(
          specifics.session_tag());
      continue;
    }

    // Handle an update or add.
    sync_api::ReadNode sync_node(trans);
    if (!sync_node.InitByIdLookup(change.id)) {
      error_handler()->OnUnrecoverableError(FROM_HERE,
          "Session node lookup failed.");
      return;
    }

    // Check that the changed node is a child of the session folder.
    DCHECK(root.GetId() == sync_node.GetParentId());
    DCHECK(syncable::SESSIONS == sync_node.GetModelType());

    const sync_pb::SessionSpecifics& specifics(
        sync_node.GetSessionSpecifics());
    if (specifics.session_tag() ==
            session_model_associator_->GetCurrentMachineTag() &&
        !setup_for_test_) {
      // We should only ever receive a change to our own machine's session info
      // if encryption was turned on. In that case, the data is still the same,
      // so we can ignore.
      LOG(WARNING) << "Dropping modification to local session.";
      StartObserving();
      return;
    }
    const int64 mtime = sync_node.GetModificationTime();
    // Model associator handles foreign session update and add the same.
    session_model_associator_->AssociateForeignSpecifics(specifics, mtime);
  }

  // Notify foreign session handlers that there are new sessions.
  NotificationService::current()->Notify(
      chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
      NotificationService::AllSources(),
      NotificationService::NoDetails());

  StartObserving();
}

void SessionChangeProcessor::StartImpl(Profile* profile) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile);
  DCHECK(profile_ == NULL);
  profile_ = profile;
  StartObserving();
}

void SessionChangeProcessor::StopImpl() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  StopObserving();
  profile_ = NULL;
}

void SessionChangeProcessor::StartObserving() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile_);
  notification_registrar_.Add(this, content::NOTIFICATION_TAB_PARENTED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_TAB_CLOSED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
      NotificationService::AllBrowserContextsAndSources());
  notification_registrar_.Add(this,
      chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
      NotificationService::AllSources());
  notification_registrar_.Add(this,
      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
      NotificationService::AllBrowserContextsAndSources());
}

void SessionChangeProcessor::StopObserving() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile_);
  notification_registrar_.RemoveAll();
}

}  // namespace browser_sync
<commit_msg>Correct bug 92544 (Crash).<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/sync/glue/session_change_processor.h"

#include <sstream>
#include <string>
#include <vector>

#include "base/logging.h"
#include "base/memory/scoped_vector.h"
#include "chrome/browser/extensions/extension_tab_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/glue/session_model_associator.h"
#include "chrome/browser/sync/internal_api/read_node.h"
#include "chrome/browser/sync/internal_api/sync_manager.h"
#include "chrome/browser/sync/profile_sync_service.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/browser/tab_contents/navigation_controller.h"
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_details.h"
#include "content/common/notification_service.h"
#include "content/common/notification_source.h"

namespace browser_sync {

namespace {
// Extract the source SyncedTabDelegate from a NotificationSource originating
// from a NavigationController, if it exists. Returns |NULL| otherwise.
SyncedTabDelegate* ExtractSyncedTabDelegate(const NotificationSource& source) {
  TabContentsWrapper* tab =  TabContentsWrapper::GetCurrentWrapperForContents(
      Source<NavigationController>(source).ptr()->tab_contents());
  if (!tab)
    return NULL;
  return tab->synced_tab_delegate();
}
}

SessionChangeProcessor::SessionChangeProcessor(
    UnrecoverableErrorHandler* error_handler,
    SessionModelAssociator* session_model_associator)
    : ChangeProcessor(error_handler),
      session_model_associator_(session_model_associator),
      profile_(NULL),
      setup_for_test_(false) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(error_handler);
  DCHECK(session_model_associator_);
}

SessionChangeProcessor::SessionChangeProcessor(
    UnrecoverableErrorHandler* error_handler,
    SessionModelAssociator* session_model_associator,
    bool setup_for_test)
    : ChangeProcessor(error_handler),
      session_model_associator_(session_model_associator),
      profile_(NULL),
      setup_for_test_(setup_for_test) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(error_handler);
  DCHECK(session_model_associator_);
}

SessionChangeProcessor::~SessionChangeProcessor() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void SessionChangeProcessor::Observe(int type,
                                     const NotificationSource& source,
                                     const NotificationDetails& details) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(running());
  DCHECK(profile_);

  // Track which windows and/or tabs are modified.
  std::vector<SyncedTabDelegate*> modified_tabs;
  switch (type) {
    case chrome::NOTIFICATION_BROWSER_OPENED: {
      Browser* browser = Source<Browser>(source).ptr();
      if (browser->profile() != profile_) {
        return;
      }
      VLOG(1) << "Received BROWSER_OPENED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_TAB_PARENTED: {
      SyncedTabDelegate* tab = Source<SyncedTabDelegate>(source).ptr();
      if (tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received TAB_PARENTED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME: {
      SyncedTabDelegate* tab =
          TabContentsWrapper::GetCurrentWrapperForContents(
              Source<TabContents>(source).ptr())->synced_tab_delegate();
      if (tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received LOAD_COMPLETED_MAIN_FRAME for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_TAB_CLOSED: {
      SyncedTabDelegate* tab = ExtractSyncedTabDelegate(source);
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received TAB_CLOSED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_NAV_LIST_PRUNED: {
      SyncedTabDelegate* tab = ExtractSyncedTabDelegate(source);
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received NAV_LIST_PRUNED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_NAV_ENTRY_CHANGED: {
      SyncedTabDelegate* tab = ExtractSyncedTabDelegate(source);
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received NAV_ENTRY_CHANGED for profile " << profile_;
      break;
    }

    case content::NOTIFICATION_NAV_ENTRY_COMMITTED: {
      SyncedTabDelegate* tab = ExtractSyncedTabDelegate(source);
      if (!tab || tab->profile() != profile_) {
        return;
      }
      modified_tabs.push_back(tab);
      VLOG(1) << "Received NAV_ENTRY_COMMITTED for profile " << profile_;
      break;
    }

    case chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED: {
      ExtensionTabHelper* extension_tab_helper =
          Source<ExtensionTabHelper>(source).ptr();
      if (extension_tab_helper->tab_contents()->browser_context() != profile_) {
        return;
      }
      if (extension_tab_helper->extension_app()) {
        modified_tabs.push_back(extension_tab_helper->tab_contents_wrapper()->
            synced_tab_delegate());
      }
      VLOG(1) << "Received TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED "
              << "for profile " << profile_;
      break;
    }

    default:
      LOG(ERROR) << "Received unexpected notification of type "
                  << type;
      break;
  }

  // Associate tabs first so the synced session tracker is aware of them.
  if (!modified_tabs.empty())
    session_model_associator_->ReassociateTabs(modified_tabs);
  // Note, we always reassociate windows because it's possible a tab became
  // "interesting" by going to a valid URL, in which case it needs to be added
  // to the window's tab information.
  session_model_associator_->ReassociateWindows(false);
}

void SessionChangeProcessor::ApplyChangesFromSyncModel(
    const sync_api::BaseTransaction* trans,
    const sync_api::SyncManager::ChangeRecord* changes,
    int change_count) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (!running()) {
    return;
  }

  StopObserving();

  sync_api::ReadNode root(trans);
  if (!root.InitByTagLookup(kSessionsTag)) {
    error_handler()->OnUnrecoverableError(FROM_HERE,
        "Sessions root node lookup failed.");
    return;
  }

  for (int i = 0; i < change_count; ++i) {
    const sync_api::SyncManager::ChangeRecord& change = changes[i];
    sync_api::SyncManager::ChangeRecord::Action action(change.action);
    if (sync_api::SyncManager::ChangeRecord::ACTION_DELETE == action) {
      // Deletions should only be for a foreign client itself, and hence affect
      // the header node, never a tab node.
      sync_api::ReadNode node(trans);
      if (!node.InitByIdLookup(change.id)) {
        error_handler()->OnUnrecoverableError(FROM_HERE,
                                              "Session node lookup failed.");
        return;
      }
      DCHECK_EQ(node.GetModelType(), syncable::SESSIONS);
      const sync_pb::SessionSpecifics& specifics = node.GetSessionSpecifics();
      session_model_associator_->DisassociateForeignSession(
          specifics.session_tag());
      continue;
    }

    // Handle an update or add.
    sync_api::ReadNode sync_node(trans);
    if (!sync_node.InitByIdLookup(change.id)) {
      error_handler()->OnUnrecoverableError(FROM_HERE,
          "Session node lookup failed.");
      return;
    }

    // Check that the changed node is a child of the session folder.
    DCHECK(root.GetId() == sync_node.GetParentId());
    DCHECK(syncable::SESSIONS == sync_node.GetModelType());

    const sync_pb::SessionSpecifics& specifics(
        sync_node.GetSessionSpecifics());
    if (specifics.session_tag() ==
            session_model_associator_->GetCurrentMachineTag() &&
        !setup_for_test_) {
      // We should only ever receive a change to our own machine's session info
      // if encryption was turned on. In that case, the data is still the same,
      // so we can ignore.
      LOG(WARNING) << "Dropping modification to local session.";
      StartObserving();
      return;
    }
    const int64 mtime = sync_node.GetModificationTime();
    // Model associator handles foreign session update and add the same.
    session_model_associator_->AssociateForeignSpecifics(specifics, mtime);
  }

  // Notify foreign session handlers that there are new sessions.
  NotificationService::current()->Notify(
      chrome::NOTIFICATION_FOREIGN_SESSION_UPDATED,
      NotificationService::AllSources(),
      NotificationService::NoDetails());

  StartObserving();
}

void SessionChangeProcessor::StartImpl(Profile* profile) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile);
  DCHECK(profile_ == NULL);
  profile_ = profile;
  StartObserving();
}

void SessionChangeProcessor::StopImpl() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  StopObserving();
  profile_ = NULL;
}

void SessionChangeProcessor::StartObserving() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile_);
  notification_registrar_.Add(this, content::NOTIFICATION_TAB_PARENTED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_TAB_CLOSED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_NAV_LIST_PRUNED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_CHANGED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED,
      NotificationService::AllSources());
  notification_registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED,
      NotificationService::AllBrowserContextsAndSources());
  notification_registrar_.Add(this,
      chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
      NotificationService::AllSources());
  notification_registrar_.Add(this,
      content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
      NotificationService::AllBrowserContextsAndSources());
}

void SessionChangeProcessor::StopObserving() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DCHECK(profile_);
  notification_registrar_.RemoveAll();
}

}  // namespace browser_sync
<|endoftext|>


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

/**
 * @file
 * Declaration of a request, the overall memory request consisting of
 the parts of the request that are persistent throughout the transaction.
 */

#ifndef __MEM_REQUEST_HH__
#define __MEM_REQUEST_HH__

#include "base/fast_alloc.hh"
#include "sim/host.hh"
#include "sim/core.hh"

#include <cassert>

class Request;

typedef Request* RequestPtr;

/** ASI information for this request if it exsits. */
const uint32_t ASI_BITS         = 0x000FF;
/** The request is a Load locked/store conditional. */
const uint32_t LOCKED           = 0x00100;
/** The virtual address is also the physical address. */
const uint32_t PHYSICAL         = 0x00200;
/** The request is an ALPHA VPTE pal access (hw_ld). */
const uint32_t VPTE             = 0x00400;
/** Use the alternate mode bits in ALPHA. */
const uint32_t ALTMODE          = 0x00800;
/** The request is to an uncacheable address. */
const uint32_t UNCACHEABLE      = 0x01000;
/** The request should not cause a page fault. */
const uint32_t NO_FAULT         = 0x02000;
/** The request should be prefetched into the exclusive state. */
const uint32_t PF_EXCLUSIVE     = 0x10000;
/** The request should be marked as LRU. */
const uint32_t EVICT_NEXT       = 0x20000;
/** The request should ignore unaligned access faults */
const uint32_t NO_ALIGN_FAULT   = 0x40000;
/** The request was an instruction read. */
const uint32_t INST_READ        = 0x80000;
/** This request is for a memory swap. */
const uint32_t MEM_SWAP         = 0x100000;
const uint32_t MEM_SWAP_COND    = 0x200000;
/** The request should ignore unaligned access faults */
const uint32_t NO_HALF_WORD_ALIGN_FAULT = 0x400000;

class Request : public FastAlloc
{
  private:
    /**
     * The physical address of the request. Valid only if validPaddr
     * is set. */
    Addr paddr;

    /**
     * The size of the request. This field must be set when vaddr or
     * paddr is written via setVirt() or setPhys(), so it is always
     * valid as long as one of the address fields is valid.  */
    int size;

    /** Flag structure for the request. */
    uint32_t flags;

    /**
     * The time this request was started. Used to calculate
     * latencies. This field is set to curTick any time paddr or vaddr
     * is written.  */
    Tick time;

    /** The address space ID. */
    int asid;

    /** This request is to a memory mapped register. */
    bool mmapedIpr;

    /** The virtual address of the request. */
    Addr vaddr;

    /** Extra data for the request, such as the return value of
     * store conditional or the compare value for a CAS. */
    uint64_t extraData;

    /** The cpu number (for statistics, typically). */
    int cpuNum;
    /** The requesting thread id (for statistics, typically). */
    int  threadNum;

    /** program counter of initiating access; for tracing/debugging */
    Addr pc;

    /** Whether or not paddr is valid (has been written yet). */
    bool validPaddr;
    /** Whether or not the asid & vaddr are valid. */
    bool validAsidVaddr;
    /** Whether or not the sc result is valid. */
    bool validExData;
    /** Whether or not the cpu number & thread ID are valid. */
    bool validCpuAndThreadNums;
    /** Whether or not the pc is valid. */
    bool validPC;

  public:
    /** Minimal constructor.  No fields are initialized. */
    Request()
        : validPaddr(false), validAsidVaddr(false),
          validExData(false), validCpuAndThreadNums(false), validPC(false)
    {}

    /**
     * Constructor for physical (e.g. device) requests.  Initializes
     * just physical address, size, flags, and timestamp (to curTick).
     * These fields are adequate to perform a request.  */
    Request(Addr _paddr, int _size, int _flags)
        : validCpuAndThreadNums(false)
    { setPhys(_paddr, _size, _flags); }

    Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc,
            int _cpuNum, int _threadNum)
    {
        setThreadContext(_cpuNum, _threadNum);
        setVirt(_asid, _vaddr, _size, _flags, _pc);
    }

    ~Request() {}  // for FastAlloc

    /**
     * Set up CPU and thread numbers. */
    void setThreadContext(int _cpuNum, int _threadNum)
    {
        cpuNum = _cpuNum;
        threadNum = _threadNum;
        validCpuAndThreadNums = true;
    }

    /**
     * Set up a physical (e.g. device) request in a previously
     * allocated Request object. */
    void setPhys(Addr _paddr, int _size, int _flags)
    {
        paddr = _paddr;
        size = _size;
        flags = _flags;
        time = curTick;
        validPaddr = true;
        validAsidVaddr = false;
        validPC = false;
        validExData = false;
        mmapedIpr = false;
    }

    /**
     * Set up a virtual (e.g., CPU) request in a previously
     * allocated Request object. */
    void setVirt(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc)
    {
        asid = _asid;
        vaddr = _vaddr;
        size = _size;
        flags = _flags;
        pc = _pc;
        time = curTick;
        validPaddr = false;
        validAsidVaddr = true;
        validPC = true;
        validExData = false;
        mmapedIpr = false;
    }

    /** Set just the physical address.  This should only be used to
     * record the result of a translation, and thus the vaddr must be
     * valid before this method is called.  Otherwise, use setPhys()
     * to guarantee that the size and flags are also set.
     */
    void setPaddr(Addr _paddr)
    {
        assert(validAsidVaddr);
        paddr = _paddr;
        validPaddr = true;
    }

    /** Accessor for paddr. */
    Addr getPaddr() { assert(validPaddr); return paddr; }

    /** Accessor for size. */
    int getSize() { assert(validPaddr || validAsidVaddr); return size; }
    /** Accessor for time. */
    Tick getTime() { assert(validPaddr || validAsidVaddr); return time; }
    void resetTime() { assert(validPaddr || validAsidVaddr); time = curTick; }

    /** Accessor for flags. */
    uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; }
    /** Accessor for paddr. */
    void setFlags(uint32_t _flags)
    { assert(validPaddr || validAsidVaddr); flags = _flags; }

    /** Accessor function for vaddr.*/
    Addr getVaddr() { assert(validAsidVaddr); return vaddr; }

    /** Accessor function for asid.*/
    int getAsid() { assert(validAsidVaddr); return asid; }

    /** Accessor function for asi.*/
    uint8_t getAsi() { assert(validAsidVaddr); return flags & ASI_BITS; }

    /** Accessor function for asi.*/
    void setAsi(uint8_t a)
    { assert(validAsidVaddr); flags = (flags & ~ASI_BITS) | a; }

    /** Accessor function for asi.*/
    bool isMmapedIpr() { assert(validPaddr); return mmapedIpr; }

    /** Accessor function for asi.*/
    void setMmapedIpr(bool r) { assert(validAsidVaddr); mmapedIpr = r; }

    /** Accessor function to check if sc result is valid. */
    bool extraDataValid() { return validExData; }
    /** Accessor function for store conditional return value.*/
    uint64_t getExtraData() { assert(validExData); return extraData; }
    /** Accessor function for store conditional return value.*/
    void setExtraData(uint64_t _extraData)
    { extraData = _extraData; validExData = true; }

    /** Accessor function for cpu number.*/
    int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; }
    /** Accessor function for thread number.*/
    int getThreadNum()  { assert(validCpuAndThreadNums); return threadNum; }

    /** Accessor function for pc.*/
    Addr getPC() { assert(validPC); return pc; }

    /** Accessor Function to Check Cacheability. */
    bool isUncacheable() { return (getFlags() & UNCACHEABLE) != 0; }

    bool isInstRead() { return (getFlags() & INST_READ) != 0; }

    bool isLocked() { return (getFlags() & LOCKED) != 0; }

    bool isSwap() { return (getFlags() & MEM_SWAP ||
                            getFlags() & MEM_SWAP_COND); }

    bool isCondSwap() { return (getFlags() & MEM_SWAP_COND) != 0; }

    bool inline isMisaligned() {return (!(getFlags() & NO_ALIGN_FAULT) &&
                                        ((vaddr & 1)  ||
                                         (!(getFlags() & NO_HALF_WORD_ALIGN_FAULT)
                                          && (vaddr & 0x2))));}

    friend class Packet;
};

#endif // __MEM_REQUEST_HH__
<commit_msg>mem: Add a method for setting the time on a packet.<commit_after>/*
 * Copyright (c) 2002-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ron Dreslinski
 *          Steve Reinhardt
 *          Ali Saidi
 */

/**
 * @file
 * Declaration of a request, the overall memory request consisting of
 the parts of the request that are persistent throughout the transaction.
 */

#ifndef __MEM_REQUEST_HH__
#define __MEM_REQUEST_HH__

#include "base/fast_alloc.hh"
#include "sim/host.hh"
#include "sim/core.hh"

#include <cassert>

class Request;

typedef Request* RequestPtr;

/** ASI information for this request if it exsits. */
const uint32_t ASI_BITS         = 0x000FF;
/** The request is a Load locked/store conditional. */
const uint32_t LOCKED           = 0x00100;
/** The virtual address is also the physical address. */
const uint32_t PHYSICAL         = 0x00200;
/** The request is an ALPHA VPTE pal access (hw_ld). */
const uint32_t VPTE             = 0x00400;
/** Use the alternate mode bits in ALPHA. */
const uint32_t ALTMODE          = 0x00800;
/** The request is to an uncacheable address. */
const uint32_t UNCACHEABLE      = 0x01000;
/** The request should not cause a page fault. */
const uint32_t NO_FAULT         = 0x02000;
/** The request should be prefetched into the exclusive state. */
const uint32_t PF_EXCLUSIVE     = 0x10000;
/** The request should be marked as LRU. */
const uint32_t EVICT_NEXT       = 0x20000;
/** The request should ignore unaligned access faults */
const uint32_t NO_ALIGN_FAULT   = 0x40000;
/** The request was an instruction read. */
const uint32_t INST_READ        = 0x80000;
/** This request is for a memory swap. */
const uint32_t MEM_SWAP         = 0x100000;
const uint32_t MEM_SWAP_COND    = 0x200000;
/** The request should ignore unaligned access faults */
const uint32_t NO_HALF_WORD_ALIGN_FAULT = 0x400000;

class Request : public FastAlloc
{
  private:
    /**
     * The physical address of the request. Valid only if validPaddr
     * is set. */
    Addr paddr;

    /**
     * The size of the request. This field must be set when vaddr or
     * paddr is written via setVirt() or setPhys(), so it is always
     * valid as long as one of the address fields is valid.  */
    int size;

    /** Flag structure for the request. */
    uint32_t flags;

    /**
     * The time this request was started. Used to calculate
     * latencies. This field is set to curTick any time paddr or vaddr
     * is written.  */
    Tick time;

    /** The address space ID. */
    int asid;

    /** This request is to a memory mapped register. */
    bool mmapedIpr;

    /** The virtual address of the request. */
    Addr vaddr;

    /** Extra data for the request, such as the return value of
     * store conditional or the compare value for a CAS. */
    uint64_t extraData;

    /** The cpu number (for statistics, typically). */
    int cpuNum;
    /** The requesting thread id (for statistics, typically). */
    int  threadNum;

    /** program counter of initiating access; for tracing/debugging */
    Addr pc;

    /** Whether or not paddr is valid (has been written yet). */
    bool validPaddr;
    /** Whether or not the asid & vaddr are valid. */
    bool validAsidVaddr;
    /** Whether or not the sc result is valid. */
    bool validExData;
    /** Whether or not the cpu number & thread ID are valid. */
    bool validCpuAndThreadNums;
    /** Whether or not the pc is valid. */
    bool validPC;

  public:
    /** Minimal constructor.  No fields are initialized. */
    Request()
        : validPaddr(false), validAsidVaddr(false),
          validExData(false), validCpuAndThreadNums(false), validPC(false)
    {}

    /**
     * Constructor for physical (e.g. device) requests.  Initializes
     * just physical address, size, flags, and timestamp (to curTick).
     * These fields are adequate to perform a request.  */
    Request(Addr _paddr, int _size, int _flags)
        : validCpuAndThreadNums(false)
    { setPhys(_paddr, _size, _flags); }

    Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc,
            int _cpuNum, int _threadNum)
    {
        setThreadContext(_cpuNum, _threadNum);
        setVirt(_asid, _vaddr, _size, _flags, _pc);
    }

    ~Request() {}  // for FastAlloc

    /**
     * Set up CPU and thread numbers. */
    void setThreadContext(int _cpuNum, int _threadNum)
    {
        cpuNum = _cpuNum;
        threadNum = _threadNum;
        validCpuAndThreadNums = true;
    }

    /**
     * Set up a physical (e.g. device) request in a previously
     * allocated Request object. */
    void setPhys(Addr _paddr, int _size, int _flags)
    {
        paddr = _paddr;
        size = _size;
        flags = _flags;
        time = curTick;
        validPaddr = true;
        validAsidVaddr = false;
        validPC = false;
        validExData = false;
        mmapedIpr = false;
    }

    /**
     * Set up a virtual (e.g., CPU) request in a previously
     * allocated Request object. */
    void setVirt(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc)
    {
        asid = _asid;
        vaddr = _vaddr;
        size = _size;
        flags = _flags;
        pc = _pc;
        time = curTick;
        validPaddr = false;
        validAsidVaddr = true;
        validPC = true;
        validExData = false;
        mmapedIpr = false;
    }

    /** Set just the physical address.  This should only be used to
     * record the result of a translation, and thus the vaddr must be
     * valid before this method is called.  Otherwise, use setPhys()
     * to guarantee that the size and flags are also set.
     */
    void setPaddr(Addr _paddr)
    {
        assert(validAsidVaddr);
        paddr = _paddr;
        validPaddr = true;
    }

    /** Accessor for paddr. */
    Addr getPaddr() { assert(validPaddr); return paddr; }

    /** Accessor for size. */
    int getSize() { assert(validPaddr || validAsidVaddr); return size; }
    /** Accessor for time. */
    Tick getTime() { assert(validPaddr || validAsidVaddr); return time; }
    void resetTime() { assert(validPaddr || validAsidVaddr); time = curTick; }
    void
    setTime(Tick when)
    {
        assert(validPaddr || validAsidVaddr);
        time = when;
    }

    /** Accessor for flags. */
    uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; }
    /** Accessor for paddr. */
    void setFlags(uint32_t _flags)
    { assert(validPaddr || validAsidVaddr); flags = _flags; }

    /** Accessor function for vaddr.*/
    Addr getVaddr() { assert(validAsidVaddr); return vaddr; }

    /** Accessor function for asid.*/
    int getAsid() { assert(validAsidVaddr); return asid; }

    /** Accessor function for asi.*/
    uint8_t getAsi() { assert(validAsidVaddr); return flags & ASI_BITS; }

    /** Accessor function for asi.*/
    void setAsi(uint8_t a)
    { assert(validAsidVaddr); flags = (flags & ~ASI_BITS) | a; }

    /** Accessor function for asi.*/
    bool isMmapedIpr() { assert(validPaddr); return mmapedIpr; }

    /** Accessor function for asi.*/
    void setMmapedIpr(bool r) { assert(validAsidVaddr); mmapedIpr = r; }

    /** Accessor function to check if sc result is valid. */
    bool extraDataValid() { return validExData; }
    /** Accessor function for store conditional return value.*/
    uint64_t getExtraData() { assert(validExData); return extraData; }
    /** Accessor function for store conditional return value.*/
    void setExtraData(uint64_t _extraData)
    { extraData = _extraData; validExData = true; }

    /** Accessor function for cpu number.*/
    int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; }
    /** Accessor function for thread number.*/
    int getThreadNum()  { assert(validCpuAndThreadNums); return threadNum; }

    /** Accessor function for pc.*/
    Addr getPC() { assert(validPC); return pc; }

    /** Accessor Function to Check Cacheability. */
    bool isUncacheable() { return (getFlags() & UNCACHEABLE) != 0; }

    bool isInstRead() { return (getFlags() & INST_READ) != 0; }

    bool isLocked() { return (getFlags() & LOCKED) != 0; }

    bool isSwap() { return (getFlags() & MEM_SWAP ||
                            getFlags() & MEM_SWAP_COND); }

    bool isCondSwap() { return (getFlags() & MEM_SWAP_COND) != 0; }

    bool inline isMisaligned() {return (!(getFlags() & NO_ALIGN_FAULT) &&
                                        ((vaddr & 1)  ||
                                         (!(getFlags() & NO_HALF_WORD_ALIGN_FAULT)
                                          && (vaddr & 0x2))));}

    friend class Packet;
};

#endif // __MEM_REQUEST_HH__
<|endoftext|>


<commit_before>#include "opencl.h"
#include "common/logger.h"
#include <fstream>
#include <sstream>
#include <cassert>

namespace ncv
{
        ocl::manager_t::manager_t()
        {
                try
                {
                        cl_int err = cl::Platform::get(&m_platforms);
                        log_info() << "OpenCL status (platform query): " << ocl::error_string(err);

                        if (m_platforms.empty())
                        {
                                log_error() << "Cannot find any OpenCL platforms!";
                                return;
                        }

                        cl_context_properties properties[] =
                        {
                                CL_CONTEXT_PLATFORM,
                                (cl_context_properties)(m_platforms[0])(),
                                0
                        };
                        m_context = cl::Context(CL_DEVICE_TYPE_GPU, properties);
                        m_devices = m_context.getInfo<CL_CONTEXT_DEVICES>();

                        if (m_devices.empty())
                        {
                                log_error() << "Cannot find any OpenCL GPU device!";
                                return;
                        }

                        for (size_t i = 0; i < m_devices.size(); i ++)
                        {
                                const cl::Device& device = m_devices[i];

                                const std::string name = device.getInfo<CL_DEVICE_NAME>();
                                const std::string vendor = device.getInfo<CL_DEVICE_VENDOR>();
                                const std::string driver = device.getInfo<CL_DRIVER_VERSION>();
                                const std::string version = device.getInfo<CL_DEVICE_VERSION>();

                                const size_t gmemsize = device.getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>();
                                const size_t lmemsize = device.getInfo<CL_DEVICE_LOCAL_MEM_SIZE>();
                                const size_t amemsize = device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>();
                                const size_t cmemsize = device.getInfo<CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE>();
                                const size_t maxcus = device.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>();
                                const size_t maxwgsize = device.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>();
                                const size_t maxwidims = device.getInfo<CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS>();
                                const std::vector<size_t> maxwisizes = device.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
                                const size_t maxkparams = device.getInfo<CL_DEVICE_MAX_PARAMETER_SIZE>();

                                std::stringstream ss;
                                ss << "OpenCL device [" << (i + 1) << "/" << m_devices.size() << "]: ";
                                const std::string base = ss.str();

                                log_info() << base << "CL_DEVICE_NAME: " << name;
                                log_info() << base << "CL_DEVICE_VENDOR:" << vendor;
                                log_info() << base << "CL_DRIVER_VERSION: " << driver;
                                log_info() << base << "CL_DEVICE_VERSION: " << version;
                                log_info() << base << "CL_DEVICE_TYPE: " << "CL_DEVICE_TYPE_GPU";
                                log_info() << base << "CL_DEVICE_GLOBAL_MEM_SIZE: " << gmemsize << "B = "
                                           << (gmemsize / 1024) << "KB = " << (gmemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_LOCAL_MEM_SIZE: " << lmemsize << "B = "
                                           << (lmemsize / 1024) << "KB = " << (lmemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: " << cmemsize << "B = "
                                           << (cmemsize / 1024) << "KB = " << (cmemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_MAX_MEM_ALLOC_SIZE: " << amemsize << "B = "
                                           << (amemsize / 1024) << "KB = " << (amemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_MAX_COMPUTE_UNITS: " << maxcus;
                                log_info() << base << "CL_DEVICE_MAX_WORK_GROUP_SIZE: " << maxwgsize;
                                log_info() << base << "CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: " << maxwidims;
                                log_info() << base << "CL_DEVICE_MAX_WORK_ITEM_SIZES: "
                                           << (maxwisizes.size() > 0 ? maxwisizes[0] : 0) << " / "
                                           << (maxwisizes.size() > 1 ? maxwisizes[1] : 0) << " / "
                                           << (maxwisizes.size() > 2 ? maxwisizes[2] : 0);
                                log_info() << base << "CL_DEVICE_MAX_PARAMETER_SIZE: " << maxkparams;
                        }
                }

                catch (cl::Error e)
                {
                        log_error() << "OpenCL fatal error: <" << e.what() << "> (" << ocl::error_string(e.err()) << ")!";

                        m_platforms.clear();
                        m_devices.clear();
                }
        }

        cl::CommandQueue ocl::manager_t::make_command_queue() const
        {
                assert(valid());

                const cl::Device& device = m_devices[0];
                return cl::CommandQueue(m_context, device, 0);
        }

        cl::Program ocl::manager_t::make_program_from_file(const std::string& filepath) const
        {
                return make_program_from_text(ocl::load_text_file(filepath));
        }

        cl::Program ocl::manager_t::make_program_from_text(const std::string& source) const
        {
                assert(valid());

                cl::Program::Sources sources(1, std::make_pair(source.c_str(), source.size()));
                cl::Program program = cl::Program(m_context, sources);

                try
                {
                        program.build(m_devices);//, "-cl-fast-relaxed-math -cl-mad-enable");
                }
                catch (cl::Error e)
                {
                        // load compilation errors
                        const cl::Device& device = m_devices[0];
                        log_error() << "OpenCL program build status: " << program.getBuildInfo<CL_PROGRAM_BUILD_STATUS>(device);
                        log_error() << "OpenCL program build options:\t" << program.getBuildInfo<CL_PROGRAM_BUILD_OPTIONS>(device);
                        log_error() << "OpenCL program build log:\t" << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device);

                        // and re-throw the exception
                        throw e;
                }

                return program;
        }

        cl::Kernel ocl::manager_t::make_kernel(const cl::Program& program, const std::string& name) const
        {
                assert(valid());

                return cl::Kernel(program, name.c_str());
        }

        cl::Buffer ocl::manager_t::make_buffer(size_t bytesize, int flags) const
        {
                assert(valid());

                return cl::Buffer(m_context, flags, bytesize, NULL);
        }

        const char* ocl::error_string(cl_int error)
        {
                static const char* errorString[] =
                {
                        "CL_SUCCESS",
                        "CL_DEVICE_NOT_FOUND",
                        "CL_DEVICE_NOT_AVAILABLE",
                        "CL_COMPILER_NOT_AVAILABLE",
                        "CL_MEM_OBJECT_ALLOCATION_FAILURE",
                        "CL_OUT_OF_RESOURCES",
                        "CL_OUT_OF_HOST_MEMORY",
                        "CL_PROFILING_INFO_NOT_AVAILABLE",
                        "CL_MEM_COPY_OVERLAP",
                        "CL_IMAGE_FORMAT_MISMATCH",
                        "CL_IMAGE_FORMAT_NOT_SUPPORTED",
                        "CL_BUILD_PROGRAM_FAILURE",
                        "CL_MAP_FAILURE",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "CL_INVALID_VALUE",
                        "CL_INVALID_DEVICE_TYPE",
                        "CL_INVALID_PLATFORM",
                        "CL_INVALID_DEVICE",
                        "CL_INVALID_CONTEXT",
                        "CL_INVALID_QUEUE_PROPERTIES",
                        "CL_INVALID_COMMAND_QUEUE",
                        "CL_INVALID_HOST_PTR",
                        "CL_INVALID_MEM_OBJECT",
                        "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR",
                        "CL_INVALID_IMAGE_SIZE",
                        "CL_INVALID_SAMPLER",
                        "CL_INVALID_BINARY",
                        "CL_INVALID_BUILD_OPTIONS",
                        "CL_INVALID_PROGRAM",
                        "CL_INVALID_PROGRAM_EXECUTABLE",
                        "CL_INVALID_KERNEL_NAME",
                        "CL_INVALID_KERNEL_DEFINITION",
                        "CL_INVALID_KERNEL",
                        "CL_INVALID_ARG_INDEX",
                        "CL_INVALID_ARG_VALUE",
                        "CL_INVALID_ARG_SIZE",
                        "CL_INVALID_KERNEL_ARGS",
                        "CL_INVALID_WORK_DIMENSION",
                        "CL_INVALID_WORK_GROUP_SIZE",
                        "CL_INVALID_WORK_ITEM_SIZE",
                        "CL_INVALID_GLOBAL_OFFSET",
                        "CL_INVALID_EVENT_WAIT_LIST",
                        "CL_INVALID_EVENT",
                        "CL_INVALID_OPERATION",
                        "CL_INVALID_GL_OBJECT",
                        "CL_INVALID_BUFFER_SIZE",
                        "CL_INVALID_MIP_LEVEL",
                        "CL_INVALID_GLOBAL_WORK_SIZE",
                };

                static const int errorCount = sizeof(errorString) / sizeof(errorString[0]);

                const int index = -error;
                return (index >= 0 && index < errorCount) ? errorString[index] : "";
        }

        std::string ocl::load_text_file(const std::string& filepath)
        {
                std::ifstream file(filepath, std::ios::in);

                if (file.is_open())
                {
                        std::ostringstream oss;
                        oss << file.rdbuf();
                        return oss.str();
                }

                else
                {
                        return std::string();
                }
        }
}

<commit_msg>compile opencl programs with mad<commit_after>#include "opencl.h"
#include "common/logger.h"
#include <fstream>
#include <sstream>
#include <cassert>

namespace ncv
{
        ocl::manager_t::manager_t()
        {
                try
                {
                        cl_int err = cl::Platform::get(&m_platforms);
                        log_info() << "OpenCL status (platform query): " << ocl::error_string(err);

                        if (m_platforms.empty())
                        {
                                log_error() << "Cannot find any OpenCL platforms!";
                                return;
                        }

                        cl_context_properties properties[] =
                        {
                                CL_CONTEXT_PLATFORM,
                                (cl_context_properties)(m_platforms[0])(),
                                0
                        };
                        m_context = cl::Context(CL_DEVICE_TYPE_GPU, properties);
                        m_devices = m_context.getInfo<CL_CONTEXT_DEVICES>();

                        if (m_devices.empty())
                        {
                                log_error() << "Cannot find any OpenCL GPU device!";
                                return;
                        }

                        for (size_t i = 0; i < m_devices.size(); i ++)
                        {
                                const cl::Device& device = m_devices[i];

                                const std::string name = device.getInfo<CL_DEVICE_NAME>();
                                const std::string vendor = device.getInfo<CL_DEVICE_VENDOR>();
                                const std::string driver = device.getInfo<CL_DRIVER_VERSION>();
                                const std::string version = device.getInfo<CL_DEVICE_VERSION>();

                                const size_t gmemsize = device.getInfo<CL_DEVICE_GLOBAL_MEM_SIZE>();
                                const size_t lmemsize = device.getInfo<CL_DEVICE_LOCAL_MEM_SIZE>();
                                const size_t amemsize = device.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>();
                                const size_t cmemsize = device.getInfo<CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE>();
                                const size_t maxcus = device.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>();
                                const size_t maxwgsize = device.getInfo<CL_DEVICE_MAX_WORK_GROUP_SIZE>();
                                const size_t maxwidims = device.getInfo<CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS>();
                                const std::vector<size_t> maxwisizes = device.getInfo<CL_DEVICE_MAX_WORK_ITEM_SIZES>();
                                const size_t maxkparams = device.getInfo<CL_DEVICE_MAX_PARAMETER_SIZE>();

                                std::stringstream ss;
                                ss << "OpenCL device [" << (i + 1) << "/" << m_devices.size() << "]: ";
                                const std::string base = ss.str();

                                log_info() << base << "CL_DEVICE_NAME: " << name;
                                log_info() << base << "CL_DEVICE_VENDOR:" << vendor;
                                log_info() << base << "CL_DRIVER_VERSION: " << driver;
                                log_info() << base << "CL_DEVICE_VERSION: " << version;
                                log_info() << base << "CL_DEVICE_TYPE: " << "CL_DEVICE_TYPE_GPU";
                                log_info() << base << "CL_DEVICE_GLOBAL_MEM_SIZE: " << gmemsize << "B = "
                                           << (gmemsize / 1024) << "KB = " << (gmemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_LOCAL_MEM_SIZE: " << lmemsize << "B = "
                                           << (lmemsize / 1024) << "KB = " << (lmemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE: " << cmemsize << "B = "
                                           << (cmemsize / 1024) << "KB = " << (cmemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_MAX_MEM_ALLOC_SIZE: " << amemsize << "B = "
                                           << (amemsize / 1024) << "KB = " << (amemsize / 1024 / 1024) << "MB";
                                log_info() << base << "CL_DEVICE_MAX_COMPUTE_UNITS: " << maxcus;
                                log_info() << base << "CL_DEVICE_MAX_WORK_GROUP_SIZE: " << maxwgsize;
                                log_info() << base << "CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS: " << maxwidims;
                                log_info() << base << "CL_DEVICE_MAX_WORK_ITEM_SIZES: "
                                           << (maxwisizes.size() > 0 ? maxwisizes[0] : 0) << " / "
                                           << (maxwisizes.size() > 1 ? maxwisizes[1] : 0) << " / "
                                           << (maxwisizes.size() > 2 ? maxwisizes[2] : 0);
                                log_info() << base << "CL_DEVICE_MAX_PARAMETER_SIZE: " << maxkparams;
                        }
                }

                catch (cl::Error e)
                {
                        log_error() << "OpenCL fatal error: <" << e.what() << "> (" << ocl::error_string(e.err()) << ")!";

                        m_platforms.clear();
                        m_devices.clear();
                }
        }

        cl::CommandQueue ocl::manager_t::make_command_queue() const
        {
                assert(valid());

                const cl::Device& device = m_devices[0];
                return cl::CommandQueue(m_context, device, 0);
        }

        cl::Program ocl::manager_t::make_program_from_file(const std::string& filepath) const
        {
                return make_program_from_text(ocl::load_text_file(filepath));
        }

        cl::Program ocl::manager_t::make_program_from_text(const std::string& source) const
        {
                assert(valid());

                cl::Program::Sources sources(1, std::make_pair(source.c_str(), source.size()));
                cl::Program program = cl::Program(m_context, sources);

                try
                {
                        program.build(m_devices, "-cl-mad-enable");//, "-cl-fast-relaxed-math");
                }
                catch (cl::Error e)
                {
                        // load compilation errors
                        const cl::Device& device = m_devices[0];
                        log_error() << "OpenCL program build status: " << program.getBuildInfo<CL_PROGRAM_BUILD_STATUS>(device);
                        log_error() << "OpenCL program build options:\t" << program.getBuildInfo<CL_PROGRAM_BUILD_OPTIONS>(device);
                        log_error() << "OpenCL program build log:\t" << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device);

                        // and re-throw the exception
                        throw e;
                }

                return program;
        }

        cl::Kernel ocl::manager_t::make_kernel(const cl::Program& program, const std::string& name) const
        {
                assert(valid());

                return cl::Kernel(program, name.c_str());
        }

        cl::Buffer ocl::manager_t::make_buffer(size_t bytesize, int flags) const
        {
                assert(valid());

                return cl::Buffer(m_context, flags, bytesize, NULL);
        }

        const char* ocl::error_string(cl_int error)
        {
                static const char* errorString[] =
                {
                        "CL_SUCCESS",
                        "CL_DEVICE_NOT_FOUND",
                        "CL_DEVICE_NOT_AVAILABLE",
                        "CL_COMPILER_NOT_AVAILABLE",
                        "CL_MEM_OBJECT_ALLOCATION_FAILURE",
                        "CL_OUT_OF_RESOURCES",
                        "CL_OUT_OF_HOST_MEMORY",
                        "CL_PROFILING_INFO_NOT_AVAILABLE",
                        "CL_MEM_COPY_OVERLAP",
                        "CL_IMAGE_FORMAT_MISMATCH",
                        "CL_IMAGE_FORMAT_NOT_SUPPORTED",
                        "CL_BUILD_PROGRAM_FAILURE",
                        "CL_MAP_FAILURE",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "",
                        "CL_INVALID_VALUE",
                        "CL_INVALID_DEVICE_TYPE",
                        "CL_INVALID_PLATFORM",
                        "CL_INVALID_DEVICE",
                        "CL_INVALID_CONTEXT",
                        "CL_INVALID_QUEUE_PROPERTIES",
                        "CL_INVALID_COMMAND_QUEUE",
                        "CL_INVALID_HOST_PTR",
                        "CL_INVALID_MEM_OBJECT",
                        "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR",
                        "CL_INVALID_IMAGE_SIZE",
                        "CL_INVALID_SAMPLER",
                        "CL_INVALID_BINARY",
                        "CL_INVALID_BUILD_OPTIONS",
                        "CL_INVALID_PROGRAM",
                        "CL_INVALID_PROGRAM_EXECUTABLE",
                        "CL_INVALID_KERNEL_NAME",
                        "CL_INVALID_KERNEL_DEFINITION",
                        "CL_INVALID_KERNEL",
                        "CL_INVALID_ARG_INDEX",
                        "CL_INVALID_ARG_VALUE",
                        "CL_INVALID_ARG_SIZE",
                        "CL_INVALID_KERNEL_ARGS",
                        "CL_INVALID_WORK_DIMENSION",
                        "CL_INVALID_WORK_GROUP_SIZE",
                        "CL_INVALID_WORK_ITEM_SIZE",
                        "CL_INVALID_GLOBAL_OFFSET",
                        "CL_INVALID_EVENT_WAIT_LIST",
                        "CL_INVALID_EVENT",
                        "CL_INVALID_OPERATION",
                        "CL_INVALID_GL_OBJECT",
                        "CL_INVALID_BUFFER_SIZE",
                        "CL_INVALID_MIP_LEVEL",
                        "CL_INVALID_GLOBAL_WORK_SIZE",
                };

                static const int errorCount = sizeof(errorString) / sizeof(errorString[0]);

                const int index = -error;
                return (index >= 0 && index < errorCount) ? errorString[index] : "";
        }

        std::string ocl::load_text_file(const std::string& filepath)
        {
                std::ifstream file(filepath, std::ios::in);

                if (file.is_open())
                {
                        std::ostringstream oss;
                        oss << file.rdbuf();
                        return oss.str();
                }

                else
                {
                        return std::string();
                }
        }
}

<|endoftext|>