<commit_before>#define DeutSelector_cxx
// The class definition in DeutSelector.h has been generated automatically
// by the ROOT utility TTree::MakeSelector(). This class is derived
// from the ROOT class TSelector. For more information on the TSelector
// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.

// The following methods are defined in this file:
//    Begin():        called every time a loop on the tree starts,
//                    a convenient place to create your histograms.
//    SlaveBegin():   called after Begin(), when on PROOF called only on the
//                    slave servers.
//    Process():      called for each event, in this function you decide what
//                    to read and fill your histograms.
//    SlaveTerminate: called at the end of the loop on the tree, when on PROOF
//                    called only on the slave servers.
//    Terminate():    called at the end of the loop on the tree,
//                    a convenient place to draw/fit your histograms.
//
// To use this file, try the following session on your Tree T:
//
// Root > T->Process("DeutSelector.C")
// Root > T->Process("DeutSelector.C","some options")
// Root > T->Process("DeutSelector.C+")
//

#include "DeutSelector.h"
#include <TH2.h>
#include <TH2F.h>
#include <TH1D.h>
#include <TStyle.h>
#include <Riostream.h>
#include <TMath.h>
#include <TCanvas.h>
#include <TAxis.h>
#include <TF1.h>

#define EPSILON 1E-5

static void BinLogAxis(const TH1 *h)
{
  //
  // Method for the correct logarithmic binning of histograms
  //
  TAxis *axis = const_cast<TAxis*>(h->GetXaxis());
  const Int_t bins = axis->GetNbins();

  const Double_t from = axis->GetXmin();
  const Double_t to = axis->GetXmax();
  Double_t *newBins = new Double_t[bins + 1];

  newBins[0] = from;
  Double_t factor = pow(to / from, 1. / bins);

  for (Int_t i = 1; i <= bins; i++) {
    newBins[i] = factor * newBins[i - 1];
  }
  axis->Set(bins, newBins);
  delete [] newBins;
}

Double_t BetheBlochAleph(Double_t bg,
			 Double_t kp1,
			 Double_t kp2,
			 Double_t kp3,
			 Double_t kp4,
			 Double_t kp5) {
  Double_t beta = bg/TMath::Sqrt(1.+ bg*bg);
  Double_t aa = TMath::Power(beta,kp4);
  Double_t bb = TMath::Power(1./bg,kp5);
  bb=TMath::Log(kp3+bb);
  return (kp2-aa-bb)*kp1/aa;
}

Double_t DeuteronTPC(Double_t *x, Double_t *par) {
  // Deuteron expected signal in TPC, taken from AntiHe4 task
  return BetheBlochAleph(x[0]/1.875612,4.69637,7.51827,0.0183746,2.60,2.7);
}

void DeutSelector::Begin(TTree * /*tree*/)
{
  // The Begin() function is called at the start of the query.
  // When running with PROOF Begin() is only called on the client.
  // The tree argument is deprecated (on PROOF 0 is passed).
  TString option = GetOption();
}

void DeutSelector::SlaveBegin(TTree * /*tree*/)
{
  // The SlaveBegin() function is called after the Begin() function.
  // When running with PROOF SlaveBegin() is called on each slave server.
  // The tree argument is deprecated (on PROOF 0 is passed).

  TString option = GetOption();
  fBeta = new TH1D("fBeta",";#beta;Entries",100,0.f,1.f);
  fBeta2D = new TH2F("fBeta2D","TOF; #frac{p}{z} (GeV/c); #beta", 500,0.01,5.,2250,0.1,1.);
  fGamma = new TH1D("fGamma",";#gamma;Entries",1000,1.f,1000.f);
  fdEdxTPC = new TH2F("fdEdxTPC",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,500,0,2000);
  fdEdxTPCSignal = new TH2F("fdEdxTPCSignal",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,2000,0,2000);
  fdEdxTPCproj = new TH2F("fdEdxTPCproj",";p (GeV/c);dE/dx (a.u.)",93,0.4,3.2,2000,0,2000);
  BinLogAxis(fdEdxTPC);
  fSignal = new TH1D("fSignal",";",600,0.1,6.1);
  GetOutputList()->Add(fdEdxTPC);
  GetOutputList()->Add(fdEdxTPCSignal);
  GetOutputList()->Add(fdEdxTPCproj);
  GetOutputList()->Add(fSignal);
  GetOutputList()->Add(fBeta);
  GetOutputList()->Add(fBeta2D);
  GetOutputList()->Add(fGamma);

  fDeutBB = new TF1("fDeutBB",DeuteronTPC,0.3,6,0);

}

Bool_t DeutSelector::Process(Long64_t entry)
{
  // The Process() function is called for each entry in the tree (or possibly
  // keyed object in the case of PROOF) to be processed. The entry argument
  // specifies which entry in the currently loaded tree is to be processed.
  // It can be passed to either DeutSelector::GetEntry() or TBranch::GetEntry()
  // to read either all or the required parts of the data. When processing
  // keyed objects with PROOF, the object is already loaded and is available
  // via the fObject pointer.
  //
  // This function should contain the "body" of the analysis. It can contain
  // simple or elaborate selection criteria, run algorithms on the data
  // of the event and typically fill histograms.
  //
  // The processing can be stopped by calling Abort().
  //
  // Use fStatus to set the return value of TTree::Process().
  //
  // The return value is currently not used.

  GetEntry(entry);
  if (TMath::Abs(eta) > 0.8)
    return kTRUE;
  if (pTPC == p) {
    return kTRUE;
  }
  fdEdxTPC->Fill(pTPC,TPCsignal);
  fdEdxTPCproj->Fill(pTPC,TPCsignal);

  if (TPCsignal > 0.7f * fDeutBB->Eval(pTPC) && TPCsignal < 1.3f * fDeutBB->Eval(pTPC)) {
    fdEdxTPCSignal->Fill(pTPC,TPCsignal);

    if (TOFtime > 0.f && length > 0.f) {
      Float_t beta = length / (2.99792457999999984e-02 * TOFtime);
      fBeta->Fill(beta);
      fBeta2D->Fill(pTPC,beta);
      if (beta < (1.f - EPSILON)) {
        Float_t gamma = 1 / TMath::Sqrt(1 - (beta * beta));
        fGamma->Fill(gamma);
        fSignal->Fill(p / (beta * gamma));
      }
    }
  }
  return kTRUE;
}

void DeutSelector::SlaveTerminate()
{
  // The SlaveTerminate() function is called after all entries or objects
  // have been processed. When running with PROOF SlaveTerminate() is called
  // on each slave server.
  delete fDeutBB;
}

void DeutSelector::Terminate()
{
  // The Terminate() function is the last function to be called during
  // a query. It always runs on the client, it can be used to present
  // the results graphically or save the results to file.

  TFile f("final.root","recreate");
  TF1 fbb("BBAleph",DeuteronTPC,0.4f,5.f,0);
  TCanvas c;
  fdEdxTPC = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPC"));
  if (fdEdxTPC) {
    c.cd();
    fdEdxTPC->DrawClone();
    fbb.DrawClone("same");
    f.cd();
    c.Write();
    fdEdxTPC->Write();
  }

  fdEdxTPCSignal = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCSignal"));
  if (fdEdxTPCSignal) {
    fdEdxTPCSignal->Write();
  }

  fdEdxTPCproj = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCproj"));
  if (fdEdxTPCproj) {
    fdEdxTPCproj->Write();
  }

  fBeta = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fBeta"));
  if (fBeta) {
    fBeta->Write();
  }

  fGamma = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fGamma"));
  if (fGamma) {
    fGamma->Write();
  }

  fSignal = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fSignal"));
  if (fSignal) {
    fSignal->Write();
  }

  fBeta2D = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fBeta2D"));
  if (fBeta2D) {
    fBeta2D->Write();
  }
  f.Close();

}
<commit_msg>Test on mass spectra<commit_after>#define DeutSelector_cxx
// The class definition in DeutSelector.h has been generated automatically
// by the ROOT utility TTree::MakeSelector(). This class is derived
// from the ROOT class TSelector. For more information on the TSelector
// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.

// The following methods are defined in this file:
//    Begin():        called every time a loop on the tree starts,
//                    a convenient place to create your histograms.
//    SlaveBegin():   called after Begin(), when on PROOF called only on the
//                    slave servers.
//    Process():      called for each event, in this function you decide what
//                    to read and fill your histograms.
//    SlaveTerminate: called at the end of the loop on the tree, when on PROOF
//                    called only on the slave servers.
//    Terminate():    called at the end of the loop on the tree,
//                    a convenient place to draw/fit your histograms.
//
// To use this file, try the following session on your Tree T:
//
// Root > T->Process("DeutSelector.C")
// Root > T->Process("DeutSelector.C","some options")
// Root > T->Process("DeutSelector.C+")
//

#include "DeutSelector.h"
#include <TH2.h>
#include <TH2F.h>
#include <TH1D.h>
#include <TStyle.h>
#include <Riostream.h>
#include <TMath.h>
#include <TCanvas.h>
#include <TAxis.h>
#include <TF1.h>

#define EPSILON 1E-5

static void BinLogAxis(const TH1 *h)
{
  //
  // Method for the correct logarithmic binning of histograms
  //
  TAxis *axis = const_cast<TAxis*>(h->GetXaxis());
  const Int_t bins = axis->GetNbins();

  const Double_t from = axis->GetXmin();
  const Double_t to = axis->GetXmax();
  Double_t *newBins = new Double_t[bins + 1];

  newBins[0] = from;
  Double_t factor = pow(to / from, 1. / bins);

  for (Int_t i = 1; i <= bins; i++) {
    newBins[i] = factor * newBins[i - 1];
  }
  axis->Set(bins, newBins);
  delete [] newBins;
}

Double_t BetheBlochAleph(Double_t bg,
			 Double_t kp1,
			 Double_t kp2,
			 Double_t kp3,
			 Double_t kp4,
			 Double_t kp5) {
  Double_t beta = bg/TMath::Sqrt(1.+ bg*bg);
  Double_t aa = TMath::Power(beta,kp4);
  Double_t bb = TMath::Power(1./bg,kp5);
  bb=TMath::Log(kp3+bb);
  return (kp2-aa-bb)*kp1/aa;
}

Double_t DeuteronTPC(Double_t *x, Double_t *par) {
  // Deuteron expected signal in TPC, taken from AntiHe4 task
  return BetheBlochAleph(x[0]/1.875612,4.69637,7.51827,0.0183746,2.60,2.7);
}

void DeutSelector::Begin(TTree * /*tree*/)
{
  // The Begin() function is called at the start of the query.
  // When running with PROOF Begin() is only called on the client.
  // The tree argument is deprecated (on PROOF 0 is passed).
  TString option = GetOption();
}

void DeutSelector::SlaveBegin(TTree * /*tree*/)
{
  // The SlaveBegin() function is called after the Begin() function.
  // When running with PROOF SlaveBegin() is called on each slave server.
  // The tree argument is deprecated (on PROOF 0 is passed).

  TString option = GetOption();
  fBeta = new TH1D("fBeta",";#beta;Entries",100,0.f,1.f);
  fBeta2D = new TH2F("fBeta2D","TOF; #frac{p}{z} (GeV/c); #beta", 500,0.01,5.,2250,0.1,1.);
  fGamma = new TH1D("fGamma",";#gamma;Entries",1000,1.f,1000.f);
  fdEdxTPC = new TH2F("fdEdxTPC",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,500,0,2000);
  fdEdxTPCSignal = new TH2F("fdEdxTPCSignal",";p (GeV/c);dE/dx (a.u.)",500,0.1,5.,2000,0,2000);
  fdEdxTPCproj = new TH2F("fdEdxTPCproj",";p (GeV/c);dE/dx (a.u.)",93,0.4,3.2,2000,0,2000);
  BinLogAxis(fdEdxTPC);
  fSignal = new TH1D("fSignal",";",600,0.1,6.1);
  GetOutputList()->Add(fdEdxTPC);
  GetOutputList()->Add(fdEdxTPCSignal);
  GetOutputList()->Add(fdEdxTPCproj);
  GetOutputList()->Add(fSignal);
  GetOutputList()->Add(fBeta);
  GetOutputList()->Add(fBeta2D);
  GetOutputList()->Add(fGamma);

  fDeutBB = new TF1("fDeutBB",DeuteronTPC,0.3,6,0);

}

Bool_t DeutSelector::Process(Long64_t entry)
{
  // The Process() function is called for each entry in the tree (or possibly
  // keyed object in the case of PROOF) to be processed. The entry argument
  // specifies which entry in the currently loaded tree is to be processed.
  // It can be passed to either DeutSelector::GetEntry() or TBranch::GetEntry()
  // to read either all or the required parts of the data. When processing
  // keyed objects with PROOF, the object is already loaded and is available
  // via the fObject pointer.
  //
  // This function should contain the "body" of the analysis. It can contain
  // simple or elaborate selection criteria, run algorithms on the data
  // of the event and typically fill histograms.
  //
  // The processing can be stopped by calling Abort().
  //
  // Use fStatus to set the return value of TTree::Process().
  //
  // The return value is currently not used.

  GetEntry(entry);
  if (TMath::Abs(eta) > 0.8)
    return kTRUE;
  if (pTPC == p) {
    return kTRUE;
  }
  fdEdxTPC->Fill(pTPC,TPCsignal);
  fdEdxTPCproj->Fill(pTPC,TPCsignal);

  if (TPCsignal > 0.7f * fDeutBB->Eval(pTPC) && TPCsignal < 1.3f * fDeutBB->Eval(pTPC)) {
    fdEdxTPCSignal->Fill(pTPC,TPCsignal);
    if (pTPC > 1.f) return kTRUE;
    if (TOFtime > 0.f && length > 0.f) {
      Float_t beta = length / (2.99792457999999984e-02 * TOFtime);
      fBeta->Fill(beta);
      fBeta2D->Fill(pTPC,beta);
      if (beta < (1.f - EPSILON)) {
        Float_t gamma = 1 / TMath::Sqrt(1 - (beta * beta));
        fGamma->Fill(gamma);
        fSignal->Fill(p / (beta * gamma));
      }
    }
  }
  return kTRUE;
}

void DeutSelector::SlaveTerminate()
{
  // The SlaveTerminate() function is called after all entries or objects
  // have been processed. When running with PROOF SlaveTerminate() is called
  // on each slave server.
  delete fDeutBB;
}

void DeutSelector::Terminate()
{
  // The Terminate() function is the last function to be called during
  // a query. It always runs on the client, it can be used to present
  // the results graphically or save the results to file.

  TFile f("final.root","recreate");
  TF1 fbb("BBAleph",DeuteronTPC,0.4f,5.f,0);
  TCanvas c;
  fdEdxTPC = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPC"));
  if (fdEdxTPC) {
    c.cd();
    fdEdxTPC->DrawClone();
    fbb.DrawClone("same");
    f.cd();
    c.Write();
    fdEdxTPC->Write();
  }

  fdEdxTPCSignal = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCSignal"));
  if (fdEdxTPCSignal) {
    fdEdxTPCSignal->Write();
  }

  fdEdxTPCproj = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fdEdxTPCproj"));
  if (fdEdxTPCproj) {
    fdEdxTPCproj->Write();
  }

  fBeta = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fBeta"));
  if (fBeta) {
    fBeta->Write();
  }

  fGamma = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fGamma"));
  if (fGamma) {
    fGamma->Write();
  }

  fSignal = dynamic_cast<TH1D*>(GetOutputList()->FindObject("fSignal"));
  if (fSignal) {
    fSignal->Write();
  }

  fBeta2D = dynamic_cast<TH2F*>(GetOutputList()->FindObject("fBeta2D"));
  if (fBeta2D) {
    fBeta2D->Write();
  }
  f.Close();

}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#pragma once

#include <cstdint>
#include <future>
#include <mutex>
#include <queue>
#include <unordered_map>
#include <vector>
#include "input/GamepadDevice.hpp"
#include "input/KeyboardDevice.hpp"
#include "input/MouseDevice.hpp"
#include "input/SystemCursor.hpp"
#include "input/TouchpadDevice.hpp"
#include "graphics/PixelFormat.hpp"
#include "math/Size2.hpp"
#include "math/Vector2.hpp"

namespace ouzel
{
    namespace input
    {
        class NativeCursor;

        class InputSystem
        {
            friend InputDevice;
            friend GamepadDevice;
            friend KeyboardDevice;
            friend MouseDevice;
            friend TouchpadDevice;
        public:
            struct Resource final
            {
                void* data;
            };

            struct Command final
            {
                enum class Type
                {
                    START_DEVICE_DISCOVERY,
                    STOP_DEVICE_DISCOVERY,
                    SET_ABSOLUTE_DPAD_VALUES,
                    SET_PLAYER_INDEX,
                    SET_VIBRATION,
                    SET_POSITION,
                    CREATE_CURSOR,
                    DESTROY_CURSOR,
                    INIT_CURSOR,
                    SET_CURSOR,
                    SET_CURSOR_VISIBLE,
                    SET_CURSOR_LOCKED,
                    SHOW_VIRTUAL_KEYBOARD,
                    HIDE_VIRTUAL_KEYBOARD
                };

                Type type;
                uint32_t deviceId = 0;

                union
                {
                    bool absoluteDPadValues;
                    int32_t playerIndex;
                    float speed;
                    bool visible;
                    bool locked;
                };

                Gamepad::Motor motor;
                Vector2 position;
                std::shared_ptr<Resource> cursor;
                SystemCursor systemCursor;
                std::vector<uint8_t> data;
                Size2 size;
                graphics::PixelFormat pixelFormat;
                Vector2 hotSpot;
            };

            struct Event final
            {
                enum class Type
                {
                    DEVICE_CONNECT,
                    DEVICE_DISCONNECT,
                    DEVICE_DISCOVERY_COMPLETE,

                    GAMEPAD_BUTTON_CHANGE,

                    KEY_PRESS,
                    KEY_RELEASE,

                    MOUSE_PRESS,
                    MOUSE_RELEASE,
                    MOUSE_SCROLL,
                    MOUSE_MOVE,
                    MOUSE_RELATIVE_MOVE,
                    MOUSE_LOCK_CHANGED,

                    TOUCH_BEGIN,
                    TOUCH_MOVE,
                    TOUCH_END,
                    TOUCH_CANCEL
                };

                Type type;
                Controller::Type deviceType;
                uint32_t deviceId = 0;
                union
                {
                    Keyboard::Key keyboardKey;
                    Mouse::Button mouseButton;
                    Gamepad::Button gamepadButton;
                    uint64_t touchId;
                };
                bool locked = false;
                bool pressed = false;
                bool previousPressed = false;
                float value = 0.0F; // force for touch events
                float previousValue = 0.0F;
                Vector2 difference;
                Vector2 position;
                Vector2 scroll;
                float force = 1.0F;
            };

            class EventHandler
            {
            public:
                virtual ~EventHandler() {}
                virtual bool handleEvent(const Event& event) = 0;
            };

            explicit InputSystem(EventHandler& initEventHandler);
            virtual ~InputSystem() {}

            void addCommand(const Command& command);
            virtual void executeCommand(const Command&) {}

            void dispatchEvents();

        protected:
            std::future<bool> postEvent(const Event& event);
            void addInputDevice(InputDevice& inputDevice);
            void removeInputDevice(const InputDevice& inputDevice);
            InputDevice* getInputDevice(uint32_t id);

            std::unordered_map<uint32_t, InputDevice*> inputDevices;

        private:
            EventHandler& eventHandler;
            std::mutex eventQueueMutex;
            std::queue<std::pair<std::promise<bool>, Event>> eventQueue;
        };
    } // namespace input
} // namespace ouzel
<commit_msg>Make inputDevices private<commit_after>// Copyright 2015-2018 Elviss Strazdins. All rights reserved.

#pragma once

#include <cstdint>
#include <future>
#include <mutex>
#include <queue>
#include <unordered_map>
#include <vector>
#include "input/GamepadDevice.hpp"
#include "input/KeyboardDevice.hpp"
#include "input/MouseDevice.hpp"
#include "input/SystemCursor.hpp"
#include "input/TouchpadDevice.hpp"
#include "graphics/PixelFormat.hpp"
#include "math/Size2.hpp"
#include "math/Vector2.hpp"

namespace ouzel
{
    namespace input
    {
        class NativeCursor;

        class InputSystem
        {
            friend InputDevice;
            friend GamepadDevice;
            friend KeyboardDevice;
            friend MouseDevice;
            friend TouchpadDevice;
        public:
            struct Resource final
            {
                void* data;
            };

            struct Command final
            {
                enum class Type
                {
                    START_DEVICE_DISCOVERY,
                    STOP_DEVICE_DISCOVERY,
                    SET_ABSOLUTE_DPAD_VALUES,
                    SET_PLAYER_INDEX,
                    SET_VIBRATION,
                    SET_POSITION,
                    CREATE_CURSOR,
                    DESTROY_CURSOR,
                    INIT_CURSOR,
                    SET_CURSOR,
                    SET_CURSOR_VISIBLE,
                    SET_CURSOR_LOCKED,
                    SHOW_VIRTUAL_KEYBOARD,
                    HIDE_VIRTUAL_KEYBOARD
                };

                Type type;
                uint32_t deviceId = 0;

                union
                {
                    bool absoluteDPadValues;
                    int32_t playerIndex;
                    float speed;
                    bool visible;
                    bool locked;
                };

                Gamepad::Motor motor;
                Vector2 position;
                std::shared_ptr<Resource> cursor;
                SystemCursor systemCursor;
                std::vector<uint8_t> data;
                Size2 size;
                graphics::PixelFormat pixelFormat;
                Vector2 hotSpot;
            };

            struct Event final
            {
                enum class Type
                {
                    DEVICE_CONNECT,
                    DEVICE_DISCONNECT,
                    DEVICE_DISCOVERY_COMPLETE,

                    GAMEPAD_BUTTON_CHANGE,

                    KEY_PRESS,
                    KEY_RELEASE,

                    MOUSE_PRESS,
                    MOUSE_RELEASE,
                    MOUSE_SCROLL,
                    MOUSE_MOVE,
                    MOUSE_RELATIVE_MOVE,
                    MOUSE_LOCK_CHANGED,

                    TOUCH_BEGIN,
                    TOUCH_MOVE,
                    TOUCH_END,
                    TOUCH_CANCEL
                };

                Type type;
                Controller::Type deviceType;
                uint32_t deviceId = 0;
                union
                {
                    Keyboard::Key keyboardKey;
                    Mouse::Button mouseButton;
                    Gamepad::Button gamepadButton;
                    uint64_t touchId;
                };
                bool locked = false;
                bool pressed = false;
                bool previousPressed = false;
                float value = 0.0F; // force for touch events
                float previousValue = 0.0F;
                Vector2 difference;
                Vector2 position;
                Vector2 scroll;
                float force = 1.0F;
            };

            class EventHandler
            {
            public:
                virtual ~EventHandler() {}
                virtual bool handleEvent(const Event& event) = 0;
            };

            explicit InputSystem(EventHandler& initEventHandler);
            virtual ~InputSystem() {}

            void addCommand(const Command& command);
            virtual void executeCommand(const Command&) {}

            void dispatchEvents();

        protected:
            std::future<bool> postEvent(const Event& event);
            void addInputDevice(InputDevice& inputDevice);
            void removeInputDevice(const InputDevice& inputDevice);
            InputDevice* getInputDevice(uint32_t id);

        private:
            EventHandler& eventHandler;
            std::mutex eventQueueMutex;
            std::queue<std::pair<std::promise<bool>, Event>> eventQueue;
            std::unordered_map<uint32_t, InputDevice*> inputDevices;
        };
    } // namespace input
} // namespace ouzel
<|endoftext|>


<commit_before>//===- Writer.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Writer.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/FileOutputBuffer.h"

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf2;

static const int PageSize = 4096;

namespace {
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
// Chunks cannot belong to more than one OutputSections. The writer
// creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
template <class ELFT> class OutputSection {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;

  OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
      : Name(Name) {
    memset(&Header, 0, sizeof(Elf_Shdr));
    Header.sh_type = sh_type;
    Header.sh_flags = sh_flags;
  }
  void setVA(uintX_t VA) { Header.sh_addr = VA; }
  void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
  void addChunk(Chunk *C);
  std::vector<Chunk *> &getChunks() { return Chunks; }
  void writeHeaderTo(Elf_Shdr *SHdr);
  StringRef getName() { return Name; }
  void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }

  // Returns the size of the section in the output file.
  uintX_t getSize() { return Header.sh_size; }
  uintX_t getFlags() { return Header.sh_flags; }
  uintX_t getOffset() { return Header.sh_offset; }

private:
  StringRef Name;
  Elf_Shdr Header;
  std::vector<Chunk *> Chunks;
};

// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
  Writer(SymbolTable *T) : Symtab(T) {}
  void run();

private:
  void createSections();
  void assignAddresses();
  void openFile(StringRef OutputPath);
  void writeHeader();
  void writeSections();

  SymbolTable *Symtab;
  std::unique_ptr<llvm::FileOutputBuffer> Buffer;
  llvm::SpecificBumpPtrAllocator<OutputSection<ELFT>> CAlloc;
  std::vector<OutputSection<ELFT> *> OutputSections;

  uintX_t FileSize;
  uintX_t SizeOfHeaders;
  uintX_t SectionHeaderOff;
  uintX_t StringTableOff;
  unsigned StringTableIndex;
  StringTableBuilder StrTabBuilder;
  unsigned NumSections;

  std::vector<std::unique_ptr<Chunk>> Chunks;
};
} // anonymous namespace

namespace lld {
namespace elf2 {

template <class ELFT>
void writeResult(SymbolTable *Symtab) { Writer<ELFT>(Symtab).run(); }

template void writeResult<ELF32LE>(SymbolTable *);
template void writeResult<ELF32BE>(SymbolTable *);
template void writeResult<ELF64LE>(SymbolTable *);
template void writeResult<ELF64BE>(SymbolTable *);

} // namespace elf2
} // namespace lld

// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
  createSections();
  assignAddresses();
  openFile(Config->OutputFile);
  writeHeader();
  writeSections();
  error(Buffer->commit());
}

template <class ELFT> void OutputSection<ELFT>::addChunk(Chunk *C) {
  Chunks.push_back(C);
  uintX_t Off = Header.sh_size;
  Off = RoundUpToAlignment(Off, C->getAlign());
  C->setOutputSectionOff(Off);
  Off += C->getSize();
  Header.sh_size = Off;
}

template <class ELFT> void OutputSection<ELFT>::writeHeaderTo(Elf_Shdr *SHdr) {
  *SHdr = Header;
}

namespace {
template <bool Is64Bits> struct SectionKey {
  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
  StringRef Name;
  uint32_t sh_type;
  uintX_t sh_flags;
};
}
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
  static SectionKey<Is64Bits> getEmptyKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
  }
  static SectionKey<Is64Bits> getTombstoneKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
                                0};
  }
  static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
    return hash_combine(Val.Name, Val.sh_type, Val.sh_flags);
  }
  static bool isEqual(const SectionKey<Is64Bits> &LHS,
                      const SectionKey<Is64Bits> &RHS) {
    return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
           LHS.sh_type == RHS.sh_type && LHS.sh_flags == RHS.sh_flags;
  }
};
}

// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::createSections() {
  SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
  for (std::unique_ptr<ObjectFileBase> &FileB : Symtab->ObjectFiles) {
    auto &File = cast<ObjectFile<ELFT>>(*FileB);
    for (SectionChunk<ELFT> *C : File.getChunks()) {
      const Elf_Shdr *H = C->getSectionHdr();
      SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type,
                                     H->sh_flags};
      OutputSection<ELFT> *&Sec = Map[Key];
      if (!Sec) {
        Sec = new (CAlloc.Allocate())
            OutputSection<ELFT>(Key.Name, Key.sh_type, Key.sh_flags);
        OutputSections.push_back(Sec);
      }
      Sec->addChunk(C);
    }
  }
}

template <class ELFT>
static bool compSec(OutputSection<ELFT> *A, OutputSection<ELFT> *B) {
  // Place SHF_ALLOC sections first.
  return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
}

// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
  SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
  uintX_t VA = 0x1000; // The first page is kept unmapped.
  uintX_t FileOff = SizeOfHeaders;

  std::stable_sort(OutputSections.begin(), OutputSections.end(), compSec<ELFT>);

  for (OutputSection<ELFT> *Sec : OutputSections) {
    if (Sec->getFlags() & SHF_ALLOC) {
      Sec->setVA(VA);
      VA += RoundUpToAlignment(Sec->getSize(), PageSize);
    }
    Sec->setFileOffset(FileOff);
    FileOff += RoundUpToAlignment(Sec->getSize(), 8);
    StrTabBuilder.add(Sec->getName());
  }

  // Regular sections.
  NumSections = OutputSections.size();

  // First dummy section.
  NumSections++;

  // String table.
  StrTabBuilder.add(".strtab");
  StringTableIndex = NumSections;
  StringTableOff = FileOff;
  StrTabBuilder.finalize(StringTableBuilder::ELF);
  FileOff += StrTabBuilder.data().size();
  NumSections++;

  FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);

  // Add space for section headers.
  SectionHeaderOff = FileOff;
  FileOff += NumSections * sizeof(Elf_Shdr_Impl<ELFT>);
  FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
}

template <class ELFT> void Writer<ELFT>::writeHeader() {
  uint8_t *Buf = Buffer->getBufferStart();
  auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
  EHdr->e_ident[EI_MAG0] = 0x7F;
  EHdr->e_ident[EI_MAG1] = 0x45;
  EHdr->e_ident[EI_MAG2] = 0x4C;
  EHdr->e_ident[EI_MAG3] = 0x46;
  EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
  EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
                               ? ELFDATA2LSB
                               : ELFDATA2MSB;
  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
  EHdr->e_ident[EI_OSABI] = ELFOSABI_NONE;

  EHdr->e_type = ET_EXEC;
  auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab->ObjectFiles[0]);
  EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
  EHdr->e_version = EV_CURRENT;
  EHdr->e_entry = 0x401000;
  EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_shoff = SectionHeaderOff;
  EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
  EHdr->e_phnum = 1;
  EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
  EHdr->e_shnum = NumSections;
  EHdr->e_shstrndx = StringTableIndex;

  auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
  PHdrs->p_type = PT_LOAD;
  PHdrs->p_flags = PF_R | PF_X;
  PHdrs->p_offset = 0x0000;
  PHdrs->p_vaddr = 0x400000;
  PHdrs->p_paddr = PHdrs->p_vaddr;
  PHdrs->p_filesz = FileSize;
  PHdrs->p_memsz = FileSize;
  PHdrs->p_align = 0x4000;

  auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
  // First entry is null.
  ++SHdrs;
  for (OutputSection<ELFT> *Sec : OutputSections) {
    Sec->setNameOffset(StrTabBuilder.getOffset(Sec->getName()));
    Sec->writeHeaderTo(SHdrs++);
  }

  // String table.
  SHdrs->sh_name = StrTabBuilder.getOffset(".strtab");
  SHdrs->sh_type = SHT_STRTAB;
  SHdrs->sh_flags = 0;
  SHdrs->sh_addr = 0;
  SHdrs->sh_offset = StringTableOff;
  SHdrs->sh_size = StrTabBuilder.data().size();
  SHdrs->sh_link = 0;
  SHdrs->sh_info = 0;
  SHdrs->sh_addralign = 1;
  SHdrs->sh_entsize = 0;
}

template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
  error(BufferOrErr, Twine("failed to open ") + Path);
  Buffer = std::move(*BufferOrErr);
}

// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
  uint8_t *Buf = Buffer->getBufferStart();
  for (OutputSection<ELFT> *Sec : OutputSections) {
    uint8_t *SecBuf = Buf + Sec->getOffset();
    for (Chunk *C : Sec->getChunks())
      C->writeTo(SecBuf);
  }

  // String table.
  StringRef Data = StrTabBuilder.data();
  memcpy(Buf + StringTableOff, Data.data(), Data.size());
}
<commit_msg>Template OutputSection only over Is64Bit.<commit_after>//===- Writer.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Chunks.h"
#include "Config.h"
#include "Error.h"
#include "SymbolTable.h"
#include "Writer.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/FileOutputBuffer.h"

using namespace llvm;
using namespace llvm::ELF;
using namespace llvm::object;

using namespace lld;
using namespace lld::elf2;

static const int PageSize = 4096;

namespace {
// OutputSection represents a section in an output file. It's a
// container of chunks. OutputSection and Chunk are 1:N relationship.
// Chunks cannot belong to more than one OutputSections. The writer
// creates multiple OutputSections and assign them unique,
// non-overlapping file offsets and VAs.
template <bool Is64Bits> class OutputSection {
public:
  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
  typedef
      typename std::conditional<Is64Bits, Elf64_Shdr, Elf32_Shdr>::type HeaderT;

  OutputSection(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
      : Name(Name) {
    memset(&Header, 0, sizeof(HeaderT));
    Header.sh_type = sh_type;
    Header.sh_flags = sh_flags;
  }
  void setVA(uintX_t VA) { Header.sh_addr = VA; }
  void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
  void addChunk(Chunk *C);
  std::vector<Chunk *> &getChunks() { return Chunks; }
  template <endianness E>
  void writeHeaderTo(typename ELFFile<ELFType<E, Is64Bits>>::Elf_Shdr *SHdr);
  StringRef getName() { return Name; }
  void setNameOffset(uintX_t Offset) { Header.sh_name = Offset; }

  // Returns the size of the section in the output file.
  uintX_t getSize() { return Header.sh_size; }
  uintX_t getFlags() { return Header.sh_flags; }
  uintX_t getOffset() { return Header.sh_offset; }

private:
  StringRef Name;
  HeaderT Header;
  std::vector<Chunk *> Chunks;
};

// The writer writes a SymbolTable result to a file.
template <class ELFT> class Writer {
public:
  typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
  typedef typename llvm::object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
  Writer(SymbolTable *T) : Symtab(T) {}
  void run();

private:
  void createSections();
  void assignAddresses();
  void openFile(StringRef OutputPath);
  void writeHeader();
  void writeSections();

  SymbolTable *Symtab;
  std::unique_ptr<llvm::FileOutputBuffer> Buffer;
  llvm::SpecificBumpPtrAllocator<OutputSection<ELFT::Is64Bits>> CAlloc;
  std::vector<OutputSection<ELFT::Is64Bits> *> OutputSections;

  uintX_t FileSize;
  uintX_t SizeOfHeaders;
  uintX_t SectionHeaderOff;
  uintX_t StringTableOff;
  unsigned StringTableIndex;
  StringTableBuilder StrTabBuilder;
  unsigned NumSections;

  std::vector<std::unique_ptr<Chunk>> Chunks;
};
} // anonymous namespace

namespace lld {
namespace elf2 {

template <class ELFT>
void writeResult(SymbolTable *Symtab) { Writer<ELFT>(Symtab).run(); }

template void writeResult<ELF32LE>(SymbolTable *);
template void writeResult<ELF32BE>(SymbolTable *);
template void writeResult<ELF64LE>(SymbolTable *);
template void writeResult<ELF64BE>(SymbolTable *);

} // namespace elf2
} // namespace lld

// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
  createSections();
  assignAddresses();
  openFile(Config->OutputFile);
  writeHeader();
  writeSections();
  error(Buffer->commit());
}

template <bool Is64Bits> void OutputSection<Is64Bits>::addChunk(Chunk *C) {
  Chunks.push_back(C);
  uintX_t Off = Header.sh_size;
  Off = RoundUpToAlignment(Off, C->getAlign());
  C->setOutputSectionOff(Off);
  Off += C->getSize();
  Header.sh_size = Off;
}

template <bool Is64Bits>
template <endianness E>
void OutputSection<Is64Bits>::writeHeaderTo(
    typename ELFFile<ELFType<E, Is64Bits>>::Elf_Shdr *SHdr) {
  SHdr->sh_name = Header.sh_name;
  SHdr->sh_type = Header.sh_type;
  SHdr->sh_flags = Header.sh_flags;
  SHdr->sh_addr = Header.sh_addr;
  SHdr->sh_offset = Header.sh_offset;
  SHdr->sh_size = Header.sh_size;
  SHdr->sh_link = Header.sh_link;
  SHdr->sh_info = Header.sh_info;
  SHdr->sh_addralign = Header.sh_addralign;
  SHdr->sh_entsize = Header.sh_entsize;
}

namespace {
template <bool Is64Bits> struct SectionKey {
  typedef typename std::conditional<Is64Bits, uint64_t, uint32_t>::type uintX_t;
  StringRef Name;
  uint32_t sh_type;
  uintX_t sh_flags;
};
}
namespace llvm {
template <bool Is64Bits> struct DenseMapInfo<SectionKey<Is64Bits>> {
  static SectionKey<Is64Bits> getEmptyKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getEmptyKey(), 0, 0};
  }
  static SectionKey<Is64Bits> getTombstoneKey() {
    return SectionKey<Is64Bits>{DenseMapInfo<StringRef>::getTombstoneKey(), 0,
                                0};
  }
  static unsigned getHashValue(const SectionKey<Is64Bits> &Val) {
    return hash_combine(Val.Name, Val.sh_type, Val.sh_flags);
  }
  static bool isEqual(const SectionKey<Is64Bits> &LHS,
                      const SectionKey<Is64Bits> &RHS) {
    return DenseMapInfo<StringRef>::isEqual(LHS.Name, RHS.Name) &&
           LHS.sh_type == RHS.sh_type && LHS.sh_flags == RHS.sh_flags;
  }
};
}

// Create output section objects and add them to OutputSections.
template <class ELFT> void Writer<ELFT>::createSections() {
  SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT::Is64Bits> *>
      Map;
  for (std::unique_ptr<ObjectFileBase> &FileB : Symtab->ObjectFiles) {
    auto &File = cast<ObjectFile<ELFT>>(*FileB);
    for (SectionChunk<ELFT> *C : File.getChunks()) {
      const Elf_Shdr *H = C->getSectionHdr();
      SectionKey<ELFT::Is64Bits> Key{C->getSectionName(), H->sh_type,
                                     H->sh_flags};
      OutputSection<ELFT::Is64Bits> *&Sec = Map[Key];
      if (!Sec) {
        Sec = new (CAlloc.Allocate())
            OutputSection<ELFT::Is64Bits>(Key.Name, Key.sh_type, Key.sh_flags);
        OutputSections.push_back(Sec);
      }
      Sec->addChunk(C);
    }
  }
}

template <bool Is64Bits>
static bool compSec(OutputSection<Is64Bits> *A, OutputSection<Is64Bits> *B) {
  // Place SHF_ALLOC sections first.
  return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
}

// Visits all sections to assign incremental, non-overlapping RVAs and
// file offsets.
template <class ELFT> void Writer<ELFT>::assignAddresses() {
  SizeOfHeaders = RoundUpToAlignment(sizeof(Elf_Ehdr_Impl<ELFT>), PageSize);
  uintX_t VA = 0x1000; // The first page is kept unmapped.
  uintX_t FileOff = SizeOfHeaders;

  std::stable_sort(OutputSections.begin(), OutputSections.end(),
                   compSec<ELFT::Is64Bits>);

  for (OutputSection<ELFT::Is64Bits> *Sec : OutputSections) {
    if (Sec->getFlags() & SHF_ALLOC) {
      Sec->setVA(VA);
      VA += RoundUpToAlignment(Sec->getSize(), PageSize);
    }
    Sec->setFileOffset(FileOff);
    FileOff += RoundUpToAlignment(Sec->getSize(), 8);
    StrTabBuilder.add(Sec->getName());
  }

  // Regular sections.
  NumSections = OutputSections.size();

  // First dummy section.
  NumSections++;

  // String table.
  StrTabBuilder.add(".strtab");
  StringTableIndex = NumSections;
  StringTableOff = FileOff;
  StrTabBuilder.finalize(StringTableBuilder::ELF);
  FileOff += StrTabBuilder.data().size();
  NumSections++;

  FileOff += OffsetToAlignment(FileOff, ELFT::Is64Bits ? 8 : 4);

  // Add space for section headers.
  SectionHeaderOff = FileOff;
  FileOff += NumSections * sizeof(Elf_Shdr_Impl<ELFT>);
  FileSize = SizeOfHeaders + RoundUpToAlignment(FileOff - SizeOfHeaders, 8);
}

template <class ELFT> void Writer<ELFT>::writeHeader() {
  uint8_t *Buf = Buffer->getBufferStart();
  auto *EHdr = reinterpret_cast<Elf_Ehdr_Impl<ELFT> *>(Buf);
  EHdr->e_ident[EI_MAG0] = 0x7F;
  EHdr->e_ident[EI_MAG1] = 0x45;
  EHdr->e_ident[EI_MAG2] = 0x4C;
  EHdr->e_ident[EI_MAG3] = 0x46;
  EHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
  EHdr->e_ident[EI_DATA] = ELFT::TargetEndianness == llvm::support::little
                               ? ELFDATA2LSB
                               : ELFDATA2MSB;
  EHdr->e_ident[EI_VERSION] = EV_CURRENT;
  EHdr->e_ident[EI_OSABI] = ELFOSABI_NONE;

  EHdr->e_type = ET_EXEC;
  auto &FirstObj = cast<ObjectFile<ELFT>>(*Symtab->ObjectFiles[0]);
  EHdr->e_machine = FirstObj.getObj()->getHeader()->e_machine;
  EHdr->e_version = EV_CURRENT;
  EHdr->e_entry = 0x401000;
  EHdr->e_phoff = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_shoff = SectionHeaderOff;
  EHdr->e_ehsize = sizeof(Elf_Ehdr_Impl<ELFT>);
  EHdr->e_phentsize = sizeof(Elf_Phdr_Impl<ELFT>);
  EHdr->e_phnum = 1;
  EHdr->e_shentsize = sizeof(Elf_Shdr_Impl<ELFT>);
  EHdr->e_shnum = NumSections;
  EHdr->e_shstrndx = StringTableIndex;

  auto PHdrs = reinterpret_cast<Elf_Phdr_Impl<ELFT> *>(Buf + EHdr->e_phoff);
  PHdrs->p_type = PT_LOAD;
  PHdrs->p_flags = PF_R | PF_X;
  PHdrs->p_offset = 0x0000;
  PHdrs->p_vaddr = 0x400000;
  PHdrs->p_paddr = PHdrs->p_vaddr;
  PHdrs->p_filesz = FileSize;
  PHdrs->p_memsz = FileSize;
  PHdrs->p_align = 0x4000;

  auto SHdrs = reinterpret_cast<Elf_Shdr_Impl<ELFT> *>(Buf + EHdr->e_shoff);
  // First entry is null.
  ++SHdrs;
  for (OutputSection<ELFT::Is64Bits> *Sec : OutputSections) {
    Sec->setNameOffset(StrTabBuilder.getOffset(Sec->getName()));
    Sec->template writeHeaderTo<ELFT::TargetEndianness>(SHdrs++);
  }

  // String table.
  SHdrs->sh_name = StrTabBuilder.getOffset(".strtab");
  SHdrs->sh_type = SHT_STRTAB;
  SHdrs->sh_flags = 0;
  SHdrs->sh_addr = 0;
  SHdrs->sh_offset = StringTableOff;
  SHdrs->sh_size = StrTabBuilder.data().size();
  SHdrs->sh_link = 0;
  SHdrs->sh_info = 0;
  SHdrs->sh_addralign = 1;
  SHdrs->sh_entsize = 0;
}

template <class ELFT> void Writer<ELFT>::openFile(StringRef Path) {
  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
      FileOutputBuffer::create(Path, FileSize, FileOutputBuffer::F_executable);
  error(BufferOrErr, Twine("failed to open ") + Path);
  Buffer = std::move(*BufferOrErr);
}

// Write section contents to a mmap'ed file.
template <class ELFT> void Writer<ELFT>::writeSections() {
  uint8_t *Buf = Buffer->getBufferStart();
  for (OutputSection<ELFT::Is64Bits> *Sec : OutputSections) {
    uint8_t *SecBuf = Buf + Sec->getOffset();
    for (Chunk *C : Sec->getChunks())
      C->writeTo(SecBuf);
  }

  // String table.
  StringRef Data = StrTabBuilder.data();
  memcpy(Buf + StringTableOff, Data.data(), Data.size());
}
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gmock/gmock.h>

#include <stout/gtest.hpp>
#include <stout/json.hpp>
#include <stout/os.hpp>
#include <stout/path.hpp>
#include <stout/stringify.hpp>

#include <process/future.hpp>
#include <process/gmock.hpp>
#include <process/owned.hpp>

#include <mesos/docker/spec.hpp>

#include "slave/containerizer/mesos/provisioner/docker/metadata_manager.hpp"
#include "slave/containerizer/mesos/provisioner/docker/paths.hpp"
#include "slave/containerizer/mesos/provisioner/docker/puller.hpp"
#include "slave/containerizer/mesos/provisioner/docker/registry_puller.hpp"
#include "slave/containerizer/mesos/provisioner/docker/store.hpp"

#include "tests/mesos.hpp"
#include "tests/utils.hpp"

namespace master = mesos::internal::master;
namespace paths = mesos::internal::slave::docker::paths;
namespace slave = mesos::internal::slave;
namespace spec = ::docker::spec;

using std::string;
using std::vector;

using process::Future;
using process::Owned;
using process::PID;
using process::Promise;

using master::Master;

using slave::ImageInfo;
using slave::Slave;

using slave::docker::Puller;
using slave::docker::RegistryPuller;
using slave::docker::Store;

namespace mesos {
namespace internal {
namespace tests {

class ProvisionerDockerLocalStoreTest : public TemporaryDirectoryTest
{
public:
  void verifyLocalDockerImage(
      const slave::Flags& flags,
      const vector<string>& layers)
  {
    // Verify contents of the image in store directory.
    const string layerPath1 = paths::getImageLayerRootfsPath(
        flags.docker_store_dir,
        "123");

    const string layerPath2 = paths::getImageLayerRootfsPath(
        flags.docker_store_dir,
        "456");

    EXPECT_TRUE(os::exists(layerPath1));
    EXPECT_TRUE(os::exists(layerPath2));

    EXPECT_SOME_EQ(
        "foo 123",
        os::read(path::join(layerPath1 , "temp")));

    EXPECT_SOME_EQ(
        "bar 456",
        os::read(path::join(layerPath2, "temp")));

    // Verify the Docker Image provided.
    vector<string> expectedLayers;
    expectedLayers.push_back(layerPath1);
    expectedLayers.push_back(layerPath2);
    EXPECT_EQ(expectedLayers, layers);
  }

protected:
  virtual void SetUp()
  {
    TemporaryDirectoryTest::SetUp();

    const string archivesDir = path::join(os::getcwd(), "images");
    const string image = path::join(archivesDir, "abc");
    ASSERT_SOME(os::mkdir(archivesDir));
    ASSERT_SOME(os::mkdir(image));

    JSON::Value repositories = JSON::parse(
        "{"
        "  \"abc\": {"
        "    \"latest\": \"456\""
        "  }"
        "}").get();
    ASSERT_SOME(
        os::write(path::join(image, "repositories"), stringify(repositories)));

    ASSERT_SOME(os::mkdir(path::join(image, "123")));
    JSON::Value manifest123 = JSON::parse(
        "{"
        "  \"parent\": \"\""
        "}").get();
    ASSERT_SOME(os::write(
        path::join(image, "123", "json"), stringify(manifest123)));
    ASSERT_SOME(os::mkdir(path::join(image, "123", "layer")));
    ASSERT_SOME(
        os::write(path::join(image, "123", "layer", "temp"), "foo 123"));

    // Must change directory to avoid carrying over /path/to/archive during tar.
    const string cwd = os::getcwd();
    ASSERT_SOME(os::chdir(path::join(image, "123", "layer")));
    ASSERT_SOME(os::tar(".", "../layer.tar"));
    ASSERT_SOME(os::chdir(cwd));
    ASSERT_SOME(os::rmdir(path::join(image, "123", "layer")));

    ASSERT_SOME(os::mkdir(path::join(image, "456")));
    JSON::Value manifest456 = JSON::parse(
        "{"
        "  \"parent\": \"123\""
        "}").get();
    ASSERT_SOME(
        os::write(path::join(image, "456", "json"), stringify(manifest456)));
    ASSERT_SOME(os::mkdir(path::join(image, "456", "layer")));
    ASSERT_SOME(
        os::write(path::join(image, "456", "layer", "temp"), "bar 456"));

    ASSERT_SOME(os::chdir(path::join(image, "456", "layer")));
    ASSERT_SOME(os::tar(".", "../layer.tar"));
    ASSERT_SOME(os::chdir(cwd));
    ASSERT_SOME(os::rmdir(path::join(image, "456", "layer")));

    ASSERT_SOME(os::chdir(image));
    ASSERT_SOME(os::tar(".", "../abc.tar"));
    ASSERT_SOME(os::chdir(cwd));
    ASSERT_SOME(os::rmdir(image));
  }
};

// This test verifies that a locally stored Docker image in the form of a
// tar achive created from a 'docker save' command can be unpacked and
// stored in the proper locations accessible to the Docker provisioner.
TEST_F(ProvisionerDockerLocalStoreTest, LocalStoreTestWithTar)
{
  const string archivesDir = path::join(os::getcwd(), "images");
  const string image = path::join(archivesDir, "abc");
  ASSERT_SOME(os::mkdir(archivesDir));
  ASSERT_SOME(os::mkdir(image));

  slave::Flags flags;
  flags.docker_registry = archivesDir;
  flags.docker_store_dir = path::join(os::getcwd(), "store");

  Try<Owned<slave::Store>> store = slave::docker::Store::create(flags);
  ASSERT_SOME(store);

  Image mesosImage;
  mesosImage.set_type(Image::DOCKER);
  mesosImage.mutable_docker()->set_name("abc");

  Future<slave::ImageInfo> imageInfo = store.get()->get(mesosImage);
  AWAIT_READY(imageInfo);

  verifyLocalDockerImage(flags, imageInfo.get().layers);
}

// This tests the ability of the metadata manger to recover the images it has
// already stored on disk when it is initialized.
TEST_F(ProvisionerDockerLocalStoreTest, MetadataManagerInitialization)
{
  slave::Flags flags;
  flags.docker_registry = path::join(os::getcwd(), "images");
  flags.docker_store_dir = path::join(os::getcwd(), "store");

  Try<Owned<slave::Store>> store = slave::docker::Store::create(flags);
  ASSERT_SOME(store);

  Image image;
  image.set_type(Image::DOCKER);
  image.mutable_docker()->set_name("abc");

  Future<slave::ImageInfo> imageInfo = store.get()->get(image);
  AWAIT_READY(imageInfo);

  // Store is deleted and recreated. Metadata Manager is initialized upon
  // creation of the store.
  store.get().reset();
  store = slave::docker::Store::create(flags);
  ASSERT_SOME(store);
  Future<Nothing> recover = store.get()->recover();
  AWAIT_READY(recover);

  imageInfo = store.get()->get(image);
  AWAIT_READY(imageInfo);
  verifyLocalDockerImage(flags, imageInfo.get().layers);
}

class MockPuller : public Puller
{
public:
  MockPuller()
  {
    EXPECT_CALL(*this, pull(_, _))
      .WillRepeatedly(Invoke(this, &MockPuller::unmocked_pull));
  }

  virtual ~MockPuller() {}

  MOCK_METHOD2(
      pull,
      Future<vector<string>>(
          const spec::ImageReference&,
          const string&));

  Future<vector<string>> unmocked_pull(
      const spec::ImageReference& reference,
      const string& directory)
  {
    // TODO(gilbert): Allow return list to be overridden.
    return vector<string>();
  }
};

// This tests the store to pull the same image simutanuously.
// This test verifies that the store only calls the puller once
// when multiple requests for the same image is in flight.
TEST_F(ProvisionerDockerLocalStoreTest, PullingSameImageSimutanuously)
{
  const string archivesDir = path::join(os::getcwd(), "images");
  const string image = path::join(archivesDir, "abc:latest");
  ASSERT_SOME(os::mkdir(archivesDir));
  ASSERT_SOME(os::mkdir(image));

  slave::Flags flags;
  flags.docker_registry = "file://" + archivesDir;
  flags.docker_store_dir = path::join(os::getcwd(), "store");

  MockPuller* puller = new MockPuller();
  Future<Nothing> pull;
  Future<string> directory;
  Promise<vector<string>> promise;

  EXPECT_CALL(*puller, pull(_, _))
    .WillOnce(testing::DoAll(FutureSatisfy(&pull),
                             FutureArg<1>(&directory),
                             Return(promise.future())));

  Try<Owned<slave::Store>> store =
      slave::docker::Store::create(flags, Owned<Puller>(puller));
  ASSERT_SOME(store);

  Image mesosImage;
  mesosImage.set_type(Image::DOCKER);
  mesosImage.mutable_docker()->set_name("abc");

  Future<slave::ImageInfo> imageInfo1 = store.get()->get(mesosImage);
  AWAIT_READY(pull);
  AWAIT_READY(directory);

  // TODO(gilbert): Need a helper method to create test layers
  // which will allow us to set manifest so that we can add
  // checks here.
  const string layerPath = path::join(directory.get(), "456");

  Try<Nothing> mkdir = os::mkdir(layerPath);
  ASSERT_SOME(mkdir);

  JSON::Value manifest = JSON::parse(
        "{"
        "  \"parent\": \"\""
        "}").get();

  ASSERT_SOME(
      os::write(path::join(layerPath, "json"), stringify(manifest)));

  ASSERT_TRUE(imageInfo1.isPending());
  Future<slave::ImageInfo> imageInfo2 = store.get()->get(mesosImage);

  const vector<string> result = {"456"};

  ASSERT_TRUE(imageInfo2.isPending());
  promise.set(result);

  AWAIT_READY(imageInfo1);
  AWAIT_READY(imageInfo2);

  EXPECT_EQ(imageInfo1.get().layers, imageInfo2.get().layers);
}

#ifdef __linux__
class ProvisionerDockerRegistryPullerTest : public MesosTest {};

// TODO(jieyu): This is a ROOT test because of MESOS-4757. Remove the
// ROOT restriction after MESOS-4757 is resolved.
TEST_F(ProvisionerDockerRegistryPullerTest, ROOT_INTERNET_CURL_ShellCommand)
{
  Try<PID<Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "docker/runtime,filesystem/linux";
  flags.image_providers = "docker";
  flags.docker_registry = "https://registry-1.docker.io";

  Try<PID<Slave>> slave = StartSlave(flags);
  ASSERT_SOME(slave);

  MockScheduler sched;
  MesosSchedulerDriver driver(
      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(&driver, _, _));

  Future<vector<Offer>> offers;
  EXPECT_CALL(sched, resourceOffers(&driver, _))
    .WillOnce(FutureArg<1>(&offers))
    .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_EQ(1u, offers->size());

  const Offer& offer = offers.get()[0];

  TaskInfo task = createTask(
      offer.slave_id(),
      Resources::parse("cpus:1;mem:128").get(),
      "ls -al /");

  Image image;
  image.set_type(Image::DOCKER);
  image.mutable_docker()->set_name("library/alpine");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);
  container->mutable_mesos()->mutable_image()->CopyFrom(image);

  Future<TaskStatus> statusRunning;
  Future<TaskStatus> statusFinished;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
    .WillOnce(FutureArg<1>(&statusRunning))
    .WillOnce(FutureArg<1>(&statusFinished));

  driver.launchTasks(offer.id(), {task});

  AWAIT_READY_FOR(statusRunning, Seconds(60));
  EXPECT_EQ(task.task_id(), statusRunning->task_id());
  EXPECT_EQ(TASK_RUNNING, statusRunning->state());

  AWAIT_READY(statusFinished);
  EXPECT_EQ(task.task_id(), statusFinished->task_id());
  EXPECT_EQ(TASK_FINISHED, statusFinished->state());

  driver.stop();
  driver.join();

  Shutdown();
}
#endif

} // namespace tests {
} // namespace internal {
} // namespace mesos {
<commit_msg>Implemented local puller shell command test.<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <gmock/gmock.h>

#include <stout/gtest.hpp>
#include <stout/json.hpp>
#include <stout/os.hpp>
#include <stout/path.hpp>
#include <stout/stringify.hpp>

#include <process/future.hpp>
#include <process/gmock.hpp>
#include <process/owned.hpp>

#include <mesos/docker/spec.hpp>

#include "slave/containerizer/mesos/provisioner/docker/metadata_manager.hpp"
#include "slave/containerizer/mesos/provisioner/docker/paths.hpp"
#include "slave/containerizer/mesos/provisioner/docker/puller.hpp"
#include "slave/containerizer/mesos/provisioner/docker/registry_puller.hpp"
#include "slave/containerizer/mesos/provisioner/docker/store.hpp"

#include "tests/environment.hpp"
#include "tests/mesos.hpp"
#include "tests/utils.hpp"

#include "tests/containerizer/docker_archive.hpp"

namespace master = mesos::internal::master;
namespace paths = mesos::internal::slave::docker::paths;
namespace slave = mesos::internal::slave;
namespace spec = ::docker::spec;

using std::string;
using std::vector;

using process::Future;
using process::Owned;
using process::PID;
using process::Promise;

using master::Master;

using slave::ImageInfo;
using slave::Slave;

using slave::docker::Puller;
using slave::docker::RegistryPuller;
using slave::docker::Store;

namespace mesos {
namespace internal {
namespace tests {

class ProvisionerDockerLocalStoreTest : public TemporaryDirectoryTest
{
public:
  void verifyLocalDockerImage(
      const slave::Flags& flags,
      const vector<string>& layers)
  {
    // Verify contents of the image in store directory.
    const string layerPath1 = paths::getImageLayerRootfsPath(
        flags.docker_store_dir,
        "123");

    const string layerPath2 = paths::getImageLayerRootfsPath(
        flags.docker_store_dir,
        "456");

    EXPECT_TRUE(os::exists(layerPath1));
    EXPECT_TRUE(os::exists(layerPath2));

    EXPECT_SOME_EQ(
        "foo 123",
        os::read(path::join(layerPath1 , "temp")));

    EXPECT_SOME_EQ(
        "bar 456",
        os::read(path::join(layerPath2, "temp")));

    // Verify the Docker Image provided.
    vector<string> expectedLayers;
    expectedLayers.push_back(layerPath1);
    expectedLayers.push_back(layerPath2);
    EXPECT_EQ(expectedLayers, layers);
  }

protected:
  virtual void SetUp()
  {
    TemporaryDirectoryTest::SetUp();

    const string archivesDir = path::join(os::getcwd(), "images");
    const string image = path::join(archivesDir, "abc");
    ASSERT_SOME(os::mkdir(archivesDir));
    ASSERT_SOME(os::mkdir(image));

    JSON::Value repositories = JSON::parse(
        "{"
        "  \"abc\": {"
        "    \"latest\": \"456\""
        "  }"
        "}").get();
    ASSERT_SOME(
        os::write(path::join(image, "repositories"), stringify(repositories)));

    ASSERT_SOME(os::mkdir(path::join(image, "123")));
    JSON::Value manifest123 = JSON::parse(
        "{"
        "  \"parent\": \"\""
        "}").get();
    ASSERT_SOME(os::write(
        path::join(image, "123", "json"), stringify(manifest123)));
    ASSERT_SOME(os::mkdir(path::join(image, "123", "layer")));
    ASSERT_SOME(
        os::write(path::join(image, "123", "layer", "temp"), "foo 123"));

    // Must change directory to avoid carrying over /path/to/archive during tar.
    const string cwd = os::getcwd();
    ASSERT_SOME(os::chdir(path::join(image, "123", "layer")));
    ASSERT_SOME(os::tar(".", "../layer.tar"));
    ASSERT_SOME(os::chdir(cwd));
    ASSERT_SOME(os::rmdir(path::join(image, "123", "layer")));

    ASSERT_SOME(os::mkdir(path::join(image, "456")));
    JSON::Value manifest456 = JSON::parse(
        "{"
        "  \"parent\": \"123\""
        "}").get();
    ASSERT_SOME(
        os::write(path::join(image, "456", "json"), stringify(manifest456)));
    ASSERT_SOME(os::mkdir(path::join(image, "456", "layer")));
    ASSERT_SOME(
        os::write(path::join(image, "456", "layer", "temp"), "bar 456"));

    ASSERT_SOME(os::chdir(path::join(image, "456", "layer")));
    ASSERT_SOME(os::tar(".", "../layer.tar"));
    ASSERT_SOME(os::chdir(cwd));
    ASSERT_SOME(os::rmdir(path::join(image, "456", "layer")));

    ASSERT_SOME(os::chdir(image));
    ASSERT_SOME(os::tar(".", "../abc.tar"));
    ASSERT_SOME(os::chdir(cwd));
    ASSERT_SOME(os::rmdir(image));
  }
};

// This test verifies that a locally stored Docker image in the form of a
// tar achive created from a 'docker save' command can be unpacked and
// stored in the proper locations accessible to the Docker provisioner.
TEST_F(ProvisionerDockerLocalStoreTest, LocalStoreTestWithTar)
{
  const string archivesDir = path::join(os::getcwd(), "images");
  const string image = path::join(archivesDir, "abc");
  ASSERT_SOME(os::mkdir(archivesDir));
  ASSERT_SOME(os::mkdir(image));

  slave::Flags flags;
  flags.docker_registry = archivesDir;
  flags.docker_store_dir = path::join(os::getcwd(), "store");

  Try<Owned<slave::Store>> store = slave::docker::Store::create(flags);
  ASSERT_SOME(store);

  Image mesosImage;
  mesosImage.set_type(Image::DOCKER);
  mesosImage.mutable_docker()->set_name("abc");

  Future<slave::ImageInfo> imageInfo = store.get()->get(mesosImage);
  AWAIT_READY(imageInfo);

  verifyLocalDockerImage(flags, imageInfo.get().layers);
}

// This tests the ability of the metadata manger to recover the images it has
// already stored on disk when it is initialized.
TEST_F(ProvisionerDockerLocalStoreTest, MetadataManagerInitialization)
{
  slave::Flags flags;
  flags.docker_registry = path::join(os::getcwd(), "images");
  flags.docker_store_dir = path::join(os::getcwd(), "store");

  Try<Owned<slave::Store>> store = slave::docker::Store::create(flags);
  ASSERT_SOME(store);

  Image image;
  image.set_type(Image::DOCKER);
  image.mutable_docker()->set_name("abc");

  Future<slave::ImageInfo> imageInfo = store.get()->get(image);
  AWAIT_READY(imageInfo);

  // Store is deleted and recreated. Metadata Manager is initialized upon
  // creation of the store.
  store.get().reset();
  store = slave::docker::Store::create(flags);
  ASSERT_SOME(store);
  Future<Nothing> recover = store.get()->recover();
  AWAIT_READY(recover);

  imageInfo = store.get()->get(image);
  AWAIT_READY(imageInfo);
  verifyLocalDockerImage(flags, imageInfo.get().layers);
}

class MockPuller : public Puller
{
public:
  MockPuller()
  {
    EXPECT_CALL(*this, pull(_, _))
      .WillRepeatedly(Invoke(this, &MockPuller::unmocked_pull));
  }

  virtual ~MockPuller() {}

  MOCK_METHOD2(
      pull,
      Future<vector<string>>(
          const spec::ImageReference&,
          const string&));

  Future<vector<string>> unmocked_pull(
      const spec::ImageReference& reference,
      const string& directory)
  {
    // TODO(gilbert): Allow return list to be overridden.
    return vector<string>();
  }
};

// This tests the store to pull the same image simutanuously.
// This test verifies that the store only calls the puller once
// when multiple requests for the same image is in flight.
TEST_F(ProvisionerDockerLocalStoreTest, PullingSameImageSimutanuously)
{
  const string archivesDir = path::join(os::getcwd(), "images");
  const string image = path::join(archivesDir, "abc:latest");
  ASSERT_SOME(os::mkdir(archivesDir));
  ASSERT_SOME(os::mkdir(image));

  slave::Flags flags;
  flags.docker_registry = "file://" + archivesDir;
  flags.docker_store_dir = path::join(os::getcwd(), "store");

  MockPuller* puller = new MockPuller();
  Future<Nothing> pull;
  Future<string> directory;
  Promise<vector<string>> promise;

  EXPECT_CALL(*puller, pull(_, _))
    .WillOnce(testing::DoAll(FutureSatisfy(&pull),
                             FutureArg<1>(&directory),
                             Return(promise.future())));

  Try<Owned<slave::Store>> store =
      slave::docker::Store::create(flags, Owned<Puller>(puller));
  ASSERT_SOME(store);

  Image mesosImage;
  mesosImage.set_type(Image::DOCKER);
  mesosImage.mutable_docker()->set_name("abc");

  Future<slave::ImageInfo> imageInfo1 = store.get()->get(mesosImage);
  AWAIT_READY(pull);
  AWAIT_READY(directory);

  // TODO(gilbert): Need a helper method to create test layers
  // which will allow us to set manifest so that we can add
  // checks here.
  const string layerPath = path::join(directory.get(), "456");

  Try<Nothing> mkdir = os::mkdir(layerPath);
  ASSERT_SOME(mkdir);

  JSON::Value manifest = JSON::parse(
        "{"
        "  \"parent\": \"\""
        "}").get();

  ASSERT_SOME(
      os::write(path::join(layerPath, "json"), stringify(manifest)));

  ASSERT_TRUE(imageInfo1.isPending());
  Future<slave::ImageInfo> imageInfo2 = store.get()->get(mesosImage);

  const vector<string> result = {"456"};

  ASSERT_TRUE(imageInfo2.isPending());
  promise.set(result);

  AWAIT_READY(imageInfo1);
  AWAIT_READY(imageInfo2);

  EXPECT_EQ(imageInfo1.get().layers, imageInfo2.get().layers);
}

#ifdef __linux__
class ProvisionerDockerPullerTest : public MesosTest {};

// This test verifies that local docker image can be pulled and
// provisioned correctly, and shell command should be executed.
TEST_F(ProvisionerDockerPullerTest, ROOT_LocalPullerShellCommand)
{
  Try<PID<Master>> master = StartMaster();
  ASSERT_SOME(master);

  Try<string> mkdtemp = environment->mkdtemp();
  ASSERT_SOME(mkdtemp);

  const string directory = path::join(mkdtemp.get(), "archives");

  Future<Nothing> testImage = DockerArchive::create(directory, "alpine");
  AWAIT_READY(testImage);

  ASSERT_TRUE(os::exists(path::join(directory, "alpine.tar")));

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "docker/runtime,filesystem/linux";
  flags.image_providers = "docker";
  flags.docker_registry = directory;
  flags.docker_store_dir = path::join(flags.work_dir, "docker");

  Try<PID<Slave>> slave = StartSlave(flags);
  ASSERT_SOME(slave);

  MockScheduler sched;
  MesosSchedulerDriver driver(
      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(&driver, _, _));

  Future<vector<Offer>> offers;
  EXPECT_CALL(sched, resourceOffers(&driver, _))
    .WillOnce(FutureArg<1>(&offers))
    .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_EQ(1u, offers->size());

  const Offer& offer = offers.get()[0];

  TaskInfo task = createTask(
      offer.slave_id(),
      Resources::parse("cpus:1;mem:128").get(),
      "ls -al /");

  Image image;
  image.set_type(Image::DOCKER);
  image.mutable_docker()->set_name("alpine");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);
  container->mutable_mesos()->mutable_image()->CopyFrom(image);

  Future<TaskStatus> statusRunning;
  Future<TaskStatus> statusFinished;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
    .WillOnce(FutureArg<1>(&statusRunning))
    .WillOnce(FutureArg<1>(&statusFinished));

  driver.launchTasks(offer.id(), {task});

  AWAIT_READY_FOR(statusRunning, Seconds(60));
  EXPECT_EQ(task.task_id(), statusRunning->task_id());
  EXPECT_EQ(TASK_RUNNING, statusRunning->state());

  AWAIT_READY(statusFinished);
  EXPECT_EQ(task.task_id(), statusFinished->task_id());
  EXPECT_EQ(TASK_FINISHED, statusFinished->state());

  driver.stop();
  driver.join();

  Shutdown();
}

// TODO(jieyu): This is a ROOT test because of MESOS-4757. Remove the
// ROOT restriction after MESOS-4757 is resolved.
TEST_F(ProvisionerDockerPullerTest, ROOT_INTERNET_CURL_ShellCommand)
{
  Try<PID<Master>> master = StartMaster();
  ASSERT_SOME(master);

  slave::Flags flags = CreateSlaveFlags();
  flags.isolation = "docker/runtime,filesystem/linux";
  flags.image_providers = "docker";
  flags.docker_registry = "https://registry-1.docker.io";

  Try<PID<Slave>> slave = StartSlave(flags);
  ASSERT_SOME(slave);

  MockScheduler sched;
  MesosSchedulerDriver driver(
      &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL);

  EXPECT_CALL(sched, registered(&driver, _, _));

  Future<vector<Offer>> offers;
  EXPECT_CALL(sched, resourceOffers(&driver, _))
    .WillOnce(FutureArg<1>(&offers))
    .WillRepeatedly(Return()); // Ignore subsequent offers.

  driver.start();

  AWAIT_READY(offers);
  ASSERT_EQ(1u, offers->size());

  const Offer& offer = offers.get()[0];

  TaskInfo task = createTask(
      offer.slave_id(),
      Resources::parse("cpus:1;mem:128").get(),
      "ls -al /");

  Image image;
  image.set_type(Image::DOCKER);
  image.mutable_docker()->set_name("library/alpine");

  ContainerInfo* container = task.mutable_container();
  container->set_type(ContainerInfo::MESOS);
  container->mutable_mesos()->mutable_image()->CopyFrom(image);

  Future<TaskStatus> statusRunning;
  Future<TaskStatus> statusFinished;
  EXPECT_CALL(sched, statusUpdate(&driver, _))
    .WillOnce(FutureArg<1>(&statusRunning))
    .WillOnce(FutureArg<1>(&statusFinished));

  driver.launchTasks(offer.id(), {task});

  AWAIT_READY_FOR(statusRunning, Seconds(60));
  EXPECT_EQ(task.task_id(), statusRunning->task_id());
  EXPECT_EQ(TASK_RUNNING, statusRunning->state());

  AWAIT_READY(statusFinished);
  EXPECT_EQ(task.task_id(), statusFinished->task_id());
  EXPECT_EQ(TASK_FINISHED, statusFinished->state());

  driver.stop();
  driver.join();

  Shutdown();
}

#endif

} // namespace tests {
} // namespace internal {
} // namespace mesos {
<|endoftext|>


<commit_before>//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// deqp_libtester_main.cpp: Entry point for tester DLL.

#include <cstdio>
#include <iostream>

#include "angle_deqp_libtester.h"
#include "common/angleutils.h"
#include "deMath.h"
#include "deUniquePtr.hpp"
#include "tcuApp.hpp"
#include "tcuCommandLine.hpp"
#include "tcuDefs.hpp"
#include "tcuPlatform.hpp"
#include "tcuRandomOrderExecutor.h"
#include "tcuResource.hpp"
#include "tcuTestLog.hpp"
#include "system_utils.h"

#if (DE_OS == DE_OS_WIN32)
#include <Windows.h>
#elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif

tcu::Platform *createPlatform();

namespace
{

tcu::Platform *g_platform = nullptr;
tcu::CommandLine *g_cmdLine = nullptr;
tcu::DirArchive *g_archive = nullptr;
tcu::TestLog *g_log = nullptr;
tcu::TestContext *g_testCtx = nullptr;
tcu::TestPackageRoot *g_root = nullptr;
tcu::RandomOrderExecutor *g_executor = nullptr;

const char *g_dEQPDataSearchDirs[] =
{
    "data",
    "third_party/deqp/data",
    "../third_party/deqp/src/data",
    "deqp_support/data",
    "third_party/deqp/src/data",
    "../../third_party/deqp/src/data",
    "../../../third_party/deqp/src/data"
};

// TODO(jmadill): upstream to dEQP?
#if (DE_OS == DE_OS_WIN32)
deBool deIsDir(const char *filename)
{
    WIN32_FILE_ATTRIBUTE_DATA fileInformation;

    BOOL result = GetFileAttributesExA(filename, GetFileExInfoStandard, &fileInformation);
    if (result)
    {
        DWORD attribs = fileInformation.dwFileAttributes;
        return (attribs != INVALID_FILE_ATTRIBUTES) && ((attribs & FILE_ATTRIBUTE_DIRECTORY) > 0);
    }

    return false;
}
#elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
deBool deIsDir(const char *filename)
{
    struct stat st;
    int result = stat(filename, &st);
    return result == 0 && ((st.st_mode & S_IFDIR) == S_IFDIR);
}
#else
#error TODO(jmadill): support other platforms
#endif

bool FindDataDir(std::string *dataDir)
{
    for (auto searchDir : g_dEQPDataSearchDirs)
    {
        if (deIsDir(searchDir))
        {
            *dataDir = searchDir;
            return true;
        }

        std::string directory = angle::GetExecutableDirectory() + searchDir;
        if (deIsDir(directory.c_str()))
        {
            *dataDir = directory;
            return true;
        }
    }

    return false;
}

bool InitPlatform(int argc, const char *argv[])
{
    try
    {
#if (DE_OS != DE_OS_WIN32)
        // Set stdout to line-buffered mode (will be fully buffered by default if stdout is pipe).
        setvbuf(stdout, DE_NULL, _IOLBF, 4 * 1024);
#endif
        g_platform = createPlatform();

        if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST))
        {
            std::cout << "Failed to set floating point rounding mode." << std::endl;
            return false;
        }

        std::string deqpDataDir;
        if (!FindDataDir(&deqpDataDir))
        {
            std::cout << "Failed to find dEQP data directory." << std::endl;
            return false;
        }

        g_cmdLine = new tcu::CommandLine(argc, argv);
        g_archive = new tcu::DirArchive(deqpDataDir.c_str());
        g_log = new tcu::TestLog(g_cmdLine->getLogFileName(), g_cmdLine->getLogFlags());
        g_testCtx = new tcu::TestContext(*g_platform, *g_archive, *g_log, *g_cmdLine, DE_NULL);
        g_root = new tcu::TestPackageRoot(*g_testCtx, tcu::TestPackageRegistry::getSingleton());
        g_executor = new tcu::RandomOrderExecutor(*g_root, *g_testCtx);
    }
    catch (const std::exception& e)
    {
        tcu::die("%s", e.what());
        return false;
    }

    return true;
}

} // anonymous namespace

// Exported to the tester app.
ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[])
{
    if (!InitPlatform(argc, argv))
    {
        tcu::die("Could not initialize the dEQP platform");
    }

    try
    {
        de::UniquePtr<tcu::App> app(new tcu::App(*g_platform, *g_archive, *g_log, *g_cmdLine));

        // Main loop.
        for (;;)
        {
            if (!app->iterate())
                break;
        }
    }
    catch (const std::exception &e)
    {
        deqp_libtester_shutdown_platform();
        tcu::die("%s", e.what());
    }

    deqp_libtester_shutdown_platform();
    return 0;
}

ANGLE_LIBTESTER_EXPORT void deqp_libtester_shutdown_platform()
{
    delete g_executor;
    delete g_root;
    delete g_testCtx;
    delete g_log;
    delete g_archive;
    delete g_cmdLine;
    delete g_platform;
}

ANGLE_LIBTESTER_EXPORT bool deqp_libtester_run(const char *caseName)
{
    const char *emptyString = "";
    if (g_platform == nullptr && !InitPlatform(1, &emptyString))
    {
        tcu::die("Failed to initialize platform.");
    }

    try
    {
        // Poll platform events
        const bool platformOk = g_platform->processEvents();

        if (platformOk)
        {
            const tcu::TestStatus &result = g_executor->execute(caseName);
            switch (result.getCode())
            {
                case QP_TEST_RESULT_PASS:
                case QP_TEST_RESULT_NOT_SUPPORTED:
                    return true;
                case QP_TEST_RESULT_QUALITY_WARNING:
                    std::cout << "Quality warning! " << result.getDescription() << std::endl;
                    return true;
                case QP_TEST_RESULT_COMPATIBILITY_WARNING:
                    std::cout << "Compatiblity warning! " << result.getDescription() << std::endl;
                    return true;
                default:
                    return false;
            }
        }
        else
        {
            std::cout << "Aborted test!" << std::endl;
        }
    }
    catch (const std::exception &e)
    {
        std::cout << "Exception running test: " << e.what() << std::endl;
    }

    return false;
}
<commit_msg>Insert slash when concatenating paths.<commit_after>//
// Copyright 2015 The ANGLE Project Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// deqp_libtester_main.cpp: Entry point for tester DLL.

#include <cstdio>
#include <iostream>

#include "angle_deqp_libtester.h"
#include "common/angleutils.h"
#include "deMath.h"
#include "deUniquePtr.hpp"
#include "tcuApp.hpp"
#include "tcuCommandLine.hpp"
#include "tcuDefs.hpp"
#include "tcuPlatform.hpp"
#include "tcuRandomOrderExecutor.h"
#include "tcuResource.hpp"
#include "tcuTestLog.hpp"
#include "system_utils.h"

#if (DE_OS == DE_OS_WIN32)
#include <Windows.h>
#elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#endif

tcu::Platform *createPlatform();

namespace
{

tcu::Platform *g_platform = nullptr;
tcu::CommandLine *g_cmdLine = nullptr;
tcu::DirArchive *g_archive = nullptr;
tcu::TestLog *g_log = nullptr;
tcu::TestContext *g_testCtx = nullptr;
tcu::TestPackageRoot *g_root = nullptr;
tcu::RandomOrderExecutor *g_executor = nullptr;

const char *g_dEQPDataSearchDirs[] =
{
    "data",
    "third_party/deqp/data",
    "../third_party/deqp/src/data",
    "deqp_support/data",
    "third_party/deqp/src/data",
    "../../third_party/deqp/src/data",
    "../../../third_party/deqp/src/data"
};

// TODO(jmadill): upstream to dEQP?
#if (DE_OS == DE_OS_WIN32)
deBool deIsDir(const char *filename)
{
    WIN32_FILE_ATTRIBUTE_DATA fileInformation;

    BOOL result = GetFileAttributesExA(filename, GetFileExInfoStandard, &fileInformation);
    if (result)
    {
        DWORD attribs = fileInformation.dwFileAttributes;
        return (attribs != INVALID_FILE_ATTRIBUTES) && ((attribs & FILE_ATTRIBUTE_DIRECTORY) > 0);
    }

    return false;
}
#elif (DE_OS == DE_OS_UNIX) || (DE_OS == DE_OS_OSX)
deBool deIsDir(const char *filename)
{
    struct stat st;
    int result = stat(filename, &st);
    return result == 0 && ((st.st_mode & S_IFDIR) == S_IFDIR);
}
#else
#error TODO(jmadill): support other platforms
#endif

bool FindDataDir(std::string *dataDir)
{
    for (auto searchDir : g_dEQPDataSearchDirs)
    {
        if (deIsDir(searchDir))
        {
            *dataDir = searchDir;
            return true;
        }

        std::string directory = angle::GetExecutableDirectory() + "/" + searchDir;
        if (deIsDir(directory.c_str()))
        {
            *dataDir = directory;
            return true;
        }
    }

    return false;
}

bool InitPlatform(int argc, const char *argv[])
{
    try
    {
#if (DE_OS != DE_OS_WIN32)
        // Set stdout to line-buffered mode (will be fully buffered by default if stdout is pipe).
        setvbuf(stdout, DE_NULL, _IOLBF, 4 * 1024);
#endif
        g_platform = createPlatform();

        if (!deSetRoundingMode(DE_ROUNDINGMODE_TO_NEAREST))
        {
            std::cout << "Failed to set floating point rounding mode." << std::endl;
            return false;
        }

        std::string deqpDataDir;
        if (!FindDataDir(&deqpDataDir))
        {
            std::cout << "Failed to find dEQP data directory." << std::endl;
            return false;
        }

        g_cmdLine = new tcu::CommandLine(argc, argv);
        g_archive = new tcu::DirArchive(deqpDataDir.c_str());
        g_log = new tcu::TestLog(g_cmdLine->getLogFileName(), g_cmdLine->getLogFlags());
        g_testCtx = new tcu::TestContext(*g_platform, *g_archive, *g_log, *g_cmdLine, DE_NULL);
        g_root = new tcu::TestPackageRoot(*g_testCtx, tcu::TestPackageRegistry::getSingleton());
        g_executor = new tcu::RandomOrderExecutor(*g_root, *g_testCtx);
    }
    catch (const std::exception& e)
    {
        tcu::die("%s", e.what());
        return false;
    }

    return true;
}

} // anonymous namespace

// Exported to the tester app.
ANGLE_LIBTESTER_EXPORT int deqp_libtester_main(int argc, const char *argv[])
{
    if (!InitPlatform(argc, argv))
    {
        tcu::die("Could not initialize the dEQP platform");
    }

    try
    {
        de::UniquePtr<tcu::App> app(new tcu::App(*g_platform, *g_archive, *g_log, *g_cmdLine));

        // Main loop.
        for (;;)
        {
            if (!app->iterate())
                break;
        }
    }
    catch (const std::exception &e)
    {
        deqp_libtester_shutdown_platform();
        tcu::die("%s", e.what());
    }

    deqp_libtester_shutdown_platform();
    return 0;
}

ANGLE_LIBTESTER_EXPORT void deqp_libtester_shutdown_platform()
{
    delete g_executor;
    delete g_root;
    delete g_testCtx;
    delete g_log;
    delete g_archive;
    delete g_cmdLine;
    delete g_platform;
}

ANGLE_LIBTESTER_EXPORT bool deqp_libtester_run(const char *caseName)
{
    const char *emptyString = "";
    if (g_platform == nullptr && !InitPlatform(1, &emptyString))
    {
        tcu::die("Failed to initialize platform.");
    }

    try
    {
        // Poll platform events
        const bool platformOk = g_platform->processEvents();

        if (platformOk)
        {
            const tcu::TestStatus &result = g_executor->execute(caseName);
            switch (result.getCode())
            {
                case QP_TEST_RESULT_PASS:
                case QP_TEST_RESULT_NOT_SUPPORTED:
                    return true;
                case QP_TEST_RESULT_QUALITY_WARNING:
                    std::cout << "Quality warning! " << result.getDescription() << std::endl;
                    return true;
                case QP_TEST_RESULT_COMPATIBILITY_WARNING:
                    std::cout << "Compatiblity warning! " << result.getDescription() << std::endl;
                    return true;
                default:
                    return false;
            }
        }
        else
        {
            std::cout << "Aborted test!" << std::endl;
        }
    }
    catch (const std::exception &e)
    {
        std::cout << "Exception running test: " << e.what() << std::endl;
    }

    return false;
}
<|endoftext|>


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

#include "es31fNegativePreciseTests.hpp"

#include "gluShaderProgram.hpp"
#include "glwEnums.hpp"

namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace NegativeTestShared
{
namespace
{

enum TestPrecise
{
	TEST_PRECISE_AS_VARIABLE_NAME = 0,
	TEST_PRECISE_AS_FUNCTION_NAME,
	TEST_PRECISE_AS_ARGUMENT_NAME,
	TEST_PRECISE_AS_MACRO_NAME,
	TEST_PRECISE_MACRO_AND_VARIABLE,
	TEST_PRECISE_MACRO_AND_FUNCTION,
	TEST_PRECISE_MACRO_AND_ARGUMENT,

	TEST_PRECISE_LAST
};

static const glu::ShaderType s_shaderTypes[] =
{
	glu::SHADERTYPE_VERTEX,
	glu::SHADERTYPE_FRAGMENT,
	glu::SHADERTYPE_GEOMETRY,
	glu::SHADERTYPE_COMPUTE,
	glu::SHADERTYPE_TESSELLATION_CONTROL,
	glu::SHADERTYPE_TESSELLATION_EVALUATION
};

std::string generateShaderSource (NegativeTestContext& ctx, glu::ShaderType shaderType, TestPrecise test)
{
	const bool				isES32	= contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
	const glu::GLSLVersion	version	= isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
	std::ostringstream		source;

	source	<< glu::getGLSLVersionDeclaration(version) << "\n"
			<< (isES32 ? "" : "#extension GL_EXT_gpu_shader5 : enable\n");

	switch (test)
	{
		case TEST_PRECISE_AS_MACRO_NAME:		source << "#define precise 0\n";		break;

		case TEST_PRECISE_MACRO_AND_VARIABLE:
		case TEST_PRECISE_MACRO_AND_FUNCTION:
		case TEST_PRECISE_MACRO_AND_ARGUMENT:	source << "#define precise aName\n";	break;
		default:
			break;
	}

    switch (shaderType)
    {
        case glu::SHADERTYPE_GEOMETRY:
            source  << (isES32 ? "" : "#extension GL_EXT_geometry_shader : enable\n")
                    << "layout(max_vertices = 5) out;\n";
            break;

        case glu::SHADERTYPE_TESSELLATION_CONTROL:
            source  << (isES32 ? "" : "#extension GL_EXT_tessellation_shader : enable\n")
                    << "layout(vertices = 3) out;\n";
            break;

        case glu::SHADERTYPE_TESSELLATION_EVALUATION:
            source  << (isES32 ? "" : "#extension GL_EXT_tessellation_shader : enable\n")
                    << "layout(triangles, equal_spacing, cw) in;\n";
            break;

        default:
            break;
    }

	switch (test)
	{
		case TEST_PRECISE_AS_FUNCTION_NAME:
		case TEST_PRECISE_MACRO_AND_FUNCTION:
			source	<< "\n"
					<< "void precise()\n"
					<< "{\n"
					<< "}\n";
			break;

		case TEST_PRECISE_AS_ARGUMENT_NAME:
		case TEST_PRECISE_MACRO_AND_ARGUMENT:
			source	<< "\n"
					<< "void example(int precise)\n"
					<< "{\n"
					<< "}\n";
			break;

		default:
			break;
	}

    source  << "void main()\n"
			<< "{\n";

	switch (test)
	{
		case TEST_PRECISE_AS_VARIABLE_NAME:
		case TEST_PRECISE_MACRO_AND_VARIABLE:	source << "	int precise = 1;\n";		break;
		case TEST_PRECISE_AS_MACRO_NAME:		source << "	int number = precise;\n";	break;
		default:
			break;
	}

	source << "}\n";

	return source.str();
}

void generateAndVerifyShader (NegativeTestContext& ctx, glu::ShaderType shaderType, TestPrecise test)
{
	glu::Shader 		shader			(ctx.getRenderContext(), shaderType);
	std::string 		shaderSource	= generateShaderSource(ctx, shaderType, test);
	const char* const	source			= shaderSource.c_str();
	const int 			length			= (int) shaderSource.size();

	shader.setSources(1, &source, &length);
	shader.compile();

	ctx.getLog() << shader;

	if (shader.getCompileStatus())
		ctx.fail("Shader was not expected to compile.");
}

void precise_as_variable_name (NegativeTestContext& ctx)
{
	TCU_CHECK_AND_THROW(NotSupportedError,
		ctx.isExtensionSupported("GL_EXT_gpu_shader5") || contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)),
		"This test requires support for the extension GL_EXT_gpu_shader5 or context version 3.2 or higher.");

	ctx.beginSection("Test that precise cannot be used as a variable name.");
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaderTypes); ++ndx)
		generateAndVerifyShader(ctx, s_shaderTypes[ndx], TEST_PRECISE_AS_VARIABLE_NAME);
	ctx.endSection();
}

void precise_as_function_name (NegativeTestContext& ctx)
{
	TCU_CHECK_AND_THROW(NotSupportedError,
		ctx.isExtensionSupported("GL_EXT_gpu_shader5") || contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)),
		"This test requires support for the extension GL_EXT_gpu_shader5 or context version 3.2 or higher.");

	ctx.beginSection("Test that precise cannot be used as a function name.");
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaderTypes); ++ndx)
		generateAndVerifyShader(ctx, s_shaderTypes[ndx], TEST_PRECISE_AS_FUNCTION_NAME);
	ctx.endSection();
}

void precise_as_function_argument (NegativeTestContext& ctx)
{
	TCU_CHECK_AND_THROW(NotSupportedError,
		ctx.isExtensionSupported("GL_EXT_gpu_shader5") || contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)),
		"This test requires support for the extension GL_EXT_gpu_shader5 or context version 3.2 or higher.");

	ctx.beginSection("Test that precise cannot be used as a argument name.");
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaderTypes); ++ndx)
		generateAndVerifyShader(ctx, s_shaderTypes[ndx], TEST_PRECISE_AS_ARGUMENT_NAME);
	ctx.endSection();
}

} // anonymous

std::vector<FunctionContainer> getNegativePreciseTestFunctions (void)
{
	const FunctionContainer funcs[] =
	{
        {precise_as_variable_name,			"precise_as_variable_name",			"Test precise keyword as variable name."			},
        {precise_as_function_name,			"precise_as_function_name",			"Test precise keyword as function name."			},
        {precise_as_function_argument,		"precise_as_function_argument",		"Test precise keyword as argument name."			},
	};

	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
}

} // NegativeTestShared
} // Functional
} // gles31
} // deqp
<commit_msg>Check for shader type support in negative precise tests am: 4a3a2d79a0 am: dd142e90db am: def3338070<commit_after>/*-------------------------------------------------------------------------
 * drawElements Quality Program OpenGL ES 3.1 Module
 * -------------------------------------------------
 *
 * Copyright 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *//*!
 * \file
 * \brief Negative Precise Tests
 *//*--------------------------------------------------------------------*/

#include "es31fNegativePreciseTests.hpp"

#include "gluShaderProgram.hpp"
#include "glwEnums.hpp"

namespace deqp
{
namespace gles31
{
namespace Functional
{
namespace NegativeTestShared
{
namespace
{

enum TestPrecise
{
	TEST_PRECISE_AS_VARIABLE_NAME = 0,
	TEST_PRECISE_AS_FUNCTION_NAME,
	TEST_PRECISE_AS_ARGUMENT_NAME,
	TEST_PRECISE_AS_MACRO_NAME,
	TEST_PRECISE_MACRO_AND_VARIABLE,
	TEST_PRECISE_MACRO_AND_FUNCTION,
	TEST_PRECISE_MACRO_AND_ARGUMENT,

	TEST_PRECISE_LAST
};

static const glu::ShaderType s_shaderTypes[] =
{
	glu::SHADERTYPE_VERTEX,
	glu::SHADERTYPE_FRAGMENT,
	glu::SHADERTYPE_GEOMETRY,
	glu::SHADERTYPE_COMPUTE,
	glu::SHADERTYPE_TESSELLATION_CONTROL,
	glu::SHADERTYPE_TESSELLATION_EVALUATION
};

std::string generateShaderSource (NegativeTestContext& ctx, glu::ShaderType shaderType, TestPrecise test)
{
	const bool				isES32	= contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2));
	const glu::GLSLVersion	version	= isES32 ? glu::GLSL_VERSION_320_ES : glu::GLSL_VERSION_310_ES;
	std::ostringstream		source;

	source	<< glu::getGLSLVersionDeclaration(version) << "\n"
			<< (isES32 ? "" : "#extension GL_EXT_gpu_shader5 : enable\n");

	switch (test)
	{
		case TEST_PRECISE_AS_MACRO_NAME:		source << "#define precise 0\n";		break;

		case TEST_PRECISE_MACRO_AND_VARIABLE:
		case TEST_PRECISE_MACRO_AND_FUNCTION:
		case TEST_PRECISE_MACRO_AND_ARGUMENT:	source << "#define precise aName\n";	break;
		default:
			break;
	}

    switch (shaderType)
    {
        case glu::SHADERTYPE_GEOMETRY:
            source  << (isES32 ? "" : "#extension GL_EXT_geometry_shader : enable\n")
                    << "layout(max_vertices = 5) out;\n";
            break;

        case glu::SHADERTYPE_TESSELLATION_CONTROL:
            source  << (isES32 ? "" : "#extension GL_EXT_tessellation_shader : enable\n")
                    << "layout(vertices = 3) out;\n";
            break;

        case glu::SHADERTYPE_TESSELLATION_EVALUATION:
            source  << (isES32 ? "" : "#extension GL_EXT_tessellation_shader : enable\n")
                    << "layout(triangles, equal_spacing, cw) in;\n";
            break;

        default:
            break;
    }

	switch (test)
	{
		case TEST_PRECISE_AS_FUNCTION_NAME:
		case TEST_PRECISE_MACRO_AND_FUNCTION:
			source	<< "\n"
					<< "void precise()\n"
					<< "{\n"
					<< "}\n";
			break;

		case TEST_PRECISE_AS_ARGUMENT_NAME:
		case TEST_PRECISE_MACRO_AND_ARGUMENT:
			source	<< "\n"
					<< "void example(int precise)\n"
					<< "{\n"
					<< "}\n";
			break;

		default:
			break;
	}

    source  << "void main()\n"
			<< "{\n";

	switch (test)
	{
		case TEST_PRECISE_AS_VARIABLE_NAME:
		case TEST_PRECISE_MACRO_AND_VARIABLE:	source << "	int precise = 1;\n";		break;
		case TEST_PRECISE_AS_MACRO_NAME:		source << "	int number = precise;\n";	break;
		default:
			break;
	}

	source << "}\n";

	return source.str();
}

void generateAndVerifyShader (NegativeTestContext& ctx, glu::ShaderType shaderType, TestPrecise test)
{
	glu::Shader 		shader			(ctx.getRenderContext(), shaderType);
	std::string 		shaderSource	= generateShaderSource(ctx, shaderType, test);
	const char* const	source			= shaderSource.c_str();
	const int 			length			= (int) shaderSource.size();

	shader.setSources(1, &source, &length);
	shader.compile();

	ctx.getLog() << shader;

	if (shader.getCompileStatus())
		ctx.fail("Shader was not expected to compile.");
}

void precise_as_variable_name (NegativeTestContext& ctx)
{
	TCU_CHECK_AND_THROW(NotSupportedError,
		ctx.isExtensionSupported("GL_EXT_gpu_shader5") || contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)),
		"This test requires support for the extension GL_EXT_gpu_shader5 or context version 3.2 or higher.");

	ctx.beginSection("Test that precise cannot be used as a variable name.");
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaderTypes); ++ndx)
	{
		if (ctx.isShaderSupported(s_shaderTypes[ndx]))
			generateAndVerifyShader(ctx, s_shaderTypes[ndx], TEST_PRECISE_AS_VARIABLE_NAME);
	}
	ctx.endSection();
}

void precise_as_function_name (NegativeTestContext& ctx)
{
	TCU_CHECK_AND_THROW(NotSupportedError,
		ctx.isExtensionSupported("GL_EXT_gpu_shader5") || contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)),
		"This test requires support for the extension GL_EXT_gpu_shader5 or context version 3.2 or higher.");

	ctx.beginSection("Test that precise cannot be used as a function name.");
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaderTypes); ++ndx)
	{
		if (ctx.isShaderSupported(s_shaderTypes[ndx]))
			generateAndVerifyShader(ctx, s_shaderTypes[ndx], TEST_PRECISE_AS_FUNCTION_NAME);
	}
	ctx.endSection();
}

void precise_as_function_argument (NegativeTestContext& ctx)
{
	TCU_CHECK_AND_THROW(NotSupportedError,
		ctx.isExtensionSupported("GL_EXT_gpu_shader5") || contextSupports(ctx.getRenderContext().getType(), glu::ApiType::es(3, 2)),
		"This test requires support for the extension GL_EXT_gpu_shader5 or context version 3.2 or higher.");

	ctx.beginSection("Test that precise cannot be used as a argument name.");
	for (int ndx = 0; ndx < DE_LENGTH_OF_ARRAY(s_shaderTypes); ++ndx)
	{
		if (ctx.isShaderSupported(s_shaderTypes[ndx]))
			generateAndVerifyShader(ctx, s_shaderTypes[ndx], TEST_PRECISE_AS_ARGUMENT_NAME);
	}
	ctx.endSection();
}

} // anonymous

std::vector<FunctionContainer> getNegativePreciseTestFunctions (void)
{
	const FunctionContainer funcs[] =
	{
        {precise_as_variable_name,			"precise_as_variable_name",			"Test precise keyword as variable name."			},
        {precise_as_function_name,			"precise_as_function_name",			"Test precise keyword as function name."			},
        {precise_as_function_argument,		"precise_as_function_argument",		"Test precise keyword as argument name."			},
	};

	return std::vector<FunctionContainer>(DE_ARRAY_BEGIN(funcs), DE_ARRAY_END(funcs));
}

} // NegativeTestShared
} // Functional
} // gles31
} // deqp
<|endoftext|>