<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief application server scheduler implementation
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ApplicationServerSchedulerImpl.h"

#include <Basics/Exceptions.h>
#include <Basics/Logger.h>
#include <Rest/PeriodicTask.h>
#include <Rest/SignalTask.h>

#include "Scheduler/SchedulerLibev.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;

// -----------------------------------------------------------------------------
// helper classes and methods
// -----------------------------------------------------------------------------

namespace {

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles control-c
  ////////////////////////////////////////////////////////////////////////////////

  class ControlCTask : public SignalTask {
    public:
      ControlCTask (ApplicationServer* server)
        : Task("Control-C"), SignalTask(), server(server) {
        addSignal(SIGINT);
        addSignal(SIGTERM);
        addSignal(SIGQUIT);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "control-c received, shutting down";

        server->beginShutdown();

        return true;
      }

    private:
      ApplicationServer* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles Hangup
  ////////////////////////////////////////////////////////////////////////////////

  class HangupTask : public SignalTask {
    public:
      HangupTask (ApplicationServerSchedulerImpl* server)
        : Task("Hangup"), SignalTask(), server(server) {
        addSignal(SIGHUP);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "Hangup received, reopen logfile";
        TRI_ReopenLogging();
        LOGGER_INFO << "Hangup received, reopen logfile";
        return true;
      }

    private:
      ApplicationServerSchedulerImpl* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief produces a scheduler status report
  ////////////////////////////////////////////////////////////////////////////////

  class SchedulerReporterTask : public PeriodicTask {
    public:
      SchedulerReporterTask (Scheduler* scheduler, double _reportIntervall)
        : Task("Scheduler-Reporter"), PeriodicTask(_reportIntervall * 0.1, _reportIntervall), scheduler(scheduler) {
      }

    public:
      bool handlePeriod () {
        scheduler->reportStatus();
        return true;
      }

    public:
      Scheduler* scheduler;
  };
}

namespace triagens {
  namespace rest {

    // -----------------------------------------------------------------------------
    // constructors and destructors
    // -----------------------------------------------------------------------------

    ApplicationServerSchedulerImpl::ApplicationServerSchedulerImpl (string const& description, string const& version)
      : ApplicationServerImpl(description, version),
        _reportIntervall(60.0),
        _multiSchedulerAllowed(false),
        _nrSchedulerThreads(1),
        _backend(0),
        reuseAddress(false),
        descriptorMinimum(0),

        _scheduler(0),
        _shutdownInProgress(false) {
    }

    ApplicationServerSchedulerImpl::~ApplicationServerSchedulerImpl () {

      // cleanup tasks and scheduler
      if (_scheduler != 0) {
        for (vector<Task*>::iterator i = _tasks.begin();  i != _tasks.end();  ++i) {
          _scheduler->destroyTask(*i);
        }

        delete _scheduler;
      }
    }

    // -----------------------------------------------------------------------------
    // public methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::buildScheduler () {
      if (_scheduler != 0) {
        LOGGER_FATAL << "a scheduler has already been created";
        exit(EXIT_FAILURE);
      }

      _scheduler = new SchedulerLibev(_nrSchedulerThreads, _backend);
    }

    void ApplicationServerSchedulerImpl::buildSchedulerReporter () {
      if (0.0 < _reportIntervall) {
        registerTask(new SchedulerReporterTask(_scheduler, _reportIntervall));
      }
    }

    void ApplicationServerSchedulerImpl::buildControlCHandler () {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create control-c handler";
        exit(EXIT_FAILURE);
      }

      registerTask(new ControlCTask(this));
      registerTask(new HangupTask(this));
    }

    void ApplicationServerSchedulerImpl::installSignalHandler (SignalTask* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot install signal handler";
        exit(EXIT_FAILURE);
      }

      registerTask(task);
    }

    void ApplicationServerSchedulerImpl::start () {
      ApplicationServerImpl::start();

      if (_scheduler != 0) {
        bool ok = _scheduler->start(&_schedulerCond);

        if (! ok) {
          LOGGER_FATAL << "the scheduler cannot be started";
          exit(EXIT_FAILURE);
        }
      }
    }

    void ApplicationServerSchedulerImpl::wait () {
      ApplicationServerImpl::wait();

      if (_scheduler != 0) {
        bool ok = _schedulerCond.lock();

        if (! ok) {
          THROW_INTERNAL_ERROR("cannot lock scheduler condition");
        }

        while (_scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";

          ok = _schedulerCond.wait();

          if (! ok) {
            THROW_INTERNAL_ERROR("cannot wait on scheduler condition");
          }
        }

        LOGGER_TRACE << "scheduler has stopped";

        ok = _schedulerCond.unlock();

        if (! ok) {
          THROW_INTERNAL_ERROR("cannot unlock scheduler condition");
        }
      }
    }

    void ApplicationServerSchedulerImpl::beginShutdown () {
      ApplicationServerImpl::beginShutdown();

      if (! _shutdownInProgress) {
        LOGGER_TRACE << "begin shutdown sequence of application server";

        if (_scheduler != 0) {
          _scheduler->beginShutdown();
        }

        _shutdownInProgress = true;
      }
      else {
        LOGGER_TRACE << "shutdown sequence of application server already initiated";
      }
    }

    void ApplicationServerSchedulerImpl::shutdown () {
      ApplicationServerImpl::shutdown();

      if (_scheduler != 0) {
        int count = 0;

        while (++count < 6 && _scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";
          sleep(1);
        }
      }
    }

    // -----------------------------------------------------------------------------
    // protected methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::registerTask (Task* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create tasks";
        exit(EXIT_FAILURE);
      }

      _scheduler->registerTask(task);
      _tasks.push_back(task);
    }

    void ApplicationServerSchedulerImpl::setupOptions (map<string, ProgramOptionsDescription>& options) {
      ApplicationServerImpl::setupOptions(options);

      // .............................................................................
      // command line options
      // .............................................................................

      options[OPTIONS_CMDLINE + ":help-extended"]
        ("show-io-backends", "show available io backends")
      ;

      // .............................................................................
      // application server options
      // .............................................................................

      options[OPTIONS_SERVER + ":help-extended"]
        ("scheduler.backend", &_backend, "1: select, 2: poll, 4: epoll")
        ("server.reuse-address", "try to reuse address")
        ("server.report", &_reportIntervall, "report intervall")
#ifdef TRI_HAVE_GETRLIMIT
        ("server.descriptors-minimum", &descriptorMinimum, "minimum number of file descriptors needed to start")
#endif
      ;

      if (_multiSchedulerAllowed) {
        options[OPTIONS_SERVER + ":help-extended"]
          ("scheduler.threads", &_nrSchedulerThreads, "number of scheduler threads")
        ;
      }
    }

    bool ApplicationServerSchedulerImpl::parsePhase1 () {
      bool ok = ApplicationServerImpl::parsePhase1();

      if (! ok) {
        return false;
      }

      // show io backends
      if (options.has("show-io-backends")) {
        cout << "available io backends are: " << SchedulerLibev::availableBackends() << endl;
        exit(EXIT_SUCCESS);
      }

      return true;
    }

    bool ApplicationServerSchedulerImpl::parsePhase2 () {
      bool ok = ApplicationServerImpl::parsePhase2();

      if (! ok) {
        return false;
      }

      // check if want to reuse the address
      if (options.has("server.reuse-address")) {
        reuseAddress = true;
      }

      // adjust file descriptors
      adjustFileDescriptors();

      return true;
    }

    // -----------------------------------------------------------------------------
    // private methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::adjustFileDescriptors () {
#ifdef TRI_HAVE_GETRLIMIT

      if (0 < descriptorMinimum) {
        struct rlimit rlim;
        int res = getrlimit(RLIMIT_NOFILE, &rlim);

        if (res != 0) {
          LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
          exit(EXIT_FAILURE);
        }

        LOGGER_DEBUG << "hard limit is " << rlim.rlim_max << ", soft limit is " << rlim.rlim_cur;

        bool changed = false;

        if (rlim.rlim_max < descriptorMinimum) {
          LOGGER_DEBUG << "hard limit " << rlim.rlim_max << " is too small, trying to raise";

          rlim.rlim_max = descriptorMinimum;
          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }
        else if (rlim.rlim_cur < descriptorMinimum) {
          LOGGER_DEBUG << "soft limit " << rlim.rlim_cur << " is too small, trying to raise";

          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }

        if (changed) {
          res = getrlimit(RLIMIT_NOFILE, &rlim);

          if (res != 0) {
            LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
            exit(EXIT_FAILURE);
          }

          LOGGER_DEBUG << "new hard limit is " << rlim.rlim_max << ", new soft limit is " << rlim.rlim_cur;
        }

        // the select backend has more restrictions
        if (_backend == 1) {
          if (FD_SETSIZE < descriptorMinimum) {
            LOGGER_FATAL << "i/o backend 'select' has been selected, which supports only " << FD_SETSIZE
                         << " descriptors, but " << descriptorMinimum << " are required";
            exit(EXIT_FAILURE);
          }
        }
      }

#endif
    }
  }
}
<commit_msg>changed return of locks<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief application server scheduler implementation
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2011 triagens GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2009-2011, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "ApplicationServerSchedulerImpl.h"

#include <Basics/Exceptions.h>
#include <Basics/Logger.h>
#include <Rest/PeriodicTask.h>
#include <Rest/SignalTask.h>

#include "Scheduler/SchedulerLibev.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;

// -----------------------------------------------------------------------------
// helper classes and methods
// -----------------------------------------------------------------------------

namespace {

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles control-c
  ////////////////////////////////////////////////////////////////////////////////

  class ControlCTask : public SignalTask {
    public:
      ControlCTask (ApplicationServer* server)
        : Task("Control-C"), SignalTask(), server(server) {
        addSignal(SIGINT);
        addSignal(SIGTERM);
        addSignal(SIGQUIT);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "control-c received, shutting down";

        server->beginShutdown();

        return true;
      }

    private:
      ApplicationServer* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief handles Hangup
  ////////////////////////////////////////////////////////////////////////////////

  class HangupTask : public SignalTask {
    public:
      HangupTask (ApplicationServerSchedulerImpl* server)
        : Task("Hangup"), SignalTask(), server(server) {
        addSignal(SIGHUP);
      }

    public:
      bool handleSignal () {
        LOGGER_INFO << "Hangup received, reopen logfile";
        TRI_ReopenLogging();
        LOGGER_INFO << "Hangup received, reopen logfile";
        return true;
      }

    private:
      ApplicationServerSchedulerImpl* server;
  };

  ////////////////////////////////////////////////////////////////////////////////
  /// @brief produces a scheduler status report
  ////////////////////////////////////////////////////////////////////////////////

  class SchedulerReporterTask : public PeriodicTask {
    public:
      SchedulerReporterTask (Scheduler* scheduler, double _reportIntervall)
        : Task("Scheduler-Reporter"), PeriodicTask(_reportIntervall * 0.1, _reportIntervall), scheduler(scheduler) {
      }

    public:
      bool handlePeriod () {
        scheduler->reportStatus();
        return true;
      }

    public:
      Scheduler* scheduler;
  };
}

namespace triagens {
  namespace rest {

    // -----------------------------------------------------------------------------
    // constructors and destructors
    // -----------------------------------------------------------------------------

    ApplicationServerSchedulerImpl::ApplicationServerSchedulerImpl (string const& description, string const& version)
      : ApplicationServerImpl(description, version),
        _reportIntervall(60.0),
        _multiSchedulerAllowed(false),
        _nrSchedulerThreads(1),
        _backend(0),
        reuseAddress(false),
        descriptorMinimum(0),

        _scheduler(0),
        _shutdownInProgress(false) {
    }

    ApplicationServerSchedulerImpl::~ApplicationServerSchedulerImpl () {

      // cleanup tasks and scheduler
      if (_scheduler != 0) {
        for (vector<Task*>::iterator i = _tasks.begin();  i != _tasks.end();  ++i) {
          _scheduler->destroyTask(*i);
        }

        delete _scheduler;
      }
    }

    // -----------------------------------------------------------------------------
    // public methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::buildScheduler () {
      if (_scheduler != 0) {
        LOGGER_FATAL << "a scheduler has already been created";
        exit(EXIT_FAILURE);
      }

      _scheduler = new SchedulerLibev(_nrSchedulerThreads, _backend);
    }

    void ApplicationServerSchedulerImpl::buildSchedulerReporter () {
      if (0.0 < _reportIntervall) {
        registerTask(new SchedulerReporterTask(_scheduler, _reportIntervall));
      }
    }

    void ApplicationServerSchedulerImpl::buildControlCHandler () {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create control-c handler";
        exit(EXIT_FAILURE);
      }

      registerTask(new ControlCTask(this));
      registerTask(new HangupTask(this));
    }

    void ApplicationServerSchedulerImpl::installSignalHandler (SignalTask* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot install signal handler";
        exit(EXIT_FAILURE);
      }

      registerTask(task);
    }

    void ApplicationServerSchedulerImpl::start () {
      ApplicationServerImpl::start();

      if (_scheduler != 0) {
        bool ok = _scheduler->start(&_schedulerCond);

        if (! ok) {
          LOGGER_FATAL << "the scheduler cannot be started";
          exit(EXIT_FAILURE);
        }
      }
    }

    void ApplicationServerSchedulerImpl::wait () {
      ApplicationServerImpl::wait();

      if (_scheduler != 0) {
        _schedulerCond.lock();

        while (_scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";
          _schedulerCond.wait();
        }

        LOGGER_TRACE << "scheduler has stopped";

        _schedulerCond.unlock();
      }
    }

    void ApplicationServerSchedulerImpl::beginShutdown () {
      ApplicationServerImpl::beginShutdown();

      if (! _shutdownInProgress) {
        LOGGER_TRACE << "begin shutdown sequence of application server";

        if (_scheduler != 0) {
          _scheduler->beginShutdown();
        }

        _shutdownInProgress = true;
      }
      else {
        LOGGER_TRACE << "shutdown sequence of application server already initiated";
      }
    }

    void ApplicationServerSchedulerImpl::shutdown () {
      ApplicationServerImpl::shutdown();

      if (_scheduler != 0) {
        int count = 0;

        while (++count < 6 && _scheduler->isRunning()) {
          LOGGER_TRACE << "waiting for scheduler to stop";
          sleep(1);
        }
      }
    }

    // -----------------------------------------------------------------------------
    // protected methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::registerTask (Task* task) {
      if (_scheduler == 0) {
        LOGGER_FATAL << "no scheduler is known, cannot create tasks";
        exit(EXIT_FAILURE);
      }

      _scheduler->registerTask(task);
      _tasks.push_back(task);
    }

    void ApplicationServerSchedulerImpl::setupOptions (map<string, ProgramOptionsDescription>& options) {
      ApplicationServerImpl::setupOptions(options);

      // .............................................................................
      // command line options
      // .............................................................................

      options[OPTIONS_CMDLINE + ":help-extended"]
        ("show-io-backends", "show available io backends")
      ;

      // .............................................................................
      // application server options
      // .............................................................................

      options[OPTIONS_SERVER + ":help-extended"]
        ("scheduler.backend", &_backend, "1: select, 2: poll, 4: epoll")
        ("server.reuse-address", "try to reuse address")
        ("server.report", &_reportIntervall, "report intervall")
#ifdef TRI_HAVE_GETRLIMIT
        ("server.descriptors-minimum", &descriptorMinimum, "minimum number of file descriptors needed to start")
#endif
      ;

      if (_multiSchedulerAllowed) {
        options[OPTIONS_SERVER + ":help-extended"]
          ("scheduler.threads", &_nrSchedulerThreads, "number of scheduler threads")
        ;
      }
    }

    bool ApplicationServerSchedulerImpl::parsePhase1 () {
      bool ok = ApplicationServerImpl::parsePhase1();

      if (! ok) {
        return false;
      }

      // show io backends
      if (options.has("show-io-backends")) {
        cout << "available io backends are: " << SchedulerLibev::availableBackends() << endl;
        exit(EXIT_SUCCESS);
      }

      return true;
    }

    bool ApplicationServerSchedulerImpl::parsePhase2 () {
      bool ok = ApplicationServerImpl::parsePhase2();

      if (! ok) {
        return false;
      }

      // check if want to reuse the address
      if (options.has("server.reuse-address")) {
        reuseAddress = true;
      }

      // adjust file descriptors
      adjustFileDescriptors();

      return true;
    }

    // -----------------------------------------------------------------------------
    // private methods
    // -----------------------------------------------------------------------------

    void ApplicationServerSchedulerImpl::adjustFileDescriptors () {
#ifdef TRI_HAVE_GETRLIMIT

      if (0 < descriptorMinimum) {
        struct rlimit rlim;
        int res = getrlimit(RLIMIT_NOFILE, &rlim);

        if (res != 0) {
          LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
          exit(EXIT_FAILURE);
        }

        LOGGER_DEBUG << "hard limit is " << rlim.rlim_max << ", soft limit is " << rlim.rlim_cur;

        bool changed = false;

        if (rlim.rlim_max < descriptorMinimum) {
          LOGGER_DEBUG << "hard limit " << rlim.rlim_max << " is too small, trying to raise";

          rlim.rlim_max = descriptorMinimum;
          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }
        else if (rlim.rlim_cur < descriptorMinimum) {
          LOGGER_DEBUG << "soft limit " << rlim.rlim_cur << " is too small, trying to raise";

          rlim.rlim_cur = descriptorMinimum;

          res = setrlimit(RLIMIT_NOFILE, &rlim);

          if (res < 0) {
            LOGGER_FATAL << "cannot raise the file descriptor limit to '" << descriptorMinimum << "', got " << strerror(errno);
            exit(EXIT_FAILURE);
          }

          changed = true;
        }

        if (changed) {
          res = getrlimit(RLIMIT_NOFILE, &rlim);

          if (res != 0) {
            LOGGER_FATAL << "cannot get the file descriptor limit: " << strerror(errno) << "'";
            exit(EXIT_FAILURE);
          }

          LOGGER_DEBUG << "new hard limit is " << rlim.rlim_max << ", new soft limit is " << rlim.rlim_cur;
        }

        // the select backend has more restrictions
        if (_backend == 1) {
          if (FD_SETSIZE < descriptorMinimum) {
            LOGGER_FATAL << "i/o backend 'select' has been selected, which supports only " << FD_SETSIZE
                         << " descriptors, but " << descriptorMinimum << " are required";
            exit(EXIT_FAILURE);
          }
        }
      }

#endif
    }
  }
}
<|endoftext|>


<commit_before>#include "CommandBase.h"
#include "Subsystems/ExampleSubsystem.h"
#include "Subsystems/Intake.h"
#include "Subsystems/IntakeArms.h"
#include "Subsystems/Lifter.h"
#include "Subsystems/Pusher.h"
#include "Subsystems/MooseLifter.h"
#include "Subsystems/AntlerMoose.h"
#include "Commands/Scheduler.h"
#include "Commands/AccelerometerTest.h"
#include "Commands/SavePreferences.h"

// Initialize a single static instance of all of your subsystems to NULL
ExampleSubsystem* CommandBase::chassis = NULL;
Intake* CommandBase::intake = NULL;
IntakeArms* CommandBase::intakearms = NULL;
OI* CommandBase::oi = NULL;
Lifter* CommandBase::lifter = NULL;
Pusher* CommandBase::pusher = NULL;
MooseLifter* CommandBase::mooseLifter = NULL;
AntlerMoose* CommandBase::antlerMoose = NULL;

Compressor* CommandBase::compressor = NULL;
//AccelerometerTest* FPS = NULL;
SavePreferences* save = NULL;

CommandBase::CommandBase(char const *name) :
		Command(name)
{
}

CommandBase::CommandBase() :
		Command()
{

}

void CommandBase::init()
{
	// Create a single static instance of all of your subsystems. The following
	// line should be repeated for each subsystem in the project.
	save = new SavePreferences();
	SmartDashboard::PutData(save);
	chassis = new ExampleSubsystem();
	intake = new Intake();
	intakearms = new IntakeArms();
	oi = new OI();
	lifter = new Lifter();
	pusher = new Pusher();
	mooseLifter = new MooseLifter();
	antlerMoose = new AntlerMoose();
	//FPS = new AccelerometerTest();
	compressor = new Compressor(COMPRESSOR);
	compressor->Start();
	//FPS->Start();
	//SmartDashboard::PutData(FPS);
}
<commit_msg>Simple Camera Feed<commit_after>#include "CommandBase.h"
#include "Subsystems/ExampleSubsystem.h"
#include "Subsystems/Intake.h"
#include "Subsystems/IntakeArms.h"
#include "Subsystems/Lifter.h"
#include "Subsystems/Pusher.h"
#include "Subsystems/MooseLifter.h"
#include "Subsystems/AntlerMoose.h"
#include "Commands/Scheduler.h"
#include "Commands/AccelerometerTest.h"
#include "Commands/SavePreferences.h"

// Initialize a single static instance of all of your subsystems to NULL
ExampleSubsystem* CommandBase::chassis = NULL;
Intake* CommandBase::intake = NULL;
IntakeArms* CommandBase::intakearms = NULL;
OI* CommandBase::oi = NULL;
Lifter* CommandBase::lifter = NULL;
Pusher* CommandBase::pusher = NULL;
MooseLifter* CommandBase::mooseLifter = NULL;
AntlerMoose* CommandBase::antlerMoose = NULL;

Compressor* CommandBase::compressor = NULL;
//AccelerometerTest* FPS = NULL;
SavePreferences* save = NULL;

CommandBase::CommandBase(char const *name) :
		Command(name)
{
}

CommandBase::CommandBase() :
		Command()
{

}

void CommandBase::init()
{
	// Create a single static instance of all of your subsystems. The following
	// line should be repeated for each subsystem in the project.
	save = new SavePreferences();
	SmartDashboard::PutData(save);
	chassis = new ExampleSubsystem();
	intake = new Intake();
	intakearms = new IntakeArms();
	oi = new OI();
	lifter = new Lifter();
	pusher = new Pusher();
	mooseLifter = new MooseLifter();
	antlerMoose = new AntlerMoose();
	//FPS = new AccelerometerTest();
	compressor = new Compressor(COMPRESSOR);
	compressor->Start();
	//FPS->Start();
	//SmartDashboard::PutData(FPS);
	CameraServer::GetInstance()->SetQuality(50);
	//the camera name (ex "cam0") can be found through the roborio web interface
	CameraServer::GetInstance()->StartAutomaticCapture();
}
<|endoftext|>


<commit_before>#include "client_net.h"
#include "interactive.h"
#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha3.h"
#include "spdlog/spdlog.h"
#include "logging.h"
#include "auth_common.h"
#include "packets/radius_packet.h"
#include "packets/eap_packet.h"
#include "packets/packet.h"

using namespace std;
const std::vector<byte> temp = {0xe0, 0xbd, 0x18, 0xdb, 0x4c, 0xc2, 0xf8, 0x5c,
                                0xed, 0xef, 0x65, 0x4f, 0xcc, 0xc4, 0xa4, 0xd8};

const std::string LOGGER_NAME = "client";
std::string hashString(std::string input, std::string hash);
int main(int argc, char **argv) {
    using namespace TCLAP;
    try {

        CmdLine cmd("NAS Test Client", ' ');

        ValueArg<string> logpathArg("l", "log",
                                    "The path where log file shall be written",
                                    false, "client.log", "string");
        cmd.add(logpathArg);

        ValueArg<string> loginArg(
            "u", "username", "The name of a user that wishes to authenticate",
            false, "", "string");
        cmd.add(loginArg);

        ValueArg<string> passArg("", "password", "The password of a user",
                                 false, "", "string");
        cmd.add(passArg);

        /*         SwitchArg interSwitch("i", "interactive", */
        /*                               "Run in the interactive mode", false);
         */
        /*         cmd.add(interSwitch); */

        SwitchArg verboseSwitch("v", "verbose", "Run in the verbose mode",
                                false);
        cmd.add(verboseSwitch);

        ValueArg<string> secretArg("s", "secret", "The secret shared with NAS",
                                   true, "", "string");
        cmd.add(secretArg);

        ValueArg<int> portArg("p", "port", "Binded port", false, 0, "number");
        cmd.add(portArg);

        ValueArg<string> bindIpArg("b", "bind-ip", "Binded IP address", false,
                                   "0.0.0.0", "IP");

        cmd.add(bindIpArg);

        ValueArg<string> ipArg("a", "address", "Server IP address", true, "",
                               "IP");

        cmd.add(ipArg);

        ValueArg<string> hashArg(
            "", "hash", "Type of hashing function (crc32 md5 sha1 sha256 sha3)",
            false, "", "string");
        cmd.add(hashArg);

        cmd.parse(argc, argv);

        int port = portArg.getValue();
        string ip = ipArg.getValue();
        string bindIp = ipArg.getValue();
        string secret = secretArg.getValue();
        string logpath = logpathArg.getValue();
        radius::initLogger(logpath, LOGGER_NAME);

        bool verbose = verboseSwitch.getValue();
        if (verbose) {
            spdlog::set_level(spdlog::level::trace);
        }

        auto logger = spdlog::get(LOGGER_NAME);

        string hash = hashArg.getValue();

        string login = loginArg.getValue();
        string pas = passArg.getValue();
        /* bool inter = interSwitch.getValue(); */
        // setup address structure //adres serwera
        struct sockaddr_in server_addr;
        memset((char *)&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        /* if (inter) { */
        /*     login = radius::getUsername(); */
        /*     pas = radius::getPassword("Enter password:\n"); */
        /* } */
        pas = hashString(pas, hash);

        // radius::packets::Packet newPack(temp, server_addr);

        radius::startClient(ip.c_str(), port);
        // 1.access-request
        using namespace radius;
        using namespace radius::packets;
        EapPacket eapIdentity;
        eapIdentity = makeIdentity(login);
        eapIdentity.setType(EapPacket::RESPONSE);
        eapIdentity.setIdentifier(1);

        EapMessage eapMessage;
        eapMessage.setValue(eapIdentity.getBuffer());

        RadiusPacket arPacket;
        arPacket.setIdentifier(1);
        arPacket.setCode(RadiusPacket::ACCESS_REQUEST);
        std::array<radius::byte, 16> authTable = generateRandom16();
        arPacket.setAuthenticator(authTable);
        arPacket.addAVP(static_cast<const RadiusAVP &>(eapMessage));
        calcAndSetMsgAuth(arPacket, secret);

        radius::packets::Packet newPack(arPacket.getBuffer(), server_addr);
        logger->error() << "\r\n" << packet2LogBytes(newPack.bytes);

        radius::sendPack(newPack);
        // 2.otrzymuj odpowiedz od Radius server
        // newPack = radius::receivePack();
        // 3.access-request z hashem tego jescze nie ma
        // radius::sendPack(newPack);
        // 4.success or failure
        /* newPack = radius::receivePack(); */

        radius::stopClient();

    } catch (ArgException &e) {
        cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
    }
}

std::string hashString(std::string input, std::string hash) {
    std::string output;

    if (hash == "sha256") {
        SHA256 sha256;
        output = sha256(input);
    } else if (hash == "sha1") {
        SHA1 sha1;
        output = sha1(input);
    } else if (hash == "sha3") {
        SHA3 sha3;
        output = sha3(input);
    } else if (hash == "md5") {
        MD5 md5;
        output = md5(input);
    } else if (hash == "crc32") {
        CRC32 crc32;
        output = crc32(input);
    } else {
        output = input;
    }
    return output;
}
<commit_msg>dodanie reszty klienta<commit_after>#include "client_net.h"
#include "interactive.h"
#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha3.h"
#include "spdlog/spdlog.h"
#include "logging.h"
#include "auth_common.h"
#include "packets/radius_packet.h"
#include "packets/eap_packet.h"
#include "packets/packet.h"

using namespace std;
const std::vector<byte> temp = {0xe0, 0xbd, 0x18, 0xdb, 0x4c, 0xc2, 0xf8, 0x5c,
                                0xed, 0xef, 0x65, 0x4f, 0xcc, 0xc4, 0xa4, 0xd8};

const std::string LOGGER_NAME = "client";
std::string hashString(std::string input, std::string hash);
int main(int argc, char **argv) {
    using namespace TCLAP;
    try {

        CmdLine cmd("NAS Test Client", ' ');

        ValueArg<string> logpathArg("l", "log",
                                    "The path where log file shall be written",
                                    false, "client.log", "string");
        cmd.add(logpathArg);

        ValueArg<string> loginArg(
            "u", "username", "The name of a user that wishes to authenticate",
            false, "", "string");
        cmd.add(loginArg);

        ValueArg<string> passArg("", "password", "The password of a user",
                                 false, "", "string");
        cmd.add(passArg);

        /*         SwitchArg interSwitch("i", "interactive", */
        /*                               "Run in the interactive mode", false);
         */
        /*         cmd.add(interSwitch); */

        SwitchArg verboseSwitch("v", "verbose", "Run in the verbose mode",
                                false);
        cmd.add(verboseSwitch);

        ValueArg<string> secretArg("s", "secret", "The secret shared with NAS",
                                   true, "", "string");
        cmd.add(secretArg);

        ValueArg<int> portArg("p", "port", "Binded port", false, 0, "number");
        cmd.add(portArg);

        ValueArg<string> bindIpArg("b", "bind-ip", "Binded IP address", false,
                                   "0.0.0.0", "IP");

        cmd.add(bindIpArg);

        ValueArg<string> ipArg("a", "address", "Server IP address", true, "",
                               "IP");

        cmd.add(ipArg);

        ValueArg<string> hashArg(
            "", "hash", "Type of hashing function (crc32 md5 sha1 sha256 sha3)",
            false, "", "string");
        cmd.add(hashArg);

        cmd.parse(argc, argv);

        int port = portArg.getValue();
        string ip = ipArg.getValue();
        string bindIp = ipArg.getValue();
        string secret = secretArg.getValue();
        string logpath = logpathArg.getValue();
        radius::initLogger(logpath, LOGGER_NAME);

        bool verbose = verboseSwitch.getValue();
        if (verbose) {
            spdlog::set_level(spdlog::level::trace);
        }

        auto logger = spdlog::get(LOGGER_NAME);

        string hash = hashArg.getValue();

        string login = loginArg.getValue();
        string pas = passArg.getValue();
        /* bool inter = interSwitch.getValue(); */
        // setup address structure //adres serwera
        struct sockaddr_in server_addr;
        memset((char *)&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        /* if (inter) { */
        /*     login = radius::getUsername(); */
        /*     pas = radius::getPassword("Enter password:\n"); */
        /* } */
        pas = hashString(pas, hash);

        // radius::packets::Packet newPack(temp, server_addr);

        radius::startClient(ip.c_str(), port);
        // 1.access-request
        using namespace radius;
        using namespace radius::packets;
			EapPacket eapIdentity;
			eapIdentity = makeIdentity(login);
			eapIdentity.setType(EapPacket::RESPONSE);
			eapIdentity.setIdentifier(1);

			EapMessage eapMessage;
			eapMessage.setValue(eapIdentity.getBuffer());

			RadiusPacket arPacket;
			arPacket.setIdentifier(1);
			arPacket.setCode(RadiusPacket::ACCESS_REQUEST);
			std::array<radius::byte, 16> authTable = generateRandom16();
			arPacket.setAuthenticator(authTable);
			arPacket.addAVP(static_cast<const RadiusAVP &>(eapMessage));
			calcAndSetMsgAuth(arPacket, secret);

        radius::packets::Packet newPack(arPacket.getBuffer(), server_addr);
        logger->error() << "\r\n" << packet2LogBytes(newPack.bytes);

        radius::sendPack(newPack);
        // 2.otrzymuj odpowiedz od Radius server
        newPack = radius::receivePack();
		        logger->error() << "\r\n" << packet2LogBytes(newPack.bytes);
        // 3.access-"response authenticator"
		RadiusPacket responsePacket(newPack.bytes);
		calcAndSetMsgAuth(arPacket, secret);
		radius::packets::Packet responsePack(responsePacket.getBuffer(), server_addr);
        logger->error() << "\r\n" << packet2LogBytes(responsePack.bytes);
        radius::sendPack(responsePack);
        // 4.success or failure
        /* newPack = radius::receivePack(); */

        radius::stopClient();

    } catch (ArgException &e) {
        cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
    }
}

std::string hashString(std::string input, std::string hash) {
    std::string output;

    if (hash == "sha256") {
        SHA256 sha256;
        output = sha256(input);
    } else if (hash == "sha1") {
        SHA1 sha1;
        output = sha1(input);
    } else if (hash == "sha3") {
        SHA3 sha3;
        output = sha3(input);
    } else if (hash == "md5") {
        MD5 md5;
        output = md5(input);
    } else if (hash == "crc32") {
        CRC32 crc32;
        output = crc32(input);
    } else {
        output = input;
    }
    return output;
}
<|endoftext|>


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

#include "base/command_line.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host.h"
#include "content/browser/site_instance.h"
#include "content/browser/tab_contents/tab_contents.h"

class RenderProcessHostTest : public InProcessBrowserTest {
 public:
  RenderProcessHostTest() {
    EnableDOMAutomation();
  }

  int RenderProcessHostCount() {
    RenderProcessHost::iterator hosts = RenderProcessHost::AllHostsIterator();
    int count = 0;
    while (!hosts.IsAtEnd()) {
      if (hosts.GetCurrentValue()->HasConnection())
        count++;
      hosts.Advance();
    }
    return count;
  }

  RenderViewHost* FindFirstDevToolsHost() {
    RenderProcessHost::iterator hosts = RenderProcessHost::AllHostsIterator();
    for (; !hosts.IsAtEnd(); hosts.Advance()) {
      RenderProcessHost* render_process_host = hosts.GetCurrentValue();
      DCHECK(render_process_host);
      if (!render_process_host->HasConnection())
        continue;
      RenderProcessHost::listeners_iterator iter(
          render_process_host->ListenersIterator());
      for (; !iter.IsAtEnd(); iter.Advance()) {
        const RenderWidgetHost* widget =
            static_cast<const RenderWidgetHost*>(iter.GetCurrentValue());
        DCHECK(widget);
        if (!widget || !widget->IsRenderView())
          continue;
        RenderViewHost* host = const_cast<RenderViewHost*>(
            static_cast<const RenderViewHost*>(widget));
        RenderViewHostDelegate* host_delegate = host->delegate();
        GURL url = host_delegate->GetURL();
        if (url.SchemeIs(chrome::kChromeDevToolsScheme))
          return host;
      }
    }
    return NULL;
  }
};

IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessPerTab) {
  // Set max renderers to 1 to force running out of processes.
  RenderProcessHost::SetMaxRendererProcessCount(1);

  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create a new TYPE_TABBED tab.  It should be in its own process.
  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another TYPE_TABBED tab.  It should share the previous process.
  GURL page2("data:text/html,hello world2");
  browser()->ShowSingletonTab(page2);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  browser()->NewTab();
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  browser()->NewTab();
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process when --process-per-tab is set. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, DevToolsOnSelfInOwnProcessPPT) {
  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsManager::GetInstance()->ToggleDevToolsWindow(
      devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, DevToolsOnSelfInOwnProcess) {
  int tab_count = 1;
  int host_count = 1;

  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsManager::GetInstance()->ToggleDevToolsWindow(
      devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// When we hit the max number of renderers, verify that the way we do process
// sharing behaves correctly.  In particular, this test is verifying that even
// when we hit the max process limit, that renderers of each type will wind up
// in a process of that type, even if that means creating a new process.
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessOverflow) {
  // Set max renderers to 1 to force running out of processes.
  RenderProcessHost::SetMaxRendererProcessCount(1);

  int tab_count = 1;
  int host_count = 1;
  TabContents* tab1 = NULL;
  TabContents* tab2 = NULL;
  RenderProcessHost* rph1 = NULL;
  RenderProcessHost* rph2 = NULL;
  RenderProcessHost* rph3 = NULL;

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab1 = browser()->GetTabContentsAt(tab_count - 1);
  rph1 = tab1->GetRenderProcessHost();
  EXPECT_EQ(tab1->GetURL(), newtab);
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create a new TYPE_TABBED tab.  It should be in its own process.
  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab1 = browser()->GetTabContentsAt(tab_count - 1);
  rph2 = tab1->GetRenderProcessHost();
  EXPECT_EQ(tab1->GetURL(), page1);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_NE(rph1, rph2);

  // Create another TYPE_TABBED tab.  It should share the previous process.
  GURL page2("data:text/html,hello world2");
  browser()->ShowSingletonTab(page2);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab2 = browser()->GetTabContentsAt(tab_count - 1);
  EXPECT_EQ(tab2->GetURL(), page2);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);

  // Create another TYPE_WEBUI tab.  It should share the process with newtab.
  // Note: intentionally create this tab after the TYPE_TABBED tabs to exercise
  // bug 43448 where extension and WebUI tabs could get combined into normal
  // renderers.
  GURL history(chrome::kChromeUIHistoryURL);
  browser()->ShowSingletonTab(history);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab2 = browser()->GetTabContentsAt(tab_count - 1);
  EXPECT_EQ(tab2->GetURL(), history);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);

  // Create a TYPE_EXTENSION tab.  It should be in its own process.
  // (the bookmark manager is implemented as an extension)
  GURL bookmarks(chrome::kChromeUIBookmarksURL);
  browser()->ShowSingletonTab(bookmarks);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab1 = browser()->GetTabContentsAt(tab_count - 1);
  rph3 = tab1->GetRenderProcessHost();
  EXPECT_EQ(tab1->GetURL(), bookmarks);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_NE(rph1, rph3);
  EXPECT_NE(rph2, rph3);
}
<commit_msg>Fix a few browser tests for touchui: Count the renderer for the keyboard and update expectations.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/command_line.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/ui_test_utils.h"
#include "content/browser/renderer_host/render_process_host.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/browser/renderer_host/render_widget_host.h"
#include "content/browser/site_instance.h"
#include "content/browser/tab_contents/tab_contents.h"

class RenderProcessHostTest : public InProcessBrowserTest {
 public:
  RenderProcessHostTest() {
    EnableDOMAutomation();
  }

  int RenderProcessHostCount() {
    RenderProcessHost::iterator hosts = RenderProcessHost::AllHostsIterator();
    int count = 0;
    while (!hosts.IsAtEnd()) {
      if (hosts.GetCurrentValue()->HasConnection())
        count++;
      hosts.Advance();
    }
    return count;
  }

  RenderViewHost* FindFirstDevToolsHost() {
    RenderProcessHost::iterator hosts = RenderProcessHost::AllHostsIterator();
    for (; !hosts.IsAtEnd(); hosts.Advance()) {
      RenderProcessHost* render_process_host = hosts.GetCurrentValue();
      DCHECK(render_process_host);
      if (!render_process_host->HasConnection())
        continue;
      RenderProcessHost::listeners_iterator iter(
          render_process_host->ListenersIterator());
      for (; !iter.IsAtEnd(); iter.Advance()) {
        const RenderWidgetHost* widget =
            static_cast<const RenderWidgetHost*>(iter.GetCurrentValue());
        DCHECK(widget);
        if (!widget || !widget->IsRenderView())
          continue;
        RenderViewHost* host = const_cast<RenderViewHost*>(
            static_cast<const RenderViewHost*>(widget));
        RenderViewHostDelegate* host_delegate = host->delegate();
        GURL url = host_delegate->GetURL();
        if (url.SchemeIs(chrome::kChromeDevToolsScheme))
          return host;
      }
    }
    return NULL;
  }
};

IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessPerTab) {
  // Set max renderers to 1 to force running out of processes.
  RenderProcessHost::SetMaxRendererProcessCount(1);

  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

#if defined(TOUCH_UI)
  ++host_count;  // For the touch keyboard.
#endif

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create a new TYPE_TABBED tab.  It should be in its own process.
  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another TYPE_TABBED tab.  It should share the previous process.
  GURL page2("data:text/html,hello world2");
  browser()->ShowSingletonTab(page2);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  browser()->NewTab();
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create another new tab.  It should share the process with the other WebUI.
  browser()->NewTab();
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process when --process-per-tab is set. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, DevToolsOnSelfInOwnProcessPPT) {
  CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
  parsed_command_line.AppendSwitch(switches::kProcessPerTab);

  int tab_count = 1;
  int host_count = 1;

#if defined(TOUCH_UI)
  ++host_count;  // For the touch keyboard.
#endif

  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsManager::GetInstance()->ToggleDevToolsWindow(
      devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// Ensure that DevTools opened to debug DevTools is launched in a separate
// process. See crbug.com/69873.
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, DevToolsOnSelfInOwnProcess) {
  int tab_count = 1;
  int host_count = 1;

#if defined(TOUCH_UI)
  ++host_count;  // For the touch keyboard.
#endif

  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // DevTools start in docked mode (no new tab), in a separate process.
  browser()->ToggleDevToolsWindow(DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());

  RenderViewHost* devtools = FindFirstDevToolsHost();
  DCHECK(devtools);

  // DevTools start in a separate process.
  DevToolsManager::GetInstance()->ToggleDevToolsWindow(
      devtools, DEVTOOLS_TOGGLE_ACTION_INSPECT);
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  EXPECT_EQ(host_count, RenderProcessHostCount());
}

// When we hit the max number of renderers, verify that the way we do process
// sharing behaves correctly.  In particular, this test is verifying that even
// when we hit the max process limit, that renderers of each type will wind up
// in a process of that type, even if that means creating a new process.
IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ProcessOverflow) {
  // Set max renderers to 1 to force running out of processes.
  RenderProcessHost::SetMaxRendererProcessCount(1);

  int tab_count = 1;
  int host_count = 1;
  TabContents* tab1 = NULL;
  TabContents* tab2 = NULL;
  RenderProcessHost* rph1 = NULL;
  RenderProcessHost* rph2 = NULL;
  RenderProcessHost* rph3 = NULL;

#if defined(TOUCH_UI)
  ++host_count;  // For the touch keyboard.
#endif

  // Change the first tab to be the new tab page (TYPE_WEBUI).
  GURL newtab(chrome::kChromeUINewTabURL);
  ui_test_utils::NavigateToURL(browser(), newtab);
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab1 = browser()->GetTabContentsAt(tab_count - 1);
  rph1 = tab1->GetRenderProcessHost();
  EXPECT_EQ(tab1->GetURL(), newtab);
  EXPECT_EQ(host_count, RenderProcessHostCount());

  // Create a new TYPE_TABBED tab.  It should be in its own process.
  GURL page1("data:text/html,hello world1");
  browser()->ShowSingletonTab(page1);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  host_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab1 = browser()->GetTabContentsAt(tab_count - 1);
  rph2 = tab1->GetRenderProcessHost();
  EXPECT_EQ(tab1->GetURL(), page1);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_NE(rph1, rph2);

  // Create another TYPE_TABBED tab.  It should share the previous process.
  GURL page2("data:text/html,hello world2");
  browser()->ShowSingletonTab(page2);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab2 = browser()->GetTabContentsAt(tab_count - 1);
  EXPECT_EQ(tab2->GetURL(), page2);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_EQ(tab2->GetRenderProcessHost(), rph2);

  // Create another TYPE_WEBUI tab.  It should share the process with newtab.
  // Note: intentionally create this tab after the TYPE_TABBED tabs to exercise
  // bug 43448 where extension and WebUI tabs could get combined into normal
  // renderers.
  GURL history(chrome::kChromeUIHistoryURL);
  browser()->ShowSingletonTab(history);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab2 = browser()->GetTabContentsAt(tab_count - 1);
  EXPECT_EQ(tab2->GetURL(), history);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_EQ(tab2->GetRenderProcessHost(), rph1);

  // Create a TYPE_EXTENSION tab.  It should be in its own process.
  // (the bookmark manager is implemented as an extension)
  GURL bookmarks(chrome::kChromeUIBookmarksURL);
  browser()->ShowSingletonTab(bookmarks);
  if (browser()->tab_count() == tab_count)
    ui_test_utils::WaitForNewTab(browser());
  tab_count++;
#if !defined(TOUCH_UI)
  // The keyboard in touchui already creates an extension process. So this
  // should not increase the process count.
  host_count++;
#endif
  EXPECT_EQ(tab_count, browser()->tab_count());
  tab1 = browser()->GetTabContentsAt(tab_count - 1);
  rph3 = tab1->GetRenderProcessHost();
  EXPECT_EQ(tab1->GetURL(), bookmarks);
  EXPECT_EQ(host_count, RenderProcessHostCount());
  EXPECT_NE(rph1, rph3);
  EXPECT_NE(rph2, rph3);
}
<|endoftext|>


<commit_before>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_COMPLEX_OPERATOR
#define MFEM_COMPLEX_OPERATOR

#include "operator.hpp"
#include "sparsemat.hpp"
#ifdef MFEM_USE_MPI
#include "hypre.hpp"
#endif

#ifdef MFEM_USE_SUITESPARSE
#include <umfpack.h>
#endif

namespace mfem
{

/** @brief Mimic the action of a complex operator using two real operators.

    This operator requires vectors that are twice the length of its internally
    stored real operators, Op_Real and Op_Imag. It is assumed that these vectors
    store the real part of the vector first followed by its imaginary part.

    ComplexOperator allows one to choose a convention upon construction, which
    facilitates symmetry.

    If we let (y_r + i y_i) = (Op_r + i Op_i)(x_r + i x_i) then Matrix-vector
    products are computed as:

    1. When Convention::HERMITIAN is used (default)
    / y_r \   / Op_r -Op_i \ / x_r \
    |     | = |            | |     |
    \ y_i /   \ Op_i  Op_r / \ x_i /

    2. When Convention::BLOCK_SYMMETRIC is used
    / y_r \   / Op_r -Op_i \ / x_r \
    |     | = |            | |     |
    \-y_i /   \-Op_i -Op_r / \ x_i /
    In other words, Matrix-vector products with Convention::BLOCK_SYMMETRIC
    compute the complex conjugate of Op*x.

    Either convention can be used with a given complex operator, however, each
    of them may be best suited for different classes of problems. For example:

    1. Convention::HERMITIAN, is well suited for Hermitian operators, i.e.,
       operators where the real part is symmetric and the imaginary part of the
       operator is anti-symmetric, hence the name. In such cases the resulting 2
       x 2 operator will be symmetric.

    2. Convention::BLOCK_SYMMETRIC, is well suited for operators where both the
       real and imaginary parts are symmetric. In this case the resulting 2 x 2
       operator will also be symmetric. Such operators are common when studying
       damped oscillations, for example.

    Note: this class cannot be used to represent a general nonlinear complex
    operator.
*/
class ComplexOperator : public Operator
{
public:
   enum Convention
   {
      HERMITIAN,      ///< Native convention for Hermitian operators
      BLOCK_SYMMETRIC ///< Alternate convention for damping operators
   };

   /** @brief Constructs complex operator object

       Note that either @p Op_Real or @p Op_Imag can be NULL, thus eliminating
       their action (see documentation of the class for more details).

       In case ownership of the passed operator is transferred to this class
       through @p ownReal and @p ownImag, the operators will be explicitly
       destroyed at the end of the life of this object.
   */
   ComplexOperator(Operator * Op_Real, Operator * Op_Imag,
                   bool ownReal, bool ownImag,
                   Convention convention = HERMITIAN);

   virtual ~ComplexOperator();

   /** @brief Check for existence of real or imaginary part of the operator

       These methods do not check that the operators are non-zero but only that
       the operators have been set.
    */
   bool hasRealPart() const { return Op_Real_ != NULL; }
   bool hasImagPart() const { return Op_Imag_ != NULL; }

   /** @brief Real or imaginary part accessor methods

       The following accessor methods should only be called if the requested
       part of the opertor is known to exist.  This can be checked with
       hasRealPart() or hasImagPart().
   */
   virtual Operator & real();
   virtual Operator & imag();
   virtual const Operator & real() const;
   virtual const Operator & imag() const;

   virtual void Mult(const Vector &x, Vector &y) const;
   virtual void MultTranspose(const Vector &x, Vector &y) const;

   virtual Type GetType() const { return Complex_Operator; }

   Convention GetConvention() const { return convention_; }

protected:
   // Let this be hidden from the public interface since the implementation
   // depends on internal members
   void Mult(const Vector &x_r, const Vector &x_i,
             Vector &y_r, Vector &y_i) const;
   void MultTranspose(const Vector &x_r, const Vector &x_i,
                      Vector &y_r, Vector &y_i) const;

protected:
   Operator * Op_Real_;
   Operator * Op_Imag_;

   bool ownReal_;
   bool ownImag_;

   Convention convention_;

   mutable Vector x_r_, x_i_, y_r_, y_i_;
   mutable Vector *u_, *v_;
};

/** @brief Specialization of the ComplexOperator built from a pair of Sparse
    Matrices.

    The purpose of this specialization is to construct a single SparseMatrix
    object which is equivalent to the 2x2 block system that the ComplexOperator
    mimics. The resulting SparseMatrix can then be passed along to solvers which
    require access to the CSR matrix data such as SuperLU, STRUMPACK, or similar
    sparse linear solvers.

    See ComplexOperator documentation above for more information.
 */
class ComplexSparseMatrix : public ComplexOperator
{
public:
   ComplexSparseMatrix(SparseMatrix * A_Real, SparseMatrix * A_Imag,
                       bool ownReal, bool ownImag,
                       Convention convention = HERMITIAN)
      : ComplexOperator(A_Real, A_Imag, ownReal, ownImag, convention)
   {}

   virtual SparseMatrix & real();
   virtual SparseMatrix & imag();

   virtual const SparseMatrix & real() const;
   virtual const SparseMatrix & imag() const;

   /** Combine the blocks making up this complex operator into a single
       SparseMatrix. The resulting matrix can be passed to solvers which require
       access to the matrix entries themselves, such as sparse direct solvers,
       rather than simply the action of the opertor. Note that this combined
       operator requires roughly twice the memory of the block structured
       operator. */
   SparseMatrix * GetSystemMatrix() const;

   virtual Type GetType() const { return MFEM_ComplexSparseMat; }
};

#ifdef MFEM_USE_SUITESPARSE
/** @brief Interface with UMFPack solver specialized for ComplexSparseMatrix
    This approach avoids forming a monolithic SparseMatrix which leads
    to increased memory and flops
 */
class ComplexUMFPackSolver : public Solver
{
protected:
   bool use_long_ints;
   bool transa;
   ComplexSparseMatrix *mat;

   void *Numeric;
   SuiteSparse_long *AI, *AJ;

   void Init();

public:
   double Control[UMFPACK_CONTROL];
   mutable double Info[UMFPACK_INFO];

   /** @brief For larger matrices, if the solver fails, set the parameter @a
       _use_long_ints = true. */
   ComplexUMFPackSolver(bool _use_long_ints = false, bool transa_ = false)
      : use_long_ints(_use_long_ints), transa(transa_) { Init(); }
   /** @brief Factorize the given ComplexSparseMatrix using the defaults.
       For larger matrices, if the solver fails, set the parameter
       @a _use_long_ints = true. */
   ComplexUMFPackSolver(ComplexSparseMatrix &A, bool _use_long_ints = false,
                        bool transa_ = false)
      : use_long_ints(_use_long_ints), transa(transa_) { Init(); SetOperator(A); }

   /** @brief Factorize the given Operator @a op which must be
       a ComplexSparseMatrix.

       The factorization uses the parameters set in the #Control data member.
       @note This method calls SparseMatrix::SortColumnIndices()
       for real and imag parts of the ComplexSparseMatrix,
       modifying the matrices if the column indices are not already sorted. */
   virtual void SetOperator(const Operator &op);

   // Set the print level field in the #Control data member.
   void SetPrintLevel(int print_lvl) { Control[UMFPACK_PRL] = print_lvl; }

   // This determines the action of MultTranspose (see below for details)
   void SetTransposeSolve(bool transa_) { transa = transa_ ; }

   /** @brief This is solving the system A x = b */
   virtual void Mult(const Vector &b, Vector &x) const;

   /** @brief
      This is solving the system:
      A^H x = b (when transa = false)
      This is equivalent to solving the transpose block system for the
      case of Convention = HERMITIAN
      A^T x = b (when transa = true)
      This is equivalent to solving the transpose block system for the
      case of Convention = BLOCK_SYMMETRIC */
   virtual void MultTranspose(const Vector &b, Vector &x) const;

   virtual ~ComplexUMFPackSolver();
};

#endif

#ifdef MFEM_USE_MPI

/** @brief Specialization of the ComplexOperator built from a pair of
    HypreParMatrices.

    The purpose of this specialization is to construct a single HypreParMatrix
    object which is equivalent to the 2x2 block system that the ComplexOperator
    mimics. The resulting HypreParMatrix can then be passed along to solvers
    which require access to the CSR matrix data such as SuperLU, STRUMPACK, or
    similar sparse linear solvers.

    See ComplexOperator documentation above for more information.
 */
class ComplexHypreParMatrix : public ComplexOperator
{
public:
   ComplexHypreParMatrix(HypreParMatrix * A_Real, HypreParMatrix * A_Imag,
                         bool ownReal, bool ownImag,
                         Convention convention = HERMITIAN);

   virtual HypreParMatrix & real();
   virtual HypreParMatrix & imag();

   virtual const HypreParMatrix & real() const;
   virtual const HypreParMatrix & imag() const;

   /** Combine the blocks making up this complex operator into a single
       HypreParMatrix. The resulting matrix can be passed to solvers which
       require access to the matrix entries themselves, such as sparse direct
       solvers or Hypre preconditioners, rather than simply the action of the
       opertor. Note that this combined operator requires roughly twice the
       memory of the block structured operator. */
   HypreParMatrix * GetSystemMatrix() const;

   virtual Type GetType() const { return Complex_Hypre_ParCSR; }

private:
   void getColStartStop(const HypreParMatrix * A_r,
                        const HypreParMatrix * A_i,
                        int & num_recv_procs,
                        HYPRE_Int *& offd_col_start_stop) const;

   MPI_Comm comm_;
   int myid_;
   int nranks_;
};

#endif // MFEM_USE_MPI

}

#endif // MFEM_COMPLEX_OPERATOR
<commit_msg>removed space in comment<commit_after>// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#ifndef MFEM_COMPLEX_OPERATOR
#define MFEM_COMPLEX_OPERATOR

#include "operator.hpp"
#include "sparsemat.hpp"
#ifdef MFEM_USE_MPI
#include "hypre.hpp"
#endif

#ifdef MFEM_USE_SUITESPARSE
#include <umfpack.h>
#endif

namespace mfem
{

/** @brief Mimic the action of a complex operator using two real operators.

    This operator requires vectors that are twice the length of its internally
    stored real operators, Op_Real and Op_Imag. It is assumed that these vectors
    store the real part of the vector first followed by its imaginary part.

    ComplexOperator allows one to choose a convention upon construction, which
    facilitates symmetry.

    If we let (y_r + i y_i) = (Op_r + i Op_i)(x_r + i x_i) then Matrix-vector
    products are computed as:

    1. When Convention::HERMITIAN is used (default)
    / y_r \   / Op_r -Op_i \ / x_r \
    |     | = |            | |     |
    \ y_i /   \ Op_i  Op_r / \ x_i /

    2. When Convention::BLOCK_SYMMETRIC is used
    / y_r \   / Op_r -Op_i \ / x_r \
    |     | = |            | |     |
    \-y_i /   \-Op_i -Op_r / \ x_i /
    In other words, Matrix-vector products with Convention::BLOCK_SYMMETRIC
    compute the complex conjugate of Op*x.

    Either convention can be used with a given complex operator, however, each
    of them may be best suited for different classes of problems. For example:

    1. Convention::HERMITIAN, is well suited for Hermitian operators, i.e.,
       operators where the real part is symmetric and the imaginary part of the
       operator is anti-symmetric, hence the name. In such cases the resulting 2
       x 2 operator will be symmetric.

    2. Convention::BLOCK_SYMMETRIC, is well suited for operators where both the
       real and imaginary parts are symmetric. In this case the resulting 2 x 2
       operator will also be symmetric. Such operators are common when studying
       damped oscillations, for example.

    Note: this class cannot be used to represent a general nonlinear complex
    operator.
*/
class ComplexOperator : public Operator
{
public:
   enum Convention
   {
      HERMITIAN,      ///< Native convention for Hermitian operators
      BLOCK_SYMMETRIC ///< Alternate convention for damping operators
   };

   /** @brief Constructs complex operator object

       Note that either @p Op_Real or @p Op_Imag can be NULL, thus eliminating
       their action (see documentation of the class for more details).

       In case ownership of the passed operator is transferred to this class
       through @p ownReal and @p ownImag, the operators will be explicitly
       destroyed at the end of the life of this object.
   */
   ComplexOperator(Operator * Op_Real, Operator * Op_Imag,
                   bool ownReal, bool ownImag,
                   Convention convention = HERMITIAN);

   virtual ~ComplexOperator();

   /** @brief Check for existence of real or imaginary part of the operator

       These methods do not check that the operators are non-zero but only that
       the operators have been set.
    */
   bool hasRealPart() const { return Op_Real_ != NULL; }
   bool hasImagPart() const { return Op_Imag_ != NULL; }

   /** @brief Real or imaginary part accessor methods

       The following accessor methods should only be called if the requested
       part of the opertor is known to exist.  This can be checked with
       hasRealPart() or hasImagPart().
   */
   virtual Operator & real();
   virtual Operator & imag();
   virtual const Operator & real() const;
   virtual const Operator & imag() const;

   virtual void Mult(const Vector &x, Vector &y) const;
   virtual void MultTranspose(const Vector &x, Vector &y) const;

   virtual Type GetType() const { return Complex_Operator; }

   Convention GetConvention() const { return convention_; }

protected:
   // Let this be hidden from the public interface since the implementation
   // depends on internal members
   void Mult(const Vector &x_r, const Vector &x_i,
             Vector &y_r, Vector &y_i) const;
   void MultTranspose(const Vector &x_r, const Vector &x_i,
                      Vector &y_r, Vector &y_i) const;

protected:
   Operator * Op_Real_;
   Operator * Op_Imag_;

   bool ownReal_;
   bool ownImag_;

   Convention convention_;

   mutable Vector x_r_, x_i_, y_r_, y_i_;
   mutable Vector *u_, *v_;
};

/** @brief Specialization of the ComplexOperator built from a pair of Sparse
    Matrices.

    The purpose of this specialization is to construct a single SparseMatrix
    object which is equivalent to the 2x2 block system that the ComplexOperator
    mimics. The resulting SparseMatrix can then be passed along to solvers which
    require access to the CSR matrix data such as SuperLU, STRUMPACK, or similar
    sparse linear solvers.

    See ComplexOperator documentation above for more information.
 */
class ComplexSparseMatrix : public ComplexOperator
{
public:
   ComplexSparseMatrix(SparseMatrix * A_Real, SparseMatrix * A_Imag,
                       bool ownReal, bool ownImag,
                       Convention convention = HERMITIAN)
      : ComplexOperator(A_Real, A_Imag, ownReal, ownImag, convention)
   {}

   virtual SparseMatrix & real();
   virtual SparseMatrix & imag();

   virtual const SparseMatrix & real() const;
   virtual const SparseMatrix & imag() const;

   /** Combine the blocks making up this complex operator into a single
       SparseMatrix. The resulting matrix can be passed to solvers which require
       access to the matrix entries themselves, such as sparse direct solvers,
       rather than simply the action of the opertor. Note that this combined
       operator requires roughly twice the memory of the block structured
       operator. */
   SparseMatrix * GetSystemMatrix() const;

   virtual Type GetType() const { return MFEM_ComplexSparseMat; }
};

#ifdef MFEM_USE_SUITESPARSE
/** @brief Interface with UMFPack solver specialized for ComplexSparseMatrix
    This approach avoids forming a monolithic SparseMatrix which leads
    to increased memory and flops
 */
class ComplexUMFPackSolver : public Solver
{
protected:
   bool use_long_ints;
   bool transa;
   ComplexSparseMatrix *mat;

   void *Numeric;
   SuiteSparse_long *AI, *AJ;

   void Init();

public:
   double Control[UMFPACK_CONTROL];
   mutable double Info[UMFPACK_INFO];

   /** @brief For larger matrices, if the solver fails, set the parameter @a
       _use_long_ints = true. */
   ComplexUMFPackSolver(bool _use_long_ints = false, bool transa_ = false)
      : use_long_ints(_use_long_ints), transa(transa_) { Init(); }
   /** @brief Factorize the given ComplexSparseMatrix using the defaults.
       For larger matrices, if the solver fails, set the parameter
       @a _use_long_ints = true. */
   ComplexUMFPackSolver(ComplexSparseMatrix &A, bool _use_long_ints = false,
                        bool transa_ = false)
      : use_long_ints(_use_long_ints), transa(transa_) { Init(); SetOperator(A); }

   /** @brief Factorize the given Operator @a op which must be
       a ComplexSparseMatrix.

       The factorization uses the parameters set in the #Control data member.
       @note This method calls SparseMatrix::SortColumnIndices()
       for real and imag parts of the ComplexSparseMatrix,
       modifying the matrices if the column indices are not already sorted. */
   virtual void SetOperator(const Operator &op);

   // Set the print level field in the #Control data member.
   void SetPrintLevel(int print_lvl) { Control[UMFPACK_PRL] = print_lvl; }

   // This determines the action of MultTranspose (see below for details)
   void SetTransposeSolve(bool transa_) { transa = transa_; }

   /** @brief This is solving the system A x = b */
   virtual void Mult(const Vector &b, Vector &x) const;

   /** @brief
      This is solving the system:
      A^H x = b (when transa = false)
      This is equivalent to solving the transpose block system for the
      case of Convention = HERMITIAN
      A^T x = b (when transa = true)
      This is equivalent to solving the transpose block system for the
      case of Convention = BLOCK_SYMMETRIC */
   virtual void MultTranspose(const Vector &b, Vector &x) const;

   virtual ~ComplexUMFPackSolver();
};

#endif

#ifdef MFEM_USE_MPI

/** @brief Specialization of the ComplexOperator built from a pair of
    HypreParMatrices.

    The purpose of this specialization is to construct a single HypreParMatrix
    object which is equivalent to the 2x2 block system that the ComplexOperator
    mimics. The resulting HypreParMatrix can then be passed along to solvers
    which require access to the CSR matrix data such as SuperLU, STRUMPACK, or
    similar sparse linear solvers.

    See ComplexOperator documentation above for more information.
 */
class ComplexHypreParMatrix : public ComplexOperator
{
public:
   ComplexHypreParMatrix(HypreParMatrix * A_Real, HypreParMatrix * A_Imag,
                         bool ownReal, bool ownImag,
                         Convention convention = HERMITIAN);

   virtual HypreParMatrix & real();
   virtual HypreParMatrix & imag();

   virtual const HypreParMatrix & real() const;
   virtual const HypreParMatrix & imag() const;

   /** Combine the blocks making up this complex operator into a single
       HypreParMatrix. The resulting matrix can be passed to solvers which
       require access to the matrix entries themselves, such as sparse direct
       solvers or Hypre preconditioners, rather than simply the action of the
       opertor. Note that this combined operator requires roughly twice the
       memory of the block structured operator. */
   HypreParMatrix * GetSystemMatrix() const;

   virtual Type GetType() const { return Complex_Hypre_ParCSR; }

private:
   void getColStartStop(const HypreParMatrix * A_r,
                        const HypreParMatrix * A_i,
                        int & num_recv_procs,
                        HYPRE_Int *& offd_col_start_stop) const;

   MPI_Comm comm_;
   int myid_;
   int nranks_;
};

#endif // MFEM_USE_MPI

}

#endif // MFEM_COMPLEX_OPERATOR
<|endoftext|>