<commit_before>#include "ViewRobot.h"
#include <KrisLibrary/GLdraw/drawextra.h>
using namespace GLDraw;

const static GLColor grey(0.5,0.5,0.5);
const static GLColor red(1,0,0);
const static GLColor orange(1,0.5,0);
const static GLColor yellow(1,1,0);
const static GLColor purple(0.5,0,1);
const static GLColor lightpurple(0.75,0.5,1);
const static GLColor blue(0,0,1);

struct GLCheckeredSphere
{
  GLCheckeredSphere();
  void Draw();

  Real radius;
  Vector3 center;
  GLColor c1,c2;
  int numSlices,numStacks;
};

GLCheckeredSphere::GLCheckeredSphere()
  :radius(1),center(Zero),numSlices(16),numStacks(8)
{
  c1.set(1,1,1);
  c2.set(0,0,0);
}

//theta is the vertical range, phi is the rotational range
void DrawSphereArc(Real r,Real theta0,Real theta1,Real phi0,Real phi1,int numSlices,int numStacks)
{
  Real thetaInc = (theta1-theta0)/Real(numStacks);
  Real phiInc = (phi1-phi0)/Real(numSlices);
  Real phi=phi0;
  Real theta;
  for(int i=0;i<numSlices;i++,phi+=phiInc) {
    Real x1=Cos(phi);
    Real x2=Cos(phi+phiInc);
    Real y1=Sin(phi);
    Real y2=Sin(phi+phiInc);
    theta=theta0;
    glBegin(GL_TRIANGLE_STRIP);
    for(int j=0;j<=numStacks;j++,theta+=thetaInc) {
      Real cz=Cos(theta);
      Real sz=Sin(theta);
      glNormal3f(x2*sz,y2*sz,cz);
      glVertex3f(r*x2*sz,r*y2*sz,r*cz);
      glNormal3f(x1*sz,y1*sz,cz);
      glVertex3f(r*x1*sz,r*y1*sz,r*cz);
    }
    glEnd();
  }
}

void GLCheckeredSphere::Draw()
{
  glEnable(GL_LIGHTING);
  glPushMatrix();
  {
    glTranslate(center);
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,c1.rgba);
    DrawSphereArc(radius, 0,Pi_2,  0,Pi_2,    numSlices/4,numStacks/2);
    DrawSphereArc(radius, 0,Pi_2,  Pi,3*Pi_2, numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, Pi_2,Pi,   numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, 3*Pi_2,TwoPi,numSlices/4,numStacks/2);
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,c2.rgba);
    DrawSphereArc(radius, 0,Pi_2,  Pi_2,Pi,   numSlices/4,numStacks/2);
    DrawSphereArc(radius, 0,Pi_2,  3*Pi_2,TwoPi,numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, 0,Pi_2,    numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, Pi,3*Pi_2, numSlices/4,numStacks/2);
  }
  glPopMatrix();
}

ViewRobot::ViewRobot(Robot* _robot)
  :robot(_robot)
{
}

ViewRobot::~ViewRobot()
{
}

void ViewRobot::Draw(Robot* _robot)
{
  robot = _robot;
  if(!robot) return;
  Draw();
}

void ViewRobot::SetColors(const GLColor& c)
{
  if(robot) {
    for(size_t i=0;i<robot->links.size();i++) {
      GLDraw::GeometryAppearance& a = Appearance(i);
      a.SetColor(c);
    }
  }
}

void ViewRobot::SetColor(int link,const GLColor& c)
{
  if(robot) {
    GLDraw::GeometryAppearance& a = Appearance(link);
    a.SetColor(c);
  }
}

void ViewRobot::SetGrey() { SetColors(grey); }

void ViewRobot::Draw()
{
  if(!robot) return;

  for(size_t i=0;i<robot->links.size();i++) {
    if(robot->IsGeometryEmpty(i)) continue;
    Matrix4 mat = robot->links[i].T_World;
    glPushMatrix();
    glMultMatrix(mat);
    GLDraw::GeometryAppearance& a = Appearance(i);
    if(a.geom != robot->geometry[i].get()) {
      a.Set(*robot->geometry[i]);
    }
    a.DrawGL();
    glPopMatrix();
  }
}

void ViewRobot::DrawLink_Local(int i,bool keepAppearance)
{
  if(!robot || robot->IsGeometryEmpty(i)) return;
  if(keepAppearance) {
    GLDraw::GeometryAppearance& a = Appearance(i);
    if(a.geom != robot->geometry[i].get())
      a.Set(*robot->geometry[i]);
    a.DrawGL();
  }
  else
    draw(*robot->geometry[i]);
}

void ViewRobot::DrawLink_World(int i,bool keepAppearance)
{
  if(!robot) return;
  Matrix4 mat = robot->links[i].T_World;
  glPushMatrix();
  glMultMatrix(mat);
  DrawLink_Local(i,keepAppearance);
  glPopMatrix();
}

void ViewRobot::DrawCenterOfMass(Real radius)
{
  if(!robot) return;
  Vector3 com = robot->GetCOM();

  GLCheckeredSphere sph;
  sph.center = com;
  sph.radius = radius;
  sph.c1.set(1,0,0);
  sph.c2.set(0,0,1);
  sph.Draw();

  glDisable(GL_LIGHTING);
  glColor3f(0,0,1);
  glBegin(GL_LINES);
  glVertex3f(com.x,com.y,com.z);
  glVertex3f(com.x,com.y,0);
  glEnd();
}

void ViewRobot::DrawLinkCenterOfMass(int i,Real radius)
{
  Vector3 com = robot->links[i].T_World*robot->links[i].com;
  GLCheckeredSphere sph;
  sph.center = com;
  sph.radius = radius;
  sph.c1.set(1,0,0);
  sph.c2.set(0,0,1);
  sph.Draw();
}

void ViewRobot::DrawLinkFrames(Real size)
{
  if(!robot) return;
  glDisable(GL_LIGHTING);
  for(size_t i=0;i<robot->links.size();i++) {
    glPushMatrix();
    glMultMatrix((Matrix4)robot->links[i].T_World);
    drawCoords(size);
    glPopMatrix();
  }
}

void ViewRobot::DrawLinkSkeleton()
{
  if(!robot) return;
  glDisable(GL_LIGHTING);
  glColor3f(1,0.5,0);
  glLineWidth(3.0);
  glBegin(GL_LINES);
  for(size_t i=0;i<robot->links.size();i++) {
    if(robot->parents[i] >= 0) {
      glVertex3v(robot->links[robot->parents[i]].T_World.t);
      glVertex3v(robot->links[i].T_World.t);
    }
  }
  glEnd();
  glLineWidth(1.0);
}

void ViewRobot::DrawTorques(const Vector& T)
{
  SetTorqueColors(T);
  Draw();
}

inline void GetTorqueColor(Real t,GLColor& color)
{
  if(t < 0.5) color.set(0.5+t,0.5+t,0.5-t);
  else if(t < 0.75) color.set(1,2-2*t,0);
  else if(t < 1) color.set(1,2-2*t,0);
  else color.set(0.5,0,0);
}

inline bool EqualColor(const GLColor& a,const GLColor& b)
{
  for(int i=0;i<4;i++)
    if(a.rgba[i] != b.rgba[i]) return false;
  return true;
}

void ViewRobot::SetTorqueColors(const Vector& T)
{
  if(T.empty()) {
    SetColors(GLColor(1,0,1));
    return;
  }
  //draw torques
  Assert(T.n == (int)robot->links.size() || T.n == (int)robot->drivers.size());
  if(T.n == (int)robot->links.size()) {
    for(int i=0;i<T.n;i++) {
      GetTorqueColor(T[i],Appearance(i).faceColor);
    }
  }
  else {
    for(int i=0;i<T.n;i++) {
      GLColor c;
      GetTorqueColor(T[i],c);
      for(size_t k=0;k<robot->drivers[i].linkIndices.size();k++)
	Appearance(robot->drivers[i].linkIndices[k]).faceColor = c;
    }
  }
}

GLDraw::GeometryAppearance& ViewRobot::Appearance(int link)
{
  Assert(robot!=NULL);
  if(appearanceStack.empty()) {
    if(robot->geomManagers[link].IsAppearanceShared())
      robot->geomManagers[link].SetUniqueAppearance();
    return *robot->geomManagers[link].Appearance();
  }
  return appearanceStack.back()[link];
}

void ViewRobot::PushAppearance()
{
  if(robot==NULL) return;
  vector<GLDraw::GeometryAppearance> app(robot->links.size());
  for(size_t i=0;i<robot->links.size();i++) {
    app[i] = Appearance(i);
    if(Appearance(i).faceDisplayList)
      Assert(app[i].faceDisplayList);
  }
  appearanceStack.push_back(app);
}

void ViewRobot::PopAppearance()
{
  if(!appearanceStack.empty()) {
    //may want to copy back face display lists up the stack
    if(appearanceStack.size()==1) {
      for(size_t i=0;i<robot->links.size();i++) {
        if(!robot->geomManagers[i].Appearance()->faceDisplayList)
          robot->geomManagers[i].Appearance()->faceDisplayList = appearanceStack.back()[i].faceDisplayList;
        if(!robot->geomManagers[i].Appearance()->vertexDisplayList)
          robot->geomManagers[i].Appearance()->vertexDisplayList = appearanceStack.back()[i].vertexDisplayList;
      }
    }
    else {
      size_t n=appearanceStack.size()-2;
      for(size_t i=0;i<robot->links.size();i++) {
        if(!appearanceStack[n][i].faceDisplayList)
          appearanceStack[n][i].faceDisplayList = appearanceStack.back()[i].faceDisplayList;
        if(!appearanceStack[n][i].vertexDisplayList)
          appearanceStack[n][i].vertexDisplayList = appearanceStack.back()[i].vertexDisplayList;
      }
    }
    appearanceStack.resize(appearanceStack.size()-1);
  }
}
void ViewRobot::RestoreAppearance()

{
  appearanceStack.resize(0);
}

vector<GLDraw::GeometryAppearance> ViewRobot::GetAppearance()
{
  vector<GLDraw::GeometryAppearance> res;
  if(!robot) return res;
  res.resize(robot->links.size());
  for(size_t i=0;i<res.size();i++)
    res[i] = Appearance(i);
  return res;
}

void ViewRobot::SetAppearance(const vector<GLDraw::GeometryAppearance>& app)
{
  if(!robot) return;
  Assert(app.size()==robot->links.size());
  for(size_t i=0;i<app.size();i++) {
    Appearance(i) = app[i];
  }
}
<commit_msg>Performance fixes for new GeometryAppearance structure<commit_after>#include "ViewRobot.h"
#include <KrisLibrary/GLdraw/drawextra.h>
using namespace GLDraw;

const static GLColor grey(0.5,0.5,0.5);
const static GLColor red(1,0,0);
const static GLColor orange(1,0.5,0);
const static GLColor yellow(1,1,0);
const static GLColor purple(0.5,0,1);
const static GLColor lightpurple(0.75,0.5,1);
const static GLColor blue(0,0,1);

struct GLCheckeredSphere
{
  GLCheckeredSphere();
  void Draw();

  Real radius;
  Vector3 center;
  GLColor c1,c2;
  int numSlices,numStacks;
};

GLCheckeredSphere::GLCheckeredSphere()
  :radius(1),center(Zero),numSlices(16),numStacks(8)
{
  c1.set(1,1,1);
  c2.set(0,0,0);
}

//theta is the vertical range, phi is the rotational range
void DrawSphereArc(Real r,Real theta0,Real theta1,Real phi0,Real phi1,int numSlices,int numStacks)
{
  Real thetaInc = (theta1-theta0)/Real(numStacks);
  Real phiInc = (phi1-phi0)/Real(numSlices);
  Real phi=phi0;
  Real theta;
  for(int i=0;i<numSlices;i++,phi+=phiInc) {
    Real x1=Cos(phi);
    Real x2=Cos(phi+phiInc);
    Real y1=Sin(phi);
    Real y2=Sin(phi+phiInc);
    theta=theta0;
    glBegin(GL_TRIANGLE_STRIP);
    for(int j=0;j<=numStacks;j++,theta+=thetaInc) {
      Real cz=Cos(theta);
      Real sz=Sin(theta);
      glNormal3f(x2*sz,y2*sz,cz);
      glVertex3f(r*x2*sz,r*y2*sz,r*cz);
      glNormal3f(x1*sz,y1*sz,cz);
      glVertex3f(r*x1*sz,r*y1*sz,r*cz);
    }
    glEnd();
  }
}

void GLCheckeredSphere::Draw()
{
  glEnable(GL_LIGHTING);
  glPushMatrix();
  {
    glTranslate(center);
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,c1.rgba);
    DrawSphereArc(radius, 0,Pi_2,  0,Pi_2,    numSlices/4,numStacks/2);
    DrawSphereArc(radius, 0,Pi_2,  Pi,3*Pi_2, numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, Pi_2,Pi,   numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, 3*Pi_2,TwoPi,numSlices/4,numStacks/2);
    glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,c2.rgba);
    DrawSphereArc(radius, 0,Pi_2,  Pi_2,Pi,   numSlices/4,numStacks/2);
    DrawSphereArc(radius, 0,Pi_2,  3*Pi_2,TwoPi,numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, 0,Pi_2,    numSlices/4,numStacks/2);
    DrawSphereArc(radius, Pi_2,Pi, Pi,3*Pi_2, numSlices/4,numStacks/2);
  }
  glPopMatrix();
}

ViewRobot::ViewRobot(Robot* _robot)
  :robot(_robot)
{
}

ViewRobot::~ViewRobot()
{
}

void ViewRobot::Draw(Robot* _robot)
{
  robot = _robot;
  if(!robot) return;
  Draw();
}

void ViewRobot::SetColors(const GLColor& c)
{
  if(robot) {
    for(size_t i=0;i<robot->links.size();i++) {
      GLDraw::GeometryAppearance& a = Appearance(i);
      a.SetColor(c);
    }
  }
}

void ViewRobot::SetColor(int link,const GLColor& c)
{
  if(robot) {
    GLDraw::GeometryAppearance& a = Appearance(link);
    a.SetColor(c);
  }
}

void ViewRobot::SetGrey() { SetColors(grey); }

void ViewRobot::Draw()
{
  if(!robot) return;

  for(size_t i=0;i<robot->links.size();i++) {
    if(robot->IsGeometryEmpty(i)) continue;
    Matrix4 mat = robot->links[i].T_World;
    glPushMatrix();
    glMultMatrix(mat);
    GLDraw::GeometryAppearance& a = Appearance(i);
    if(a.geom != robot->geometry[i].get()) {
      a.Set(*robot->geometry[i]);
    }
    a.DrawGL();
    glPopMatrix();
  }
}

void ViewRobot::DrawLink_Local(int i,bool keepAppearance)
{
  if(!robot || robot->IsGeometryEmpty(i)) return;
  if(keepAppearance) {
    GLDraw::GeometryAppearance& a = Appearance(i);
    if(a.geom != robot->geometry[i].get())
      a.Set(*robot->geometry[i]);
    a.DrawGL();
  }
  else
    draw(*robot->geometry[i]);
}

void ViewRobot::DrawLink_World(int i,bool keepAppearance)
{
  if(!robot) return;
  Matrix4 mat = robot->links[i].T_World;
  glPushMatrix();
  glMultMatrix(mat);
  DrawLink_Local(i,keepAppearance);
  glPopMatrix();
}

void ViewRobot::DrawCenterOfMass(Real radius)
{
  if(!robot) return;
  Vector3 com = robot->GetCOM();

  GLCheckeredSphere sph;
  sph.center = com;
  sph.radius = radius;
  sph.c1.set(1,0,0);
  sph.c2.set(0,0,1);
  sph.Draw();

  glDisable(GL_LIGHTING);
  glColor3f(0,0,1);
  glBegin(GL_LINES);
  glVertex3f(com.x,com.y,com.z);
  glVertex3f(com.x,com.y,0);
  glEnd();
}

void ViewRobot::DrawLinkCenterOfMass(int i,Real radius)
{
  Vector3 com = robot->links[i].T_World*robot->links[i].com;
  GLCheckeredSphere sph;
  sph.center = com;
  sph.radius = radius;
  sph.c1.set(1,0,0);
  sph.c2.set(0,0,1);
  sph.Draw();
}

void ViewRobot::DrawLinkFrames(Real size)
{
  if(!robot) return;
  glDisable(GL_LIGHTING);
  for(size_t i=0;i<robot->links.size();i++) {
    glPushMatrix();
    glMultMatrix((Matrix4)robot->links[i].T_World);
    drawCoords(size);
    glPopMatrix();
  }
}

void ViewRobot::DrawLinkSkeleton()
{
  if(!robot) return;
  glDisable(GL_LIGHTING);
  glColor3f(1,0.5,0);
  glLineWidth(3.0);
  glBegin(GL_LINES);
  for(size_t i=0;i<robot->links.size();i++) {
    if(robot->parents[i] >= 0) {
      glVertex3v(robot->links[robot->parents[i]].T_World.t);
      glVertex3v(robot->links[i].T_World.t);
    }
  }
  glEnd();
  glLineWidth(1.0);
}

void ViewRobot::DrawTorques(const Vector& T)
{
  SetTorqueColors(T);
  Draw();
}

inline void GetTorqueColor(Real t,GLColor& color)
{
  if(t < 0.5) color.set(0.5+t,0.5+t,0.5-t);
  else if(t < 0.75) color.set(1,2-2*t,0);
  else if(t < 1) color.set(1,2-2*t,0);
  else color.set(0.5,0,0);
}

inline bool EqualColor(const GLColor& a,const GLColor& b)
{
  for(int i=0;i<4;i++)
    if(a.rgba[i] != b.rgba[i]) return false;
  return true;
}

void ViewRobot::SetTorqueColors(const Vector& T)
{
  if(T.empty()) {
    SetColors(GLColor(1,0,1));
    return;
  }
  //draw torques
  Assert(T.n == (int)robot->links.size() || T.n == (int)robot->drivers.size());
  if(T.n == (int)robot->links.size()) {
    for(int i=0;i<T.n;i++) {
      GetTorqueColor(T[i],Appearance(i).faceColor);
    }
  }
  else {
    for(int i=0;i<T.n;i++) {
      GLColor c;
      GetTorqueColor(T[i],c);
      for(size_t k=0;k<robot->drivers[i].linkIndices.size();k++)
	Appearance(robot->drivers[i].linkIndices[k]).faceColor = c;
    }
  }
}

GLDraw::GeometryAppearance& ViewRobot::Appearance(int link)
{
  Assert(robot!=NULL);
  if(appearanceStack.empty()) {
    if(robot->geomManagers[link].IsAppearanceShared())
      robot->geomManagers[link].SetUniqueAppearance();
    return *robot->geomManagers[link].Appearance();
  }
  return appearanceStack.back()[link];
}

void ViewRobot::PushAppearance()
{
  if(robot==NULL) return;
  vector<GLDraw::GeometryAppearance> app(robot->links.size());
  for(size_t i=0;i<robot->links.size();i++) {
    app[i] = Appearance(i);
    if(Appearance(i).faceDisplayList)
      Assert(app[i].faceDisplayList);
  }
  appearanceStack.push_back(app);
}

void ViewRobot::PopAppearance()
{
  if(!appearanceStack.empty()) {
    //may want to copy back face display lists up the stack
    if(appearanceStack.size()==1) {
      for(size_t i=0;i<robot->links.size();i++) {
        if(!robot->geomManagers[i].Appearance()->faceDisplayList)
          robot->geomManagers[i].Appearance()->faceDisplayList = appearanceStack.back()[i].faceDisplayList;
        if(!robot->geomManagers[i].Appearance()->edgeDisplayList)
          robot->geomManagers[i].Appearance()->edgeDisplayList = appearanceStack.back()[i].edgeDisplayList;
        if(!robot->geomManagers[i].Appearance()->vertexDisplayList)
          robot->geomManagers[i].Appearance()->vertexDisplayList = appearanceStack.back()[i].vertexDisplayList;
        if(!robot->geomManagers[i].Appearance()->silhouetteDisplayList)
          robot->geomManagers[i].Appearance()->silhouetteDisplayList = appearanceStack.back()[i].silhouetteDisplayList;
        if(!robot->geomManagers[i].Appearance()->tempMesh)
          robot->geomManagers[i].Appearance()->tempMesh = appearanceStack.back()[i].tempMesh;
        if(!robot->geomManagers[i].Appearance()->tempMesh2)
          robot->geomManagers[i].Appearance()->tempMesh2 = appearanceStack.back()[i].tempMesh2;
      }
    }
    else {
      size_t n=appearanceStack.size()-2;
      for(size_t i=0;i<robot->links.size();i++) {
        if(!appearanceStack[n][i].faceDisplayList)
          appearanceStack[n][i].faceDisplayList = appearanceStack.back()[i].faceDisplayList;
        if(!appearanceStack[n][i].edgeDisplayList)
          appearanceStack[n][i].edgeDisplayList = appearanceStack.back()[i].edgeDisplayList;
        if(!appearanceStack[n][i].vertexDisplayList)
          appearanceStack[n][i].vertexDisplayList = appearanceStack.back()[i].vertexDisplayList;
        if(!appearanceStack[n][i].silhouetteDisplayList)
          appearanceStack[n][i].silhouetteDisplayList = appearanceStack.back()[i].silhouetteDisplayList;
        if(!appearanceStack[n][i].tempMesh)
          appearanceStack[n][i].tempMesh = appearanceStack.back()[i].tempMesh;
        if(!appearanceStack[n][i].tempMesh2)
          appearanceStack[n][i].tempMesh2 = appearanceStack.back()[i].tempMesh2;
      }
    }
    appearanceStack.resize(appearanceStack.size()-1);
  }
}
void ViewRobot::RestoreAppearance()

{
  appearanceStack.resize(0);
}

vector<GLDraw::GeometryAppearance> ViewRobot::GetAppearance()
{
  vector<GLDraw::GeometryAppearance> res;
  if(!robot) return res;
  res.resize(robot->links.size());
  for(size_t i=0;i<res.size();i++)
    res[i] = Appearance(i);
  return res;
}

void ViewRobot::SetAppearance(const vector<GLDraw::GeometryAppearance>& app)
{
  if(!robot) return;
  Assert(app.size()==robot->links.size());
  for(size_t i=0;i<app.size();i++) {
    Appearance(i) = app[i];
  }
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <getopt.h>             /* getopt_long() */

#include <fcntl.h>              /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>

#include <linux/videodev2.h>

#include <GLFW/glfw3.h>

#include <vector>

static void errno_exit(const char *s)
{
        fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
        exit(EXIT_FAILURE);
}

static int xioctl(int fh, int request, void *arg)
{
        int r;

        do {
                r = ioctl(fh, request, arg);
        } while (-1 == r && EINTR == errno);

        return r;
}

struct buffer { void * start; size_t length; };
#pragma pack(push, 1)
struct z16y8_pixel { uint16_t z; uint8_t y; };
#pragma pack(pop)

int main(int argc, char * argv[])
{
    char            *dev_name = "/dev/video1";
    int              fd = -1;
    std::vector<buffer> buffers;
    //buffer          *buffers = 0;
    //unsigned int     n_buffers = 0;
    int              force_format = 0;

    struct stat st;
    if (stat(dev_name, &st) < 0)
    {
        fprintf(stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror(errno));
        return EXIT_FAILURE;
    }

    if (!S_ISCHR(st.st_mode))
    {
        fprintf(stderr, "%s is no device\n", dev_name);
        return EXIT_FAILURE;
    }

    fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);

    if (-1 == fd) {
            fprintf(stderr, "Cannot open '%s': %d, %s\n",
                     dev_name, errno, strerror(errno));
            exit(EXIT_FAILURE);
    }

    v4l2_capability cap = {};
    if(xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
    {
        if (EINVAL == errno) {
                fprintf(stderr, "%s is no V4L2 device\n",
                         dev_name);
                exit(EXIT_FAILURE);
        } else {
                errno_exit("VIDIOC_QUERYCAP");
        }
    }

    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
            fprintf(stderr, "%s is no video capture device\n",
                     dev_name);
            exit(EXIT_FAILURE);
    }

    if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
            fprintf(stderr, "%s does not support streaming i/o\n",
                     dev_name);
            exit(EXIT_FAILURE);
    }

    // Select video input, video standard and tune here.
    v4l2_cropcap cropcap = {};
    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap))
    {
        v4l2_crop crop = {};
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        crop.c = cropcap.defrect; // reset to default
        if (xioctl(fd, VIDIOC_S_CROP, &crop) < 0)
        {
            switch (errno)
            {
            case EINVAL: break; // Cropping not supported
            default: break; // Errors ignored
            }
        }
    } else {} // Errors ignored

    v4l2_format fmt = {};
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (force_format)
    {
        fmt.fmt.pix.width       = 640;
        fmt.fmt.pix.height      = 480;
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
        if(xioctl(fd, VIDIOC_S_FMT, &fmt) < 0) errno_exit("VIDIOC_S_FMT");
        // Note VIDIOC_S_FMT may change width and height
    }
    else
    {
        // Preserve original settings as set by v4l2-ctl for example
        if(xioctl(fd, VIDIOC_G_FMT, &fmt) < 0) errno_exit("VIDIOC_G_FMT");
    }

    // Buggy driver paranoia.
    unsigned int min = fmt.fmt.pix.width * 2;
    if (fmt.fmt.pix.bytesperline < min)
            fmt.fmt.pix.bytesperline = min;
    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
    if (fmt.fmt.pix.sizeimage < min)
            fmt.fmt.pix.sizeimage = min;

    // Init memory mapped IO

    v4l2_requestbuffers req = {};
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if(xioctl(fd, VIDIOC_REQBUFS, &req) < 0)
    {
        if (EINVAL == errno) {
                fprintf(stderr, "%s does not support "
                         "memory mapping\n", dev_name);
                exit(EXIT_FAILURE);
        } else {
                errno_exit("VIDIOC_REQBUFS");
        }
    }

    if (req.count < 2) {
        fprintf(stderr, "Insufficient buffer memory on %s\n",
                 dev_name);
        exit(EXIT_FAILURE);
    }

    buffers.resize(req.count);
    for(int i=0; i<buffers.size(); ++i)
    {
        v4l2_buffer buf = {};
        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory      = V4L2_MEMORY_MMAP;
        buf.index       = i;
        if(xioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) errno_exit("VIDIOC_QUERYBUF");

        buffers[i].length = buf.length;
        buffers[i].start = mmap(NULL /* start anywhere */,
                      buf.length,
                      PROT_READ | PROT_WRITE /* required */,
                      MAP_SHARED /* recommended */,
                      fd, buf.m.offset);
        if (MAP_FAILED == buffers[i].start)
                errno_exit("mmap");
    }

    // Start capturing
    for(int i = 0; i < buffers.size(); ++i)
    {
        v4l2_buffer buf = {};
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        if(xioctl(fd, VIDIOC_QBUF, &buf) < 0) errno_exit("VIDIOC_QBUF");
    }

    v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(xioctl(fd, VIDIOC_STREAMON, &type) < 0) errno_exit("VIDIOC_STREAMON");

    // Open a GLFW window
    glfwInit();
    GLFWwindow * win = glfwCreateWindow(640, 480, "V4L2 test", 0, 0);
    glfwMakeContextCurrent(win);

    // While window is open
    while (!glfwWindowShouldClose(win))
    {
        glfwPollEvents();

        int w,h;
        glfwGetFramebufferSize(win, &w, &h);
        glViewport(0, 0, w, h);
        glClear(GL_COLOR_BUFFER_BIT);

        glPushMatrix();
        glfwGetWindowSize(win, &w, &h);
        glOrtho(0, w, h, 0, -1, +1);
        for (;;)
        {
            fd_set fds;
            struct timeval tv;
            int r;

            FD_ZERO(&fds);
            FD_SET(fd, &fds);

            /* Timeout. */
            tv.tv_sec = 2;
            tv.tv_usec = 0;

            r = select(fd + 1, &fds, NULL, NULL, &tv);

            if (-1 == r) {
                    if (EINTR == errno)
                            continue;
                    errno_exit("select");
            }

            if (0 == r) {
                    fprintf(stderr, "select timeout\n");
                    exit(EXIT_FAILURE);
            }

            v4l2_buffer buf = {};
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory = V4L2_MEMORY_MMAP;
            if(xioctl(fd, VIDIOC_DQBUF, &buf) < 0)
            {
                if(errno == EAGAIN) continue;
                errno_exit("VIDIOC_DQBUF");
            }
            assert(buf.index < buffers.size());

            uint16_t z[320*240]; uint8_t y[320*240];
            auto in = reinterpret_cast<const z16y8_pixel *>(buffers[buf.index].start);
            for(int i=0; i<320*240; ++i)
            {
                z[i] = in[i].z;
                y[i] = in[i].y;
            }

            glRasterPos2i(0, 240);
            glDrawPixels(320, 240, GL_LUMINANCE, GL_UNSIGNED_SHORT, z);
            glRasterPos2i(320, 240);
            glDrawPixels(320, 240, GL_LUMINANCE, GL_UNSIGNED_BYTE, y);
            printf("%d %d\n", buf.bytesused, 320*240*3);

            if(xioctl(fd, VIDIOC_QBUF, &buf) < 0) errno_exit("VIDIOC_QBUF");
            break;
        }

        glPopMatrix();
        glfwSwapBuffers(win);
    }
    glfwDestroyWindow(win);
    glfwTerminate();

    if(xioctl(fd, VIDIOC_STREAMOFF, &type) < 0) errno_exit("VIDIOC_STREAMOFF");

    for(int i = 0; i < buffers.size(); ++i)
    {
        if(munmap(buffers[i].start, buffers[i].length) < 0) errno_exit("munmap");
    }

    if(close(fd) < 0) errno_exit("close");

    return EXIT_SUCCESS;
}

<commit_msg>Formatting changes<commit_after>#include <cassert>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>

#include <GLFW/glfw3.h>

#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>

static void errno_exit(const char *s)
{
        fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno));
        exit(EXIT_FAILURE);
}

static int xioctl(int fh, int request, void *arg)
{
        int r;

        do {
                r = ioctl(fh, request, arg);
        } while (-1 == r && EINTR == errno);

        return r;
}

struct buffer { void * start; size_t length; };
#pragma pack(push, 1)
struct z16y8_pixel { uint16_t z; uint8_t y; };
#pragma pack(pop)

int main(int argc, char * argv[])
{
    const char * dev_name = "/dev/video1";
    struct stat st;
    if(stat(dev_name, &st) < 0)
    {
        fprintf(stderr, "Cannot identify '%s': %d, %s\n", dev_name, errno, strerror(errno));
        return EXIT_FAILURE;
    }
    if(!S_ISCHR(st.st_mode))
    {
        fprintf(stderr, "%s is no device\n", dev_name);
        return EXIT_FAILURE;
    }

    int fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
    if(fd < 0)
    {
        fprintf(stderr, "Cannot open '%s': %d, %s\n", dev_name, errno, strerror(errno));
        return EXIT_FAILURE;
    }

    v4l2_capability cap = {};
    if(xioctl(fd, VIDIOC_QUERYCAP, &cap) < 0)
    {
        if (EINVAL == errno)
        {
            fprintf(stderr, "%s is no V4L2 device\n", dev_name);
            return EXIT_FAILURE;
        }
        else errno_exit("VIDIOC_QUERYCAP");
    }

    if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
    {
        fprintf(stderr, "%s is no video capture device\n", dev_name);
        return EXIT_FAILURE;
    }

    if (!(cap.capabilities & V4L2_CAP_STREAMING))
    {
        fprintf(stderr, "%s does not support streaming i/o\n", dev_name);
        return EXIT_FAILURE;
    }

    // Select video input, video standard and tune here.
    v4l2_cropcap cropcap = {};
    cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap))
    {
        v4l2_crop crop = {};
        crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        crop.c = cropcap.defrect; // reset to default
        if (xioctl(fd, VIDIOC_S_CROP, &crop) < 0)
        {
            switch (errno)
            {
            case EINVAL: break; // Cropping not supported
            default: break; // Errors ignored
            }
        }
    } else {} // Errors ignored

    v4l2_format fmt = {};
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(false) // Force format?
    {
        fmt.fmt.pix.width       = 640;
        fmt.fmt.pix.height      = 480;
        fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
        fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
        if(xioctl(fd, VIDIOC_S_FMT, &fmt) < 0) errno_exit("VIDIOC_S_FMT");
        // Note VIDIOC_S_FMT may change width and height
    }
    else
    {
        // Preserve original settings as set by v4l2-ctl for example
        if(xioctl(fd, VIDIOC_G_FMT, &fmt) < 0) errno_exit("VIDIOC_G_FMT");
    }

    // Buggy driver paranoia.
    unsigned int min = fmt.fmt.pix.width * 2;
    if(fmt.fmt.pix.bytesperline < min) fmt.fmt.pix.bytesperline = min;
    min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
    if(fmt.fmt.pix.sizeimage < min) fmt.fmt.pix.sizeimage = min;

    // Init memory mapped IO
    v4l2_requestbuffers req = {};
    req.count = 4;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if(xioctl(fd, VIDIOC_REQBUFS, &req) < 0)
    {
        if(errno == EINVAL)
        {
            fprintf(stderr, "%s does not support memory mapping\n", dev_name);
            return EXIT_FAILURE;
        }
        else errno_exit("VIDIOC_REQBUFS");
    }
    if(req.count < 2)
    {
        fprintf(stderr, "Insufficient buffer memory on %s\n", dev_name);
        return EXIT_FAILURE;
    }

    std::vector<buffer> buffers(req.count);
    for(int i=0; i<buffers.size(); ++i)
    {
        v4l2_buffer buf = {};
        buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory      = V4L2_MEMORY_MMAP;
        buf.index       = i;
        if(xioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) errno_exit("VIDIOC_QUERYBUF");

        buffers[i].length = buf.length;
        buffers[i].start = mmap(NULL /* start anywhere */,
                      buf.length,
                      PROT_READ | PROT_WRITE /* required */,
                      MAP_SHARED /* recommended */,
                      fd, buf.m.offset);
        if(buffers[i].start == MAP_FAILED) errno_exit("mmap");
    }

    // Start capturing
    for(int i = 0; i < buffers.size(); ++i)
    {
        v4l2_buffer buf = {};
        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        buf.memory = V4L2_MEMORY_MMAP;
        buf.index = i;
        if(xioctl(fd, VIDIOC_QBUF, &buf) < 0) errno_exit("VIDIOC_QBUF");
    }

    v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if(xioctl(fd, VIDIOC_STREAMON, &type) < 0) errno_exit("VIDIOC_STREAMON");

    // Open a GLFW window
    glfwInit();
    GLFWwindow * win = glfwCreateWindow(640, 480, "V4L2 test", 0, 0);
    glfwMakeContextCurrent(win);

    // While window is open
    while (!glfwWindowShouldClose(win))
    {
        glfwPollEvents();

        int w,h;
        glfwGetFramebufferSize(win, &w, &h);
        glViewport(0, 0, w, h);
        glClear(GL_COLOR_BUFFER_BIT);

        glPushMatrix();
        glfwGetWindowSize(win, &w, &h);
        glOrtho(0, w, h, 0, -1, +1);
        for (;;)
        {
            fd_set fds;
            struct timeval tv;
            int r;

            FD_ZERO(&fds);
            FD_SET(fd, &fds);

            /* Timeout. */
            tv.tv_sec = 2;
            tv.tv_usec = 0;

            r = select(fd + 1, &fds, NULL, NULL, &tv);

            if (-1 == r) {
                    if (EINTR == errno)
                            continue;
                    errno_exit("select");
            }

            if (0 == r) {
                    fprintf(stderr, "select timeout\n");
                    exit(EXIT_FAILURE);
            }

            v4l2_buffer buf = {};
            buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            buf.memory = V4L2_MEMORY_MMAP;
            if(xioctl(fd, VIDIOC_DQBUF, &buf) < 0)
            {
                if(errno == EAGAIN) continue;
                errno_exit("VIDIOC_DQBUF");
            }
            assert(buf.index < buffers.size());

            uint16_t z[320*240]; uint8_t y[320*240];
            auto in = reinterpret_cast<const z16y8_pixel *>(buffers[buf.index].start);
            for(int i=0; i<320*240; ++i)
            {
                z[i] = in[i].z;
                y[i] = in[i].y;
            }

            glRasterPos2i(0, 240);
            glDrawPixels(320, 240, GL_LUMINANCE, GL_UNSIGNED_SHORT, z);
            glRasterPos2i(320, 240);
            glDrawPixels(320, 240, GL_LUMINANCE, GL_UNSIGNED_BYTE, y);
            printf("%d %d\n", buf.bytesused, 320*240*3);

            if(xioctl(fd, VIDIOC_QBUF, &buf) < 0) errno_exit("VIDIOC_QBUF");
            break;
        }

        glPopMatrix();
        glfwSwapBuffers(win);
    }
    glfwDestroyWindow(win);
    glfwTerminate();

    if(xioctl(fd, VIDIOC_STREAMOFF, &type) < 0) errno_exit("VIDIOC_STREAMOFF");

    for(int i = 0; i < buffers.size(); ++i)
    {
        if(munmap(buffers[i].start, buffers[i].length) < 0) errno_exit("munmap");
    }

    if(close(fd) < 0) errno_exit("close");

    return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#pragma once

#include "Communicator.hpp"
#include "CompletionEvent.hpp"
#include "Tasking.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "Delegate.hpp"
#include "Collective.hpp"
#include "Timestamp.hpp"
#include <type_traits>

namespace Grappa {

/// GlobalCompletionEvent (GCE):
/// Synchronization construct for determining when a global phase of asynchronous tasks have all completed.
/// For example, can be used to ensure that all tasks of a parallel loop have completed, including tasks or asynchronous delegates spawned during execution of the parallel loop.
///
/// A GlobalCompletionEvent must be replicated at the same address on all cores (the easiest way is to declare it as file-global or static storage).
///
/// Anyone calling "wait" after at least some work has been "enrolled" globally will block. When *all* work has been completed on all cores, all tasks waiting on the GCE will be woken.
///
/// To ensure consistent behavior and guarantee deadlock freedom, every "enroll" must be causally followed by "complete", so either must be completed from the same task that called "enroll" or from a task spawned (transitively) from the enrolling task.
class GlobalCompletionEvent : public CompletionEvent {
  // All nodes
  // (count)
  // (cv)
  bool event_in_progress;
  Core master_core;

  // Master barrier only
  Core cores_out;

  /// pointer to shared arg for loops that use a GCE
  const void * shared_ptr;

public:

  GlobalCompletionEvent(): master_core(0) { reset(); }

  inline void set_shared_ptr(const void* p) { shared_ptr = p; }
  template<typename T> inline const T* get_shared_ptr() { return reinterpret_cast<const T*>(shared_ptr); }

  /// SPMD (either all cores call this following a barrier, or use `reset_all` from one task,
  /// then spawn parallel work)
  void reset() {
    count = 0;
    cv.waiters_ = 0;
    cores_out = 0;
    event_in_progress = false;
  }

  /// Called from single task (probably `user_main`).
  void reset_all() {
    call_on_all_cores([this]{ reset(); });
  }

  /// Enroll more things that need to be completed before the global completion is, well, complete.
  /// This will send a cancel to the master if this core previously entered the cancellable barrier.
  ///
  /// Blocks until cancel completes (if it must cancel) to ensure correct ordering, therefore
  /// cannot be called from message handler (but I don't think we ever do).
  void enroll(int64_t inc = 1) {
    if (inc == 0) return;

    CHECK_GE(inc, 1);
    count += inc;

    // first one to have work here
    if (count == inc) { // count[0 -> inc]
      event_in_progress = true; // optimization to save checking in wait()
      // cancel barrier
      Core co = delegate::call(master_core, [this] {
        cores_out++;
        return cores_out;
      });
      // first one to cancel barrier should make sure other cores are ready to wait
      if (co == 1) { // cores_out[0 -> 1]
        event_in_progress = true;
        call_on_all_cores([this] {
          event_in_progress = true;
        });
        CHECK(event_in_progress);
      }
      // block until cancelled
      CHECK_GT(count, 0);
      VLOG(2) << "cores_out: " << co << ", count: " << count;
    }
  }

  /// Mark a certain number of things completed. When the global count on all cores goes to 0, all
  /// tasks waiting on the GCE will be woken.
  ///
  /// Note: this can be called in a message handler (e.g. remote completes from stolen tasks).
  void complete(int64_t dec = 1) {
    count -= dec;
    DVLOG(4) << "complete (" << count << ") -- " << this;

    // out of work here
    if (count == 0) { // count[dec -> 0]
      // enter cancellable barrier
      send_heap_message(master_core, [this] {
        cores_out--;

        // if all are in
        if (cores_out == 0) { // cores_out[1 -> 0]
          CHECK_EQ(count, 0);
          // notify everyone to wake
          for (Core c = 0; c < cores(); c++) {
            send_heap_message(c, [this] {
              CHECK_EQ(count, 0);
              broadcast(&cv); // wake anyone who was waiting here
              reset(); // reset, now anyone else calling `wait` should fall through
            });
          }
        }
      });
    }
  }

  void wait() {
    VLOG(3) << "wait(): event_in_progress: " << event_in_progress << ", count: " << count;
    if (event_in_progress) {
      Grappa::wait(&cv);
    } else {
      // conservative check, in case we're calling `wait` without calling `enroll`
      if (delegate::call(master_core, [this]{ return cores_out; }) > 0) {
//      if (delegate::call(master_core, [this]{ return event_in_progress; })) {
        Grappa::wait(&cv);
        VLOG(3) << "woke from conservative check";
      }
      VLOG(3) << "fell thru conservative check";
    }
    CHECK(!event_in_progress);
    CHECK_EQ(count, 0);
  }

};

} // namespace Grappa

/// Synchronizing delegates
namespace Grappa {
  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  template<typename TF>
  void privateTask(GlobalCompletionEvent * gce, TF tf) {
    gce->enroll();
    privateTask([gce,tf] {
      tf();
      gce->complete();
    });
  }

  template<GlobalCompletionEvent * GCE, typename TF>
  void privateTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    privateTask([tf] {
      tf();
      if (GCE) GCE->complete();
    });
  }

  /// Synchronizing public task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// sends `complete`  message when done (if GCE is non-null).
  template<GlobalCompletionEvent * GCE, typename TF>
  inline void publicTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    publicTask([origin,tf] {
      tf();
      if (GCE) complete(make_global(GCE,origin));
    });
  }

} // namespace Grappa
<commit_msg>Update documentation of GlobalCompletionEvent.<commit_after>#pragma once

#include "Communicator.hpp"
#include "CompletionEvent.hpp"
#include "Tasking.hpp"
#include "Message.hpp"
#include "MessagePool.hpp"
#include "Delegate.hpp"
#include "Collective.hpp"
#include "Timestamp.hpp"
#include <type_traits>

namespace Grappa {

/// GlobalCompletionEvent (GCE):
/// Synchronization construct for determining when a global phase of asynchronous tasks have
/// all completed. For example, can be used to ensure that all tasks of a parallel loop have
/// completed, including tasks or asynchronous delegates spawned during execution of the
/// parallel loop.
///
/// A GlobalCompletionEvent must be replicated at the same address on all cores (the easiest
/// way is to declare it as file-global or static storage). TODO: allow dynamic allocation
/// in Grappa linear address space.
///
/// Anyone calling "wait" after at least some work has been "enrolled" globally will block.
/// When *all* work has been completed on all cores, all tasks waiting on the GCE will be woken.
///
/// To ensure consistent behavior and guarantee deadlock freedom, every "enroll" must be
/// causally followed by "complete", so either must be completed from the same task that
/// called "enroll" or from a task spawned (transitively) from the enrolling task.
///
/// This is meant to be a reusable barrier; GCE's should begin in a state where a call to
/// `wait` will fall through, and end up, after all tasks are completed, back in the same
/// state. Note: `reset` no longer needs to be called between phases. Instead, it just
/// must be guaranteed that at least one task has been enrolled before anyone tries to
/// call `wait` otherwise they may fall through before the enrollment has completed.
class GlobalCompletionEvent : public CompletionEvent {
  // All nodes
  // (count)
  // (cv)
  bool event_in_progress;
  Core master_core;

  // Master barrier only
  Core cores_out;

  /// pointer to shared arg for loops that use a GCE
  const void * shared_ptr;

public:

  GlobalCompletionEvent(): master_core(0) { reset(); }

  inline void set_shared_ptr(const void* p) { shared_ptr = p; }
  template<typename T> inline const T* get_shared_ptr() { return reinterpret_cast<const T*>(shared_ptr); }

  /// This is the state the GCE's on each core should be in at the beginning, and the
  /// state they should end up in after a Completion phase. I should no longer be necessary
  /// to call `reset` between calls to `wait` as long as nothing fishy is going on.
  void reset() {
    count = 0;
    cv.waiters_ = 0;
    cores_out = 0;
    event_in_progress = false;
  }

  /// Enroll more things that need to be completed before the global completion is, well, complete.
  /// This will send a cancel to the master if this core previously entered the cancellable barrier.
  ///
  /// Blocks until cancel completes (if it must cancel) to ensure correct ordering, therefore
  /// cannot be called from message handler.
  void enroll(int64_t inc = 1) {
    if (inc == 0) return;

    CHECK_GE(inc, 1);
    count += inc;

    // first one to have work here
    if (count == inc) { // count[0 -> inc]
      event_in_progress = true; // optimization to save checking in wait()
      // cancel barrier
      Core co = delegate::call(master_core, [this] {
        cores_out++;
        return cores_out;
      });
      // first one to cancel barrier should make sure other cores are ready to wait
      if (co == 1) { // cores_out[0 -> 1]
        event_in_progress = true;
        call_on_all_cores([this] {
          event_in_progress = true;
        });
        CHECK(event_in_progress);
      }
      // block until cancelled
      CHECK_GT(count, 0);
      VLOG(2) << "cores_out: " << co << ", count: " << count;
    }
  }

  /// Mark a certain number of things completed. When the global count on all cores goes to 0, all
  /// tasks waiting on the GCE will be woken.
  ///
  /// Note: this can be called in a message handler (e.g. remote completes from stolen tasks).
  void complete(int64_t dec = 1) {
    count -= dec;
    DVLOG(4) << "complete (" << count << ") -- " << this;

    // out of work here
    if (count == 0) { // count[dec -> 0]
      // enter cancellable barrier
      send_heap_message(master_core, [this] {
        cores_out--;

        // if all are in
        if (cores_out == 0) { // cores_out[1 -> 0]
          CHECK_EQ(count, 0);
          // notify everyone to wake
          for (Core c = 0; c < cores(); c++) {
            send_heap_message(c, [this] {
              CHECK_EQ(count, 0);
              broadcast(&cv); // wake anyone who was waiting here
              reset(); // reset, now anyone else calling `wait` should fall through
            });
          }
        }
      });
    }
  }

  /// Suspend calling task until all tasks completed (including additional tasks enrolled
  /// before count goes to 0). This can be called from as many tasks as desired on
  /// different cores, as long as it is ensured that a task in the desired phase has been
  /// enrolled before wait is called.
  ///
  /// If no tasks have been enrolled, or all have been completed by the time `wait` is called,
  /// this will fall through and not suspend the calling task.
  void wait() {
    VLOG(3) << "wait(): event_in_progress: " << event_in_progress << ", count: " << count;
    if (event_in_progress) {
      Grappa::wait(&cv);
    } else {
      // conservative check, in case we're calling `wait` without calling `enroll`
      if (delegate::call(master_core, [this]{ return cores_out; }) > 0) {
//      if (delegate::call(master_core, [this]{ return event_in_progress; })) {
        Grappa::wait(&cv);
        VLOG(3) << "woke from conservative check";
      }
      VLOG(3) << "fell thru conservative check";
    }
    CHECK(!event_in_progress);
    CHECK_EQ(count, 0);
  }

};

} // namespace Grappa

/// Synchronizing delegates
namespace Grappa {
  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  template<typename TF>
  void privateTask(GlobalCompletionEvent * gce, TF tf) {
    gce->enroll();
    privateTask([gce,tf] {
      tf();
      gce->complete();
    });
  }

  /// Synchronizing private task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// does local `complete` when done (if GCE is non-null).
  /// In this version, GCE is a template parameter to avoid taking up space in the task's args.
  template<GlobalCompletionEvent * GCE, typename TF>
  void privateTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    privateTask([tf] {
      tf();
      if (GCE) GCE->complete();
    });
  }

  /// Synchronizing public task spawn. Automatically enrolls task with GlobalCompletionEvent and
  /// sends `complete`  message when done (if GCE is non-null).
  template<GlobalCompletionEvent * GCE, typename TF>
  inline void publicTask(TF tf) {
    if (GCE) GCE->enroll();
    Core origin = mycore();
    publicTask([origin,tf] {
      tf();
      if (GCE) complete(make_global(GCE,origin));
    });
  }

} // namespace Grappa
<|endoftext|>


<commit_before>#include "common.h"

#include "hex/basics/hexgrid.h"
#include "hex/game/game.h"
#include "hex/game/movement/movement.h"
#include "hex/resources/view_def.h"
#include "hex/view/player.h"
#include "hex/view/view.h"

Ghost::Ghost(GameView *view, UnitStack::pointer stack, const IntSet selected_units, Path path, UnitStack::pointer target_stack):
        finished(false), view(view), step(0), progress(0) {

    // Create ghost
    UnitStack::pointer ghost_stack = stack->copy_subset(selected_units);
    stack_view = boost::make_shared<UnitStackView>(ghost_stack);
    view->set_view_def(*stack_view);
    stack_view->path = path;

    // Lock target
    target_view = view->get_stack_view(target_stack->id);
    target_view->locked = true;
    if (stack == target_stack || target_stack->units.size() == 0)
        target_view->moving = true;
}

void Ghost::update(unsigned int update_ms) {
    UnitViewDef::pointer& view_def = stack_view->view_def;
    progress += frame_incr(view_def->move_speed, update_ms);
    if (progress > 1000) {
        stack_view->stack->position = stack_view->path[step];
        step++;
        progress -= 1000;
    }

    UnitStack::pointer& target = target_view->stack;
    if (step >= stack_view->path.size()) {
        view->set_view_def(*target_view);
        target_view->locked = false;
        if (target_view->moving) {
            target_view->moving = false;
            target_view->facing = stack_view->facing;
        }
        if (view->player->has_view(target->owner)) {
            view->level_view.visibility.unmask(*target);
            view->update_visibility();
        }
        finished = true;
        return;
    }

    Point next_pos = stack_view->path[step];
    stack_view->facing = get_direction(next_pos, stack_view->stack->position);
    stack_view->phase += frame_incr(view_def->move_animations[stack_view->facing].bpm, update_ms);
    if (view->player->has_view(target->owner)) {
        view->level_view.discovered.draw(next_pos, target->sight(), true);
        view->level_view.ghost_visibility.draw(next_pos, target->sight(), true);
    }
}
<commit_msg>Fix bug where ghosts aren't animated properly.<commit_after>#include "common.h"

#include "hex/basics/hexgrid.h"
#include "hex/game/game.h"
#include "hex/game/movement/movement.h"
#include "hex/resources/view_def.h"
#include "hex/view/player.h"
#include "hex/view/view.h"

Ghost::Ghost(GameView *view, UnitStack::pointer stack, const IntSet selected_units, Path path, UnitStack::pointer target_stack):
        finished(false), view(view), step(0), progress(0) {

    // Create ghost
    UnitStack::pointer ghost_stack = stack->copy_subset(selected_units);
    stack_view = boost::make_shared<UnitStackView>(ghost_stack);
    view->set_view_def(*stack_view);
    stack_view->path = path;
    stack_view->moving = true;

    // Lock target
    target_view = view->get_stack_view(target_stack->id);
    target_view->locked = true;
    if (stack == target_stack || target_stack->units.size() == 0)
        target_view->moving = true;
}

void Ghost::update(unsigned int update_ms) {
    UnitViewDef::pointer& view_def = stack_view->view_def;
    progress += frame_incr(view_def->move_speed, update_ms);
    if (progress > 1000) {
        stack_view->stack->position = stack_view->path[step];
        step++;
        progress -= 1000;
    }

    UnitStack::pointer& target = target_view->stack;
    if (step >= stack_view->path.size()) {
        view->set_view_def(*target_view);
        target_view->locked = false;
        if (target_view->moving) {
            target_view->moving = false;
            target_view->facing = stack_view->facing;
        }
        if (view->player->has_view(target->owner)) {
            view->level_view.visibility.unmask(*target);
            view->update_visibility();
        }
        finished = true;
        return;
    }

    Point next_pos = stack_view->path[step];
    stack_view->facing = get_direction(next_pos, stack_view->stack->position);
    stack_view->phase += frame_incr(view_def->move_animations[stack_view->facing].bpm, update_ms);
    if (view->player->has_view(target->owner)) {
        view->level_view.discovered.draw(next_pos, target->sight(), true);
        view->level_view.ghost_visibility.draw(next_pos, target->sight(), true);
    }
}
<|endoftext|>


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

// POSIX
#include <signal.h>

// STL
#include <tr1/memory>

// Google Log
#include <glog/logging.h>

// e
#include <e/timer.h>

// Configuration
#include <configuration/coordinatorlink.h>

// HyperDex
#include <hyperdex/daemon.h>
#include <hyperdex/datalayer.h>
#include <hyperdex/logical.h>
#include <hyperdex/network_worker.h>
#include <hyperdex/replication_manager.h>
#include <hyperdex/searches.h>

typedef std::tr1::shared_ptr<po6::threads::thread> thread_ptr;

static bool s_continue = true;

void
sig_handle(int /*signum*/)
{
    LOG(ERROR) << "signal received; triggering exit..";
    s_continue = false;
}

int
hyperdex :: daemon(po6::pathname datadir,
                   po6::net::location coordinator,
                   po6::net::ipaddr bind_to,
                   uint16_t num_threads)
{
    // Catch signals.
    struct sigaction handle;
    handle.sa_handler = sig_handle;
    sigfillset(&handle.sa_mask);
    handle.sa_flags = SA_RESTART;
    int ret = 0;
    ret += sigaction(SIGHUP, &handle, NULL);
    ret += sigaction(SIGINT, &handle, NULL);

    if (ret < 0)
    {
        PLOG(INFO) << "could not set signal handlers (sigaction)";
        return EXIT_FAILURE;
    }

    // Setup the data component.
    datalayer data; // XXX Pass in the proper directory
    // Setup the communication component.
    logical comm(bind_to);
    comm.pause(); // Pause is idempotent.  The first unpause will cancel this one.
    // Setup the search component.
    searches ssss(&data, &comm);
    // Setup the replication component.
    replication_manager repl(&data, &comm);
    // Create our announce string.
    std::ostringstream announce;
    announce << "instance\t" << comm.inst().inbound << "\t"
                             << comm.inst().outbound;
    // Setup our link to the coordinator.
    coordinatorlink cl(coordinator, announce.str());
    LOG(INFO) << "Connecting to the coordinator.";

    while (s_continue && cl.connect() != coordinatorlink::SUCCESS)
    {
        PLOG(INFO) << "Coordinator connection failed";
    }

    // Start the network workers.
    LOG(INFO) << "Starting network workers.";
    num_threads = s_continue ? num_threads : 0;
    network_worker nw(&data, &comm, &ssss, &repl);
    std::tr1::function<void (hyperdex::network_worker*)> fnw(&hyperdex::network_worker::run);
    std::vector<thread_ptr> threads;

    for (size_t i = 0; i < num_threads; ++i)
    {
        thread_ptr t(new po6::threads::thread(std::tr1::bind(fnw, &nw)));
        t->start();
        threads.push_back(t);
    }

    LOG(INFO) << "Network workers started.";

    while (s_continue)
    {
        if (cl.unacknowledged())
        {
            LOG(INFO) << "Installing new configuration.";
            // Prepare for our new configuration.
            // These operations should assume that there will be network
            // activity, and that the network threads will be in full force..
            comm.prepare(cl.config());
            data.prepare(cl.config(), comm.inst());
            repl.prepare(cl.config(), comm.inst());

            // Protect ourself against exceptions.
            e::guard g1 = e::makeobjguard(comm, &hyperdex::logical::unpause);
            e::guard g2 = e::makeobjguard(comm, &hyperdex::logical::shutdown);

            LOG(INFO) << "Pausing communication for reconfiguration.";

            // Make sure that we wait until everyone is paused.
            comm.pause();

            while (comm.num_paused() < num_threads)
            {
                e::sleep_ms(0, 10);
            }

            // Here is the critical section.  This is is mutually exclusive with the
            // network workers' loop.
            comm.reconfigure(cl.config());
            data.reconfigure(cl.config(), comm.inst());
            repl.reconfigure(cl.config(), comm.inst());
            comm.unpause();
            g1.dismiss();
            g2.dismiss();
            LOG(INFO) << "Reconfiguration complete; unpausing communication.";

            // Cleanup anything not specified by our new configuration.
            // These operations should assume that there will be network
            // activity, and that the network threads will be in full force..
            repl.cleanup(cl.config(), comm.inst());
            data.cleanup(cl.config(), comm.inst());
            comm.cleanup(cl.config());
            cl.acknowledge();
        }

        switch (cl.loop(1, -1))
        {
            case coordinatorlink::SHUTDOWN:
                s_continue = false;
                break;
            case coordinatorlink::SUCCESS:
                break;
            case coordinatorlink::CONNECTFAIL:
            case coordinatorlink::DISCONNECT:
                if (cl.connect() != coordinatorlink::SUCCESS)
                {
                    PLOG(INFO) << "Coordinator connection failed";
                }

                break;
            case coordinatorlink::LOGICERROR:
            default:
                assert(!"Programming error.");
        }
    }

    LOG(INFO) << "Exiting daemon.";

    // Stop replication.
    repl.shutdown();
    // Turn off the network.
    comm.shutdown();
    // Cleanup the network_worker threads.
    nw.shutdown();
    // Cleanup the master thread.
    cl.shutdown();
    // Stop the data layer.
    data.shutdown();

    for (std::vector<thread_ptr>::iterator t = threads.begin();
            t != threads.end(); ++t)
    {
        (*t)->join();
    }

    return EXIT_SUCCESS;
}

#if 0
    catch (po6::error& e)
    {
        LOG(ERROR) << "Uncaught system error:  " << e.what();
    }
    catch (std::bad_alloc& ba)
    {
        LOG(ERROR) << "Out of memory:  " << ba.what();
    }
#endif
<commit_msg>Remove commented-out code.<commit_after>// Copyright (c) 2011, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// POSIX
#include <signal.h>

// STL
#include <tr1/memory>

// Google Log
#include <glog/logging.h>

// e
#include <e/timer.h>

// Configuration
#include <configuration/coordinatorlink.h>

// HyperDex
#include <hyperdex/daemon.h>
#include <hyperdex/datalayer.h>
#include <hyperdex/logical.h>
#include <hyperdex/network_worker.h>
#include <hyperdex/replication_manager.h>
#include <hyperdex/searches.h>

typedef std::tr1::shared_ptr<po6::threads::thread> thread_ptr;

static bool s_continue = true;

void
sig_handle(int /*signum*/)
{
    LOG(ERROR) << "signal received; triggering exit..";
    s_continue = false;
}

int
hyperdex :: daemon(po6::pathname datadir,
                   po6::net::location coordinator,
                   po6::net::ipaddr bind_to,
                   uint16_t num_threads)
{
    // Catch signals.
    struct sigaction handle;
    handle.sa_handler = sig_handle;
    sigfillset(&handle.sa_mask);
    handle.sa_flags = SA_RESTART;
    int ret = 0;
    ret += sigaction(SIGHUP, &handle, NULL);
    ret += sigaction(SIGINT, &handle, NULL);

    if (ret < 0)
    {
        PLOG(INFO) << "could not set signal handlers (sigaction)";
        return EXIT_FAILURE;
    }

    // Setup the data component.
    datalayer data; // XXX Pass in the proper directory
    // Setup the communication component.
    logical comm(bind_to);
    comm.pause(); // Pause is idempotent.  The first unpause will cancel this one.
    // Setup the search component.
    searches ssss(&data, &comm);
    // Setup the replication component.
    replication_manager repl(&data, &comm);
    // Create our announce string.
    std::ostringstream announce;
    announce << "instance\t" << comm.inst().inbound << "\t"
                             << comm.inst().outbound;
    // Setup our link to the coordinator.
    coordinatorlink cl(coordinator, announce.str());
    LOG(INFO) << "Connecting to the coordinator.";

    while (s_continue && cl.connect() != coordinatorlink::SUCCESS)
    {
        PLOG(INFO) << "Coordinator connection failed";
    }

    // Start the network workers.
    LOG(INFO) << "Starting network workers.";
    num_threads = s_continue ? num_threads : 0;
    network_worker nw(&data, &comm, &ssss, &repl);
    std::tr1::function<void (hyperdex::network_worker*)> fnw(&hyperdex::network_worker::run);
    std::vector<thread_ptr> threads;

    for (size_t i = 0; i < num_threads; ++i)
    {
        thread_ptr t(new po6::threads::thread(std::tr1::bind(fnw, &nw)));
        t->start();
        threads.push_back(t);
    }

    LOG(INFO) << "Network workers started.";

    while (s_continue)
    {
        if (cl.unacknowledged())
        {
            LOG(INFO) << "Installing new configuration.";
            // Prepare for our new configuration.
            // These operations should assume that there will be network
            // activity, and that the network threads will be in full force..
            comm.prepare(cl.config());
            data.prepare(cl.config(), comm.inst());
            repl.prepare(cl.config(), comm.inst());

            // Protect ourself against exceptions.
            e::guard g1 = e::makeobjguard(comm, &hyperdex::logical::unpause);
            e::guard g2 = e::makeobjguard(comm, &hyperdex::logical::shutdown);

            LOG(INFO) << "Pausing communication for reconfiguration.";

            // Make sure that we wait until everyone is paused.
            comm.pause();

            while (comm.num_paused() < num_threads)
            {
                e::sleep_ms(0, 10);
            }

            // Here is the critical section.  This is is mutually exclusive with the
            // network workers' loop.
            comm.reconfigure(cl.config());
            data.reconfigure(cl.config(), comm.inst());
            repl.reconfigure(cl.config(), comm.inst());
            comm.unpause();
            g1.dismiss();
            g2.dismiss();
            LOG(INFO) << "Reconfiguration complete; unpausing communication.";

            // Cleanup anything not specified by our new configuration.
            // These operations should assume that there will be network
            // activity, and that the network threads will be in full force..
            repl.cleanup(cl.config(), comm.inst());
            data.cleanup(cl.config(), comm.inst());
            comm.cleanup(cl.config());
            cl.acknowledge();
        }

        switch (cl.loop(1, -1))
        {
            case coordinatorlink::SHUTDOWN:
                s_continue = false;
                break;
            case coordinatorlink::SUCCESS:
                break;
            case coordinatorlink::CONNECTFAIL:
            case coordinatorlink::DISCONNECT:
                if (cl.connect() != coordinatorlink::SUCCESS)
                {
                    PLOG(INFO) << "Coordinator connection failed";
                }

                break;
            case coordinatorlink::LOGICERROR:
            default:
                assert(!"Programming error.");
        }
    }

    LOG(INFO) << "Exiting daemon.";

    // Stop replication.
    repl.shutdown();
    // Turn off the network.
    comm.shutdown();
    // Cleanup the network_worker threads.
    nw.shutdown();
    // Cleanup the master thread.
    cl.shutdown();
    // Stop the data layer.
    data.shutdown();

    for (std::vector<thread_ptr>::iterator t = threads.begin();
            t != threads.end(); ++t)
    {
        (*t)->join();
    }

    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>/* Copyright 2018-present Barefoot Networks, Inc.
 *
 * 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.
 */

/*
 * Antonin Bas (antonin@barefootnetworks.com)
 *
 */

#include <bm/bm_sim/_assert.h>
#include <bm/bm_sim/logger.h>

#ifdef WITH_PI
#include <bm/PI/pi.h>
#endif

#include <bm/simple_switch/runner.h>

#include <PI/pi.h>
#include <PI/target/pi_imp.h>

#include "simple_switch.h"

namespace bm {

namespace sswitch {

SimpleSwitchRunner::SimpleSwitchRunner()
    : simple_switch(
          new SimpleSwitch(512 /* max_port */, true /* enable_swap */)) { }

SimpleSwitchRunner::~SimpleSwitchRunner() = default;

int SimpleSwitchRunner::init_and_start(const bm::OptionsParser &parser) {
  int status = simple_switch->init_from_options_parser(
      parser, nullptr, nullptr);
  if (status != 0) return status;

#ifdef WITH_PI
  auto transmit_fn = [this](bm::DevMgrIface::port_t port_num,
                            packet_id_t pkt_id, const char *buf, int len) {
    (void)pkt_id;
    if (cpu_port > 0 && port_num == cpu_port) {
      BMLOG_DEBUG("Transmitting packet-in");
      auto status = pi_packetin_receive(simple_switch->get_device_id(),
                                        buf, static_cast<size_t>(len));
      if (status != PI_STATUS_SUCCESS)
        bm::Logger::get()->error("Error when transmitting packet-in");
    } else {
      simple_switch->transmit_fn(port_num, buf, len);
    }
  };
  simple_switch->set_transmit_fn(transmit_fn);

  bm::pi::register_switch(simple_switch.get(), cpu_port);
#endif

  simple_switch->start_and_return();

  return 0;
}

}  // namespace sswitch

}  // namespace bm
<commit_msg>Add missing #ifdef for PI include in simple_switch runner<commit_after>/* Copyright 2018-present Barefoot Networks, Inc.
 *
 * 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.
 */

/*
 * Antonin Bas (antonin@barefootnetworks.com)
 *
 */

#include <bm/bm_sim/_assert.h>
#include <bm/bm_sim/logger.h>

#ifdef WITH_PI
#include <bm/PI/pi.h>
#endif

#include <bm/simple_switch/runner.h>

#ifdef WITH_PI
#include <PI/pi.h>
#include <PI/target/pi_imp.h>
#endif

#include "simple_switch.h"

namespace bm {

namespace sswitch {

SimpleSwitchRunner::SimpleSwitchRunner()
    : simple_switch(
          new SimpleSwitch(512 /* max_port */, true /* enable_swap */)) { }

SimpleSwitchRunner::~SimpleSwitchRunner() = default;

int SimpleSwitchRunner::init_and_start(const bm::OptionsParser &parser) {
  int status = simple_switch->init_from_options_parser(
      parser, nullptr, nullptr);
  if (status != 0) return status;

#ifdef WITH_PI
  auto transmit_fn = [this](bm::DevMgrIface::port_t port_num,
                            packet_id_t pkt_id, const char *buf, int len) {
    (void)pkt_id;
    if (cpu_port > 0 && port_num == cpu_port) {
      BMLOG_DEBUG("Transmitting packet-in");
      auto status = pi_packetin_receive(simple_switch->get_device_id(),
                                        buf, static_cast<size_t>(len));
      if (status != PI_STATUS_SUCCESS)
        bm::Logger::get()->error("Error when transmitting packet-in");
    } else {
      simple_switch->transmit_fn(port_num, buf, len);
    }
  };
  simple_switch->set_transmit_fn(transmit_fn);

  bm::pi::register_switch(simple_switch.get(), cpu_port);
#endif

  simple_switch->start_and_return();

  return 0;
}

}  // namespace sswitch

}  // namespace bm
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "il/GlobalArray.hpp"
#include "AssemblyFileWriter.hpp"

using namespace eddic;

GlobalArray::GlobalArray(std::string n, BaseType t, int s) : name(n), type(t), size(s) {}

void GlobalArray::write(AssemblyFileWriter& writer){
    writer.stream() << "VA" << name << ":" <<std::endl;
    writer.stream() << ".rept " << size << std::endl;

    if(type == BaseType::INT){
        writer.stream() << ".long 0" << std::endl;
    } else if(type == BaseType::STRING){
        writer.stream() << ".long S3" << std::endl;
        writer.stream() << ".long 0" << std::endl;
    }

    writer.stream() << ".endr" << std::endl;
}
<commit_msg>Include the size of the array in the array memory layout<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include "il/GlobalArray.hpp"
#include "AssemblyFileWriter.hpp"

using namespace eddic;

GlobalArray::GlobalArray(std::string n, BaseType t, int s) : name(n), type(t), size(s) {}

void GlobalArray::write(AssemblyFileWriter& writer){
    writer.stream() << "VA" << name << ":" <<std::endl;
    writer.stream() << ".long " << size << std::endl;
    writer.stream() << ".rept " << size << std::endl;

    if(type == BaseType::INT){
        writer.stream() << ".long 0" << std::endl;
    } else if(type == BaseType::STRING){
        writer.stream() << ".long S3" << std::endl;
        writer.stream() << ".long 0" << std::endl;
    }

    writer.stream() << ".endr" << std::endl;
}
<|endoftext|>


<commit_before>/**
 ** \file libport/path.cc
 ** \brief path: implements file libport/path.hh
 */

#include <iostream>
#include <libport/fcntl.h>
#include <libport/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cctype>

#include <libport/contract.hh>
#include <libport/detect-win32.h>
#include <libport/finally.hh>
#include <libport/foreach.hh>
#include <libport/path.hh>

// Implementation detail: if path_ is empty and absolute_ is false,
// then the path is '.'

namespace libport
{
  path::path(const std::string& p)
  {
    init(p);
  }

  path::path(const char* p)
  {
    init(p);
  }

  void
  path::init(std::string p)
  {
    if (p.empty())
      throw invalid_path("Path can't be empty.");

    // Compute volume_ and absolute_.
#if defined WIN32
    // Under Win32, absolute paths start with a letter followed by
    // ":\". If the trailing slash is missing, this is a relative
    // path.
    if (2 <= p.length()
	&& isalpha(p[0]) && p[1] == ':')
    {
      volume_ = p.substr(0, 2);
      absolute_ = p.length() >= 3 && p[2] == '\\';
      p.erase(0, absolute_ ? 3 : 2);
    }
    // Network share, such as "\\shared volume\foo\bar"
    else if (3 <= p.length()
	     && p[0] == '\\' && p[1] == '\\')
    {
      absolute_ = true;
      std::string::size_type pos = p.find("\\", 3);
      if (pos == std::string::npos)
      {
	volume_ = p;
	p = "";
      }
      else
      {
	volume_ = p.substr(0, pos);
	p = p.erase(0, pos);
      }
    }
    // Fallback to Unix cases for subsystems such as cygwin
    else
#endif // WIN32
    if (!p.empty() && p[0] == '/')
    {
      absolute_ = true;
      p = p.erase(0, 0);
    }
    else
      absolute_ = false;

    // Cut directories on / and \.
    for (std::string::size_type pos = p.find_first_of(separator_);
	 pos != std::string::npos;
	 pos = p.find_first_of(separator_))
    {
      append_dir(p.substr(0, pos));
      p.erase(0, pos + 1);
    }
    append_dir(p);
  }

  path&
  path::operator=(const path& rhs)
  {
    absolute_ = rhs.absolute_;
    path_ = rhs.path_;
#if defined WIN32
    volume_ = rhs.volume_;
#endif
    return *this;
  }

  path&
  path::operator/=(const path& rhs)
  {
    if (rhs.absolute_get())
      throw invalid_path(
        "Rhs of concatenation is absolute: " + rhs.to_string());
#ifdef WIN32
    if (!rhs.volume_.empty())
      throw invalid_path("concatenation of path with volume: " +
			 rhs.to_string());
#endif
    for (path_type::const_iterator dir = rhs.path_.begin();
	 dir != rhs.path_.end();
	 ++dir)
      append_dir(*dir);

    return *this;
  }

  path
  path::operator/(const path& rhs) const
  {
    path res = *this;
    return res /= rhs;
  }

  path::operator std::string() const
  {
    return to_string();
  }

  std::string
  path::to_string() const
  {
    if (!absolute_ && path_.empty())
      return ".";

    std::string res = WIN32_IF(volume_, "");
    if (absolute_)
      res += separator_;
    bool tail = false;
    foreach (const std::string& dir, path_)
    {
      if (tail++)
	res += separator_;
      res += dir;
    }
    return res;
  }

  bool
  path::operator==(const path& rhs) const
  {
    return path_ == rhs.path_;
  }

  std::ostream&
  path::dump(std::ostream& o) const
  {
    return o << operator std::string();
  }

  void
  path::append_dir(const std::string& dir)
  {
    precondition(dir.find(separator_) == std::string::npos);

    if (dir != "" && dir != ".")
    {
      // The following does not work properly with symlinks.  One
      // cannot expect that removing "foo/../" inside a valid path
      // results in the same path.  We should check whether "foo" is
      // *not* a symlink before playing this kind of trick.
#if 0
      if (dir == ".."
          && !path_.empty() && *path_.rbegin() != "..")
        path_.pop_back();
      else
#endif
	path_.push_back(dir);
    }
  }

  std::string
  path::basename() const
  {
    // basename of / is /, basename of . is .
    if (path_.empty())
      return *this;

    return path_.back();
  }

  path
  path::dirname() const
  {
    // dirname of / is /, dirname of . is .
    if (path_.empty())
      return *this;

    std::string last = path_.back();
    // The const cast here is justified since the modification is
    // systematically reverted
    const_cast<path*>(this)->path_.pop_back();
    libport::Finally finally(
      boost::bind(&path_type::push_back,
		  boost::ref(const_cast<path*>(this)->path_), last));
    path res = path_.empty() ? "." : *this;
    return res;
  }

  bool path::exists() const
  {
    struct stat buf;
    return 0 == stat(to_string().c_str(), &buf);
  }

  bool path::create() const
  {
    int fd = open(to_string().c_str(),
                  O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    if (fd == -1)
      return false;
    close(fd);
    return true;
  }

  bool path::remove() const
  {
    return !unlink(to_string().c_str());
  }

  const path::path_type& path::components() const
  {
    return path_;
  }
}
<commit_msg>libport: clean path.<commit_after>/**
 ** \file libport/path.cc
 ** \brief path: implements file libport/path.hh
 */

#include <iostream>
#include <libport/fcntl.h>
#include <libport/unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cctype>

#include <libport/contract.hh>
#include <libport/detect-win32.h>
#include <libport/finally.hh>
#include <libport/foreach.hh>
#include <libport/path.hh>

// Implementation detail: if path_ is empty and absolute_ is false,
// then the path is '.'

namespace libport
{
  path::path(const std::string& p)
  {
    init(p);
  }

  path::path(const char* p)
  {
    init(p);
  }

  void
  path::init(std::string p)
  {
    if (p.empty())
      throw invalid_path("Path can't be empty.");

    // Compute volume_ and absolute_.
#if defined WIN32
    // Under Win32, absolute paths start with a letter followed by
    // ":\". If the trailing slash is missing, this is a relative
    // path.
    if (2 <= p.length()
	&& isalpha(p[0]) && p[1] == ':')
    {
      volume_ = p.substr(0, 2);
      absolute_ = p.length() >= 3 && p[2] == '\\';
      p.erase(0, absolute_ ? 3 : 2);
    }
    // Network share, such as "\\shared volume\foo\bar"
    else if (3 <= p.length()
	     && p[0] == '\\' && p[1] == '\\')
    {
      absolute_ = true;
      std::string::size_type pos = p.find('\\', 3);
      if (pos == std::string::npos)
      {
	volume_ = p;
	p.clear();
      }
      else
      {
	volume_ = p.substr(0, pos);
	p = p.erase(0, pos);
      }
    }
    // Fallback to Unix cases for subsystems such as cygwin
    else
#endif // WIN32
    if (!p.empty() && p[0] == '/')
    {
      absolute_ = true;
      p = p.erase(0, 0);
    }
    else
      absolute_ = false;

    // Cut directories on / and \.
    for (std::string::size_type pos = p.find_first_of(separator_);
	 pos != std::string::npos;
	 pos = p.find_first_of(separator_))
    {
      append_dir(p.substr(0, pos));
      p.erase(0, pos + 1);
    }
    append_dir(p);
  }

  path&
  path::operator=(const path& rhs)
  {
    absolute_ = rhs.absolute_;
    path_ = rhs.path_;
#if defined WIN32
    volume_ = rhs.volume_;
#endif
    return *this;
  }

  path&
  path::operator/=(const path& rhs)
  {
    if (rhs.absolute_get())
      throw invalid_path(
        "Rhs of concatenation is absolute: " + rhs.to_string());
#ifdef WIN32
    if (!rhs.volume_.empty())
      throw invalid_path("concatenation of path with volume: " +
			 rhs.to_string());
#endif
    for (path_type::const_iterator dir = rhs.path_.begin();
	 dir != rhs.path_.end();
	 ++dir)
      append_dir(*dir);

    return *this;
  }

  path
  path::operator/(const path& rhs) const
  {
    path res = *this;
    return res /= rhs;
  }

  path::operator std::string() const
  {
    return to_string();
  }

  std::string
  path::to_string() const
  {
    if (!absolute_ && path_.empty())
      return ".";

    std::string res = WIN32_IF(volume_, "");
    if (absolute_)
      res += separator_;
    bool tail = false;
    foreach (const std::string& dir, path_)
    {
      if (tail++)
	res += separator_;
      res += dir;
    }
    return res;
  }

  bool
  path::operator==(const path& rhs) const
  {
    return path_ == rhs.path_;
  }

  std::ostream&
  path::dump(std::ostream& o) const
  {
    return o << operator std::string();
  }

  void
  path::append_dir(const std::string& dir)
  {
    precondition(dir.find(separator_) == std::string::npos);

    if (!dir.empty() && dir != ".")
    {
      // The following does not work properly with symlinks.  One
      // cannot expect that removing "foo/../" inside a valid path
      // results in the same path.  We should check whether "foo" is
      // *not* a symlink before playing this kind of trick.
#if 0
      if (dir == ".."
          && !path_.empty() && *path_.rbegin() != "..")
        path_.pop_back();
      else
#endif
	path_.push_back(dir);
    }
  }

  std::string
  path::basename() const
  {
    // basename of / is /, basename of . is .
    if (path_.empty())
      return *this;

    return path_.back();
  }

  path
  path::dirname() const
  {
    // dirname of / is /, dirname of . is .
    if (path_.empty())
      return *this;

    std::string last = path_.back();
    // The const cast here is justified since the modification is
    // systematically reverted
    const_cast<path*>(this)->path_.pop_back();
    libport::Finally finally(
      boost::bind(&path_type::push_back,
		  boost::ref(const_cast<path*>(this)->path_), last));
    path res = path_.empty() ? "." : *this;
    return res;
  }

  bool path::exists() const
  {
    struct stat buf;
    return 0 == stat(to_string().c_str(), &buf);
  }

  bool path::create() const
  {
    int fd = open(to_string().c_str(),
                  O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
    if (fd == -1)
      return false;
    close(fd);
    return true;
  }

  bool path::remove() const
  {
    return !unlink(to_string().c_str());
  }

  const path::path_type& path::components() const
  {
    return path_;
  }
}
<|endoftext|>


<commit_before>#include "hal.h"
#include "renameFile.h"

using namespace std;
using namespace hal;

static void initParser(CLParser &optionsParser) {
    optionsParser.setDescription("Rename genomes in a HAL file in-place.");
    optionsParser.addArgument("halFile", "hal file");
    optionsParser.addArgument("renameFile", "Tab-separated file. First column: existing genome"
                                            " name, second column: new genome name. Any "
                                            "genomes not provided will stay the same.");
}

int main(int argc, char *argv[]) {
    CLParser optionsParser(WRITE_ACCESS);
    initParser(optionsParser);
    string halPath, renamePath;
    try {
        optionsParser.parseOptions(argc, argv);
        halPath = optionsParser.getArgument<string>("halFile");
        renamePath = optionsParser.getArgument<string>("renameFile");
    } catch (exception &e) {
        cerr << e.what() << endl;
        optionsParser.printUsage(cerr);
        return 1;
    }

    AlignmentPtr alignment(openHalAlignment(halPath, &optionsParser));
    map<string, string> renameMap = ingestRenameFile(renamePath);

    // Check that the alignment has all the old genome names, and none
    // of the new genome names.
    for (map<string, string>::iterator it = renameMap.begin(); it != renameMap.end(); it++) {
        Genome *genome = alignment->openGenome(it->first);
        if (genome == NULL) {
            throw hal_exception("Genome " + it->first + " not found in alignment");
        }

        genome = alignment->openGenome(it->second);
        if (genome != NULL) {
            throw hal_exception("Attempting to rename " + it->first + " to " + it->second + " failed: " + it->second +
                                " is already in the alignment! Name it to something"
                                " temporary first");
        }
    }

    // Do the actual renaming now that we are relatively sure nothing
    // will go wrong.
    for (map<string, string>::iterator it = renameMap.begin(); it != renameMap.end(); it++) {
        cout << "Renaming " << it->first << " to " << it->second << endl;
        Genome *genome = alignment->openGenome(it->first);
        genome->rename(it->second);
    }

    alignment->close();
}
<commit_msg>add write access for halRenameGenomes<commit_after>#include "hal.h"
#include "renameFile.h"

using namespace std;
using namespace hal;

static void initParser(CLParser &optionsParser) {
    optionsParser.setDescription("Rename genomes in a HAL file in-place.");
    optionsParser.addArgument("halFile", "hal file");
    optionsParser.addArgument("renameFile", "Tab-separated file. First column: existing genome"
                                            " name, second column: new genome name. Any "
                                            "genomes not provided will stay the same.");
}

int main(int argc, char *argv[]) {
    CLParser optionsParser(WRITE_ACCESS);
    initParser(optionsParser);
    string halPath, renamePath;
    try {
        optionsParser.parseOptions(argc, argv);
        halPath = optionsParser.getArgument<string>("halFile");
        renamePath = optionsParser.getArgument<string>("renameFile");
    } catch (exception &e) {
        cerr << e.what() << endl;
        optionsParser.printUsage(cerr);
        return 1;
    }

    AlignmentPtr alignment(openHalAlignment(halPath, &optionsParser, WRITE_ACCESS | READ_ACCESS));
    map<string, string> renameMap = ingestRenameFile(renamePath);

    // Check that the alignment has all the old genome names, and none
    // of the new genome names.
    for (map<string, string>::iterator it = renameMap.begin(); it != renameMap.end(); it++) {
        Genome *genome = alignment->openGenome(it->first);
        if (genome == NULL) {
            throw hal_exception("Genome " + it->first + " not found in alignment");
        }

        genome = alignment->openGenome(it->second);
        if (genome != NULL) {
            throw hal_exception("Attempting to rename " + it->first + " to " + it->second + " failed: " + it->second +
                                " is already in the alignment! Name it to something"
                                " temporary first");
        }
    }

    // Do the actual renaming now that we are relatively sure nothing
    // will go wrong.
    for (map<string, string>::iterator it = renameMap.begin(); it != renameMap.end(); it++) {
        cout << "Renaming " << it->first << " to " << it->second << endl;
        Genome *genome = alignment->openGenome(it->first);
        genome->rename(it->second);
    }

    alignment->close();
}
<|endoftext|>