<commit_before>#include "mpi.h"
#include <Python.h>
#include <string>
#include <iostream>
#include <cstring>

#include "parquet/api/reader.h"
#include "parquet/arrow/reader.h"
#include "arrow/table.h"

using parquet::arrow::FileReader;
using parquet::ParquetFileReader;

int64_t pq_get_size(std::string* file_name, int64_t column_idx);
int pq_read(std::string* file_name, int64_t column_idx, void* out);

PyMODINIT_FUNC PyInit_parquet_cpp(void) {
    PyObject *m;
    static struct PyModuleDef moduledef = {
            PyModuleDef_HEAD_INIT, "parquet_cpp", "No docs", -1, NULL, };
    m = PyModule_Create(&moduledef);
    if (m == NULL)
        return NULL;

    PyObject_SetAttrString(m, "read",
                            PyLong_FromVoidPtr((void*)(&pq_read)));
    PyObject_SetAttrString(m, "get_size",
                            PyLong_FromVoidPtr((void*)(&pq_get_size)));

    return m;
}

int64_t pq_get_size(std::string* file_name, int64_t column_idx)
{
    auto pqreader = ParquetFileReader::OpenFile(*file_name);
    int64_t nrows = pqreader->metadata()->num_rows();
    // std::cout << nrows << std::endl;
    pqreader->Close();
    return nrows;
}

int pq_read(std::string* file_name, int64_t column_idx, void* out_data)
{
    auto pool = ::arrow::default_memory_pool();
    std::unique_ptr<FileReader> arrow_reader;
    arrow_reader.reset(new FileReader(pool,
        ParquetFileReader::OpenFile(*file_name, false)));
    //
    std::shared_ptr<::arrow::Table> table;
    arrow_reader->ReadTable(&table);
    // std::vector<int> column_indices;
    // column_indices.push_back(column_idx);
    // arrow_reader->ReadRowGroup(0, column_indices, &table);
    std::shared_ptr< ::arrow::Column > column = table->column(column_idx);
    int64_t num_values = column->length();
    std::shared_ptr< ::arrow::ChunkedArray > data = column->data();
    for(int i=0; i<data->num_chunks(); i++) {
        std::shared_ptr< ::arrow::Array > arr = data->chunk(i);
        auto buffers = arr->data()->buffers;
        std::cout<<"num buffs: "<< buffers.size()<<std::endl;
        int buff_size = buffers[1]->size();
        memcpy(out_data, buffers[1]->data(), buff_size);
    }

    return 0;
}
<commit_msg>parquet read cleanup<commit_after>#include "mpi.h"
#include <Python.h>
#include <string>
#include <iostream>
#include <cstring>

#include "parquet/api/reader.h"
#include "parquet/arrow/reader.h"
#include "arrow/table.h"

using parquet::arrow::FileReader;
using parquet::ParquetFileReader;

int64_t pq_get_size(std::string* file_name, int64_t column_idx);
int pq_read(std::string* file_name, int64_t column_idx, void* out);

PyMODINIT_FUNC PyInit_parquet_cpp(void) {
    PyObject *m;
    static struct PyModuleDef moduledef = {
            PyModuleDef_HEAD_INIT, "parquet_cpp", "No docs", -1, NULL, };
    m = PyModule_Create(&moduledef);
    if (m == NULL)
        return NULL;

    PyObject_SetAttrString(m, "read",
                            PyLong_FromVoidPtr((void*)(&pq_read)));
    PyObject_SetAttrString(m, "get_size",
                            PyLong_FromVoidPtr((void*)(&pq_get_size)));

    return m;
}

int64_t pq_get_size(std::string* file_name, int64_t column_idx)
{
    auto pqreader = ParquetFileReader::OpenFile(*file_name);
    int64_t nrows = pqreader->metadata()->num_rows();
    // std::cout << nrows << std::endl;
    pqreader->Close();
    return nrows;
}

int pq_read(std::string* file_name, int64_t column_idx, void* out_data)
{
    auto pool = ::arrow::default_memory_pool();
    std::unique_ptr<FileReader> arrow_reader;
    arrow_reader.reset(new FileReader(pool,
        ParquetFileReader::OpenFile(*file_name, false)));
    //
    std::shared_ptr< ::arrow::Array > arr;
    arrow_reader->ReadColumn(column_idx, &arr);
    // std::cout << arr->ToString() << std::endl;

    auto buffers = arr->data()->buffers;
    // std::cout<<"num buffs: "<< buffers.size()<<std::endl;
    if (buffers.size()!=2) {
        std::cerr << "invalid parquet number of array buffers" << std::endl;
    }
    int64_t buff_size = buffers[1]->size();
    memcpy(out_data, buffers[1]->data(), buff_size);
    return 0;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMultiProcessController.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// This will be the default.
#include "vtkMultiProcessController.h"
#include "vtkDummyController.h"
#include "vtkProcessGroup.h"
#include "vtkSubCommunicator.h"
#include "vtkToolkits.h"

#ifdef VTK_USE_MPI
#include "vtkMPIController.h"
#endif

#include "vtkCollection.h"
#include "vtkObjectFactory.h"
#include "vtkOutputWindow.h"

//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkMultiProcessController);

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

// Helper class to contain the RMI information.
// A subclass of vtkObject so that I can keep them in a collection.
class VTK_PARALLEL_EXPORT vtkMultiProcessControllerRMI : public vtkObject
{
public:
  static vtkMultiProcessControllerRMI *New();
  vtkTypeRevisionMacro(vtkMultiProcessControllerRMI, vtkObject);

  int Tag;
  vtkRMIFunctionType Function;
  void *LocalArgument;

  unsigned long Id;

protected:
  vtkMultiProcessControllerRMI() {};
  vtkMultiProcessControllerRMI(const vtkMultiProcessControllerRMI&);
  void operator=(const vtkMultiProcessControllerRMI&);
};

vtkCxxRevisionMacro(vtkMultiProcessControllerRMI, "1.32");
vtkStandardNewMacro(vtkMultiProcessControllerRMI);

vtkCxxRevisionMacro(vtkMultiProcessController, "1.32");

//----------------------------------------------------------------------------
// An RMI function that will break the "ProcessRMIs" loop.
void vtkMultiProcessControllerBreakRMI(void *localArg,
                                       void *remoteArg, int remoteArgLength,
                                       int vtkNotUsed(remoteId))
{
  vtkMultiProcessController *controller;
  remoteArg = remoteArg;
  remoteArgLength = remoteArgLength;
  controller = (vtkMultiProcessController*)(localArg);
  controller->SetBreakFlag(1);
}

//----------------------------------------------------------------------------
vtkMultiProcessController::vtkMultiProcessController()
{
  int i;

  this->RMICount = 1;

  this->RMIs = vtkCollection::New();

  this->SingleMethod = 0;
  this->SingleData = 0;

  this->Communicator = 0;
  this->RMICommunicator = 0;

  for ( i = 0; i < VTK_MAX_THREADS; i++ )
    {
    this->MultipleMethod[i] = NULL;
    this->MultipleData[i] = NULL;
    }

  this->BreakFlag = 0;
  this->ForceDeepCopy = 1;

  this->OutputWindow = 0;

  // Define an rmi internally to exit from the processing loop.
  this->AddRMI(vtkMultiProcessControllerBreakRMI, this, BREAK_RMI_TAG);
}

//----------------------------------------------------------------------------
// This is an old comment that I do not know is true:
// (We need to have a "GetNetReferenceCount" to avoid memory leaks.)
vtkMultiProcessController::~vtkMultiProcessController()
{
  if ( this->OutputWindow &&
       (this->OutputWindow == vtkOutputWindow::GetInstance()) )
    {
    vtkOutputWindow::SetInstance(0);
    }

  if (this->OutputWindow)
    {
    this->OutputWindow->Delete();
    }

  this->RMIs->Delete();
  this->RMIs = NULL;
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  vtkMultiProcessControllerRMI *rmi;
  vtkIndent nextIndent = indent.GetNextIndent();

  os << indent << "Break flag: " << (this->BreakFlag ? "(yes)" : "(no)")
     << endl;
  os << indent << "Force deep copy: " << (this->ForceDeepCopy ? "(yes)" : "(no)")
     << endl;
  os << indent << "Output window: ";
  if (this->OutputWindow)
    {
    os << endl;
    this->OutputWindow->PrintSelf(os, nextIndent);
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "Communicator: ";
  if (this->Communicator)
    {
    os << endl;
    this->Communicator->PrintSelf(os, nextIndent);
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "RMI communicator: ";
  if (this->RMICommunicator)
    {
    os << endl;
    this->RMICommunicator->PrintSelf(os, nextIndent);
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "RMIs: \n";

  this->RMIs->InitTraversal();
  while ( (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    os << nextIndent << rmi->Tag << endl;
    }

}

//----------------------------------------------------------------------------
void vtkMultiProcessController::SetNumberOfProcesses(int num)
{
  if(this->Communicator)
    {
    this->Communicator->SetNumberOfProcesses(num);
    }
  else
    {
    vtkErrorMacro("Communicator not set.");
    }
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::GetNumberOfProcesses()
{
  if(this->Communicator)
    {
    return this->Communicator->GetNumberOfProcesses();
    }
  else
    {
    vtkErrorMacro("Communicator not set.");
    return 0;
    }
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::GetLocalProcessId()
{
  if(this->Communicator)
    {
    return this->Communicator->GetLocalProcessId();
    }
  else
    {
    vtkErrorMacro("Communicator not set.");
    return -1;
    }
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::SetSingleMethod( vtkProcessFunctionType f,
                                                 void *data )
{
  this->SingleMethod = f;
  this->SingleData   = data;
}

//----------------------------------------------------------------------------
// Set one of the user defined methods that will be run on NumberOfProcesses
// processes when MultipleMethodExecute is called. This method should be
// called with index = 0, 1, ..,  NumberOfProcesses-1 to set up all the
// required user defined methods
void vtkMultiProcessController::SetMultipleMethod( int index,
                                 vtkProcessFunctionType f, void *data )
{
  // You can only set the method for 0 through NumberOfProcesses-1
  if ( index >= this->GetNumberOfProcesses() )
    {
    vtkErrorMacro( << "Can't set method " << index <<
      " with a processes count of " << this->GetNumberOfProcesses() );
    }
  else
    {
    this->MultipleMethod[index] = f;
    this->MultipleData[index]   = data;
    }
}

//-----------------------------------------------------------------------------
vtkMultiProcessController *vtkMultiProcessController::CreateSubController(
                                                         vtkProcessGroup *group)
{
  if (group->GetCommunicator() != this->Communicator)
    {
    vtkErrorMacro(<< "Invalid group for creating a sub controller.");
    return NULL;
    }

  if (group->FindProcessId(this->GetLocalProcessId()) < 0)
    {
    // The group does not contain this process.  Just return NULL.
    return NULL;
    }

  vtkSubCommunicator *subcomm = vtkSubCommunicator::New();
  subcomm->SetGroup(group);

  // We only need a basic implementation of vtkMultiProcessController for the
  // subgroup, so we just use vtkDummyController here.  It's a bit of a misnomer
  // and may lead to confusion, but I think it's better than creating yet
  // another class we have to maintain.
  vtkDummyController *subcontroller = vtkDummyController::New();
  subcontroller->SetCommunicator(subcomm);
  subcontroller->SetRMICommunicator(subcomm);

  subcomm->Delete();

  return subcontroller;
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::RemoveFirstRMI(int tag)
{
  vtkMultiProcessControllerRMI *rmi = NULL;
  this->RMIs->InitTraversal();
  while ( (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    if (rmi->Tag == tag)
      {
      this->RMIs->RemoveItem(rmi);
      return 1;
      }
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::RemoveRMI(unsigned long id)
{
  vtkMultiProcessControllerRMI *rmi = NULL;
  this->RMIs->InitTraversal();
  while ( (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    if (rmi->Id == id)
      {
      this->RMIs->RemoveItem(rmi);
      return 1;
      }
    }

  return 0;
}

//----------------------------------------------------------------------------
unsigned long vtkMultiProcessController::AddRMI(vtkRMIFunctionType f,
                                       void *localArg, int tag)
{
  vtkMultiProcessControllerRMI *rmi = vtkMultiProcessControllerRMI::New();

  // Remove any previously registered RMI handler for the tag.
  this->RemoveFirstRMI(tag);

  rmi->Tag = tag;
  rmi->Function = f;
  rmi->LocalArgument = localArg;
  rmi->Id = this->RMICount;
  this->RMICount++;

  this->RMIs->AddItem(rmi);
  rmi->Delete();

  return rmi->Id;
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerRMIOnAllChildren(
  void *arg, int argLength, int rmiTag)
{
  int myid = this->GetLocalProcessId();
  int childid = 2 * myid + 1;
  int numProcs = this->GetNumberOfProcesses();
  if (numProcs > childid)
    {
    this->TriggerRMIInternal(childid, arg, argLength, rmiTag, true);
    }
  childid++;
  if (numProcs > childid)
    {
    this->TriggerRMIInternal(childid, arg, argLength, rmiTag, true);
    }
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerRMI(int remoteProcessId,
                                           void *arg, int argLength,
                                           int rmiTag)
{
  // Deal with sending RMI to ourself here for now.
  if (remoteProcessId == this->GetLocalProcessId())
    {
    this->ProcessRMI(remoteProcessId, arg, argLength, rmiTag);
    return;
    }

  this->TriggerRMIInternal(remoteProcessId, arg, argLength, rmiTag, false);
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerRMIInternal(int remoteProcessId,
    void* arg, int argLength, int rmiTag, bool propagate)
{
  int triggerMessage[128];
  triggerMessage[0] = rmiTag;
  triggerMessage[1] = argLength;

  // It is important for the remote process to know what process invoked it.
  // Multiple processes might try to invoke the method at the same time.
  // The remote method will know where to get additional args.
  triggerMessage[2] = this->GetLocalProcessId();

  // Pass the propagate flag.
  triggerMessage[3] = propagate? 1 : 0;

  // If the message is small, we will try to get the message sent over using a
  // single Send(), rather than two. This helps speed up communication
  // significantly, since sending multiple small messages is generally slower
  // than sending a single large message.
  if (argLength >= 0 && static_cast<unsigned int>(argLength) < sizeof(int)*(128-4))
    {
    if (argLength > 0)
      {
      memcpy(&triggerMessage[4], arg, argLength);
      }
    int num_ints = 4 + ceil(argLength/static_cast<double>(sizeof(int)));
    this->RMICommunicator->Send(triggerMessage, num_ints, remoteProcessId, RMI_TAG);
    }
  else
    {
    this->RMICommunicator->Send(triggerMessage, 4, remoteProcessId, RMI_TAG);
    if (argLength > 0)
      {
      this->RMICommunicator->Send((char*)arg, argLength, remoteProcessId,
        RMI_ARG_TAG);
      }
    }
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerBreakRMIs()
{
  int idx, num;

  if (this->GetLocalProcessId() != 0)
    {
    vtkErrorMacro("Break should be triggered from process 0.");
    return;
    }

  num = this->GetNumberOfProcesses();
  for (idx = 1; idx < num; ++idx)
    {
    this->TriggerRMI(idx, NULL, 0, BREAK_RMI_TAG);
    }
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::ProcessRMIs()
{
  return this->ProcessRMIs(1, 0);
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::ProcessRMIs(int reportErrors, int dont_loop)
{
  int triggerMessage[128];
  unsigned char *arg = NULL;
  int error = RMI_NO_ERROR;

  do
    {
    if (!this->RMICommunicator->Receive(triggerMessage, 128, ANY_SOURCE, RMI_TAG) ||
      this->RMICommunicator->GetCount() < 4)
      {
      if (reportErrors)
        {
        vtkErrorMacro("Could not receive RMI trigger message.");
        }
      error = RMI_TAG_ERROR;
      break;
      }

    if (triggerMessage[1] > 0)
      {
      arg = new unsigned char[triggerMessage[1]];
      // If the message length is small enough, the TriggerRMIInternal() call
      // packs the message data inline. So depending on the message length we
      // use the inline data or make a second receive to fetch the data.
      if (static_cast<unsigned int>(triggerMessage[1]) < sizeof(int)*(128-4))
        {
        int num_ints = 4 + ceil(triggerMessage[1]/static_cast<double>(sizeof(int)));
        if (this->RMICommunicator->GetCount() != num_ints)
          {
          if (reportErrors)
            {
            vtkErrorMacro("Could not receive the RMI argument in its entirety.");
            }
          error= RMI_ARG_ERROR;
          break;
          }
        memcpy(arg, &triggerMessage[4], triggerMessage[1]);
        }
      else
        {
        if (!this->RMICommunicator->Receive((char*)(arg), triggerMessage[1],
            triggerMessage[2], RMI_ARG_TAG) ||
          this->RMICommunicator->GetCount() != triggerMessage[1])
          {
          if (reportErrors)
            {
            vtkErrorMacro("Could not receive RMI argument.");
            }
          error = RMI_ARG_ERROR;
          break;
          }
        }
      }
    if (triggerMessage[3] == 1)//propagate==true
      {
      this->TriggerRMIOnAllChildren(arg, triggerMessage[1], triggerMessage[0]);
      }
    this->ProcessRMI(triggerMessage[2], arg, triggerMessage[1],
      triggerMessage[0]);
    if (arg)
      {
      delete [] arg;
      arg = NULL;
      }

    // check for break
    if (this->BreakFlag)
      {
      this->BreakFlag = 0;
      return error;
      }
    } while (!dont_loop);

  return error;
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::ProcessRMI(int remoteProcessId,
                                           void *arg, int argLength,
                                           int rmiTag)
{
  vtkMultiProcessControllerRMI *rmi = NULL;
  int found = 0;

  // find the rmi
  this->RMIs->InitTraversal();
  while ( !found &&
   (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    if (rmi->Tag == rmiTag)
      {
      found = 1;
      }
    }

  if ( ! found)
    {
    vtkErrorMacro("Process " << this->GetLocalProcessId() <<
                  " Could not find RMI with tag " << rmiTag);
    }
  else
    {
    if ( rmi->Function )
      {
      (*rmi->Function)(rmi->LocalArgument, arg, argLength, remoteProcessId);
      }
    }
}

//============================================================================
// The intent is to give access to a processes controller from a static method.

vtkMultiProcessController *VTK_GLOBAL_MULTI_PROCESS_CONTROLLER = NULL;
//----------------------------------------------------------------------------
vtkMultiProcessController *vtkMultiProcessController::GetGlobalController()
{
  if (VTK_GLOBAL_MULTI_PROCESS_CONTROLLER == NULL)
    {
    return NULL;
    }

  return VTK_GLOBAL_MULTI_PROCESS_CONTROLLER->GetLocalController();
}
//----------------------------------------------------------------------------
// This can be overridden in the subclass to translate controllers.
vtkMultiProcessController *vtkMultiProcessController::GetLocalController()
{
  return VTK_GLOBAL_MULTI_PROCESS_CONTROLLER;
}
//----------------------------------------------------------------------------
// This can be overridden in the subclass to translate controllers.
void vtkMultiProcessController::SetGlobalController(
                                   vtkMultiProcessController *controller)
{
  VTK_GLOBAL_MULTI_PROCESS_CONTROLLER = controller;
}

<commit_msg>BUG: Fixed TriggerRMIOnAllChildren to work with SocketCommunicator. COMP: Fixed warnings.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMultiProcessController.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// This will be the default.
#include "vtkMultiProcessController.h"
#include "vtkDummyController.h"
#include "vtkProcessGroup.h"
#include "vtkSubCommunicator.h"
#include "vtkToolkits.h"

#ifdef VTK_USE_MPI
#include "vtkMPIController.h"
#endif

#include "vtkCollection.h"
#include "vtkObjectFactory.h"
#include "vtkOutputWindow.h"

//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkMultiProcessController);

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

// Helper class to contain the RMI information.
// A subclass of vtkObject so that I can keep them in a collection.
class VTK_PARALLEL_EXPORT vtkMultiProcessControllerRMI : public vtkObject
{
public:
  static vtkMultiProcessControllerRMI *New();
  vtkTypeRevisionMacro(vtkMultiProcessControllerRMI, vtkObject);

  int Tag;
  vtkRMIFunctionType Function;
  void *LocalArgument;

  unsigned long Id;

protected:
  vtkMultiProcessControllerRMI() {};
  vtkMultiProcessControllerRMI(const vtkMultiProcessControllerRMI&);
  void operator=(const vtkMultiProcessControllerRMI&);
};

vtkCxxRevisionMacro(vtkMultiProcessControllerRMI, "1.33");
vtkStandardNewMacro(vtkMultiProcessControllerRMI);

vtkCxxRevisionMacro(vtkMultiProcessController, "1.33");

//----------------------------------------------------------------------------
// An RMI function that will break the "ProcessRMIs" loop.
void vtkMultiProcessControllerBreakRMI(void *localArg,
                                       void *remoteArg, int remoteArgLength,
                                       int vtkNotUsed(remoteId))
{
  vtkMultiProcessController *controller;
  remoteArg = remoteArg;
  remoteArgLength = remoteArgLength;
  controller = (vtkMultiProcessController*)(localArg);
  controller->SetBreakFlag(1);
}

//----------------------------------------------------------------------------
vtkMultiProcessController::vtkMultiProcessController()
{
  int i;

  this->RMICount = 1;

  this->RMIs = vtkCollection::New();

  this->SingleMethod = 0;
  this->SingleData = 0;

  this->Communicator = 0;
  this->RMICommunicator = 0;

  for ( i = 0; i < VTK_MAX_THREADS; i++ )
    {
    this->MultipleMethod[i] = NULL;
    this->MultipleData[i] = NULL;
    }

  this->BreakFlag = 0;
  this->ForceDeepCopy = 1;

  this->OutputWindow = 0;

  // Define an rmi internally to exit from the processing loop.
  this->AddRMI(vtkMultiProcessControllerBreakRMI, this, BREAK_RMI_TAG);
}

//----------------------------------------------------------------------------
// This is an old comment that I do not know is true:
// (We need to have a "GetNetReferenceCount" to avoid memory leaks.)
vtkMultiProcessController::~vtkMultiProcessController()
{
  if ( this->OutputWindow &&
       (this->OutputWindow == vtkOutputWindow::GetInstance()) )
    {
    vtkOutputWindow::SetInstance(0);
    }

  if (this->OutputWindow)
    {
    this->OutputWindow->Delete();
    }

  this->RMIs->Delete();
  this->RMIs = NULL;
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  vtkMultiProcessControllerRMI *rmi;
  vtkIndent nextIndent = indent.GetNextIndent();

  os << indent << "Break flag: " << (this->BreakFlag ? "(yes)" : "(no)")
     << endl;
  os << indent << "Force deep copy: " << (this->ForceDeepCopy ? "(yes)" : "(no)")
     << endl;
  os << indent << "Output window: ";
  if (this->OutputWindow)
    {
    os << endl;
    this->OutputWindow->PrintSelf(os, nextIndent);
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "Communicator: ";
  if (this->Communicator)
    {
    os << endl;
    this->Communicator->PrintSelf(os, nextIndent);
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "RMI communicator: ";
  if (this->RMICommunicator)
    {
    os << endl;
    this->RMICommunicator->PrintSelf(os, nextIndent);
    }
  else
    {
    os << "(none)" << endl;
    }
  os << indent << "RMIs: \n";

  this->RMIs->InitTraversal();
  while ( (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    os << nextIndent << rmi->Tag << endl;
    }

}

//----------------------------------------------------------------------------
void vtkMultiProcessController::SetNumberOfProcesses(int num)
{
  if(this->Communicator)
    {
    this->Communicator->SetNumberOfProcesses(num);
    }
  else
    {
    vtkErrorMacro("Communicator not set.");
    }
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::GetNumberOfProcesses()
{
  if(this->Communicator)
    {
    return this->Communicator->GetNumberOfProcesses();
    }
  else
    {
    vtkErrorMacro("Communicator not set.");
    return 0;
    }
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::GetLocalProcessId()
{
  if(this->Communicator)
    {
    return this->Communicator->GetLocalProcessId();
    }
  else
    {
    vtkErrorMacro("Communicator not set.");
    return -1;
    }
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::SetSingleMethod( vtkProcessFunctionType f,
                                                 void *data )
{
  this->SingleMethod = f;
  this->SingleData   = data;
}

//----------------------------------------------------------------------------
// Set one of the user defined methods that will be run on NumberOfProcesses
// processes when MultipleMethodExecute is called. This method should be
// called with index = 0, 1, ..,  NumberOfProcesses-1 to set up all the
// required user defined methods
void vtkMultiProcessController::SetMultipleMethod( int index,
                                 vtkProcessFunctionType f, void *data )
{
  // You can only set the method for 0 through NumberOfProcesses-1
  if ( index >= this->GetNumberOfProcesses() )
    {
    vtkErrorMacro( << "Can't set method " << index <<
      " with a processes count of " << this->GetNumberOfProcesses() );
    }
  else
    {
    this->MultipleMethod[index] = f;
    this->MultipleData[index]   = data;
    }
}

//-----------------------------------------------------------------------------
vtkMultiProcessController *vtkMultiProcessController::CreateSubController(
                                                         vtkProcessGroup *group)
{
  if (group->GetCommunicator() != this->Communicator)
    {
    vtkErrorMacro(<< "Invalid group for creating a sub controller.");
    return NULL;
    }

  if (group->FindProcessId(this->GetLocalProcessId()) < 0)
    {
    // The group does not contain this process.  Just return NULL.
    return NULL;
    }

  vtkSubCommunicator *subcomm = vtkSubCommunicator::New();
  subcomm->SetGroup(group);

  // We only need a basic implementation of vtkMultiProcessController for the
  // subgroup, so we just use vtkDummyController here.  It's a bit of a misnomer
  // and may lead to confusion, but I think it's better than creating yet
  // another class we have to maintain.
  vtkDummyController *subcontroller = vtkDummyController::New();
  subcontroller->SetCommunicator(subcomm);
  subcontroller->SetRMICommunicator(subcomm);

  subcomm->Delete();

  return subcontroller;
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::RemoveFirstRMI(int tag)
{
  vtkMultiProcessControllerRMI *rmi = NULL;
  this->RMIs->InitTraversal();
  while ( (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    if (rmi->Tag == tag)
      {
      this->RMIs->RemoveItem(rmi);
      return 1;
      }
    }
  return 0;
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::RemoveRMI(unsigned long id)
{
  vtkMultiProcessControllerRMI *rmi = NULL;
  this->RMIs->InitTraversal();
  while ( (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    if (rmi->Id == id)
      {
      this->RMIs->RemoveItem(rmi);
      return 1;
      }
    }

  return 0;
}

//----------------------------------------------------------------------------
unsigned long vtkMultiProcessController::AddRMI(vtkRMIFunctionType f,
                                       void *localArg, int tag)
{
  vtkMultiProcessControllerRMI *rmi = vtkMultiProcessControllerRMI::New();

  // Remove any previously registered RMI handler for the tag.
  this->RemoveFirstRMI(tag);

  rmi->Tag = tag;
  rmi->Function = f;
  rmi->LocalArgument = localArg;
  rmi->Id = this->RMICount;
  this->RMICount++;

  this->RMIs->AddItem(rmi);
  rmi->Delete();

  return rmi->Id;
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerRMIOnAllChildren(
  void *arg, int argLength, int rmiTag)
{
  int myid = this->GetLocalProcessId();
  int childid = 2 * myid + 1;
  int numProcs = this->GetNumberOfProcesses();
  if (numProcs > childid)
    {
    this->TriggerRMIInternal(childid, arg, argLength, rmiTag, true);
    }
  childid++;
  if (numProcs > childid)
    {
    this->TriggerRMIInternal(childid, arg, argLength, rmiTag, true);
    }
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerRMI(int remoteProcessId,
                                           void *arg, int argLength,
                                           int rmiTag)
{
  // Deal with sending RMI to ourself here for now.
  if (remoteProcessId == this->GetLocalProcessId())
    {
    this->ProcessRMI(remoteProcessId, arg, argLength, rmiTag);
    return;
    }

  this->TriggerRMIInternal(remoteProcessId, arg, argLength, rmiTag, false);
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerRMIInternal(int remoteProcessId,
    void* arg, int argLength, int rmiTag, bool propagate)
{
  int triggerMessage[128];
  triggerMessage[0] = rmiTag;
  triggerMessage[1] = argLength;

  // It is important for the remote process to know what process invoked it.
  // Multiple processes might try to invoke the method at the same time.
  // The remote method will know where to get additional args.
  triggerMessage[2] = this->GetLocalProcessId();

  // Pass the propagate flag.
  triggerMessage[3] = propagate? 1 : 0;

  // If the message is small, we will try to get the message sent over using a
  // single Send(), rather than two. This helps speed up communication
  // significantly, since sending multiple small messages is generally slower
  // than sending a single large message.
  if (argLength >= 0 && static_cast<unsigned int>(argLength) < sizeof(int)*(128-4))
    {
    if (argLength > 0)
      {
      memcpy(&triggerMessage[4], arg, argLength);
      }
    int num_ints = 4 + static_cast<int>(ceil(argLength/static_cast<double>(sizeof(int))));
    this->RMICommunicator->Send(triggerMessage, num_ints, remoteProcessId, RMI_TAG);
    }
  else
    {
    this->RMICommunicator->Send(triggerMessage, 4, remoteProcessId, RMI_TAG);
    if (argLength > 0)
      {
      this->RMICommunicator->Send((char*)arg, argLength, remoteProcessId,
        RMI_ARG_TAG);
      }
    }
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::TriggerBreakRMIs()
{
  int idx, num;

  if (this->GetLocalProcessId() != 0)
    {
    vtkErrorMacro("Break should be triggered from process 0.");
    return;
    }

  num = this->GetNumberOfProcesses();
  for (idx = 1; idx < num; ++idx)
    {
    this->TriggerRMI(idx, NULL, 0, BREAK_RMI_TAG);
    }
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::ProcessRMIs()
{
  return this->ProcessRMIs(1, 0);
}

//----------------------------------------------------------------------------
int vtkMultiProcessController::ProcessRMIs(int reportErrors, int dont_loop)
{
  int triggerMessage[128];
  unsigned char *arg = NULL;
  int error = RMI_NO_ERROR;

  do
    {
    if (!this->RMICommunicator->Receive(triggerMessage, 128, ANY_SOURCE, RMI_TAG) ||
      this->RMICommunicator->GetCount() < 4)
      {
      if (reportErrors)
        {
        vtkErrorMacro("Could not receive RMI trigger message.");
        }
      error = RMI_TAG_ERROR;
      break;
      }

    if (triggerMessage[1] > 0)
      {
      arg = new unsigned char[triggerMessage[1]];
      // If the message length is small enough, the TriggerRMIInternal() call
      // packs the message data inline. So depending on the message length we
      // use the inline data or make a second receive to fetch the data.
      if (static_cast<unsigned int>(triggerMessage[1]) < sizeof(int)*(128-4))
        {
        int num_ints = 4 + ceil(triggerMessage[1]/static_cast<double>(sizeof(int)));
        if (this->RMICommunicator->GetCount() != num_ints)
          {
          if (reportErrors)
            {
            vtkErrorMacro("Could not receive the RMI argument in its entirety.");
            }
          error= RMI_ARG_ERROR;
          break;
          }
        memcpy(arg, &triggerMessage[4], triggerMessage[1]);
        }
      else
        {
        if (!this->RMICommunicator->Receive((char*)(arg), triggerMessage[1],
            triggerMessage[2], RMI_ARG_TAG) ||
          this->RMICommunicator->GetCount() != triggerMessage[1])
          {
          if (reportErrors)
            {
            vtkErrorMacro("Could not receive RMI argument.");
            }
          error = RMI_ARG_ERROR;
          break;
          }
        }
      }
    if (triggerMessage[3] == 1 && this->GetNumberOfProcesses() > 3)//propagate==true
      {
      this->TriggerRMIOnAllChildren(arg, triggerMessage[1], triggerMessage[0]);
      }
    this->ProcessRMI(triggerMessage[2], arg, triggerMessage[1],
      triggerMessage[0]);
    if (arg)
      {
      delete [] arg;
      arg = NULL;
      }

    // check for break
    if (this->BreakFlag)
      {
      this->BreakFlag = 0;
      return error;
      }
    } while (!dont_loop);

  return error;
}

//----------------------------------------------------------------------------
void vtkMultiProcessController::ProcessRMI(int remoteProcessId,
                                           void *arg, int argLength,
                                           int rmiTag)
{
  vtkMultiProcessControllerRMI *rmi = NULL;
  int found = 0;

  // find the rmi
  this->RMIs->InitTraversal();
  while ( !found &&
   (rmi = (vtkMultiProcessControllerRMI*)(this->RMIs->GetNextItemAsObject())) )
    {
    if (rmi->Tag == rmiTag)
      {
      found = 1;
      }
    }

  if ( ! found)
    {
    vtkErrorMacro("Process " << this->GetLocalProcessId() <<
                  " Could not find RMI with tag " << rmiTag);
    }
  else
    {
    if ( rmi->Function )
      {
      (*rmi->Function)(rmi->LocalArgument, arg, argLength, remoteProcessId);
      }
    }
}

//============================================================================
// The intent is to give access to a processes controller from a static method.

vtkMultiProcessController *VTK_GLOBAL_MULTI_PROCESS_CONTROLLER = NULL;
//----------------------------------------------------------------------------
vtkMultiProcessController *vtkMultiProcessController::GetGlobalController()
{
  if (VTK_GLOBAL_MULTI_PROCESS_CONTROLLER == NULL)
    {
    return NULL;
    }

  return VTK_GLOBAL_MULTI_PROCESS_CONTROLLER->GetLocalController();
}
//----------------------------------------------------------------------------
// This can be overridden in the subclass to translate controllers.
vtkMultiProcessController *vtkMultiProcessController::GetLocalController()
{
  return VTK_GLOBAL_MULTI_PROCESS_CONTROLLER;
}
//----------------------------------------------------------------------------
// This can be overridden in the subclass to translate controllers.
void vtkMultiProcessController::SetGlobalController(
                                   vtkMultiProcessController *controller)
{
  VTK_GLOBAL_MULTI_PROCESS_CONTROLLER = controller;
}

<|endoftext|>


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

/**
 * guard.cc: Functions for thread-safe static initialisation.
 *
 * Static values in C++ can be initialised lazily their first use.  This file
 * contains functions that are used to ensure that two threads attempting to
 * initialize the same static do not call the constructor twice.  This is
 * important because constructors can have side effects, so calling the
 * constructor twice may be very bad.
 *
 * Statics that require initialisation are protected by a 64-bit value.  Any
 * platform that can do 32-bit atomic test and set operations can use this
 * value as a low-overhead lock.  Because statics (in most sane code) are
 * accessed far more times than they are initialised, this lock implementation
 * is heavily optimised towards the case where the static has already been
 * initialised.
 */
#include <stdint.h>
#include <pthread.h>
#include <assert.h>
#include "atomic.h"

#ifdef __arm__
// ARM ABI - 32-bit guards.

/**
 * Acquires a lock on a guard, returning 0 if the object has already been
 * initialised, and 1 if it has not.  If the object is already constructed then
 * this function just needs to read a byte from memory and return.
 */
extern "C" int __cxa_guard_acquire(volatile int32_t *guard_object)
{
	if ((1<<31) == *guard_object) { return 0; }
	// If we can atomically move the value from 0 -> 1, then this is
	// uninitialised.
	if (__sync_bool_compare_and_swap(guard_object, 0, 1))
	{
		return 1;
	}
	// If the value is not 0, some other thread was initialising this.  Spin
	// until it's finished.
	while (__sync_bool_compare_and_swap(guard_object, (1<<31), (1<<31)))
	{
		// If the other thread aborted, then we grab the lock
		if (__sync_bool_compare_and_swap(guard_object, 0, 1))
		{
			return 1;
		}
		sched_yield();
	}
	return 0;
}

/**
 * Releases the lock without marking the object as initialised.  This function
 * is called if initialising a static causes an exception to be thrown.
 */
extern "C" void __cxa_guard_abort(int32_t *guard_object)
{
	assert(__sync_bool_compare_and_swap(guard_object, 1, 0));
}
/**
 * Releases the guard and marks the object as initialised.  This function is
 * called after successful initialisation of a static.
 */
extern "C" void __cxa_guard_release(int32_t *guard_object)
{
	assert(__sync_bool_compare_and_swap(guard_object, 1, (1<<31)));
}

#else
// Itanium ABI: 64-bit guards

/**
 * Returns a pointer to the low 32 bits in a 64-bit value, respecting the
 * platform's byte order.
 */
static int32_t *low_32_bits(volatile int64_t *ptr)
{
	int32_t *low= (int32_t*)ptr;
	// Test if the machine is big endian - constant propagation at compile
	// time should eliminate this completely.
	int one = 1;
	if (*(char*)&one != 1)
	{
		low++;
	}
	return low;
}

/**
 * Acquires a lock on a guard, returning 0 if the object has already been
 * initialised, and 1 if it has not.  If the object is already constructed then
 * this function just needs to read a byte from memory and return.
 */
extern "C" int __cxa_guard_acquire(volatile int64_t *guard_object)
{
	char first_byte = (*guard_object) >> 56;
	if (1 == first_byte) { return 0; }
	int32_t *lock = low_32_bits(guard_object);
	// Simple spin lock using the low 32 bits.  We assume that concurrent
	// attempts to initialize statics are very rare, so we don't need to
	// optimise for the case where we have lots of threads trying to acquire
	// the lock at the same time.
	while (!__sync_bool_compare_and_swap_4(lock, 0, 1))
	{
		if (1 == ((*guard_object) >> 56))
		{
			break;
		}
		sched_yield();
	}
	// We have to test the guard again, in case another thread has performed
	// the initialisation while we were trying to acquire the lock.
	first_byte = (*guard_object) >> 56;
	return (1 != first_byte);
}

/**
 * Releases the lock without marking the object as initialised.  This function
 * is called if initialising a static causes an exception to be thrown.
 */
extern "C" void __cxa_guard_abort(int64_t *guard_object)
{
	int32_t *lock = low_32_bits(guard_object);
	ATOMIC_STORE(lock, 0);
}
/**
 * Releases the guard and marks the object as initialised.  This function is
 * called after successful initialisation of a static.
 */
extern "C" void __cxa_guard_release(int64_t *guard_object)
{
	// Set the first byte to 1
	// Note: We don't do an atomic load here because getting a stale value
	// is not a problem in the current implementation.
	ATOMIC_STORE(guard_object, (*guard_object | ((int64_t)1) << 56));
	__cxa_guard_abort(guard_object);
}

#endif
<commit_msg>am 992fe3a8: Fixes for ARM guard initialisation.<commit_after>/*
 * Copyright 2010-2012 PathScale, Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * guard.cc: Functions for thread-safe static initialisation.
 *
 * Static values in C++ can be initialised lazily their first use.  This file
 * contains functions that are used to ensure that two threads attempting to
 * initialize the same static do not call the constructor twice.  This is
 * important because constructors can have side effects, so calling the
 * constructor twice may be very bad.
 *
 * Statics that require initialisation are protected by a 64-bit value.  Any
 * platform that can do 32-bit atomic test and set operations can use this
 * value as a low-overhead lock.  Because statics (in most sane code) are
 * accessed far more times than they are initialised, this lock implementation
 * is heavily optimised towards the case where the static has already been
 * initialised.
 */
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include "atomic.h"

#ifdef __arm__
// ARM ABI - 32-bit guards.

/*
 * The least significant bit of the guard variable indicates that the object
 * has been initialised, the most significant bit is used for a spinlock.
 */
static const uint32_t LOCKED = ((uint32_t)1) << 31;
static const uint32_t INITIALISED = 1;

/**
 * Acquires a lock on a guard, returning 0 if the object has already been
 * initialised, and 1 if it has not.  If the object is already constructed then
 * this function just needs to read a byte from memory and return.
 */
extern "C" int __cxa_guard_acquire(volatile uint32_t *guard_object)
{
	// Not an atomic read, doesn't establish a happens-before relationship, but
	// if one is already established and we end up seeing an initialised state
	// then it's a fast path, otherwise we'll do something more expensive than
	// this test anyway...
	if ((INITIALISED == *guard_object)) { return 0; }
	// Spin trying to do the initialisation
	while (1)
	{
		// Loop trying to move the value of the guard from 0 (not
		// locked, not initialised) to the locked-uninitialised
		// position.
		switch (__sync_val_compare_and_swap(guard_object, 0, LOCKED))
		{
			// If the old value was 0, we succeeded, so continue
			// initialising
			case 0:
				return 1;
			// If this was already initialised, return and let the caller skip
			// initialising it again.
			case INITIALISED:
				return 0;
			// If it is locked by another thread, relinquish the CPU and try
			// again later.
			case LOCKED:
				sched_yield();
				break;
			// If it is some other value, then something has gone badly wrong.
			// Give up.
			default:
				fprintf(stderr, "Invalid state detected attempting to lock static initialiser.\n");
				abort();
		}
	}
	__builtin_unreachable();
}

/**
 * Releases the lock without marking the object as initialised.  This function
 * is called if initialising a static causes an exception to be thrown.
 */
extern "C" void __cxa_guard_abort(uint32_t *guard_object)
{
	__attribute__((unused))
	bool reset = __sync_bool_compare_and_swap(guard_object, LOCKED, 0);
	assert(reset);
}
/**
 * Releases the guard and marks the object as initialised.  This function is
 * called after successful initialisation of a static.
 */
extern "C" void __cxa_guard_release(uint32_t *guard_object)
{
	__attribute__((unused))
	bool reset = __sync_bool_compare_and_swap(guard_object, LOCKED, INITIALISED);
	assert(reset);
}

#else
// Itanium ABI: 64-bit guards

/**
 * Returns a pointer to the low 32 bits in a 64-bit value, respecting the
 * platform's byte order.
 */
static int32_t *low_32_bits(volatile int64_t *ptr)
{
	int32_t *low= (int32_t*)ptr;
	// Test if the machine is big endian - constant propagation at compile
	// time should eliminate this completely.
	int one = 1;
	if (*(char*)&one != 1)
	{
		low++;
	}
	return low;
}

/**
 * Acquires a lock on a guard, returning 0 if the object has already been
 * initialised, and 1 if it has not.  If the object is already constructed then
 * this function just needs to read a byte from memory and return.
 */
extern "C" int __cxa_guard_acquire(volatile int64_t *guard_object)
{
	char first_byte = (*guard_object) >> 56;
	if (1 == first_byte) { return 0; }
	int32_t *lock = low_32_bits(guard_object);
	// Simple spin lock using the low 32 bits.  We assume that concurrent
	// attempts to initialize statics are very rare, so we don't need to
	// optimise for the case where we have lots of threads trying to acquire
	// the lock at the same time.
	while (!__sync_bool_compare_and_swap_4(lock, 0, 1))
	{
		if (1 == ((*guard_object) >> 56))
		{
			break;
		}
		sched_yield();
	}
	// We have to test the guard again, in case another thread has performed
	// the initialisation while we were trying to acquire the lock.
	first_byte = (*guard_object) >> 56;
	return (1 != first_byte);
}

/**
 * Releases the lock without marking the object as initialised.  This function
 * is called if initialising a static causes an exception to be thrown.
 */
extern "C" void __cxa_guard_abort(int64_t *guard_object)
{
	int32_t *lock = low_32_bits(guard_object);
	ATOMIC_STORE(lock, 0);
}
/**
 * Releases the guard and marks the object as initialised.  This function is
 * called after successful initialisation of a static.
 */
extern "C" void __cxa_guard_release(int64_t *guard_object)
{
	// Set the first byte to 1
	// Note: We don't do an atomic load here because getting a stale value
	// is not a problem in the current implementation.
	ATOMIC_STORE(guard_object, (*guard_object | ((int64_t)1) << 56));
	__cxa_guard_abort(guard_object);
}

#endif
<|endoftext|>


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

#include <stdio.h>
#include <stdlib.h>

#include <map>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/process/launch.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "tools/gn/commands.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/input_file.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/setup.h"
#include "tools/gn/standard_out.h"
#include "tools/gn/tokenizer.h"
#include "tools/gn/trace.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#endif

namespace commands {

namespace {

const char kSwitchList[] = "list";
const char kSwitchShort[] = "short";

bool DoesLineBeginWithComment(const base::StringPiece& line) {
  // Skip whitespace.
  size_t i = 0;
  while (i < line.size() && IsAsciiWhitespace(line[i]))
    i++;

  return i < line.size() && line[i] == '#';
}

// Returns the offset of the beginning of the line identified by |offset|.
size_t BackUpToLineBegin(const std::string& data, size_t offset) {
  // Degenerate case of an empty line. Below we'll try to return the
  // character after the newline, but that will be incorrect in this case.
  if (offset == 0 || Tokenizer::IsNewline(data, offset))
    return offset;

  size_t cur = offset;
  do {
    cur --;
    if (Tokenizer::IsNewline(data, cur))
      return cur + 1;  // Want the first character *after* the newline.
  } while (cur > 0);
  return 0;
}

// Assumes DoesLineBeginWithComment(), this strips the # character from the
// beginning and normalizes preceeding whitespace.
std::string StripHashFromLine(const base::StringPiece& line) {
  // Replace the # sign and everything before it with 3 spaces, so that a
  // normal comment that has a space after the # will be indented 4 spaces
  // (which makes our formatting come out nicely). If the comment is indented
  // from there, we want to preserve that indenting.
  return "   " + line.substr(line.find('#') + 1).as_string();
}

// Tries to find the comment before the setting of the given value.
void GetContextForValue(const Value& value,
                        std::string* location_str,
                        std::string* comment) {
  Location location = value.origin()->GetRange().begin();
  const InputFile* file = location.file();
  if (!file)
    return;

  *location_str = file->name().value() + ":" +
      base::IntToString(location.line_number());

  const std::string& data = file->contents();
  size_t line_off =
      Tokenizer::ByteOffsetOfNthLine(data, location.line_number());

  while (line_off > 1) {
    line_off -= 2;  // Back up to end of previous line.
    size_t previous_line_offset = BackUpToLineBegin(data, line_off);

    base::StringPiece line(&data[previous_line_offset],
                           line_off - previous_line_offset + 1);
    if (!DoesLineBeginWithComment(line))
      break;

    comment->insert(0, StripHashFromLine(line) + "\n");
    line_off = previous_line_offset;
  }
}

void PrintArgHelp(const base::StringPiece& name, const Value& value) {
  OutputString(name.as_string(), DECORATION_YELLOW);
  OutputString("  Default = " + value.ToString(true) + "\n");

  if (value.origin()) {
    std::string location, comment;
    GetContextForValue(value, &location, &comment);
    OutputString("    " + location + "\n" + comment);
  } else {
    OutputString("    (Internally set)\n");
  }
}

int ListArgs(const std::string& build_dir) {
  Setup* setup = new Setup;
  setup->set_check_for_bad_items(false);
  if (!setup->DoSetup(build_dir, false) || !setup->Run())
    return 1;

  Scope::KeyValueMap build_args;
  setup->build_settings().build_args().MergeDeclaredArguments(&build_args);

  // Find all of the arguments we care about. Use a regular map so they're
  // sorted nicely when we write them out.
  std::map<base::StringPiece, Value> sorted_args;
  std::string list_value =
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kSwitchList);
  if (list_value.empty()) {
    // List all values.
    for (const auto& arg : build_args)
      sorted_args.insert(arg);
  } else {
    // List just the one specified as the parameter to --list.
    Scope::KeyValueMap::const_iterator found_arg = build_args.find(list_value);
    if (found_arg == build_args.end()) {
      Err(Location(), "Unknown build argument.",
          "You asked for \"" + list_value + "\" which I didn't find in any "
          "build file\nassociated with this build.").PrintToStdout();
      return 1;
    }
    sorted_args.insert(*found_arg);
  }

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchShort)) {
    // Short key=value output.
    for (const auto& arg : sorted_args) {
      OutputString(arg.first.as_string());
      OutputString(" = ");
      OutputString(arg.second.ToString(true));
      OutputString("\n");
    }
    return 0;
  }

  // Long output.
  for (const auto& arg : sorted_args) {
    PrintArgHelp(arg.first, arg.second);
    OutputString("\n");
  }

  return 0;
}

#if defined(OS_WIN)

bool RunEditor(const base::FilePath& file_to_edit) {
  SHELLEXECUTEINFO info;
  memset(&info, 0, sizeof(info));
  info.cbSize = sizeof(info);
  info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_CLASSNAME;
  info.lpFile = file_to_edit.value().c_str();
  info.nShow = SW_SHOW;
  info.lpClass = L".txt";
  if (!::ShellExecuteEx(&info)) {
    Err(Location(), "Couldn't run editor.",
        "Just edit \"" + FilePathToUTF8(file_to_edit) +
        "\" manually instead.").PrintToStdout();
    return false;
  }

  if (!info.hProcess) {
    // Windows re-used an existing process.
    OutputString("\"" + FilePathToUTF8(file_to_edit) +
                 "\" opened in editor, save it and press <Enter> when done.\n");
    getchar();
  } else {
    OutputString("Waiting for editor on \"" + FilePathToUTF8(file_to_edit) +
                 "\"...\n");
    ::WaitForSingleObject(info.hProcess, INFINITE);
    ::CloseHandle(info.hProcess);
  }
  return true;
}

#else  // POSIX

bool RunEditor(const base::FilePath& file_to_edit) {
  // Prefer $VISUAL, then $EDITOR, then vi.
  const char* editor_ptr = getenv("VISUAL");
  if (!editor_ptr)
    editor_ptr = getenv("EDITOR");
  if (!editor_ptr)
    editor_ptr = "vi";

  std::string cmd(editor_ptr);
  cmd.append(" \"");

  // Its impossible to do this properly since we don't know the user's shell,
  // but quoting and escaping internal quotes should handle 99.999% of all
  // cases.
  std::string escaped_name = file_to_edit.value();
  ReplaceSubstringsAfterOffset(&escaped_name, 0, "\"", "\\\"");
  cmd.append(escaped_name);
  cmd.push_back('"');

  OutputString("Waiting for editor on \"" + file_to_edit.value() +
               "\"...\n");
  return system(cmd.c_str()) == 0;
}

#endif

int EditArgsFile(const std::string& build_dir) {
  {
    // Scope the setup. We only use it for some basic state. We'll do the
    // "real" build below in the gen command.
    Setup setup;
    setup.set_check_for_bad_items(false);
    // Don't fill build arguments. We're about to edit the file which supplies
    // these in the first place.
    setup.set_fill_arguments(false);
    if (!setup.DoSetup(build_dir, true))
      return 1;

    // Ensure the file exists. Need to normalize path separators since on
    // Windows they can come out as forward slashes here, and that confuses some
    // of the commands.
    base::FilePath arg_file =
        setup.build_settings().GetFullPath(setup.GetBuildArgFile())
        .NormalizePathSeparators();
    if (!base::PathExists(arg_file)) {
      std::string argfile_default_contents =
          "# Build arguments go here. Examples:\n"
          "#   enable_doom_melon = true\n"
          "#   crazy_something = \"absolutely\"\n";
#if defined(OS_WIN)
      // Use Windows lineendings for this file since it will often open in
      // Notepad which can't handle Unix ones.
      ReplaceSubstringsAfterOffset(&argfile_default_contents, 0, "\n", "\r\n");
#endif
      base::CreateDirectory(arg_file.DirName());
      base::WriteFile(arg_file, argfile_default_contents.c_str(),
                      static_cast<int>(argfile_default_contents.size()));
    }

    ScopedTrace editor_trace(TraceItem::TRACE_SETUP, "Waiting for editor");
    if (!RunEditor(arg_file))
      return 1;
  }

  // Now do a normal "gen" command.
  OutputString("Generating files...\n");
  std::vector<std::string> gen_commands;
  gen_commands.push_back(build_dir);
  return RunGen(gen_commands);
}

}  // namespace

extern const char kArgs[] = "args";
extern const char kArgs_HelpShort[] =
    "args: Display or configure arguments declared by the build.";
extern const char kArgs_Help[] =
    "gn args [arg name]\n"
    "\n"
    "  See also \"gn help buildargs\" for a more high-level overview of how\n"
    "  build arguments work.\n"
    "\n"
    "Usage\n"
    "  gn args <dir_name>\n"
    "      Open the arguments for the given build directory in an editor\n"
    "      (as specified by the EDITOR environment variable). If the given\n"
    "      build directory doesn't exist, it will be created and an empty\n"
    "      args file will be opened in the editor. You would type something\n"
    "      like this into that file:\n"
    "          enable_doom_melon=false\n"
    "          os=\"android\"\n"
    "\n"
    "      Note: you can edit the build args manually by editing the file\n"
    "      \"args.gn\" in the build directory and then running\n"
    "      \"gn gen <build_dir>\".\n"
    "\n"
    "  gn args <dir_name> --list[=<exact_arg>] [--short]\n"
    "      Lists all build arguments available in the current configuration,\n"
    "      or, if an exact_arg is specified for the list flag, just that one\n"
    "      build argument.\n"
    "\n"
    "      The output will list the declaration location, default value, and\n"
    "      comment preceeding the declaration. If --short is specified,\n"
    "      only the names and values will be printed.\n"
    "\n"
    "      If the dir_name is specified, the build configuration will be\n"
    "      taken from that build directory. The reason this is needed is that\n"
    "      the definition of some arguments is dependent on the build\n"
    "      configuration, so setting some values might add, remove, or change\n"
    "      the default values for other arguments. Specifying your exact\n"
    "      configuration allows the proper arguments to be displayed.\n"
    "\n"
    "      Instead of specifying the dir_name, you can also use the\n"
    "      command-line flag to specify the build configuration:\n"
    "        --args=<exact list of args to use>\n"
    "\n"
    "Examples\n"
    "  gn args out/Debug\n"
    "    Opens an editor with the args for out/Debug.\n"
    "\n"
    "  gn args out/Debug --list --short\n"
    "    Prints all arguments with their default values for the out/Debug\n"
    "    build.\n"
    "\n"
    "  gn args out/Debug --list=cpu_arch\n"
    "    Prints information about the \"cpu_arch\" argument for the out/Debug\n"
    "    build.\n"
    "\n"
    "  gn args --list --args=\"os=\\\"android\\\" enable_doom_melon=true\"\n"
    "    Prints all arguments with the default values for a build with the\n"
    "    given arguments set (which may affect the values of other\n"
    "    arguments).\n";

int RunArgs(const std::vector<std::string>& args) {
  if (args.size() != 1) {
    Err(Location(), "Exactly one build dir needed.",
        "Usage: \"gn args <build_dir>\"\n"
        "Or see \"gn help args\" for more variants.").PrintToStdout();
    return 1;
  }

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchList))
    return ListArgs(args[0]);
  return EditArgsFile(args[0]);
}

}  // namespace commands
<commit_msg>gn: Check GN_EDITOR before EDITOR in environment variables.<commit_after>// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>
#include <stdlib.h>

#include <map>

#include "base/command_line.h"
#include "base/environment.h"
#include "base/files/file_util.h"
#include "base/process/launch.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "tools/gn/commands.h"
#include "tools/gn/filesystem_utils.h"
#include "tools/gn/input_file.h"
#include "tools/gn/parse_tree.h"
#include "tools/gn/setup.h"
#include "tools/gn/standard_out.h"
#include "tools/gn/tokenizer.h"
#include "tools/gn/trace.h"

#if defined(OS_WIN)
#include <windows.h>
#include <shellapi.h>
#endif

namespace commands {

namespace {

const char kSwitchList[] = "list";
const char kSwitchShort[] = "short";

bool DoesLineBeginWithComment(const base::StringPiece& line) {
  // Skip whitespace.
  size_t i = 0;
  while (i < line.size() && IsAsciiWhitespace(line[i]))
    i++;

  return i < line.size() && line[i] == '#';
}

// Returns the offset of the beginning of the line identified by |offset|.
size_t BackUpToLineBegin(const std::string& data, size_t offset) {
  // Degenerate case of an empty line. Below we'll try to return the
  // character after the newline, but that will be incorrect in this case.
  if (offset == 0 || Tokenizer::IsNewline(data, offset))
    return offset;

  size_t cur = offset;
  do {
    cur --;
    if (Tokenizer::IsNewline(data, cur))
      return cur + 1;  // Want the first character *after* the newline.
  } while (cur > 0);
  return 0;
}

// Assumes DoesLineBeginWithComment(), this strips the # character from the
// beginning and normalizes preceeding whitespace.
std::string StripHashFromLine(const base::StringPiece& line) {
  // Replace the # sign and everything before it with 3 spaces, so that a
  // normal comment that has a space after the # will be indented 4 spaces
  // (which makes our formatting come out nicely). If the comment is indented
  // from there, we want to preserve that indenting.
  return "   " + line.substr(line.find('#') + 1).as_string();
}

// Tries to find the comment before the setting of the given value.
void GetContextForValue(const Value& value,
                        std::string* location_str,
                        std::string* comment) {
  Location location = value.origin()->GetRange().begin();
  const InputFile* file = location.file();
  if (!file)
    return;

  *location_str = file->name().value() + ":" +
      base::IntToString(location.line_number());

  const std::string& data = file->contents();
  size_t line_off =
      Tokenizer::ByteOffsetOfNthLine(data, location.line_number());

  while (line_off > 1) {
    line_off -= 2;  // Back up to end of previous line.
    size_t previous_line_offset = BackUpToLineBegin(data, line_off);

    base::StringPiece line(&data[previous_line_offset],
                           line_off - previous_line_offset + 1);
    if (!DoesLineBeginWithComment(line))
      break;

    comment->insert(0, StripHashFromLine(line) + "\n");
    line_off = previous_line_offset;
  }
}

void PrintArgHelp(const base::StringPiece& name, const Value& value) {
  OutputString(name.as_string(), DECORATION_YELLOW);
  OutputString("  Default = " + value.ToString(true) + "\n");

  if (value.origin()) {
    std::string location, comment;
    GetContextForValue(value, &location, &comment);
    OutputString("    " + location + "\n" + comment);
  } else {
    OutputString("    (Internally set)\n");
  }
}

int ListArgs(const std::string& build_dir) {
  Setup* setup = new Setup;
  setup->set_check_for_bad_items(false);
  if (!setup->DoSetup(build_dir, false) || !setup->Run())
    return 1;

  Scope::KeyValueMap build_args;
  setup->build_settings().build_args().MergeDeclaredArguments(&build_args);

  // Find all of the arguments we care about. Use a regular map so they're
  // sorted nicely when we write them out.
  std::map<base::StringPiece, Value> sorted_args;
  std::string list_value =
      base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(kSwitchList);
  if (list_value.empty()) {
    // List all values.
    for (const auto& arg : build_args)
      sorted_args.insert(arg);
  } else {
    // List just the one specified as the parameter to --list.
    Scope::KeyValueMap::const_iterator found_arg = build_args.find(list_value);
    if (found_arg == build_args.end()) {
      Err(Location(), "Unknown build argument.",
          "You asked for \"" + list_value + "\" which I didn't find in any "
          "build file\nassociated with this build.").PrintToStdout();
      return 1;
    }
    sorted_args.insert(*found_arg);
  }

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchShort)) {
    // Short key=value output.
    for (const auto& arg : sorted_args) {
      OutputString(arg.first.as_string());
      OutputString(" = ");
      OutputString(arg.second.ToString(true));
      OutputString("\n");
    }
    return 0;
  }

  // Long output.
  for (const auto& arg : sorted_args) {
    PrintArgHelp(arg.first, arg.second);
    OutputString("\n");
  }

  return 0;
}

#if defined(OS_WIN)

bool RunEditor(const base::FilePath& file_to_edit) {
  SHELLEXECUTEINFO info;
  memset(&info, 0, sizeof(info));
  info.cbSize = sizeof(info);
  info.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_CLASSNAME;
  info.lpFile = file_to_edit.value().c_str();
  info.nShow = SW_SHOW;
  info.lpClass = L".txt";
  if (!::ShellExecuteEx(&info)) {
    Err(Location(), "Couldn't run editor.",
        "Just edit \"" + FilePathToUTF8(file_to_edit) +
        "\" manually instead.").PrintToStdout();
    return false;
  }

  if (!info.hProcess) {
    // Windows re-used an existing process.
    OutputString("\"" + FilePathToUTF8(file_to_edit) +
                 "\" opened in editor, save it and press <Enter> when done.\n");
    getchar();
  } else {
    OutputString("Waiting for editor on \"" + FilePathToUTF8(file_to_edit) +
                 "\"...\n");
    ::WaitForSingleObject(info.hProcess, INFINITE);
    ::CloseHandle(info.hProcess);
  }
  return true;
}

#else  // POSIX

bool RunEditor(const base::FilePath& file_to_edit) {
  const char* editor_ptr = getenv("VISUAL");
  if (!editor_ptr)
    editor_ptr = getenv("GN_EDITOR");
  if (!editor_ptr)
    editor_ptr = getenv("EDITOR");
  if (!editor_ptr)
    editor_ptr = "vi";

  std::string cmd(editor_ptr);
  cmd.append(" \"");

  // Its impossible to do this properly since we don't know the user's shell,
  // but quoting and escaping internal quotes should handle 99.999% of all
  // cases.
  std::string escaped_name = file_to_edit.value();
  ReplaceSubstringsAfterOffset(&escaped_name, 0, "\"", "\\\"");
  cmd.append(escaped_name);
  cmd.push_back('"');

  OutputString("Waiting for editor on \"" + file_to_edit.value() +
               "\"...\n");
  return system(cmd.c_str()) == 0;
}

#endif

int EditArgsFile(const std::string& build_dir) {
  {
    // Scope the setup. We only use it for some basic state. We'll do the
    // "real" build below in the gen command.
    Setup setup;
    setup.set_check_for_bad_items(false);
    // Don't fill build arguments. We're about to edit the file which supplies
    // these in the first place.
    setup.set_fill_arguments(false);
    if (!setup.DoSetup(build_dir, true))
      return 1;

    // Ensure the file exists. Need to normalize path separators since on
    // Windows they can come out as forward slashes here, and that confuses some
    // of the commands.
    base::FilePath arg_file =
        setup.build_settings().GetFullPath(setup.GetBuildArgFile())
        .NormalizePathSeparators();
    if (!base::PathExists(arg_file)) {
      std::string argfile_default_contents =
          "# Build arguments go here. Examples:\n"
          "#   enable_doom_melon = true\n"
          "#   crazy_something = \"absolutely\"\n";
#if defined(OS_WIN)
      // Use Windows lineendings for this file since it will often open in
      // Notepad which can't handle Unix ones.
      ReplaceSubstringsAfterOffset(&argfile_default_contents, 0, "\n", "\r\n");
#endif
      base::CreateDirectory(arg_file.DirName());
      base::WriteFile(arg_file, argfile_default_contents.c_str(),
                      static_cast<int>(argfile_default_contents.size()));
    }

    ScopedTrace editor_trace(TraceItem::TRACE_SETUP, "Waiting for editor");
    if (!RunEditor(arg_file))
      return 1;
  }

  // Now do a normal "gen" command.
  OutputString("Generating files...\n");
  std::vector<std::string> gen_commands;
  gen_commands.push_back(build_dir);
  return RunGen(gen_commands);
}

}  // namespace

extern const char kArgs[] = "args";
extern const char kArgs_HelpShort[] =
    "args: Display or configure arguments declared by the build.";
extern const char kArgs_Help[] =
    "gn args [arg name]\n"
    "\n"
    "  See also \"gn help buildargs\" for a more high-level overview of how\n"
    "  build arguments work.\n"
    "\n"
    "Usage\n"
    "  gn args <dir_name>\n"
    "      Open the arguments for the given build directory in an editor\n"
    "      (as specified by the EDITOR environment variable). If the given\n"
    "      build directory doesn't exist, it will be created and an empty\n"
    "      args file will be opened in the editor. You would type something\n"
    "      like this into that file:\n"
    "          enable_doom_melon=false\n"
    "          os=\"android\"\n"
    "\n"
    "      Note: you can edit the build args manually by editing the file\n"
    "      \"args.gn\" in the build directory and then running\n"
    "      \"gn gen <build_dir>\".\n"
    "\n"
    "  gn args <dir_name> --list[=<exact_arg>] [--short]\n"
    "      Lists all build arguments available in the current configuration,\n"
    "      or, if an exact_arg is specified for the list flag, just that one\n"
    "      build argument.\n"
    "\n"
    "      The output will list the declaration location, default value, and\n"
    "      comment preceeding the declaration. If --short is specified,\n"
    "      only the names and values will be printed.\n"
    "\n"
    "      If the dir_name is specified, the build configuration will be\n"
    "      taken from that build directory. The reason this is needed is that\n"
    "      the definition of some arguments is dependent on the build\n"
    "      configuration, so setting some values might add, remove, or change\n"
    "      the default values for other arguments. Specifying your exact\n"
    "      configuration allows the proper arguments to be displayed.\n"
    "\n"
    "      Instead of specifying the dir_name, you can also use the\n"
    "      command-line flag to specify the build configuration:\n"
    "        --args=<exact list of args to use>\n"
    "\n"
    "Examples\n"
    "  gn args out/Debug\n"
    "    Opens an editor with the args for out/Debug.\n"
    "\n"
    "  gn args out/Debug --list --short\n"
    "    Prints all arguments with their default values for the out/Debug\n"
    "    build.\n"
    "\n"
    "  gn args out/Debug --list=cpu_arch\n"
    "    Prints information about the \"cpu_arch\" argument for the out/Debug\n"
    "    build.\n"
    "\n"
    "  gn args --list --args=\"os=\\\"android\\\" enable_doom_melon=true\"\n"
    "    Prints all arguments with the default values for a build with the\n"
    "    given arguments set (which may affect the values of other\n"
    "    arguments).\n";

int RunArgs(const std::vector<std::string>& args) {
  if (args.size() != 1) {
    Err(Location(), "Exactly one build dir needed.",
        "Usage: \"gn args <build_dir>\"\n"
        "Or see \"gn help args\" for more variants.").PrintToStdout();
    return 1;
  }

  if (base::CommandLine::ForCurrentProcess()->HasSwitch(kSwitchList))
    return ListArgs(args[0]);
  return EditArgsFile(args[0]);
}

}  // namespace commands
<|endoftext|>


<commit_before>#include "otc/otcli.h"
#include "otc/util.h"
using namespace otc;
typedef otc::RootedTreeNode<RTSplits> Node_t;
typedef RTreeOttIDMapping<RTSplits> RootedTreeForNodeType;
typedef otc::RootedTree<RTSplits, RootedTreeForNodeType> Tree_t;
bool processNextTree(OTCLI & otCLI, std::unique_ptr<Tree_t> tree);
extern const char * badNTreesMessage;
const char * badNTreesMessage = "Expecting only 1 tree to prune\n";

struct SubtreePrunerState {
    std::unique_ptr<Tree_t> toPrune;
    std::set<long> designators;
    bool emitParent;
    int numErrors;
    SubtreePrunerState()
        :toPrune(nullptr),
        emitParent(false),
        numErrors(0) {
    }

    void summarize(OTCLI &otCLI) {
        if (toPrune == nullptr) {
            otCLI.err << badNTreesMessage;
            numErrors = 1;
            return;
        }
        if (designators.empty()) {
            otCLI.err << "Expecting a -n or -p arg to specify the IDs whose MRCA defines the subtree";
            numErrors = 1;
            return;
        }
        const Node_t * mrca = findMRCAFromIDSet(*toPrune, designators, -1);
        if (mrca == nullptr) {
            otCLI.err << "MRCA could not be found\n";
            numErrors = 1;
            return;
        }
        const Node_t * toEmit = (emitParent ? mrca->getParent() : mrca);
        if (toEmit == nullptr) {
            otCLI.err << "MRCA had no parent\n";
            numErrors = 1;
            return;
        }
        writeNewick<Node_t>(otCLI.out, toEmit);
        otCLI.out << ";\n";
    }
};

inline bool processNextTree(OTCLI & otCLI, std::unique_ptr<Tree_t> tree) {
    SubtreePrunerState * ctsp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(ctsp != nullptr);
    assert(tree != nullptr);
    if (ctsp->toPrune == nullptr) {
        ctsp->toPrune = std::move(tree);
    } else {
        otCLI.err << badNTreesMessage;
        return false;
    }
    return true;
}

bool handleNodeFlag(OTCLI & otCLI, const std::string &nextArg);
bool handleParentFlag(OTCLI & otCLI, const std::string &nextArg);

bool handleNodeFlag(OTCLI & otCLI, const std::string &nextArg) {
    SubtreePrunerState * fusp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(fusp != nullptr);
    assert(!nextArg.empty());
    fusp->designators = parseDelimSeparatedIDs(nextArg, ',');
    return true;
}

bool handleParentFlag(OTCLI & otCLI, const std::string &nextArg) {
    if (!handleNodeFlag(otCLI, nextArg)) {
        return false;
    }
    SubtreePrunerState * fusp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(fusp != nullptr);
    fusp->emitParent = true;
    return true;
}

int main(int argc, char *argv[]) {
    OTCLI otCLI("otc-prune-to-subtree",
                "takes a -p or -n argument followed by one filepath to a newick. Writes the specified subtree to standard output stream.",
                "-n5315,3512 some.tre");
    SubtreePrunerState cts;
    otCLI.blob = static_cast<void *>(&cts);
    otCLI.addFlag('p',
                  "ARG=a comma separated list of OTT numbers. The parent of the MRCA of the IDs will be printed.",
                  handleParentFlag,
                  true);
    otCLI.addFlag('n',
                  "ARG=a comma separated list of OTT numbers. The MRCA of the IDs will be printed.",
                  handleNodeFlag,
                  true);
    auto rc = treeProcessingMain<Tree_t>(otCLI, argc, argv, processNextTree, nullptr, 1);
    if (rc == 0) {
        cts.summarize(otCLI);
        return cts.numErrors;
    }
    return rc;
}
<commit_msg>added -c and -s flags to emit children newicks and sibling newicks<commit_after>#include "otc/otcli.h"
#include "otc/util.h"
using namespace otc;
typedef otc::RootedTreeNode<RTSplits> Node_t;
typedef RTreeOttIDMapping<RTSplits> RootedTreeForNodeType;
typedef otc::RootedTree<RTSplits, RootedTreeForNodeType> Tree_t;
bool processNextTree(OTCLI & otCLI, std::unique_ptr<Tree_t> tree);
extern const char * badNTreesMessage;
const char * badNTreesMessage = "Expecting only 1 tree to prune\n";

struct SubtreePrunerState {
    std::unique_ptr<Tree_t> toPrune;
    std::set<long> designators;
    bool emitParent;
    bool emitChildren;
    bool emitSiblings;
    int numErrors;
    SubtreePrunerState()
        :toPrune(nullptr),
        emitParent(false),
        emitChildren(false),
        emitSiblings(false),
        numErrors(0) {
    }

    void summarize(OTCLI &otCLI) {
        if (toPrune == nullptr) {
            otCLI.err << badNTreesMessage;
            numErrors = 1;
            return;
        }
        if (designators.empty()) {
            otCLI.err << "Expecting a -n or -p arg to specify the IDs whose MRCA defines the subtree";
            numErrors = 1;
            return;
        }
        const Node_t * mrca = findMRCAFromIDSet(*toPrune, designators, -1);
        if (mrca == nullptr) {
            otCLI.err << "MRCA could not be found\n";
            numErrors = 1;
            return;
        }
        const Node_t * toEmit = ((emitParent || emitSiblings) ? mrca->getParent() : mrca);
        if (toEmit == nullptr) {
            otCLI.err << "MRCA had no parent\n";
            numErrors = 1;
            return;
        }
        if ((!emitSiblings) && (!emitChildren)) {
            writeNewick<Node_t>(otCLI.out, toEmit);
            otCLI.out << ";\n";
        } else {
            for (auto c : iter_child_const(*toEmit)) {
                if (emitSiblings && c == mrca) {
                    continue;
                }
                writeNewick<Node_t>(otCLI.out, c);
                otCLI.out << ";\n";
            }
        }
    }
};

inline bool processNextTree(OTCLI & otCLI, std::unique_ptr<Tree_t> tree) {
    SubtreePrunerState * ctsp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(ctsp != nullptr);
    assert(tree != nullptr);
    if (ctsp->toPrune == nullptr) {
        ctsp->toPrune = std::move(tree);
    } else {
        otCLI.err << badNTreesMessage;
        return false;
    }
    return true;
}

bool handleNodeFlag(OTCLI & otCLI, const std::string &nextArg);
bool handleParentFlag(OTCLI & otCLI, const std::string &nextArg);
bool handleChildrenFlag(OTCLI & otCLI, const std::string &nextArg);
bool handleSiblingsFlag(OTCLI & otCLI, const std::string &nextArg);

bool handleNodeFlag(OTCLI & otCLI, const std::string &nextArg) {
    SubtreePrunerState * fusp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(fusp != nullptr);
    assert(!nextArg.empty());
    if (!fusp->designators.empty()) {
        otCLI.err << "Expecting only 1 flag listing designators.\n";
        return false;
    }
    fusp->designators = parseDelimSeparatedIDs(nextArg, ',');
    return true;
}

bool handleParentFlag(OTCLI & otCLI, const std::string &nextArg) {
    if (!handleNodeFlag(otCLI, nextArg)) {
        return false;
    }
    SubtreePrunerState * fusp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(fusp != nullptr);
    fusp->emitParent = true;
    return true;
}

bool handleChildrenFlag(OTCLI & otCLI, const std::string &nextArg) {
    if (!handleNodeFlag(otCLI, nextArg)) {
        return false;
    }
    SubtreePrunerState * fusp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(fusp != nullptr);
    fusp->emitChildren = true;
    return true;
}

bool handleSiblingsFlag(OTCLI & otCLI, const std::string &nextArg) {
    if (!handleNodeFlag(otCLI, nextArg)) {
        return false;
    }
    SubtreePrunerState * fusp = static_cast<SubtreePrunerState *>(otCLI.blob);
    assert(fusp != nullptr);
    fusp->emitSiblings = true;
    return true;
}

int main(int argc, char *argv[]) {
    OTCLI otCLI("otc-prune-to-subtree",
                "takes a -p or -n argument followed by one filepath to a newick. Writes the specified subtree to standard output stream.",
                "-n5315,3512 some.tre");
    SubtreePrunerState cts;
    otCLI.blob = static_cast<void *>(&cts);
    otCLI.addFlag('p',
                  "ARG=a comma separated list of OTT numbers. The parent of the MRCA of the IDs will be printed.",
                  handleParentFlag,
                  true);
    otCLI.addFlag('n',
                  "ARG=a comma separated list of OTT numbers. The MRCA of the IDs will be printed.",
                  handleNodeFlag,
                  true);
    otCLI.addFlag('s',
                  "ARG=a comma separated list of OTT numbers. The siblings of the MRCA of the IDs will be printed.",
                  handleSiblingsFlag,
                  true);
    otCLI.addFlag('c',
                  "ARG=a comma separated list of OTT numbers. The children of the MRCA of the IDs will be printed.",
                  handleChildrenFlag,
                  true);
    auto rc = treeProcessingMain<Tree_t>(otCLI, argc, argv, processNextTree, nullptr, 1);
    if (rc == 0) {
        cts.summarize(otCLI);
        return cts.numErrors;
    }
    return rc;
}
<|endoftext|>