<commit_before>// @(#) $Id: AliHLTTPCCATracker.cxx 34611 2009-09-04 00:22:05Z sgorbuno $
// **************************************************************************
// This file is property of and copyright by the ALICE HLT Project          *
// ALICE Experiment at CERN, All rights reserved.                           *
//                                                                          *
// Primary Authors: Sergey Gorbunov <sergey.gorbunov@kip.uni-heidelberg.de> *
//                  Ivan Kisel <kisel@kip.uni-heidelberg.de>                *
//                  for The ALICE HLT Project.                              *
//                                                                          *
// Permission to use, copy, modify and distribute this software and its     *
// documentation strictly for non-commercial purposes is hereby granted     *
// without fee, provided that the above copyright notice appears in all     *
// copies and that both the copyright notice and this permission notice     *
// appear in the supporting documentation. The authors make no claims       *
// about the suitability of this software for any purpose. It is            *
// provided "as is" without express or implied warranty.                    *
//                                                                          *
//***************************************************************************

#include "AliHLTTPCCADef.h"
#include "AliHLTTPCCAGPUConfig.h"
#include "AliHLTTPCCATrackerFramework.h"
#include "AliHLTTPCCAGPUTracker.h"
#include "AliHLTTPCCATracker.h"
#include "AliHLTTPCCAMath.h"
#include "AliHLTTPCCAClusterData.h"

#ifdef R__WIN32
#include <windows.h>
#include <winbase.h>
#else
#include <dlfcn.h>
#endif

#ifdef HLTCA_STANDALONE
#include <omp.h>
#endif

ClassImp( AliHLTTPCCATrackerFramework )

int AliHLTTPCCATrackerFramework::InitGPU(int sliceCount, int forceDeviceID)
{
	//Initialize GPU Tracker and determine if GPU available
	int retVal;
	if (!fGPULibAvailable)
	{
		HLTError("GPU Library not loaded\n");
		return(1);
	}
	if (fGPUTrackerAvailable && (retVal = ExitGPU())) return(retVal);
	retVal = fGPUTracker->InitGPU(sliceCount, forceDeviceID);
	fUseGPUTracker = fGPUTrackerAvailable = retVal == 0;
	return(retVal);
}

int AliHLTTPCCATrackerFramework::ExitGPU()
{
	//Uninitialize GPU Tracker
	if (!fGPUTrackerAvailable) return(0);
	fUseGPUTracker = false;
	fGPUTrackerAvailable = false;
	return(fGPUTracker->ExitGPU());
}

void AliHLTTPCCATrackerFramework::SetGPUDebugLevel(int Level, std::ostream *OutFile, std::ostream *GPUOutFile)
{
	//Set Debug Level for GPU Tracker and also for CPU Tracker for comparison reasons
	fGPUTracker->SetDebugLevel(Level, GPUOutFile);
	fGPUDebugLevel = Level;
	for (int i = 0;i < fgkNSlices;i++)
	{
		fCPUTrackers[i].SetGPUDebugLevel(Level, OutFile);
	}
}

int AliHLTTPCCATrackerFramework::SetGPUTracker(bool enable)
{
	//Enable / disable GPU Tracker
	if (enable && !fGPUTrackerAvailable)
	{
		fUseGPUTracker = false;
		return(1);
	}
	fUseGPUTracker = enable;
	return(0);
}

GPUhd() void AliHLTTPCCATrackerFramework::SetOutputControl( AliHLTTPCCASliceOutput::outputControlStruct* val)
{
	//Set Output Control Pointers
	fOutputControl = val;
	fGPUTracker->SetOutputControl(val);
	for (int i = 0;i < fgkNSlices;i++)
	{
		fCPUTrackers[i].SetOutputControl(val);
	}
}

int AliHLTTPCCATrackerFramework::ProcessSlices(int firstSlice, int sliceCount, AliHLTTPCCAClusterData* pClusterData, AliHLTTPCCASliceOutput** pOutput)
{
	int useGlobalTracking = fGlobalTracking;
	if (fGlobalTracking && (firstSlice || sliceCount != fgkNSlices))
	{
		HLTWarning("Global Tracking only available if all slices are processed!");
		useGlobalTracking = 0;
	}

	//Process sliceCount slices starting from firstslice, in is pClusterData array, out pOutput array
	if (fUseGPUTracker)
	{
		if (fGPUTracker->Reconstruct(pOutput, pClusterData, firstSlice, CAMath::Min(sliceCount, fgkNSlices - firstSlice))) return(1);
	}
	else
	{
#ifdef HLTCA_STANDALONE
		if (fOutputControl->fOutputPtr && omp_get_max_threads() > 1)
		{
			HLTError("fOutputPtr must not be used with OpenMP\n");
			return(1);
		}
		int nLocalTracks = 0, nGlobalTracks = 0, nOutputTracks = 0, nLocalHits = 0, nGlobalHits = 0;

#pragma omp parallel for
#endif
		for (int iSlice = 0;iSlice < CAMath::Min(sliceCount, fgkNSlices - firstSlice);iSlice++)
		{
#ifdef HLTCA_STANDALONE
			fCPUTrackers[firstSlice + iSlice].StandalonePerfTime(0);
#endif
			fCPUTrackers[firstSlice + iSlice].ReadEvent(&pClusterData[iSlice]);
			fCPUTrackers[firstSlice + iSlice].SetOutput(&pOutput[iSlice]);
			fCPUTrackers[firstSlice + iSlice].Reconstruct();
			fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNLocalTracks = fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNTracks;
			fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNLocalTrackHits = fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNTrackHits;
			if (!useGlobalTracking)
			{
				fCPUTrackers[firstSlice + iSlice].ReconstructOutput();
#ifdef HLTCA_STANDALONE
				nOutputTracks += (*fCPUTrackers[firstSlice + iSlice].Output())->NTracks();
				nLocalTracks += fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNTracks;
#endif
				if (!fKeepData)
				{
					fCPUTrackers[firstSlice + iSlice].SetupCommonMemory();
				}
			}
		}

		if (useGlobalTracking)
		{
			for (int iSlice = 0;iSlice < CAMath::Min(sliceCount, fgkNSlices - firstSlice);iSlice++)
			{
				int sliceLeft = (iSlice + (fgkNSlices / 2 - 1)) % (fgkNSlices / 2);
				int sliceRight = (iSlice + 1) % (fgkNSlices / 2);
				if (iSlice >= fgkNSlices / 2)
				{
					sliceLeft += fgkNSlices / 2;
					sliceRight += fgkNSlices / 2;
				}
				fCPUTrackers[iSlice].PerformGlobalTracking(fCPUTrackers[sliceLeft], fCPUTrackers[sliceRight], CAMath::Min(fCPUTrackers[sliceLeft].CommonMemory()->fNTracklets, fCPUTrackers[sliceRight].CommonMemory()->fNTracklets) * 2);
			}
			for (int iSlice = 0;iSlice < CAMath::Min(sliceCount, fgkNSlices - firstSlice);iSlice++)
			{
				fCPUTrackers[firstSlice + iSlice].ReconstructOutput();
#ifdef HLTCA_STANDALONE
				//printf("Slice %d - Tracks: Local %d Global %d - Hits: Local %d Global %d\n", iSlice, fCPUTrackers[iSlice].CommonMemory()->fNLocalTracks, fCPUTrackers[iSlice].CommonMemory()->fNTracks, fCPUTrackers[iSlice].CommonMemory()->fNLocalTrackHits, fCPUTrackers[iSlice].CommonMemory()->fNTrackHits);
				nLocalTracks += fCPUTrackers[iSlice].CommonMemory()->fNLocalTracks;
				nGlobalTracks += fCPUTrackers[iSlice].CommonMemory()->fNTracks;
				nLocalHits += fCPUTrackers[iSlice].CommonMemory()->fNLocalTrackHits;
				nGlobalHits += fCPUTrackers[iSlice].CommonMemory()->fNTrackHits;
				nOutputTracks += (*fCPUTrackers[iSlice].Output())->NTracks();
#endif
				if (!fKeepData)
				{
					fCPUTrackers[firstSlice + iSlice].SetupCommonMemory();
				}
			}
		}
#ifdef HLTCA_STANDALONE
		//printf("Slice Tracks Output %d: - Tracks: %d local, %d global -  Hits: %d local, %d global\n", nOutputTracks, nLocalTracks, nGlobalTracks, nLocalHits, nGlobalHits);
		/*for (int i = firstSlice;i < firstSlice + sliceCount;i++)
		{
			fCPUTrackers[i].DumpOutput(stdout);
		}*/
#endif
	}

	if (fGPUDebugLevel >= 6 && fUseGPUTracker)
	{
	    fUseGPUTracker = 0;
	    ProcessSlices(firstSlice, sliceCount, pClusterData, pOutput);
	    fUseGPUTracker = 1;
	}

	return(0);
}

unsigned long long int* AliHLTTPCCATrackerFramework::PerfTimer(int GPU, int iSlice, int iTimer)
{
	//Performance information for slice trackers
	return(GPU ? fGPUTracker->PerfTimer(iSlice, iTimer) : fCPUTrackers[iSlice].PerfTimer(iTimer));
}

int AliHLTTPCCATrackerFramework::InitializeSliceParam(int iSlice, AliHLTTPCCAParam &param)
{
	//Initialize Tracker Parameters for a slice
	if (fGPUTrackerAvailable && fGPUTracker->InitializeSliceParam(iSlice, param)) return(1);
	fCPUTrackers[iSlice].Initialize(param);
	return(0);
}

#ifdef HLTCA_STANDALONE
#define GPULIBNAME "libAliHLTTPCCAGPUSA"
#else
#define GPULIBNAME "libAliHLTTPCCAGPU"
#endif

AliHLTTPCCATrackerFramework::AliHLTTPCCATrackerFramework(int allowGPU) : fGPULibAvailable(false), fGPUTrackerAvailable(false), fUseGPUTracker(false), fGPUDebugLevel(0), fGPUTracker(NULL), fGPULib(NULL), fOutputControl( NULL ), fKeepData(false), fGlobalTracking(false)
{
	//Constructor
#ifdef R__WIN32
	HMODULE hGPULib = LoadLibraryEx(GPULIBNAME ".dll", NULL, NULL);
#else
	void* hGPULib = dlopen(GPULIBNAME ".so", RTLD_NOW);
#endif
	if (hGPULib == NULL)
	{
		if (allowGPU)
		{
			#ifndef R__WIN32
				HLTInfo("The following error occured during dlopen: %s", dlerror());
			#endif
			HLTError("Error Opening cagpu library for GPU Tracker, will fallback to CPU");
		}
		else
		{
			HLTDebug("Cagpu library was not found, Tracking on GPU will not be available");
		}
		fGPUTracker = new AliHLTTPCCAGPUTracker;
	}
	else
	{
#ifdef R__WIN32
		FARPROC createFunc = GetProcAddress(hGPULib, "AliHLTTPCCAGPUTrackerNVCCCreate");
#else
		void* createFunc = (void*) dlsym(hGPULib, "AliHLTTPCCAGPUTrackerNVCCCreate");
#endif
		if (createFunc == NULL)
		{
			HLTError("Error Creating GPU Tracker\n");
#ifdef R__WIN32
			FreeLibrary(hGPULib);
#else
			dlclose(hGPULib);
#endif
			fGPUTracker = new AliHLTTPCCAGPUTracker;
		}
		else
		{
			AliHLTTPCCAGPUTracker* (*tmp)() = (AliHLTTPCCAGPUTracker* (*)()) createFunc;
			fGPUTracker = tmp();
			fGPULibAvailable = true;
			fGPULib = (void*) (size_t) hGPULib;
			HLTImportant("GPU Tracker library loaded and GPU tracker object created sucessfully (%sactive)", allowGPU ? "" : "in");
		}
	}

	if (allowGPU && fGPULibAvailable)
	{
		fUseGPUTracker = (fGPUTrackerAvailable = (fGPUTracker->InitGPU() == 0));
		HLTInfo("GPU Tracker Initialized and available in framework");
	}
}

AliHLTTPCCATrackerFramework::~AliHLTTPCCATrackerFramework()
{
#ifdef R__WIN32
	HMODULE hGPULib = (HMODULE) (size_t) fGPULib;
#else
	void* hGPULib = fGPULib;
#endif
	if (fGPULib)
	{
		if (fGPUTracker)
		{
#ifdef R__WIN32
			FARPROC destroyFunc = GetProcAddress(hGPULib, "AliHLTTPCCAGPUTrackerNVCCDestroy");
#else
			void* destroyFunc = (void*) dlsym(hGPULib, "AliHLTTPCCAGPUTrackerNVCCDestroy");
#endif
			if (destroyFunc == NULL)
			{
				HLTError("Error Freeing GPU Tracker\n");
			}
			else
			{
				void (*tmp)(AliHLTTPCCAGPUTracker*) =  (void (*)(AliHLTTPCCAGPUTracker*)) destroyFunc;
				tmp(fGPUTracker);
			}
		}

#ifdef R__WIN32
		FreeLibrary(hGPULib);
#else
		dlclose(hGPULib);
#endif
	}
	else if (fGPUTracker)
	{
		delete fGPUTracker;
	}
	fGPULib = NULL;
	fGPUTracker = NULL;
}
<commit_msg>fix deinitialization of the component in aliroot<commit_after>// @(#) $Id: AliHLTTPCCATracker.cxx 34611 2009-09-04 00:22:05Z sgorbuno $
// **************************************************************************
// This file is property of and copyright by the ALICE HLT Project          *
// ALICE Experiment at CERN, All rights reserved.                           *
//                                                                          *
// Primary Authors: Sergey Gorbunov <sergey.gorbunov@kip.uni-heidelberg.de> *
//                  Ivan Kisel <kisel@kip.uni-heidelberg.de>                *
//                  for The ALICE HLT Project.                              *
//                                                                          *
// Permission to use, copy, modify and distribute this software and its     *
// documentation strictly for non-commercial purposes is hereby granted     *
// without fee, provided that the above copyright notice appears in all     *
// copies and that both the copyright notice and this permission notice     *
// appear in the supporting documentation. The authors make no claims       *
// about the suitability of this software for any purpose. It is            *
// provided "as is" without express or implied warranty.                    *
//                                                                          *
//***************************************************************************

#include "AliHLTTPCCADef.h"
#include "AliHLTTPCCAGPUConfig.h"
#include "AliHLTTPCCATrackerFramework.h"
#include "AliHLTTPCCAGPUTracker.h"
#include "AliHLTTPCCATracker.h"
#include "AliHLTTPCCAMath.h"
#include "AliHLTTPCCAClusterData.h"

#ifdef R__WIN32
#include <windows.h>
#include <winbase.h>
#else
#include <dlfcn.h>
#endif

#ifdef HLTCA_STANDALONE
#include <omp.h>
#endif

ClassImp( AliHLTTPCCATrackerFramework )

int AliHLTTPCCATrackerFramework::InitGPU(int sliceCount, int forceDeviceID)
{
	//Initialize GPU Tracker and determine if GPU available
	int retVal;
	if (!fGPULibAvailable)
	{
		HLTError("GPU Library not loaded\n");
		return(1);
	}
	if (fGPUTrackerAvailable && (retVal = ExitGPU())) return(retVal);
	retVal = fGPUTracker->InitGPU(sliceCount, forceDeviceID);
	fUseGPUTracker = fGPUTrackerAvailable = retVal == 0;
	return(retVal);
}

int AliHLTTPCCATrackerFramework::ExitGPU()
{
	//Uninitialize GPU Tracker
	if (!fGPUTrackerAvailable) return(0);
	fUseGPUTracker = false;
	fGPUTrackerAvailable = false;
	return(fGPUTracker->ExitGPU());
}

void AliHLTTPCCATrackerFramework::SetGPUDebugLevel(int Level, std::ostream *OutFile, std::ostream *GPUOutFile)
{
	//Set Debug Level for GPU Tracker and also for CPU Tracker for comparison reasons
	fGPUTracker->SetDebugLevel(Level, GPUOutFile);
	fGPUDebugLevel = Level;
	for (int i = 0;i < fgkNSlices;i++)
	{
		fCPUTrackers[i].SetGPUDebugLevel(Level, OutFile);
	}
}

int AliHLTTPCCATrackerFramework::SetGPUTracker(bool enable)
{
	//Enable / disable GPU Tracker
	if (enable && !fGPUTrackerAvailable)
	{
		fUseGPUTracker = false;
		return(1);
	}
	fUseGPUTracker = enable;
	return(0);
}

GPUhd() void AliHLTTPCCATrackerFramework::SetOutputControl( AliHLTTPCCASliceOutput::outputControlStruct* val)
{
	//Set Output Control Pointers
	fOutputControl = val;
	fGPUTracker->SetOutputControl(val);
	for (int i = 0;i < fgkNSlices;i++)
	{
		fCPUTrackers[i].SetOutputControl(val);
	}
}

int AliHLTTPCCATrackerFramework::ProcessSlices(int firstSlice, int sliceCount, AliHLTTPCCAClusterData* pClusterData, AliHLTTPCCASliceOutput** pOutput)
{
	int useGlobalTracking = fGlobalTracking;
	if (fGlobalTracking && (firstSlice || sliceCount != fgkNSlices))
	{
		HLTWarning("Global Tracking only available if all slices are processed!");
		useGlobalTracking = 0;
	}

	//Process sliceCount slices starting from firstslice, in is pClusterData array, out pOutput array
	if (fUseGPUTracker)
	{
		if (fGPUTracker->Reconstruct(pOutput, pClusterData, firstSlice, CAMath::Min(sliceCount, fgkNSlices - firstSlice))) return(1);
	}
	else
	{
#ifdef HLTCA_STANDALONE
		if (fOutputControl->fOutputPtr && omp_get_max_threads() > 1)
		{
			HLTError("fOutputPtr must not be used with OpenMP\n");
			return(1);
		}
		int nLocalTracks = 0, nGlobalTracks = 0, nOutputTracks = 0, nLocalHits = 0, nGlobalHits = 0;

#pragma omp parallel for
#endif
		for (int iSlice = 0;iSlice < CAMath::Min(sliceCount, fgkNSlices - firstSlice);iSlice++)
		{
#ifdef HLTCA_STANDALONE
			fCPUTrackers[firstSlice + iSlice].StandalonePerfTime(0);
#endif
			fCPUTrackers[firstSlice + iSlice].ReadEvent(&pClusterData[iSlice]);
			fCPUTrackers[firstSlice + iSlice].SetOutput(&pOutput[iSlice]);
			fCPUTrackers[firstSlice + iSlice].Reconstruct();
			fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNLocalTracks = fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNTracks;
			fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNLocalTrackHits = fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNTrackHits;
			if (!useGlobalTracking)
			{
				fCPUTrackers[firstSlice + iSlice].ReconstructOutput();
#ifdef HLTCA_STANDALONE
				nOutputTracks += (*fCPUTrackers[firstSlice + iSlice].Output())->NTracks();
				nLocalTracks += fCPUTrackers[firstSlice + iSlice].CommonMemory()->fNTracks;
#endif
				if (!fKeepData)
				{
					fCPUTrackers[firstSlice + iSlice].SetupCommonMemory();
				}
			}
		}

		if (useGlobalTracking)
		{
			for (int iSlice = 0;iSlice < CAMath::Min(sliceCount, fgkNSlices - firstSlice);iSlice++)
			{
				int sliceLeft = (iSlice + (fgkNSlices / 2 - 1)) % (fgkNSlices / 2);
				int sliceRight = (iSlice + 1) % (fgkNSlices / 2);
				if (iSlice >= fgkNSlices / 2)
				{
					sliceLeft += fgkNSlices / 2;
					sliceRight += fgkNSlices / 2;
				}
				fCPUTrackers[iSlice].PerformGlobalTracking(fCPUTrackers[sliceLeft], fCPUTrackers[sliceRight], CAMath::Min(fCPUTrackers[sliceLeft].CommonMemory()->fNTracklets, fCPUTrackers[sliceRight].CommonMemory()->fNTracklets) * 2);
			}
			for (int iSlice = 0;iSlice < CAMath::Min(sliceCount, fgkNSlices - firstSlice);iSlice++)
			{
				fCPUTrackers[firstSlice + iSlice].ReconstructOutput();
#ifdef HLTCA_STANDALONE
				//printf("Slice %d - Tracks: Local %d Global %d - Hits: Local %d Global %d\n", iSlice, fCPUTrackers[iSlice].CommonMemory()->fNLocalTracks, fCPUTrackers[iSlice].CommonMemory()->fNTracks, fCPUTrackers[iSlice].CommonMemory()->fNLocalTrackHits, fCPUTrackers[iSlice].CommonMemory()->fNTrackHits);
				nLocalTracks += fCPUTrackers[iSlice].CommonMemory()->fNLocalTracks;
				nGlobalTracks += fCPUTrackers[iSlice].CommonMemory()->fNTracks;
				nLocalHits += fCPUTrackers[iSlice].CommonMemory()->fNLocalTrackHits;
				nGlobalHits += fCPUTrackers[iSlice].CommonMemory()->fNTrackHits;
				nOutputTracks += (*fCPUTrackers[iSlice].Output())->NTracks();
#endif
				if (!fKeepData)
				{
					fCPUTrackers[firstSlice + iSlice].SetupCommonMemory();
				}
			}
		}
#ifdef HLTCA_STANDALONE
		//printf("Slice Tracks Output %d: - Tracks: %d local, %d global -  Hits: %d local, %d global\n", nOutputTracks, nLocalTracks, nGlobalTracks, nLocalHits, nGlobalHits);
		/*for (int i = firstSlice;i < firstSlice + sliceCount;i++)
		{
			fCPUTrackers[i].DumpOutput(stdout);
		}*/
#endif
	}

	if (fGPUDebugLevel >= 6 && fUseGPUTracker)
	{
	    fUseGPUTracker = 0;
	    ProcessSlices(firstSlice, sliceCount, pClusterData, pOutput);
	    fUseGPUTracker = 1;
	}

	return(0);
}

unsigned long long int* AliHLTTPCCATrackerFramework::PerfTimer(int GPU, int iSlice, int iTimer)
{
	//Performance information for slice trackers
	return(GPU ? fGPUTracker->PerfTimer(iSlice, iTimer) : fCPUTrackers[iSlice].PerfTimer(iTimer));
}

int AliHLTTPCCATrackerFramework::InitializeSliceParam(int iSlice, AliHLTTPCCAParam &param)
{
	//Initialize Tracker Parameters for a slice
	if (fGPUTrackerAvailable && fGPUTracker->InitializeSliceParam(iSlice, param)) return(1);
	fCPUTrackers[iSlice].Initialize(param);
	return(0);
}

#ifdef HLTCA_STANDALONE
#define GPULIBNAME "libAliHLTTPCCAGPUSA"
#else
#define GPULIBNAME "libAliHLTTPCCAGPU"
#endif

AliHLTTPCCATrackerFramework::AliHLTTPCCATrackerFramework(int allowGPU) : fGPULibAvailable(false), fGPUTrackerAvailable(false), fUseGPUTracker(false), fGPUDebugLevel(0), fGPUTracker(NULL), fGPULib(NULL), fOutputControl( NULL ), fKeepData(false), fGlobalTracking(false)
{
	//Constructor
#ifdef R__WIN32
	HMODULE hGPULib = LoadLibraryEx(GPULIBNAME ".dll", NULL, NULL);
#else
	void* hGPULib = dlopen(GPULIBNAME ".so", RTLD_NOW);
#endif
	if (hGPULib == NULL)
	{
		if (allowGPU)
		{
			#ifndef R__WIN32
				HLTInfo("The following error occured during dlopen: %s", dlerror());
			#endif
			HLTError("Error Opening cagpu library for GPU Tracker, will fallback to CPU");
		}
		else
		{
			HLTDebug("Cagpu library was not found, Tracking on GPU will not be available");
		}
		fGPUTracker = new AliHLTTPCCAGPUTracker;
	}
	else
	{
#ifdef R__WIN32
		FARPROC createFunc = GetProcAddress(hGPULib, "AliHLTTPCCAGPUTrackerNVCCCreate");
#else
		void* createFunc = (void*) dlsym(hGPULib, "AliHLTTPCCAGPUTrackerNVCCCreate");
#endif
		if (createFunc == NULL)
		{
			HLTError("Error Creating GPU Tracker\n");
#ifdef R__WIN32
			FreeLibrary(hGPULib);
#else
			dlclose(hGPULib);
#endif
			fGPUTracker = new AliHLTTPCCAGPUTracker;
		}
		else
		{
			AliHLTTPCCAGPUTracker* (*tmp)() = (AliHLTTPCCAGPUTracker* (*)()) createFunc;
			fGPUTracker = tmp();
			fGPULibAvailable = true;
			fGPULib = (void*) (size_t) hGPULib;
			HLTImportant("GPU Tracker library loaded and GPU tracker object created sucessfully (%sactive)", allowGPU ? "" : "in");
		}
	}

	if (allowGPU && fGPULibAvailable)
	{
		fUseGPUTracker = (fGPUTrackerAvailable = (fGPUTracker->InitGPU() == 0));
		HLTInfo("GPU Tracker Initialized and available in framework");
	}
}

AliHLTTPCCATrackerFramework::~AliHLTTPCCATrackerFramework()
{
#ifdef R__WIN32
	HMODULE hGPULib = (HMODULE) (size_t) fGPULib;
#else
	void* hGPULib = fGPULib;
#endif
	if (fGPULib)
	{
		if (fGPUTracker)
		{
			ExitGPU();
#ifdef R__WIN32
			FARPROC destroyFunc = GetProcAddress(hGPULib, "AliHLTTPCCAGPUTrackerNVCCDestroy");
#else
			void* destroyFunc = (void*) dlsym(hGPULib, "AliHLTTPCCAGPUTrackerNVCCDestroy");
#endif
			if (destroyFunc == NULL)
			{
				HLTError("Error Freeing GPU Tracker\n");
			}
			else
			{
				void (*tmp)(AliHLTTPCCAGPUTracker*) =  (void (*)(AliHLTTPCCAGPUTracker*)) destroyFunc;
				tmp(fGPUTracker);
			}
		}

#ifdef R__WIN32
		FreeLibrary(hGPULib);
#else
		dlclose(hGPULib);
#endif
	}
	else if (fGPUTracker)
	{
		delete fGPUTracker;
	}
	fGPULib = NULL;
	fGPUTracker = NULL;
}
<|endoftext|>


<commit_before>#include <fcntl.h>
#include "conn.h"
#include "event_base.h"
#include "logging.h"
#include "util.h"
#include "poller.h"

#ifdef OS_LINUX
#include <sys/epoll.h>
#elif defined(OS_MACOSX)
#include <sys/event.h>
#else
#error "platform unsupported"
#endif

namespace handy {

#ifdef OS_LINUX

struct PollerEpoll : public PollerBase {
    int fd_;
    std::set<Channel *> liveChannels_;
    // for epoll selected active events
    struct epoll_event activeEvs_[kMaxEvents];
    PollerEpoll();
    ~PollerEpoll();
    void addChannel(Channel *ch) override;
    void removeChannel(Channel *ch) override;
    void updateChannel(Channel *ch) override;
    void loop_once(int waitMs) override;
};

PollerBase *createPoller() {
    return new PollerEpoll();
}

PollerEpoll::PollerEpoll() {
    fd_ = epoll_create1(EPOLL_CLOEXEC);
    fatalif(fd_ < 0, "epoll_create error %d %s", errno, strerror(errno));
    info("poller epoll %d created", fd_);
}

PollerEpoll::~PollerEpoll() {
    info("destroying poller %d", fd_);
    while (liveChannels_.size()) {
        (*liveChannels_.begin())->close();
    }
    ::close(fd_);
    info("poller %d destroyed", fd_);
}

void PollerEpoll::addChannel(Channel *ch) {
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.events = ch->events();
    ev.data.ptr = ch;
    trace("adding channel %lld fd %d events %d epoll %d", (long long) ch->id(), ch->fd(), ev.events, fd_);
    int r = epoll_ctl(fd_, EPOLL_CTL_ADD, ch->fd(), &ev);
    fatalif(r, "epoll_ctl add failed %d %s", errno, strerror(errno));
    liveChannels_.insert(ch);
}

void PollerEpoll::updateChannel(Channel *ch) {
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.events = ch->events();
    ev.data.ptr = ch;
    trace("modifying channel %lld fd %d events read %d write %d epoll %d", (long long) ch->id(), ch->fd(), ev.events & POLLIN, ev.events & POLLOUT, fd_);
    int r = epoll_ctl(fd_, EPOLL_CTL_MOD, ch->fd(), &ev);
    fatalif(r, "epoll_ctl mod failed %d %s", errno, strerror(errno));
}

void PollerEpoll::removeChannel(Channel *ch) {
    trace("deleting channel %lld fd %d epoll %d", (long long) ch->id(), ch->fd(), fd_);
    liveChannels_.erase(ch);
    for (int i = lastActive_; i >= 0; i--) {
        if (ch == activeEvs_[i].data.ptr) {
            activeEvs_[i].data.ptr = NULL;
            break;
        }
    }
}

void PollerEpoll::loop_once(int waitMs) {
    int64_t ticks = util::timeMilli();
    lastActive_ = epoll_wait(fd_, activeEvs_, kMaxEvents, waitMs);
    int64_t used = util::timeMilli() - ticks;
    trace("epoll wait %d return %d errno %d used %lld millsecond", waitMs, lastActive_, errno, (long long) used);
    fatalif(lastActive_ == -1 && errno != EINTR, "epoll return error %d %s", errno, strerror(errno));
    while (--lastActive_ >= 0) {
        int i = lastActive_;
        Channel *ch = (Channel *) activeEvs_[i].data.ptr;
        int events = activeEvs_[i].events;
        if (ch) {
            if (events & kWriteEvent) {
                trace("channel %lld fd %d handle write", (long long) ch->id(), ch->fd());
                ch->handleWrite();
            }
            if (events & (kReadEvent | POLLERR)) {
                trace("channel %lld fd %d handle read", (long long) ch->id(), ch->fd());
                ch->handleRead();
            }
            if (!(events & (kReadEvent | kWriteEvent | POLLERR))){
                fatal("unexpected poller events");
            }
        }
    }
}

#elif defined(OS_MACOSX)

struct PollerKqueue : public PollerBase {
    int fd_;
    std::set<Channel *> liveChannels_;
    // for epoll selected active events
    struct kevent activeEvs_[kMaxEvents];
    PollerKqueue();
    ~PollerKqueue();
    void addChannel(Channel *ch) override;
    void removeChannel(Channel *ch) override;
    void updateChannel(Channel *ch) override;
    void loop_once(int waitMs) override;
};

PollerBase *createPoller() {
    return new PollerKqueue();
}

PollerKqueue::PollerKqueue() {
    fd_ = kqueue();
    fatalif(fd_ < 0, "kqueue error %d %s", errno, strerror(errno));
    info("poller kqueue %d created", fd_);
}

PollerKqueue::~PollerKqueue() {
    info("destroying poller %d", fd_);
    while (liveChannels_.size()) {
        (*liveChannels_.begin())->close();
    }
    ::close(fd_);
    info("poller %d destroyed", fd_);
}

void PollerKqueue::addChannel(Channel *ch) {
    struct timespec now;
    now.tv_nsec = 0;
    now.tv_sec = 0;
    struct kevent ev[2];
    int n = 0;
    if (ch->readEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, ch);
    }
    if (ch->writeEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, ch);
    }
    trace("adding channel %lld fd %d events read %d write %d  epoll %d", (long long) ch->id(), ch->fd(), ch->events() & POLLIN, ch->events() & POLLOUT, fd_);
    int r = kevent(fd_, ev, n, NULL, 0, &now);
    fatalif(r, "kevent add failed %d %s", errno, strerror(errno));
    liveChannels_.insert(ch);
}

void PollerKqueue::updateChannel(Channel *ch) {
    struct timespec now;
    now.tv_nsec = 0;
    now.tv_sec = 0;
    struct kevent ev[2];
    int n = 0;
    if (ch->readEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, ch);
    } else {
        EV_SET(&ev[n++], ch->fd(), EVFILT_READ, EV_DELETE, 0, 0, ch);
    }
    if (ch->writeEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, ch);
    } else {
        EV_SET(&ev[n++], ch->fd(), EVFILT_WRITE, EV_DELETE, 0, 0, ch);
    }
    trace("modifying channel %lld fd %d events read %d write %d epoll %d", (long long) ch->id(), ch->fd(), ch->events() & POLLIN, ch->events() & POLLOUT, fd_);
    int r = kevent(fd_, ev, n, NULL, 0, &now);
    fatalif(r, "kevent mod failed %d %s", errno, strerror(errno));
}

void PollerKqueue::removeChannel(Channel *ch) {
    trace("deleting channel %lld fd %d epoll %d", (long long) ch->id(), ch->fd(), fd_);
    liveChannels_.erase(ch);
    // remove channel if in ready stat
    for (int i = lastActive_; i >= 0; i--) {
        if (ch == activeEvs_[i].udata) {
            activeEvs_[i].udata = NULL;
            break;
        }
    }
}

void PollerKqueue::loop_once(int waitMs) {
    struct timespec timeout;
    timeout.tv_sec = waitMs / 1000;
    timeout.tv_nsec = (waitMs % 1000) * 1000 * 1000;
    long ticks = util::timeMilli();
    lastActive_ = kevent(fd_, NULL, 0, activeEvs_, kMaxEvents, &timeout);
    trace("kevent wait %d return %d errno %d used %lld millsecond", waitMs, lastActive_, errno, util::timeMilli() - ticks);
    fatalif(lastActive_ == -1 && errno != EINTR, "kevent return error %d %s", errno, strerror(errno));
    while (--lastActive_ >= 0) {
        int i = lastActive_;
        Channel *ch = (Channel *) activeEvs_[i].udata;
        struct kevent &ke = activeEvs_[i];
        if (ch) {
            // only handle write if read and write are enabled
            if (!(ke.flags & EV_EOF) && ch->writeEnabled()) {
                trace("channel %lld fd %d handle write", (long long) ch->id(), ch->fd());
                ch->handleWrite();
            } else if ((ke.flags & EV_EOF) || ch->readEnabled()) {
                trace("channel %lld fd %d handle read", (long long) ch->id(), ch->fd());
                ch->handleRead();
            } else {
                fatal("unexpected epoll events %d", ch->events());
            }
        }
    }
}

#endif
}  // namespace handy<commit_msg>revert loop_once handle read/write in one loop<commit_after>#include <fcntl.h>
#include "conn.h"
#include "event_base.h"
#include "logging.h"
#include "util.h"
#include "poller.h"

#ifdef OS_LINUX
#include <sys/epoll.h>
#elif defined(OS_MACOSX)
#include <sys/event.h>
#else
#error "platform unsupported"
#endif

namespace handy {

#ifdef OS_LINUX

struct PollerEpoll : public PollerBase {
    int fd_;
    std::set<Channel *> liveChannels_;
    // for epoll selected active events
    struct epoll_event activeEvs_[kMaxEvents];
    PollerEpoll();
    ~PollerEpoll();
    void addChannel(Channel *ch) override;
    void removeChannel(Channel *ch) override;
    void updateChannel(Channel *ch) override;
    void loop_once(int waitMs) override;
};

PollerBase *createPoller() {
    return new PollerEpoll();
}

PollerEpoll::PollerEpoll() {
    fd_ = epoll_create1(EPOLL_CLOEXEC);
    fatalif(fd_ < 0, "epoll_create error %d %s", errno, strerror(errno));
    info("poller epoll %d created", fd_);
}

PollerEpoll::~PollerEpoll() {
    info("destroying poller %d", fd_);
    while (liveChannels_.size()) {
        (*liveChannels_.begin())->close();
    }
    ::close(fd_);
    info("poller %d destroyed", fd_);
}

void PollerEpoll::addChannel(Channel *ch) {
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.events = ch->events();
    ev.data.ptr = ch;
    trace("adding channel %lld fd %d events %d epoll %d", (long long) ch->id(), ch->fd(), ev.events, fd_);
    int r = epoll_ctl(fd_, EPOLL_CTL_ADD, ch->fd(), &ev);
    fatalif(r, "epoll_ctl add failed %d %s", errno, strerror(errno));
    liveChannels_.insert(ch);
}

void PollerEpoll::updateChannel(Channel *ch) {
    struct epoll_event ev;
    memset(&ev, 0, sizeof(ev));
    ev.events = ch->events();
    ev.data.ptr = ch;
    trace("modifying channel %lld fd %d events read %d write %d epoll %d", (long long) ch->id(), ch->fd(), ev.events & POLLIN, ev.events & POLLOUT, fd_);
    int r = epoll_ctl(fd_, EPOLL_CTL_MOD, ch->fd(), &ev);
    fatalif(r, "epoll_ctl mod failed %d %s", errno, strerror(errno));
}

void PollerEpoll::removeChannel(Channel *ch) {
    trace("deleting channel %lld fd %d epoll %d", (long long) ch->id(), ch->fd(), fd_);
    liveChannels_.erase(ch);
    for (int i = lastActive_; i >= 0; i--) {
        if (ch == activeEvs_[i].data.ptr) {
            activeEvs_[i].data.ptr = NULL;
            break;
        }
    }
}

void PollerEpoll::loop_once(int waitMs) {
    int64_t ticks = util::timeMilli();
    lastActive_ = epoll_wait(fd_, activeEvs_, kMaxEvents, waitMs);
    int64_t used = util::timeMilli() - ticks;
    trace("epoll wait %d return %d errno %d used %lld millsecond", waitMs, lastActive_, errno, (long long) used);
    fatalif(lastActive_ == -1 && errno != EINTR, "epoll return error %d %s", errno, strerror(errno));
    while (--lastActive_ >= 0) {
        int i = lastActive_;
        Channel *ch = (Channel *) activeEvs_[i].data.ptr;
        int events = activeEvs_[i].events;
        if (ch) {
            if (events & (kReadEvent | POLLERR)) {
                trace("channel %lld fd %d handle read", (long long) ch->id(), ch->fd());
                ch->handleRead();
            } else if (events & kWriteEvent) {
                trace("channel %lld fd %d handle write", (long long) ch->id(), ch->fd());
                ch->handleWrite();
            } else {
                fatal("unexpected poller events");
            }
        }
    }
}

#elif defined(OS_MACOSX)

struct PollerKqueue : public PollerBase {
    int fd_;
    std::set<Channel *> liveChannels_;
    // for epoll selected active events
    struct kevent activeEvs_[kMaxEvents];
    PollerKqueue();
    ~PollerKqueue();
    void addChannel(Channel *ch) override;
    void removeChannel(Channel *ch) override;
    void updateChannel(Channel *ch) override;
    void loop_once(int waitMs) override;
};

PollerBase *createPoller() {
    return new PollerKqueue();
}

PollerKqueue::PollerKqueue() {
    fd_ = kqueue();
    fatalif(fd_ < 0, "kqueue error %d %s", errno, strerror(errno));
    info("poller kqueue %d created", fd_);
}

PollerKqueue::~PollerKqueue() {
    info("destroying poller %d", fd_);
    while (liveChannels_.size()) {
        (*liveChannels_.begin())->close();
    }
    ::close(fd_);
    info("poller %d destroyed", fd_);
}

void PollerKqueue::addChannel(Channel *ch) {
    struct timespec now;
    now.tv_nsec = 0;
    now.tv_sec = 0;
    struct kevent ev[2];
    int n = 0;
    if (ch->readEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, ch);
    }
    if (ch->writeEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, ch);
    }
    trace("adding channel %lld fd %d events read %d write %d  epoll %d", (long long) ch->id(), ch->fd(), ch->events() & POLLIN, ch->events() & POLLOUT, fd_);
    int r = kevent(fd_, ev, n, NULL, 0, &now);
    fatalif(r, "kevent add failed %d %s", errno, strerror(errno));
    liveChannels_.insert(ch);
}

void PollerKqueue::updateChannel(Channel *ch) {
    struct timespec now;
    now.tv_nsec = 0;
    now.tv_sec = 0;
    struct kevent ev[2];
    int n = 0;
    if (ch->readEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, ch);
    } else {
        EV_SET(&ev[n++], ch->fd(), EVFILT_READ, EV_DELETE, 0, 0, ch);
    }
    if (ch->writeEnabled()) {
        EV_SET(&ev[n++], ch->fd(), EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, ch);
    } else {
        EV_SET(&ev[n++], ch->fd(), EVFILT_WRITE, EV_DELETE, 0, 0, ch);
    }
    trace("modifying channel %lld fd %d events read %d write %d epoll %d", (long long) ch->id(), ch->fd(), ch->events() & POLLIN, ch->events() & POLLOUT, fd_);
    int r = kevent(fd_, ev, n, NULL, 0, &now);
    fatalif(r, "kevent mod failed %d %s", errno, strerror(errno));
}

void PollerKqueue::removeChannel(Channel *ch) {
    trace("deleting channel %lld fd %d epoll %d", (long long) ch->id(), ch->fd(), fd_);
    liveChannels_.erase(ch);
    // remove channel if in ready stat
    for (int i = lastActive_; i >= 0; i--) {
        if (ch == activeEvs_[i].udata) {
            activeEvs_[i].udata = NULL;
            break;
        }
    }
}

void PollerKqueue::loop_once(int waitMs) {
    struct timespec timeout;
    timeout.tv_sec = waitMs / 1000;
    timeout.tv_nsec = (waitMs % 1000) * 1000 * 1000;
    long ticks = util::timeMilli();
    lastActive_ = kevent(fd_, NULL, 0, activeEvs_, kMaxEvents, &timeout);
    trace("kevent wait %d return %d errno %d used %lld millsecond", waitMs, lastActive_, errno, util::timeMilli() - ticks);
    fatalif(lastActive_ == -1 && errno != EINTR, "kevent return error %d %s", errno, strerror(errno));
    while (--lastActive_ >= 0) {
        int i = lastActive_;
        Channel *ch = (Channel *) activeEvs_[i].udata;
        struct kevent &ke = activeEvs_[i];
        if (ch) {
            // only handle write if read and write are enabled
            if (!(ke.flags & EV_EOF) && ch->writeEnabled()) {
                trace("channel %lld fd %d handle write", (long long) ch->id(), ch->fd());
                ch->handleWrite();
            } else if ((ke.flags & EV_EOF) || ch->readEnabled()) {
                trace("channel %lld fd %d handle read", (long long) ch->id(), ch->fd());
                ch->handleRead();
            } else {
                fatal("unexpected epoll events %d", ch->events());
            }
        }
    }
}

#endif
}  // namespace handy<|endoftext|>


<commit_before>// Copyright (c) 2010 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/net/view_http_cache_job_factory.h"

#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/task.h"
#include "base/string_util.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_simple_job.h"
#include "net/url_request/view_cache_helper.h"

namespace {

// A job subclass that dumps an HTTP cache entry.
class ViewHttpCacheJob : public net::URLRequestJob {
 public:
  explicit ViewHttpCacheJob(net::URLRequest* request)
      : URLRequestJob(request), data_offset_(0),
        ALLOW_THIS_IN_INITIALIZER_LIST(
            callback_(this, &ViewHttpCacheJob::OnIOComplete)),
        ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {}

  virtual void Start();
  virtual bool GetMimeType(std::string* mime_type) const;
  virtual bool GetCharset(std::string* charset);
  virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);

 private:
  ~ViewHttpCacheJob() {}

  // Called when ViewCacheHelper completes the operation.
  void OnIOComplete(int result);

  std::string data_;
  int data_offset_;
  net::ViewCacheHelper cache_helper_;
  net::CompletionCallbackImpl<ViewHttpCacheJob> callback_;
  ScopedRunnableMethodFactory<ViewHttpCacheJob> method_factory_;
};

void ViewHttpCacheJob::Start() {
  if (!request_ || is_done())
    return;

  std::string cache_key =
      request_->url().spec().substr(strlen(chrome::kNetworkViewCacheURL));

  int rv;
  if (cache_key.empty()) {
    rv = cache_helper_.GetContentsHTML(request_->context(),
                                       chrome::kNetworkViewCacheURL, &data_,
                                       &callback_);
  } else {
    rv = cache_helper_.GetEntryInfoHTML(cache_key, request_->context(),
                                        &data_, &callback_);
  }

  if (rv != net::ERR_IO_PENDING) {
    // Start reading asynchronously so that all error reporting and data
    // callbacks happen as they would for network requests.
    MessageLoop::current()->PostTask(
        FROM_HERE,
        method_factory_.NewRunnableMethod(
            &ViewHttpCacheJob::OnIOComplete, rv));
  }
}

bool ViewHttpCacheJob::GetMimeType(std::string* mime_type) const {
  mime_type->assign("text/html");
  return true;
}

bool ViewHttpCacheJob::GetCharset(std::string* charset) {
  charset->assign("UTF-8");
  return true;
}

bool ViewHttpCacheJob::ReadRawData(net::IOBuffer* buf, int buf_size,
                                   int* bytes_read) {
  DCHECK(bytes_read);
  int remaining = static_cast<int>(data_.size()) - data_offset_;
  if (buf_size > remaining)
    buf_size = remaining;
  memcpy(buf->data(), data_.data() + data_offset_, buf_size);
  data_offset_ += buf_size;
  *bytes_read = buf_size;
  return true;
}

void ViewHttpCacheJob::OnIOComplete(int result) {
  DCHECK_EQ(net::OK, result);

  // Notify that the headers are complete.
  NotifyHeadersComplete();
}

}  // namespace.

// Static.
bool ViewHttpCacheJobFactory::IsSupportedURL(const GURL& url) {
  return StartsWithASCII(url.spec(), chrome::kNetworkViewCacheURL,
                         true /*case_sensitive*/);
}

// Static.
URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest(
    net::URLRequest* request) {
  return new ViewHttpCacheJob(request);
}
<commit_msg>Revert portion of r68206 that may be unsafe.<commit_after>// Copyright (c) 2010 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/net/view_http_cache_job_factory.h"

#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_errors.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_simple_job.h"
#include "net/url_request/view_cache_helper.h"

namespace {

// A job subclass that dumps an HTTP cache entry.
class ViewHttpCacheJob : public net::URLRequestJob {
 public:
  explicit ViewHttpCacheJob(net::URLRequest* request)
      : URLRequestJob(request), data_offset_(0), cancel_(false), busy_(false),
        ALLOW_THIS_IN_INITIALIZER_LIST(
            callback_(this, &ViewHttpCacheJob::OnIOComplete)) {}

  virtual void Start();
  virtual void Kill();
  virtual bool GetMimeType(std::string* mime_type) const;
  virtual bool GetCharset(std::string* charset);
  virtual bool ReadRawData(net::IOBuffer* buf, int buf_size, int *bytes_read);

 private:
  ~ViewHttpCacheJob() {}

  // Called when ViewCacheHelper completes the operation.
  void OnIOComplete(int result);

  std::string data_;
  int data_offset_;
  bool cancel_;
  bool busy_;
  net::ViewCacheHelper cache_helper_;
  net::CompletionCallbackImpl<ViewHttpCacheJob> callback_;
};

void ViewHttpCacheJob::Start() {
  if (!request_ || cancel_)
    return;

  busy_ = true;
  AddRef();  // Released on OnIOComplete().
  std::string cache_key =
      request_->url().spec().substr(strlen(chrome::kNetworkViewCacheURL));

  int rv;
  if (cache_key.empty()) {
    rv = cache_helper_.GetContentsHTML(request_->context(),
                                       chrome::kNetworkViewCacheURL, &data_,
                                       &callback_);
  } else {
    rv = cache_helper_.GetEntryInfoHTML(cache_key, request_->context(),
                                        &data_, &callback_);
  }

  if (rv != net::ERR_IO_PENDING) {
    // Start reading asynchronously so that all error reporting and data
    // callbacks happen as they would for network requests.
    MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
        this, &ViewHttpCacheJob::OnIOComplete, rv));
  }
}

void ViewHttpCacheJob::Kill() {
  // We don't want to delete this object while we are busy; we'll do it when it
  // is safe.
  cancel_ = true;
  if (!busy_)
    URLRequestJob::Kill();
}

bool ViewHttpCacheJob::GetMimeType(std::string* mime_type) const {
  mime_type->assign("text/html");
  return true;
}

bool ViewHttpCacheJob::GetCharset(std::string* charset) {
  charset->assign("UTF-8");
  return true;
}

bool ViewHttpCacheJob::ReadRawData(net::IOBuffer* buf, int buf_size,
                                   int* bytes_read) {
  DCHECK(bytes_read);
  int remaining = static_cast<int>(data_.size()) - data_offset_;
  if (buf_size > remaining)
    buf_size = remaining;
  memcpy(buf->data(), data_.data() + data_offset_, buf_size);
  data_offset_ += buf_size;
  *bytes_read = buf_size;
  return true;
}

void ViewHttpCacheJob::OnIOComplete(int result) {
  // We may be holding the last reference to this job.
  scoped_refptr<ViewHttpCacheJob> self(this);
  DCHECK_EQ(net::OK, result);
  busy_ = false;
  Release();  // Acquired on Start().

  if (cancel_)
    return URLRequestJob::Kill();

  // Notify that the headers are complete.
  NotifyHeadersComplete();
}

}  // namespace.

// Static.
bool ViewHttpCacheJobFactory::IsSupportedURL(const GURL& url) {
  return StartsWithASCII(url.spec(), chrome::kNetworkViewCacheURL,
                         true /*case_sensitive*/);
}

// Static.
URLRequestJob* ViewHttpCacheJobFactory::CreateJobForRequest(
    net::URLRequest* request) {
  return new ViewHttpCacheJob(request);
}
<|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/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/common/chrome_switches.h"

namespace prerender {

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerender)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerender);

    if (switch_value == switches::kPrerenderSwitchValueAuto) {
#if defined(OS_CHROMEOS)
      // Prerender is temporarily disabled on CrOS.
      // http://crosbug.com/12483
      prerender_option = PRERENDER_OPTION_DISABLED;
#else
      prerender_option = PRERENDER_OPTION_AUTO;
#endif
    } else if (switch_value == switches::kPrerenderSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value == switches::kPrerenderSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      const base::FieldTrial::Probability kPrefetchDivisor = 1000;
      const base::FieldTrial::Probability kYesPrefetchProbability = 0;
      const base::FieldTrial::Probability kPrerenderExperimentProbability = 450;
      const base::FieldTrial::Probability kPrerenderControlProbability = 450;

      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", kPrefetchDivisor,
                               "ContentPrefetchDisabled", 2011, 6, 30));

      const int kNoPrefetchGroup = trial->kDefaultGroupNumber;
      const int kYesPrefetchGroup =
          trial->AppendGroup("ContentPrefetchEnabled", kYesPrefetchProbability);
      const int kPrerenderExperimentGroup =
          trial->AppendGroup("ContentPrefetchPrerender",
                             kPrerenderExperimentProbability);
      const int kPrerenderControlGroup =
          trial->AppendGroup("ContentPrefetchPrerenderControl",
                             kPrerenderControlProbability);
      const int trial_group = trial->group();
      if (trial_group == kYesPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kNoPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kPrerenderExperimentGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else if (trial_group == kPrerenderControlGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);
}

}  // namespace prerender
<commit_msg>Set PrerenderExperiment to 80%, PrerenderControl to 20%, and artificially split them each into 2 equivalent groups of equal size for comparison purposes.<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/prerender/prerender_field_trial.h"

#include "base/command_line.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram.h"
#include "content/browser/renderer_host/resource_dispatcher_host.h"
#include "chrome/browser/prerender/prerender_manager.h"
#include "chrome/common/chrome_switches.h"

namespace prerender {

void ConfigurePrefetchAndPrerender(const CommandLine& command_line) {
  enum PrerenderOption {
    PRERENDER_OPTION_AUTO,
    PRERENDER_OPTION_DISABLED,
    PRERENDER_OPTION_ENABLED,
    PRERENDER_OPTION_PREFETCH_ONLY,
  };

  PrerenderOption prerender_option = PRERENDER_OPTION_AUTO;
  if (command_line.HasSwitch(switches::kPrerender)) {
    const std::string switch_value =
        command_line.GetSwitchValueASCII(switches::kPrerender);

    if (switch_value == switches::kPrerenderSwitchValueAuto) {
#if defined(OS_CHROMEOS)
      // Prerender is temporarily disabled on CrOS.
      // http://crosbug.com/12483
      prerender_option = PRERENDER_OPTION_DISABLED;
#else
      prerender_option = PRERENDER_OPTION_AUTO;
#endif
    } else if (switch_value == switches::kPrerenderSwitchValueDisabled) {
      prerender_option = PRERENDER_OPTION_DISABLED;
    } else if (switch_value.empty() ||
               switch_value == switches::kPrerenderSwitchValueEnabled) {
      // The empty string means the option was provided with no value, and that
      // means enable.
      prerender_option = PRERENDER_OPTION_ENABLED;
    } else if (switch_value == switches::kPrerenderSwitchValuePrefetchOnly) {
      prerender_option = PRERENDER_OPTION_PREFETCH_ONLY;
    } else {
      prerender_option = PRERENDER_OPTION_DISABLED;
      LOG(ERROR) << "Invalid --prerender option received on command line: "
                 << switch_value;
      LOG(ERROR) << "Disabling prerendering!";
    }
  }

  switch (prerender_option) {
    case PRERENDER_OPTION_AUTO: {
      const base::FieldTrial::Probability kPrefetchDivisor = 1000;
      const base::FieldTrial::Probability kYesPrefetchProbability = 0;
      const base::FieldTrial::Probability kPrerenderExp1Probability = 400;
      const base::FieldTrial::Probability kPrerenderControl1Probability = 100;
      const base::FieldTrial::Probability kPrerenderExp2Probability = 400;
      const base::FieldTrial::Probability kPrerenderControl2Probability = 100;

      scoped_refptr<base::FieldTrial> trial(
          new base::FieldTrial("Prefetch", kPrefetchDivisor,
                               "ContentPrefetchDisabled", 2011, 6, 30));

      const int kNoPrefetchGroup = trial->kDefaultGroupNumber;
      const int kYesPrefetchGroup =
          trial->AppendGroup("ContentPrefetchEnabled", kYesPrefetchProbability);
      const int kPrerenderExperiment1Group =
          trial->AppendGroup("ContentPrefetchPrerender1",
                             kPrerenderExp1Probability);
      const int kPrerenderControl1Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl1",
                             kPrerenderControl1Probability);
      const int kPrerenderExperiment2Group =
          trial->AppendGroup("ContentPrefetchPrerender2",
                             kPrerenderExp2Probability);
      const int kPrerenderControl2Group =
          trial->AppendGroup("ContentPrefetchPrerenderControl2",
                             kPrerenderControl2Probability);
      const int trial_group = trial->group();
      if (trial_group == kYesPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kNoPrefetchGroup) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_DISABLED);
      } else if (trial_group == kPrerenderExperiment1Group ||
                 trial_group == kPrerenderExperiment2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(true);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP);
      } else if (trial_group == kPrerenderControl1Group ||
                 trial_group == kPrerenderControl2Group) {
        ResourceDispatcherHost::set_is_prefetch_enabled(false);
        PrerenderManager::SetMode(
            PrerenderManager::PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP);
      } else {
        NOTREACHED();
      }
      break;
    }
    case PRERENDER_OPTION_DISABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(false);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    case PRERENDER_OPTION_ENABLED:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_ENABLED);
      break;
    case PRERENDER_OPTION_PREFETCH_ONLY:
      ResourceDispatcherHost::set_is_prefetch_enabled(true);
      PrerenderManager::SetMode(PrerenderManager::PRERENDER_MODE_DISABLED);
      break;
    default:
      NOTREACHED();
  }

  UMA_HISTOGRAM_ENUMERATION("Prerender.Sessions",
                            PrerenderManager::GetMode(),
                            PrerenderManager::PRERENDER_MODE_MAX);
}

}  // namespace prerender
<|endoftext|>


<commit_before>// Copyright (c) 2009 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_frame/test/net/test_automation_provider.h"

#include "base/command_line.h"
#include "chrome/test/automation/automation_messages.h"

#include "chrome_frame/test/net/test_automation_resource_message_filter.h"

namespace {

// A special command line switch to just run the unit tests without CF in
// the picture.  Can be useful when the harness itself needs to be debugged.
const wchar_t kNoCfTestRun[] = L"no-cf-test-run";

bool CFTestsDisabled() {
  static bool switch_present = CommandLine::ForCurrentProcess()->
      HasSwitch(kNoCfTestRun);
  return switch_present;
}

}  // end namespace

TestAutomationProvider* TestAutomationProvider::g_provider_instance_ = NULL;

TestAutomationProvider::TestAutomationProvider(
    Profile* profile,
    TestAutomationProviderDelegate* delegate)
    : AutomationProvider(profile), tab_handle_(-1), delegate_(delegate) {
  filter_ = new TestAutomationResourceMessageFilter(this);
  URLRequest::RegisterProtocolFactory("http",
                                      TestAutomationProvider::Factory);
  URLRequest::RegisterProtocolFactory("https",
                                      TestAutomationProvider::Factory);
  g_provider_instance_ = this;
}

TestAutomationProvider::~TestAutomationProvider() {
  g_provider_instance_ = NULL;
}

void TestAutomationProvider::OnMessageReceived(const IPC::Message& msg) {
  if (filter_->OnMessageReceived(msg))
    return;  // Message handled by the filter.

  __super::OnMessageReceived(msg);
}

// IPC override to grab the tab handle.
bool TestAutomationProvider::Send(IPC::Message* msg) {
  if (msg->type() == AutomationMsg_TabLoaded::ID) {
    DCHECK(tab_handle_ == -1) << "Currently only support one tab";
    void* iter = NULL;
    CHECK(msg->ReadInt(&iter, &tab_handle_));
    DLOG(INFO) << "Got tab handle: " << tab_handle_;
    DCHECK(tab_handle_ != -1 && tab_handle_ != 0);
    delegate_->OnInitialTabLoaded();
  }

  return AutomationProvider::Send(msg);
}

URLRequestJob* TestAutomationProvider::Factory(URLRequest* request,
                                               const std::string& scheme) {
  if (CFTestsDisabled())
    return NULL;

  if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
    // Only look at requests that don't have any user data.
    // ResourceDispatcherHost uses the user data for requests that it manages.
    // We don't want to mess with those.

    // We could also check if the current thread is our TestUrlRequest thread
    // and only intercept requests that belong to that thread.
    if (g_provider_instance_ && request->GetUserData(NULL) == NULL &&
        g_provider_instance_->tab_handle_ != -1) {
      // We generate our own request id which is also what
      // ResourceDispatcherHost does (well, the id is actually generated by
      // ResourceDispatcher).  Since these requests are divided into with
      // and without userdata, we're OK.  However, just to make debugging
      // a little easier, we have a significantly higher start value.
      static int new_id = 0x00100000;
      URLRequestAutomationJob* job = new URLRequestAutomationJob(request,
          g_provider_instance_->tab_handle_, new_id++,
          g_provider_instance_->filter_, false);
      return job;
    }
  }

  return NULL;
}

// static
TestAutomationProvider* TestAutomationProvider::NewAutomationProvider(
    Profile* p, const std::string& channel,
    TestAutomationProviderDelegate* delegate) {
  TestAutomationProvider* automation = new TestAutomationProvider(p, delegate);
  automation->ConnectToChannel(channel);
  automation->SetExpectedTabCount(1);
  return automation;
}
<commit_msg>Attempt 2 at fixing the chrome frame net tests hang on the builders. This hang occurs because of a race condition in registering the http/https protocol factories. The net tests registers a protocol factory and the Chrome AutomationResourceMessageFilter also registers factories. If the net tests ends up being first in the chain then the requests are incorrectly dropped.<commit_after>// Copyright (c) 2009 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_frame/test/net/test_automation_provider.h"

#include "base/command_line.h"
#include "chrome/test/automation/automation_messages.h"

#include "chrome_frame/test/net/test_automation_resource_message_filter.h"

namespace {

// A special command line switch to just run the unit tests without CF in
// the picture.  Can be useful when the harness itself needs to be debugged.
const wchar_t kNoCfTestRun[] = L"no-cf-test-run";

bool CFTestsDisabled() {
  static bool switch_present = CommandLine::ForCurrentProcess()->
      HasSwitch(kNoCfTestRun);
  return switch_present;
}

}  // end namespace

TestAutomationProvider* TestAutomationProvider::g_provider_instance_ = NULL;

TestAutomationProvider::TestAutomationProvider(
    Profile* profile,
    TestAutomationProviderDelegate* delegate)
    : AutomationProvider(profile), tab_handle_(-1), delegate_(delegate) {
  // We need to register the protocol factory before the
  // AutomationResourceMessageFilter registers the automation job factory to
  // ensure that we don't inadvarently end up handling http requests which
  // we don't expect. The initial chrome frame page for the network tests
  // issues http requests which our test factory should not handle.
  URLRequest::RegisterProtocolFactory("http",
                                      TestAutomationProvider::Factory);
  URLRequest::RegisterProtocolFactory("https",
                                      TestAutomationProvider::Factory);
  filter_ = new TestAutomationResourceMessageFilter(this);
  g_provider_instance_ = this;
}

TestAutomationProvider::~TestAutomationProvider() {
  g_provider_instance_ = NULL;
}

void TestAutomationProvider::OnMessageReceived(const IPC::Message& msg) {
  if (filter_->OnMessageReceived(msg))
    return;  // Message handled by the filter.

  __super::OnMessageReceived(msg);
}

// IPC override to grab the tab handle.
bool TestAutomationProvider::Send(IPC::Message* msg) {
  if (msg->type() == AutomationMsg_TabLoaded::ID) {
    DCHECK(tab_handle_ == -1) << "Currently only support one tab";
    void* iter = NULL;
    CHECK(msg->ReadInt(&iter, &tab_handle_));
    DLOG(INFO) << "Got tab handle: " << tab_handle_;
    DCHECK(tab_handle_ != -1 && tab_handle_ != 0);
    delegate_->OnInitialTabLoaded();
  }

  return AutomationProvider::Send(msg);
}

URLRequestJob* TestAutomationProvider::Factory(URLRequest* request,
                                               const std::string& scheme) {
  if (CFTestsDisabled())
    return NULL;

  if (request->url().SchemeIs("http") || request->url().SchemeIs("https")) {
    // Only look at requests that don't have any user data.
    // ResourceDispatcherHost uses the user data for requests that it manages.
    // We don't want to mess with those.

    // We could also check if the current thread is our TestUrlRequest thread
    // and only intercept requests that belong to that thread.
    if (g_provider_instance_ && request->GetUserData(NULL) == NULL &&
        g_provider_instance_->tab_handle_ != -1) {
      // We generate our own request id which is also what
      // ResourceDispatcherHost does (well, the id is actually generated by
      // ResourceDispatcher).  Since these requests are divided into with
      // and without userdata, we're OK.  However, just to make debugging
      // a little easier, we have a significantly higher start value.
      static int new_id = 0x00100000;
      URLRequestAutomationJob* job = new URLRequestAutomationJob(request,
          g_provider_instance_->tab_handle_, new_id++,
          g_provider_instance_->filter_, false);
      return job;
    }
  }

  return NULL;
}

// static
TestAutomationProvider* TestAutomationProvider::NewAutomationProvider(
    Profile* p, const std::string& channel,
    TestAutomationProviderDelegate* delegate) {
  TestAutomationProvider* automation = new TestAutomationProvider(p, delegate);
  automation->ConnectToChannel(channel);
  automation->SetExpectedTabCount(1);
  return automation;
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "ExceptionFilterTest.h"
#include "EventReceiver.h"
#include "ExceptionFilter.h"
#include <stdexcept>
#include <sstream>
#include <iostream>

using namespace std;

string FormatMessage(int value) {
  std::stringstream sstr;
  sstr << "custom_exception: " << value;
  return sstr.str();
}

class custom_exception:
  public std::exception
{
public:
  custom_exception(int value):
    m_value(value)
  {
  }

  int m_value;
};

/// <summary>
/// Exception type which can track its own destruction
/// </summary>
class tracking_exception:
  public std::exception
{
public:
  tracking_exception(int) {
    s_count++;
  }
  tracking_exception(const tracking_exception& rhs) {
    s_count++;
  }
  NOEXCEPT(~tracking_exception(void)) {
    s_count--;
  }

  static size_t s_count;
};

size_t tracking_exception::s_count = 0;

class ThrowingListener:
  public virtual EventReceiver
{
public:
  virtual void DoThrow(void) = 0;
};

template<class Ex>
class ThrowsWhenRun:
  public CoreThread
{
public:
  ThrowsWhenRun(void) {
    Ready();
  }

  // This convoluted syntax is required to evade warnings on Mac
  decltype(throw_rethrowable Ex(100)) MakeException() {
    return throw_rethrowable Ex(100);
  }

  void Run(void) override {
    MakeException();
  }
};

template<int i = 200>
class ThrowsWhenFired:
  public ThrowingListener
{
public:
  ThrowsWhenFired(void):
    hit(false)
  {}

  bool hit;

  void DoThrow(void) override {
    hit = true;
    throw_rethrowable custom_exception(i);
  }
};

class GenericFilter:
  public ExceptionFilter
{
public:
  GenericFilter(void):
    m_hit(false),
    m_specific(false),
    m_generic(false),
    m_fireSpecific(false)
  {
  }

  bool m_hit;
  bool m_specific;
  bool m_generic;
  bool m_fireSpecific;

  virtual void Filter(const std::function<void()>& rethrower) override {
    m_hit = true;
    try {
      rethrower();
    } catch(tracking_exception&) {
    } catch(custom_exception& custom) {
      EXPECT_EQ(100, custom.m_value) << "A filtered custom exception did not have the expected member field value";
      m_specific = true;
    } catch(...) {
      m_generic = true;
    }
  }

  virtual void Filter(const std::function<void()>& rethrower, const EventReceiverProxyBase* pProxy, EventReceiver* pRecipient) override {
    m_hit = true;
    try {
      rethrower();
    } catch(custom_exception& custom) {
      EXPECT_EQ(200, custom.m_value) << "A fired exception did not have the expected value, probable copy malfunction";
      m_fireSpecific = true;
    } catch(...) {
      m_generic = true;
    }
  }
};

TEST_F(ExceptionFilterTest, ExceptionDestruction) {
  // Add the exception filter type to the context first
  AutoRequired<GenericFilter> filter;

  // Now add something that will throw when it's run:
  AutoRequired<ThrowsWhenRun<tracking_exception>> thrower;

  // Run:
  m_create->InitiateCoreThreads();
  thrower->Wait();

  // Verify that the exception was destroyed the correct number of times:
  EXPECT_EQ(0UL, tracking_exception::s_count) << "Exception was not destroyed the correct number of times";
}

TEST_F(ExceptionFilterTest, CheckThrowThrow) {
  class example {
  public:
    example() {
      throw std::exception();
    }
  };

  EXPECT_THROW(throw example(), std::exception) << "An exception type which throws from its ctor did not throw the expected type";
}

TEST_F(ExceptionFilterTest, ThreadThrowsCheck) {
  // Add the exception filter type to the context first
  AutoRequired<GenericFilter> filter;

  // Now add something that will throw when it's run:
  AutoRequired<ThrowsWhenRun<custom_exception>> thrower;

  // Wait for the thrower to terminate, should be pretty fast:
  m_create->InitiateCoreThreads();
  thrower->Wait();

  // Hopefully the filter got hit in the right spot:
  EXPECT_TRUE(filter->m_hit) << "Filter was not invoked for a thrown exception";
  EXPECT_TRUE(filter->m_specific) << "Filter did not correctly detect the exception type";
  EXPECT_FALSE(filter->m_generic) << "Filter did not correctly filter out a specific exception";
}

TEST_F(ExceptionFilterTest, FireThrowsCheck) {
  // Add the generic filter:
  AutoRequired<GenericFilter> filter;

  // Add a context member which will throw when its event is fired, and a firing class:
  AutoRequired<ThrowsWhenFired<>> fireThrower;

  // Add something to fire the exception:
  AutoFired<ThrowingListener> broadcaster;
  broadcaster(&ThrowingListener::DoThrow)();

  // Verify that the exception was filtered properly by the generic filter:
  EXPECT_TRUE(filter->m_fireSpecific) << "Filter was not invoked on a Fired exception";
}

TEST_F(ExceptionFilterTest, EnclosedThrowCheck) {
  // Create our listener:
  AutoRequired<GenericFilter> filter;

  // Now the subcontext:
  AutoCreateContext subCtxt;
  CurrentContextPusher pshr(subCtxt);

  // Create and start:
  AutoRequired<ThrowsWhenRun<custom_exception>> runThrower;
  subCtxt->InitiateCoreThreads();

  // Wait for the exception to get thrown:
  subCtxt->Wait();

  // Verify that the filter caught the exception:
  EXPECT_TRUE(filter->m_hit) << "Filter operating in a superior context did not catch an exception thrown from a child context";
}

TEST_F(ExceptionFilterTest, VerifyThrowingRecipients) {
  // Create a pair of classes which throw exceptions:
  AutoRequired<ThrowsWhenFired<200>> v200;
  AutoRequired<ThrowsWhenFired<201>> v201;

  // Now try to throw:
  AutoFired<ThrowingListener> tl;
  tl(&ThrowingListener::DoThrow)();

  // Verify that BOTH are hit:
  EXPECT_TRUE(v200->hit && v201->hit) << "Expected all receivers of a fired event will be processed, even if some throw exceptions";
}<commit_msg>Exceptions should not percolate out of a Fire call<commit_after>// Copyright (c) 2010 - 2013 Leap Motion. All rights reserved. Proprietary and confidential.
#include "stdafx.h"
#include "ExceptionFilterTest.h"
#include "EventReceiver.h"
#include "ExceptionFilter.h"
#include <stdexcept>
#include <sstream>
#include <iostream>

using namespace std;

string FormatMessage(int value) {
  std::stringstream sstr;
  sstr << "custom_exception: " << value;
  return sstr.str();
}

class custom_exception:
  public std::exception
{
public:
  custom_exception(int value):
    m_value(value)
  {
  }

  int m_value;
};

/// <summary>
/// Exception type which can track its own destruction
/// </summary>
class tracking_exception:
  public std::exception
{
public:
  tracking_exception(int) {
    s_count++;
  }
  tracking_exception(const tracking_exception& rhs) {
    s_count++;
  }
  NOEXCEPT(~tracking_exception(void)) {
    s_count--;
  }

  static size_t s_count;
};

size_t tracking_exception::s_count = 0;

class ThrowingListener:
  public virtual EventReceiver
{
public:
  virtual void DoThrow(void) = 0;
};

template<class Ex>
class ThrowsWhenRun:
  public CoreThread
{
public:
  ThrowsWhenRun(void) {
    Ready();
  }

  // This convoluted syntax is required to evade warnings on Mac
  decltype(throw_rethrowable Ex(100)) MakeException() {
    return throw_rethrowable Ex(100);
  }

  void Run(void) override {
    MakeException();
  }
};

template<int i = 200>
class ThrowsWhenFired:
  public ThrowingListener
{
public:
  ThrowsWhenFired(void):
    hit(false)
  {}

  bool hit;

  void DoThrow(void) override {
    hit = true;
    throw_rethrowable custom_exception(i);
  }
};

class GenericFilter:
  public ExceptionFilter
{
public:
  GenericFilter(void):
    m_hit(false),
    m_specific(false),
    m_generic(false),
    m_fireSpecific(false)
  {
  }

  bool m_hit;
  bool m_specific;
  bool m_generic;
  bool m_fireSpecific;

  virtual void Filter(const std::function<void()>& rethrower) override {
    m_hit = true;
    try {
      rethrower();
    } catch(tracking_exception&) {
    } catch(custom_exception& custom) {
      EXPECT_EQ(100, custom.m_value) << "A filtered custom exception did not have the expected member field value";
      m_specific = true;
    } catch(...) {
      m_generic = true;
    }
  }

  virtual void Filter(const std::function<void()>& rethrower, const EventReceiverProxyBase* pProxy, EventReceiver* pRecipient) override {
    m_hit = true;
    try {
      rethrower();
    } catch(custom_exception& custom) {
      EXPECT_EQ(200, custom.m_value) << "A fired exception did not have the expected value, probable copy malfunction";
      m_fireSpecific = true;
    } catch(...) {
      m_generic = true;
    }
  }
};

TEST_F(ExceptionFilterTest, ExceptionDestruction) {
  // Add the exception filter type to the context first
  AutoRequired<GenericFilter> filter;

  // Now add something that will throw when it's run:
  AutoRequired<ThrowsWhenRun<tracking_exception>> thrower;

  // Run:
  m_create->InitiateCoreThreads();
  thrower->Wait();

  // Verify that the exception was destroyed the correct number of times:
  EXPECT_EQ(0UL, tracking_exception::s_count) << "Exception was not destroyed the correct number of times";
}

TEST_F(ExceptionFilterTest, CheckThrowThrow) {
  class example {
  public:
    example() {
      throw std::exception();
    }
  };

  EXPECT_THROW(throw example(), std::exception) << "An exception type which throws from its ctor did not throw the expected type";
}

TEST_F(ExceptionFilterTest, ThreadThrowsCheck) {
  // Add the exception filter type to the context first
  AutoRequired<GenericFilter> filter;

  // Now add something that will throw when it's run:
  AutoRequired<ThrowsWhenRun<custom_exception>> thrower;

  // Wait for the thrower to terminate, should be pretty fast:
  m_create->InitiateCoreThreads();
  thrower->Wait();

  // Hopefully the filter got hit in the right spot:
  EXPECT_TRUE(filter->m_hit) << "Filter was not invoked for a thrown exception";
  EXPECT_TRUE(filter->m_specific) << "Filter did not correctly detect the exception type";
  EXPECT_FALSE(filter->m_generic) << "Filter did not correctly filter out a specific exception";
}

TEST_F(ExceptionFilterTest, FireThrowsCheck) {
  // Firing will occur at the parent context scope:
  AutoFired<ThrowingListener> broadcaster;

  // Create a subcontext
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  // Add the generic filter:
  AutoRequired<GenericFilter> filter;

  // Add a context member which will throw when its event is fired, and a firing class:
  AutoRequired<ThrowsWhenFired<>> fireThrower;

  // Add something to fire the exception:
  EXPECT_NO_THROW(broadcaster(&ThrowingListener::DoThrow)());

  // Verify that the exception was filtered properly by the generic filter:
  EXPECT_TRUE(filter->m_fireSpecific) << "Filter was not invoked on a Fired exception";

  // Verify that our context was torn down:
  EXPECT_TRUE(ctxt->ShouldStop()) << "An unhandled exception from a fire call in a context should have signalled it to stop";

  // Verify that the parent context is intact:
  EXPECT_FALSE(m_create->ShouldStop()) << "An unhandled exception incorrectly terminated a parent context";
}

TEST_F(ExceptionFilterTest, EnclosedThrowCheck) {
  // Create our listener:
  AutoRequired<GenericFilter> filter;

  // Now the subcontext:
  AutoCreateContext subCtxt;
  CurrentContextPusher pshr(subCtxt);

  // Create and start:
  AutoRequired<ThrowsWhenRun<custom_exception>> runThrower;
  subCtxt->InitiateCoreThreads();

  // Wait for the exception to get thrown:
  subCtxt->Wait();

  // Verify that the filter caught the exception:
  EXPECT_TRUE(filter->m_hit) << "Filter operating in a superior context did not catch an exception thrown from a child context";
}

TEST_F(ExceptionFilterTest, VerifyThrowingRecipients) {
  // Create a pair of classes which throw exceptions:
  AutoRequired<ThrowsWhenFired<200>> v200;
  AutoRequired<ThrowsWhenFired<201>> v201;

  // Now try to throw:
  AutoFired<ThrowingListener> tl;
  tl(&ThrowingListener::DoThrow)();

  // Verify that BOTH are hit:
  EXPECT_TRUE(v200->hit && v201->hit) << "Expected all receivers of a fired event will be processed, even if some throw exceptions";
}<|endoftext|>


<commit_before>/**************************************************************************
 * Copyright(c) 1998-2000, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

 //////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Forward Multiplicity Detector based on Silicon plates                    //
//  This class contains the procedures simulation ADC  signal for            //
//  the Forward Multiplicity detector  : hits -> digits                      //
//  ADC signal consists                                                      //
//   - number of detector;                                                   //
//   - number of ring;                                                       //
//   - number of sector;                                                     //
//   - ADC signal in this channel                                            //
//                                                                           //
 //////////////////////////////////////////////////////////////////////////////

#include <TTree.h>
#include <TVector.h>
#include <TObjArray.h>
#include <TFile.h>
#include <TDirectory.h>
#include <TRandom.h>

#include "AliFMDDigitizer.h"
#include "AliFMD.h"
#include "AliFMDhit.h"
#include "AliFMDdigit.h"
#include "AliRunDigitizer.h"

#include "AliRun.h"
#include "AliLoader.h"
#include "AliRunLoader.h"

#include <stdlib.h>
#include <Riostream.h>
#include <Riostream.h>

ClassImp(AliFMDDigitizer)

//___________________________________________
  AliFMDDigitizer::AliFMDDigitizer()  :AliDigitizer()
{
// Default ctor - don't use it
  ;
}

//___________________________________________
AliFMDDigitizer::AliFMDDigitizer(AliRunDigitizer* manager)
    :AliDigitizer(manager)
{
  // ctor which should be used
  //  fDebug =0;
   if (GetDebug()>1)
     Info("AliFMDDigitizer"," processed");

}

//------------------------------------------------------------------------
AliFMDDigitizer::~AliFMDDigitizer()
{
// Destructor

}

 //------------------------------------------------------------------------
Bool_t AliFMDDigitizer::Init()
{
// Initialization
// cout<<"AliFMDDigitizer::Init"<<endl;
 return kTRUE;
}

//---------------------------------------------------------------------

void AliFMDDigitizer::Exec(Option_t * /*option*/)
{

  /*
   Conver hits to digits:
   - number of detector;
   - number of ring;
   - number of sector;
   - ADC signal in this channel
  */

  AliRunLoader *inRL, *outRL;//in and out Run Loaders
  AliLoader *pInFMD, *pOutFMD;// in and out ITSLoaders

  outRL = AliRunLoader::GetRunLoader(fManager->GetOutputFolderName());
  pOutFMD = outRL->GetLoader("FMDLoader");

#ifdef DEBUG
  Info("Hits2Digits Exec"," start...";
#endif

  Int_t volume, sector, ring, charge;
  Float_t e;
  Float_t de[10][50][520];
  Int_t hit;
  Int_t digit[5];
  Int_t ivol, iSector, iRing;
  for (Int_t i=0; i<10; i++)
    for(Int_t j=0; j<50; j++)
      for(Int_t ij=0; ij<520; ij++)
     de[i][j][ij]=0;
  Int_t numberOfRings[5]= {512,256,512,256,512};
  Int_t numberOfSector[5] =  {20,40,20,40,20};

  AliFMDhit *fmdHit=0;
  TTree *tH=0;
  TBranch *brHits=0;
  TBranch *brD=0;

  inRL = AliRunLoader::GetRunLoader(fManager->GetInputFolderName(0));

  if (inRL == 0x0)
    {
      Error("Exec","Can not find Run Loader for input stream 0");
      return;
    }

  if (!inRL->GetAliRun()) inRL->LoadgAlice();

  AliFMD * fFMD = (AliFMD *) inRL->GetAliRun()->GetDetector("FMD");

  if (fFMD == 0x0)
   {
     Error("Exec","Can not get FMD from gAlice");
     return;
   }
// Loop over files to digitize

  Int_t nFiles=GetManager()->GetNinputs();
  for (Int_t inputFile=0; inputFile<nFiles;inputFile++)
   {

#ifdef DEBUG
  Info(" Digitizing event number ",fManager->GetOutputEventNr()) ;
#endif

    if (fFMD)
     {

      inRL = AliRunLoader::GetRunLoader(fManager->GetInputFolderName(inputFile));
      pInFMD = inRL->GetLoader("FMDLoader");
      pInFMD->LoadHits("READ");

      tH = pInFMD->TreeH();
      if (tH == 0x0)
       {
         pInFMD->LoadHits("read");
         tH = pInFMD->TreeH();
       }
      brHits = tH->GetBranch("FMD");
      if (brHits) {
          fFMD->SetHitsAddressBranch(brHits);
      }else{
        Fatal("Exec","EXEC Branch FMD hit not found");
      }
      TClonesArray *fFMDhits = fFMD->Hits ();

      Int_t ntracks    = (Int_t) tH->GetEntries();

      for (Int_t track = 0; track < ntracks; track++)
       {
         brHits->GetEntry(track);
         Int_t nhits = fFMDhits->GetEntries ();

         for (hit = 0; hit < nhits; hit++)
           {
             fmdHit = (AliFMDhit *) fFMDhits->UncheckedAt(hit);

             volume = fmdHit->Volume ();
             sector = fmdHit->NumberOfSector ();
             ring = fmdHit->NumberOfRing ();
             e = fmdHit->Edep ();
             de[volume][sector][ring] += e;

           }          //hit loop
       }               //track loop
    }
//if FMD

  // Put noise and make ADC signal
   Float_t mipI = 1.664 * 0.04 * 2.33 / 22400;     // = 6.923e-6;
   for ( ivol=1; ivol<=5; ivol++){
     for ( iSector=1; iSector<=numberOfSector[ivol-1]; iSector++){
       for ( iRing=1; iRing<=numberOfRings[ivol-1]; iRing++){
         digit[0]=ivol;
         digit[1]=iSector;
         digit[2]=iRing;
         charge = Int_t (de[ivol][iSector][iRing] / mipI);
         Int_t pedestal=Int_t(gRandom->Gaus(500,250));
  //       digit[3]=PutNoise(charge);
         digit[3]=charge + pedestal;
         if(digit[3]<= 500) digit[3]=500;
    //dynamic range from MIP(0.155MeV) to 30MIP(4.65MeV)
    //1024 ADC channels
         Float_t channelWidth=(22400*50)/1024;
         digit[4]=Int_t(digit[3]/channelWidth);
         if (digit[4]>1024) digit[4]=1024;
         fFMD->AddDigit(digit);
       } //ivol
     } //iSector
   } //iRing

   TTree* treeD = pOutFMD->TreeD();

   if (treeD == 0x0) {
     pOutFMD->MakeTree("D");
     treeD = pOutFMD->TreeD();

   }

   treeD->Reset();
   fFMD->MakeBranchInTreeD(treeD);
   brD = treeD->GetBranch("FMD");

   treeD->Fill();  //this operator does not work for events >1

   pOutFMD->WriteDigits("OVERWRITE");
   pOutFMD->UnloadHits();
   inRL->GetAliRun() ->ResetDigits();
   }
}

<commit_msg> warning remove<commit_after> /**************************************************************************
 * Copyright(c) 1998-2000, ALICE Experiment at CERN, All rights reserved. *
 *                                                                        *
 * Author: The ALICE Off-line Project.                                    *
 * Contributors are mentioned in the code where appropriate.              *
 *                                                                        *
 * Permission to use, copy, modify and distribute this software and its   *
 * documentation strictly for non-commercial purposes is hereby granted   *
 * without fee, provided that the above copyright notice appears in all   *
 * copies and that both the copyright notice and this permission notice   *
 * appear in the supporting documentation. The authors make no claims     *
 * about the suitability of this software for any purpose. It is          *
 * provided "as is" without express or implied warranty.                  *
 **************************************************************************/

 //////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  Forward Multiplicity Detector based on Silicon plates                    //
//  This class contains the procedures simulation ADC  signal for            //
//  the Forward Multiplicity detector  : hits -> digits                      //
//  ADC signal consists                                                      //
//   - number of detector;                                                   //
//   - number of ring;                                                       //
//   - number of sector;                                                     //
//   - ADC signal in this channel                                            //
//                                                                           //
 //////////////////////////////////////////////////////////////////////////////

#include <TTree.h>
#include <TVector.h>
#include <TObjArray.h>
#include <TFile.h>
#include <TDirectory.h>
#include <TRandom.h>

#include "AliFMDDigitizer.h"
#include "AliFMD.h"
#include "AliFMDhit.h"
#include "AliFMDdigit.h"
#include "AliRunDigitizer.h"

#include "AliRun.h"
#include "AliLoader.h"
#include "AliRunLoader.h"

#include <stdlib.h>
#include <Riostream.h>
#include <Riostream.h>

ClassImp(AliFMDDigitizer)

//___________________________________________
  AliFMDDigitizer::AliFMDDigitizer()  :AliDigitizer()
{
// Default ctor - don't use it
  ;
}

//___________________________________________
AliFMDDigitizer::AliFMDDigitizer(AliRunDigitizer* manager)
    :AliDigitizer(manager)
{
  // ctor which should be used
  //  fDebug =0;
#ifgef DEBUG
     Info("AliFMDDigitizer"," processed");
#endif
}

//------------------------------------------------------------------------
AliFMDDigitizer::~AliFMDDigitizer()
{
// Destructor

}

 //------------------------------------------------------------------------
Bool_t AliFMDDigitizer::Init()
{
// Initialization
// cout<<"AliFMDDigitizer::Init"<<endl;
 return kTRUE;
}

//---------------------------------------------------------------------

void AliFMDDigitizer::Exec(Option_t * /*option*/)
{

  /*
   Conver hits to digits:
   - number of detector;
   - number of ring;
   - number of sector;
   - ADC signal in this channel
  */

  AliRunLoader *inRL, *outRL;//in and out Run Loaders
  AliLoader *pInFMD, *pOutFMD;// in and out ITSLoaders

  outRL = AliRunLoader::GetRunLoader(fManager->GetOutputFolderName());
  pOutFMD = outRL->GetLoader("FMDLoader");

#ifdef DEBUG
  Info("Hits2Digits Exec"," start...";
#endif

  Int_t volume, sector, ring, charge;
  Float_t e;
  Float_t de[10][50][520];
  Int_t hit;
  Int_t digit[5];
  Int_t ivol, iSector, iRing;
  for (Int_t i=0; i<10; i++)
    for(Int_t j=0; j<50; j++)
      for(Int_t ij=0; ij<520; ij++)
     de[i][j][ij]=0;
  Int_t numberOfRings[5]= {512,256,512,256,512};
  Int_t numberOfSector[5] =  {20,40,20,40,20};

  AliFMDhit *fmdHit=0;
  TTree *tH=0;
  TBranch *brHits=0;
  TBranch *brD=0;

  inRL = AliRunLoader::GetRunLoader(fManager->GetInputFolderName(0));

  if (inRL == 0x0)
    {
      Error("Exec","Can not find Run Loader for input stream 0");
      return;
    }

  if (!inRL->GetAliRun()) inRL->LoadgAlice();

  AliFMD * fFMD = (AliFMD *) inRL->GetAliRun()->GetDetector("FMD");

  if (fFMD == 0x0)
   {
     Error("Exec","Can not get FMD from gAlice");
     return;
   }
// Loop over files to digitize

  Int_t nFiles=GetManager()->GetNinputs();
  for (Int_t inputFile=0; inputFile<nFiles;inputFile++)
   {

#ifdef DEBUG
  Info(" Digitizing event number ",fManager->GetOutputEventNr()) ;
#endif

    if (fFMD)
     {

      inRL = AliRunLoader::GetRunLoader(fManager->GetInputFolderName(inputFile));
      pInFMD = inRL->GetLoader("FMDLoader");
      pInFMD->LoadHits("READ");

      tH = pInFMD->TreeH();
      if (tH == 0x0)
       {
         pInFMD->LoadHits("read");
         tH = pInFMD->TreeH();
       }
      brHits = tH->GetBranch("FMD");
      if (brHits) {
          fFMD->SetHitsAddressBranch(brHits);
      }else{
        Fatal("Exec","EXEC Branch FMD hit not found");
      }
      TClonesArray *fFMDhits = fFMD->Hits ();

      Int_t ntracks    = (Int_t) tH->GetEntries();

      for (Int_t track = 0; track < ntracks; track++)
       {
         brHits->GetEntry(track);
         Int_t nhits = fFMDhits->GetEntries ();

         for (hit = 0; hit < nhits; hit++)
           {
             fmdHit = (AliFMDhit *) fFMDhits->UncheckedAt(hit);

             volume = fmdHit->Volume ();
             sector = fmdHit->NumberOfSector ();
             ring = fmdHit->NumberOfRing ();
             e = fmdHit->Edep ();
             de[volume][sector][ring] += e;

           }          //hit loop
       }               //track loop
    }
//if FMD

  // Put noise and make ADC signal
   Float_t mipI = 1.664 * 0.04 * 2.33 / 22400;     // = 6.923e-6;
   for ( ivol=1; ivol<=5; ivol++){
     for ( iSector=1; iSector<=numberOfSector[ivol-1]; iSector++){
       for ( iRing=1; iRing<=numberOfRings[ivol-1]; iRing++){
         digit[0]=ivol;
         digit[1]=iSector;
         digit[2]=iRing;
         charge = Int_t (de[ivol][iSector][iRing] / mipI);
         Int_t pedestal=Int_t(gRandom->Gaus(500,250));
  //       digit[3]=PutNoise(charge);
         digit[3]=charge + pedestal;
         if(digit[3]<= 500) digit[3]=500;
    //dynamic range from MIP(0.155MeV) to 30MIP(4.65MeV)
    //1024 ADC channels
         Float_t channelWidth=(22400*50)/1024;
         digit[4]=Int_t(digit[3]/channelWidth);
         if (digit[4]>1024) digit[4]=1024;
         fFMD->AddDigit(digit);
       } //ivol
     } //iSector
   } //iRing

   TTree* treeD = pOutFMD->TreeD();

   if (treeD == 0x0) {
     pOutFMD->MakeTree("D");
     treeD = pOutFMD->TreeD();

   }

   treeD->Reset();
   fFMD->MakeBranchInTreeD(treeD);
   brD = treeD->GetBranch("FMD");

   treeD->Fill();  //this operator does not work for events >1

   pOutFMD->WriteDigits("OVERWRITE");
   pOutFMD->UnloadHits();
   inRL->GetAliRun() ->ResetDigits();
   }
}

<|endoftext|>