<commit_before>#ifndef _MSP_GPIO_HPP
#define _MSP_GPIO_HPP
#include <stdint.h>
#include <msp430.h>
#include "utilities/utilities.hpp"

namespace McuPeripheral {

template<uint8_t _input, uint8_t _select2>
class McuPort
{
public:
	static const uint8_t mInputReg = _input;
	static const uint8_t mOutputReg = _input+1;
	static const uint8_t mDirectionReg = _input+2;
	static const uint8_t mIntFlagReg = _input+3;
	static const uint8_t mIntEdgeSelReg = _input+4;
	static const uint8_t mIntEnableReg = _input+5;
	static const uint8_t mSelectReg = _input+6;
	static const uint8_t mResistorReg = _input+7;
	static const uint8_t mSelect2Reg = _select2;
};

template < class _port, uint8_t _pin >
class McuPin
{
public:

	static void set()
	{
		*((volatile uint8_t*)_port::mOutputReg) |= _pin;
	}
	static bool read()
	{
		return *((volatile uint8_t*)_port::mInputReg) & _pin;
	}
	static void clear()
	{
		*((volatile uint8_t*)_port::mOutputReg) &= ~_pin;
	}
	static void toggle()
	{
		*((volatile uint8_t*)_port::mOutputReg) ^= _pin;
	}
	static void output()
	{
		*((volatile uint8_t*)_port::mDirectionReg) |= _pin;
	}
	static void input()
	{
		*((volatile uint8_t*)_port::mDirectionReg) &= ~_pin;
	}
	static void pullUp()
	{
		*((volatile uint8_t*)_port::mResistor) |= _pin;
		set();
	}
	static void pullDown()
	{
		*((volatile uint8_t*)_port::mResistor) |= _pin;
		clear();
	}
	static void pullOff()
	{
		*((volatile uint8_t*)_port::mResistor) &= ~_pin;
	}
	static void intEnable()
	{
		*((volatile uint8_t*)_port::mIntEnableReg) |= _pin;
	}
	static void intDisable()
	{
		*((volatile uint8_t*)_port::mIntEnableReg) &= ~_pin;
	}
	static void edgeHighToLow()
	{
		*((volatile uint8_t*)_port::mIntEdgeSelReg) |= _pin;
	}
	static void edgeLowToHigh()
	{
		*((volatile uint8_t*)_port::mIntEdgeSelReg) &= ~_pin;
	}
	static bool irqFlag()
	{
		return *((volatile uint8_t*)_port::mInputReg) & _pin;
	}
	static void selectOff()
	{
		*((volatile uint8_t*)_port::mSelectReg) &= ~_pin;
	}
	static void select2Off()
	{
		*((volatile uint8_t*)_port::mSelect2Reg) &= ~_pin;
	}
	static void selectOn()
	{
		*((volatile uint8_t*)_port::mSelectReg) |= _pin;
	}
	static void select2On()
	{
		*((volatile uint8_t*)_port::mSelect2Reg) |= _pin;
	}
	static void setPinIrqHandler(callback_t cb, callback_args_t args)
	{
		mPinHandler = cb;
		mPinArgs = args;
	}

	static callback_t mPinHandler;
	static callback_args_t mPinArgs;

};

template < class _port, uint8_t _pin >
callback_t McuPin<_port,_pin>::mPinHandler;
template < class _port, uint8_t _pin >
callback_args_t McuPin<_port,_pin>::mPinArgs;

class FakePin
{
public:

	static void set()
	{
		return;
	}
	static bool read()
	{
		return true;
	}
	static void clear()
	{
		return;
	}
	static void toggle()
	{
		return;
	}
	static void output()
	{
		return;
	}
	static void input()
	{
		return;
	}
	static void pull_up()
	{
		return;
	}
	static void pull_down()
	{
		return;
	}
	static void pull_off()
	{
		return;
	}
	static void select_off()
	{
		return;
	}
	static void select2_off()
	{
		return;
	}
	static void selectOn()
	{
		return;
	}
	static void select2On()
	{
		return;
	}
};

}

using McuPort1 =  McuPeripheral::McuPort<P1IN_,P1SEL2_>;
using McuPort2 =  McuPeripheral::McuPort<P2IN_,P2SEL2_>;
#endif //_MSP_GPIO_HPP
<commit_msg>Added ability to get gpio bit of pin, if fake pin then returns 0.<commit_after>#ifndef _MSP_GPIO_HPP
#define _MSP_GPIO_HPP
#include <stdint.h>
#include <msp430.h>
#include "utilities/utilities.hpp"

namespace McuPeripheral {

template<uint8_t _input, uint8_t _select2>
class McuPort
{
public:
	static const uint8_t mInputReg = _input;
	static const uint8_t mOutputReg = _input+1;
	static const uint8_t mDirectionReg = _input+2;
	static const uint8_t mIntFlagReg = _input+3;
	static const uint8_t mIntEdgeSelReg = _input+4;
	static const uint8_t mIntEnableReg = _input+5;
	static const uint8_t mSelectReg = _input+6;
	static const uint8_t mResistorReg = _input+7;
	static const uint8_t mSelect2Reg = _select2;
};

template < class _port, uint8_t _pin >
class McuPin
{
public:

	static void set()
	{
		*((volatile uint8_t*)_port::mOutputReg) |= _pin;
	}
	static bool read()
	{
		return *((volatile uint8_t*)_port::mInputReg) & _pin;
	}
	static void clear()
	{
		*((volatile uint8_t*)_port::mOutputReg) &= ~_pin;
	}
	static void toggle()
	{
		*((volatile uint8_t*)_port::mOutputReg) ^= _pin;
	}
	static void output()
	{
		*((volatile uint8_t*)_port::mDirectionReg) |= _pin;
	}
	static void input()
	{
		*((volatile uint8_t*)_port::mDirectionReg) &= ~_pin;
	}
	static void pullUp()
	{
		*((volatile uint8_t*)_port::mResistor) |= _pin;
		set();
	}
	static void pullDown()
	{
		*((volatile uint8_t*)_port::mResistor) |= _pin;
		clear();
	}
	static void pullOff()
	{
		*((volatile uint8_t*)_port::mResistor) &= ~_pin;
	}
	static void intEnable()
	{
		*((volatile uint8_t*)_port::mIntEnableReg) |= _pin;
	}
	static void intDisable()
	{
		*((volatile uint8_t*)_port::mIntEnableReg) &= ~_pin;
	}
	static void edgeHighToLow()
	{
		*((volatile uint8_t*)_port::mIntEdgeSelReg) |= _pin;
	}
	static void edgeLowToHigh()
	{
		*((volatile uint8_t*)_port::mIntEdgeSelReg) &= ~_pin;
	}
	static bool irqFlag()
	{
		return *((volatile uint8_t*)_port::mInputReg) & _pin;
	}
	static void selectOff()
	{
		*((volatile uint8_t*)_port::mSelectReg) &= ~_pin;
	}
	static void select2Off()
	{
		*((volatile uint8_t*)_port::mSelect2Reg) &= ~_pin;
	}
	static void selectOn()
	{
		*((volatile uint8_t*)_port::mSelectReg) |= _pin;
	}
	static void select2On()
	{
		*((volatile uint8_t*)_port::mSelect2Reg) |= _pin;
	}
	static void setPinIrqHandler(callback_t cb, callback_args_t args)
	{
		mPinHandler = cb;
		mPinArgs = args;
	}
	static constexpr uint8_t getBitValue()
	{
		return _pin;
	}

	static callback_t mPinHandler;
	static callback_args_t mPinArgs;

};

template < class _port, uint8_t _pin >
callback_t McuPin<_port,_pin>::mPinHandler;
template < class _port, uint8_t _pin >
callback_args_t McuPin<_port,_pin>::mPinArgs;

class FakePin
{
public:

	static void set()
	{
		return;
	}
	static bool read()
	{
		return true;
	}
	static void clear()
	{
		return;
	}
	static void toggle()
	{
		return;
	}
	static void output()
	{
		return;
	}
	static void input()
	{
		return;
	}
	static void pull_up()
	{
		return;
	}
	static void pull_down()
	{
		return;
	}
	static void pull_off()
	{
		return;
	}
	static void select_off()
	{
		return;
	}
	static void select2_off()
	{
		return;
	}
	static void selectOn()
	{
		return;
	}
	static void select2On()
	{
		return;
	}
	static constexpr uint8_t getBitValue()
	{
		return 0;
	}
};

}

using McuPort1 =  McuPeripheral::McuPort<P1IN_,P1SEL2_>;
using McuPort2 =  McuPeripheral::McuPort<P2IN_,P2SEL2_>;
#endif //_MSP_GPIO_HPP
<|endoftext|>


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

#include "chrome/browser/printing/print_job.h"

#include "base/message_loop.h"
#include "base/timer.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/common/notification_service.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"

using base::TimeDelta;

namespace printing {

PrintJob::PrintJob()
    : ui_message_loop_(MessageLoop::current()),
      source_(NULL),
      worker_(),
      settings_(),
      is_job_pending_(false),
      is_print_dialog_box_shown_(false),
      is_canceling_(false) {
  DCHECK(ui_message_loop_);
  // This is normally a UI message loop, but in unit tests, the message loop is
  // of the 'default' type.
  DCHECK(ui_message_loop_->type() == MessageLoop::TYPE_UI ||
         ui_message_loop_->type() == MessageLoop::TYPE_DEFAULT);
  ui_message_loop_->AddDestructionObserver(this);
}

PrintJob::~PrintJob() {
  ui_message_loop_->RemoveDestructionObserver(this);
  // The job should be finished (or at least canceled) when it is destroyed.
  DCHECK(!is_job_pending_);
  DCHECK(!is_print_dialog_box_shown_);
  DCHECK(!is_canceling_);
  if (worker_.get())
    DCHECK(worker_->message_loop() == NULL);
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
}

void PrintJob::Initialize(PrintJobWorkerOwner* job,
                          PrintedPagesSource* source) {
  DCHECK(!source_);
  DCHECK(!worker_.get());
  DCHECK(!is_job_pending_);
  DCHECK(!is_print_dialog_box_shown_);
  DCHECK(!is_canceling_);
  DCHECK(!document_.get());
  source_ = source;
  worker_.reset(job->DetachWorker(this));
  settings_ = job->settings();

  UpdatePrintedDocument(new PrintedDocument(settings_, source_, job->cookie()));

  // Don't forget to register to our own messages.
  registrar_.Add(this, NotificationType::PRINT_JOB_EVENT,
                 Source<PrintJob>(this));
}

void PrintJob::Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  switch (type.value) {
    case NotificationType::PRINT_JOB_EVENT: {
      OnNotifyPrintJobEvent(*Details<JobEventDetails>(details).ptr());
      break;
    }
    default: {
      break;
    }
  }
}

void PrintJob::GetSettingsDone(const PrintSettings& new_settings,
                               PrintingContext::Result result) {
  NOTREACHED();
}

PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
  NOTREACHED();
  return NULL;
}

MessageLoop* PrintJob::message_loop() {
  return ui_message_loop_;
}

const PrintSettings& PrintJob::settings() const {
  return settings_;
}

int PrintJob::cookie() const {
  if (!document_.get())
    // Always use an invalid cookie in this case.
    return 0;
  return document_->cookie();
}

void PrintJob::WillDestroyCurrentMessageLoop() {
  NOTREACHED();
}

void PrintJob::StartPrinting() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  DCHECK(worker_->message_loop());
  DCHECK(!is_job_pending_);
  DCHECK(!is_print_dialog_box_shown_);
  if (!worker_->message_loop() || is_job_pending_)
    return;

  // Real work is done in PrintJobWorker::StartPrinting().
  worker_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
      worker_.get(), &PrintJobWorker::StartPrinting, document_));
  // Set the flag right now.
  is_job_pending_ = true;

  // Tell everyone!
  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL));
  NotificationService::current()->Notify(
      NotificationType::PRINT_JOB_EVENT,
      Source<PrintJob>(this),
      Details<JobEventDetails>(details.get()));
}

void PrintJob::Stop() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());

  // Be sure to live long enough.
  scoped_refptr<PrintJob> handle(this);

  MessageLoop* worker_loop = worker_->message_loop();
  if (worker_loop) {
    if (is_print_dialog_box_shown_) {
      // Make sure there is no Print... dialog box.
      worker_loop->PostTask(FROM_HERE, NewRunnableMethod(
          worker_.get(), &PrintJobWorker::DismissDialog));
      is_print_dialog_box_shown_ = false;
    }

    ControlledWorkerShutdown();

    is_job_pending_ = false;
    registrar_.Remove(this, NotificationType::PRINT_JOB_EVENT,
                      Source<PrintJob>(this));
  }
  // Flush the cached document.
  UpdatePrintedDocument(NULL);
}

void PrintJob::Cancel() {
  if (is_canceling_)
    return;
  is_canceling_ = true;

  // Be sure to live long enough.
  scoped_refptr<PrintJob> handle(this);

  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  MessageLoop* worker_loop = worker_.get() ? worker_->message_loop() : NULL;
  if (worker_loop) {
    // Call this right now so it renders the context invalid. Do not use
    // InvokeLater since it would take too much time.
    worker_->Cancel();
  }
  // Make sure a Cancel() is broadcast.
  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::FAILED, NULL, NULL));
  NotificationService::current()->Notify(
      NotificationType::PRINT_JOB_EVENT,
      Source<PrintJob>(this),
      Details<JobEventDetails>(details.get()));
  Stop();
  is_canceling_ = false;
}

bool PrintJob::FlushJob(int timeout_ms) {
  // Make sure the object outlive this message loop.
  scoped_refptr<PrintJob> handle(this);

  // Stop() will eventually be called, which will get out of the inner message
  // loop. But, don't take it for granted and set a timer in case something goes
  // wrong.
  base::OneShotTimer<MessageLoop> quit_task;
  if (timeout_ms) {
    quit_task.Start(TimeDelta::FromMilliseconds(timeout_ms),
                    MessageLoop::current(), &MessageLoop::Quit);
  }

  bool old_state = MessageLoop::current()->NestableTasksAllowed();
  MessageLoop::current()->SetNestableTasksAllowed(true);
  MessageLoop::current()->Run();
  // Restore task state.
  MessageLoop::current()->SetNestableTasksAllowed(old_state);

  return true;
}

void PrintJob::DisconnectSource() {
  source_ = NULL;
  if (document_.get())
    document_->DisconnectSource();
}

bool PrintJob::is_job_pending() const {
  return is_job_pending_;
}

bool PrintJob::is_print_dialog_box_shown() const {
  return is_print_dialog_box_shown_;
}

PrintedDocument* PrintJob::document() const {
  return document_.get();
}

void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
  if (document_.get() == new_document)
    return;

  document_ = new_document;

  if (document_.get()) {
    settings_ = document_->settings();
  }

  if (worker_.get() && worker_->message_loop()) {
    DCHECK(!is_job_pending_);
    // Sync the document with the worker.
    worker_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        worker_.get(), &PrintJobWorker::OnDocumentChanged, document_));
  }
}

void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
  switch (event_details.type()) {
    case JobEventDetails::FAILED: {
      settings_.Clear();
      // Update internal state.
      is_print_dialog_box_shown_ = false;
      // No need to cancel since the worker already canceled itself.
      Stop();
      break;
    }
    case JobEventDetails::USER_INIT_DONE:
    case JobEventDetails::DEFAULT_INIT_DONE:
    case JobEventDetails::USER_INIT_CANCELED: {
      DCHECK_EQ(event_details.document(), document_.get());
      break;
    }
    case JobEventDetails::NEW_DOC:
    case JobEventDetails::NEW_PAGE:
    case JobEventDetails::PAGE_DONE:
    case JobEventDetails::JOB_DONE:
    case JobEventDetails::ALL_PAGES_REQUESTED: {
      // Don't care.
      break;
    }
    case JobEventDetails::DOC_DONE: {
      // This will call Stop() and broadcast a JOB_DONE message.
      MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
          this, &PrintJob::OnDocumentDone));
      break;
    }
    default: {
      NOTREACHED();
      break;
    }
  }
}

void PrintJob::OnDocumentDone() {
  // Be sure to live long enough. The instance could be destroyed by the
  // JOB_DONE broadcast.
  scoped_refptr<PrintJob> handle(this);

  // Stop the worker thread.
  Stop();

  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL));
  NotificationService::current()->Notify(
      NotificationType::PRINT_JOB_EVENT,
      Source<PrintJob>(this),
      Details<JobEventDetails>(details.get()));
}

void PrintJob::ControlledWorkerShutdown() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());

  // The deadlock this code works around is specific to window messaging on
  // Windows, so we aren't likely to need it on any other platforms.
#if defined(OS_WIN)
  // We could easily get into a deadlock case if worker_->Stop() is used; the
  // printer driver created a window as a child of the browser window. By
  // canceling the job, the printer driver initiated dialog box is destroyed,
  // which sends a blocking message to its parent window. If the browser window
  // thread is not processing messages, a deadlock occurs.
  //
  // This function ensures that the dialog box will be destroyed in a timely
  // manner by the mere fact that the thread will terminate. So the potential
  // deadlock is eliminated.
  worker_->StopSoon();

  // Run a tight message loop until the worker terminates. It may seems like a
  // hack but I see no other way to get it to work flawlessly. The issues here
  // are:
  // - We don't want to run tasks while the thread is quitting.
  // - We want this code path to wait on the thread to quit before continuing.
  MSG msg;
  HANDLE thread_handle = worker_->thread_handle();
  for (; thread_handle;) {
    // Note that we don't do any kind of message priorization since we don't
    // execute any pending task or timer.
    DWORD result = MsgWaitForMultipleObjects(1, &thread_handle,
                                             FALSE, INFINITE, QS_ALLINPUT);
    if (result == WAIT_OBJECT_0 + 1) {
      while (PeekMessage(&msg, NULL, 0, 0, TRUE) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      // Continue looping.
    } else if (result == WAIT_OBJECT_0) {
      // The thread quit.
      break;
    } else {
      // An error occured. Assume the thread quit.
      NOTREACHED();
      break;
    }
  }
#endif

  // Now make sure the thread object is cleaned up.
  worker_->Stop();
}

// Takes settings_ ownership and will be deleted in the receiving thread.
JobEventDetails::JobEventDetails(Type type,
                                 PrintedDocument* document,
                                 PrintedPage* page)
    : document_(document),
      page_(page),
      type_(type) {
}

JobEventDetails::~JobEventDetails() {
}

PrintedDocument* JobEventDetails::document() const {
  return document_;
}

PrintedPage* JobEventDetails::page() const {
  return page_;
}

}  // namespace printing
<commit_msg>Printing: Allow file IO on the UI thread.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/printing/print_job.h"

#include "base/message_loop.h"
#include "base/thread_restrictions.h"
#include "base/timer.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/common/notification_service.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"

using base::TimeDelta;

namespace printing {

PrintJob::PrintJob()
    : ui_message_loop_(MessageLoop::current()),
      source_(NULL),
      worker_(),
      settings_(),
      is_job_pending_(false),
      is_print_dialog_box_shown_(false),
      is_canceling_(false) {
  DCHECK(ui_message_loop_);
  // This is normally a UI message loop, but in unit tests, the message loop is
  // of the 'default' type.
  DCHECK(ui_message_loop_->type() == MessageLoop::TYPE_UI ||
         ui_message_loop_->type() == MessageLoop::TYPE_DEFAULT);
  ui_message_loop_->AddDestructionObserver(this);
}

PrintJob::~PrintJob() {
  ui_message_loop_->RemoveDestructionObserver(this);
  // The job should be finished (or at least canceled) when it is destroyed.
  DCHECK(!is_job_pending_);
  DCHECK(!is_print_dialog_box_shown_);
  DCHECK(!is_canceling_);
  if (worker_.get())
    DCHECK(worker_->message_loop() == NULL);
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
}

void PrintJob::Initialize(PrintJobWorkerOwner* job,
                          PrintedPagesSource* source) {
  DCHECK(!source_);
  DCHECK(!worker_.get());
  DCHECK(!is_job_pending_);
  DCHECK(!is_print_dialog_box_shown_);
  DCHECK(!is_canceling_);
  DCHECK(!document_.get());
  source_ = source;
  worker_.reset(job->DetachWorker(this));
  settings_ = job->settings();

  UpdatePrintedDocument(new PrintedDocument(settings_, source_, job->cookie()));

  // Don't forget to register to our own messages.
  registrar_.Add(this, NotificationType::PRINT_JOB_EVENT,
                 Source<PrintJob>(this));
}

void PrintJob::Observe(NotificationType type,
                       const NotificationSource& source,
                       const NotificationDetails& details) {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  switch (type.value) {
    case NotificationType::PRINT_JOB_EVENT: {
      OnNotifyPrintJobEvent(*Details<JobEventDetails>(details).ptr());
      break;
    }
    default: {
      break;
    }
  }
}

void PrintJob::GetSettingsDone(const PrintSettings& new_settings,
                               PrintingContext::Result result) {
  NOTREACHED();
}

PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
  NOTREACHED();
  return NULL;
}

MessageLoop* PrintJob::message_loop() {
  return ui_message_loop_;
}

const PrintSettings& PrintJob::settings() const {
  return settings_;
}

int PrintJob::cookie() const {
  if (!document_.get())
    // Always use an invalid cookie in this case.
    return 0;
  return document_->cookie();
}

void PrintJob::WillDestroyCurrentMessageLoop() {
  NOTREACHED();
}

void PrintJob::StartPrinting() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  DCHECK(worker_->message_loop());
  DCHECK(!is_job_pending_);
  DCHECK(!is_print_dialog_box_shown_);
  if (!worker_->message_loop() || is_job_pending_)
    return;

  // Real work is done in PrintJobWorker::StartPrinting().
  worker_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
      worker_.get(), &PrintJobWorker::StartPrinting, document_));
  // Set the flag right now.
  is_job_pending_ = true;

  // Tell everyone!
  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL));
  NotificationService::current()->Notify(
      NotificationType::PRINT_JOB_EVENT,
      Source<PrintJob>(this),
      Details<JobEventDetails>(details.get()));
}

void PrintJob::Stop() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());

  // Be sure to live long enough.
  scoped_refptr<PrintJob> handle(this);

  MessageLoop* worker_loop = worker_->message_loop();
  if (worker_loop) {
    if (is_print_dialog_box_shown_) {
      // Make sure there is no Print... dialog box.
      worker_loop->PostTask(FROM_HERE, NewRunnableMethod(
          worker_.get(), &PrintJobWorker::DismissDialog));
      is_print_dialog_box_shown_ = false;
    }

    ControlledWorkerShutdown();

    is_job_pending_ = false;
    registrar_.Remove(this, NotificationType::PRINT_JOB_EVENT,
                      Source<PrintJob>(this));
  }
  // Flush the cached document.
  UpdatePrintedDocument(NULL);
}

void PrintJob::Cancel() {
  if (is_canceling_)
    return;
  is_canceling_ = true;

  // Be sure to live long enough.
  scoped_refptr<PrintJob> handle(this);

  DCHECK_EQ(ui_message_loop_, MessageLoop::current());
  MessageLoop* worker_loop = worker_.get() ? worker_->message_loop() : NULL;
  if (worker_loop) {
    // Call this right now so it renders the context invalid. Do not use
    // InvokeLater since it would take too much time.
    worker_->Cancel();
  }
  // Make sure a Cancel() is broadcast.
  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::FAILED, NULL, NULL));
  NotificationService::current()->Notify(
      NotificationType::PRINT_JOB_EVENT,
      Source<PrintJob>(this),
      Details<JobEventDetails>(details.get()));
  Stop();
  is_canceling_ = false;
}

bool PrintJob::FlushJob(int timeout_ms) {
  // Make sure the object outlive this message loop.
  scoped_refptr<PrintJob> handle(this);

  // Stop() will eventually be called, which will get out of the inner message
  // loop. But, don't take it for granted and set a timer in case something goes
  // wrong.
  base::OneShotTimer<MessageLoop> quit_task;
  if (timeout_ms) {
    quit_task.Start(TimeDelta::FromMilliseconds(timeout_ms),
                    MessageLoop::current(), &MessageLoop::Quit);
  }

  bool old_state = MessageLoop::current()->NestableTasksAllowed();
  MessageLoop::current()->SetNestableTasksAllowed(true);
  MessageLoop::current()->Run();
  // Restore task state.
  MessageLoop::current()->SetNestableTasksAllowed(old_state);

  return true;
}

void PrintJob::DisconnectSource() {
  source_ = NULL;
  if (document_.get())
    document_->DisconnectSource();
}

bool PrintJob::is_job_pending() const {
  return is_job_pending_;
}

bool PrintJob::is_print_dialog_box_shown() const {
  return is_print_dialog_box_shown_;
}

PrintedDocument* PrintJob::document() const {
  return document_.get();
}

void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
  if (document_.get() == new_document)
    return;

  document_ = new_document;

  if (document_.get()) {
    settings_ = document_->settings();
  }

  if (worker_.get() && worker_->message_loop()) {
    DCHECK(!is_job_pending_);
    // Sync the document with the worker.
    worker_->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(
        worker_.get(), &PrintJobWorker::OnDocumentChanged, document_));
  }
}

void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
  switch (event_details.type()) {
    case JobEventDetails::FAILED: {
      settings_.Clear();
      // Update internal state.
      is_print_dialog_box_shown_ = false;
      // No need to cancel since the worker already canceled itself.
      Stop();
      break;
    }
    case JobEventDetails::USER_INIT_DONE:
    case JobEventDetails::DEFAULT_INIT_DONE:
    case JobEventDetails::USER_INIT_CANCELED: {
      DCHECK_EQ(event_details.document(), document_.get());
      break;
    }
    case JobEventDetails::NEW_DOC:
    case JobEventDetails::NEW_PAGE:
    case JobEventDetails::PAGE_DONE:
    case JobEventDetails::JOB_DONE:
    case JobEventDetails::ALL_PAGES_REQUESTED: {
      // Don't care.
      break;
    }
    case JobEventDetails::DOC_DONE: {
      // This will call Stop() and broadcast a JOB_DONE message.
      MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod(
          this, &PrintJob::OnDocumentDone));
      break;
    }
    default: {
      NOTREACHED();
      break;
    }
  }
}

void PrintJob::OnDocumentDone() {
  // Be sure to live long enough. The instance could be destroyed by the
  // JOB_DONE broadcast.
  scoped_refptr<PrintJob> handle(this);

  // Stop the worker thread.
  Stop();

  scoped_refptr<JobEventDetails> details(
      new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL));
  NotificationService::current()->Notify(
      NotificationType::PRINT_JOB_EVENT,
      Source<PrintJob>(this),
      Details<JobEventDetails>(details.get()));
}

void PrintJob::ControlledWorkerShutdown() {
  DCHECK_EQ(ui_message_loop_, MessageLoop::current());

  // The deadlock this code works around is specific to window messaging on
  // Windows, so we aren't likely to need it on any other platforms.
#if defined(OS_WIN)
  // We could easily get into a deadlock case if worker_->Stop() is used; the
  // printer driver created a window as a child of the browser window. By
  // canceling the job, the printer driver initiated dialog box is destroyed,
  // which sends a blocking message to its parent window. If the browser window
  // thread is not processing messages, a deadlock occurs.
  //
  // This function ensures that the dialog box will be destroyed in a timely
  // manner by the mere fact that the thread will terminate. So the potential
  // deadlock is eliminated.
  worker_->StopSoon();

  // Run a tight message loop until the worker terminates. It may seems like a
  // hack but I see no other way to get it to work flawlessly. The issues here
  // are:
  // - We don't want to run tasks while the thread is quitting.
  // - We want this code path to wait on the thread to quit before continuing.
  MSG msg;
  HANDLE thread_handle = worker_->thread_handle();
  for (; thread_handle;) {
    // Note that we don't do any kind of message priorization since we don't
    // execute any pending task or timer.
    DWORD result = MsgWaitForMultipleObjects(1, &thread_handle,
                                             FALSE, INFINITE, QS_ALLINPUT);
    if (result == WAIT_OBJECT_0 + 1) {
      while (PeekMessage(&msg, NULL, 0, 0, TRUE) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
      // Continue looping.
    } else if (result == WAIT_OBJECT_0) {
      // The thread quit.
      break;
    } else {
      // An error occured. Assume the thread quit.
      NOTREACHED();
      break;
    }
  }
#endif

  // Temporarily allow it until we fix
  // http://code.google.com/p/chromium/issues/detail?id=67044
  base::ThreadRestrictions::ScopedAllowIO allow_io;

  // Now make sure the thread object is cleaned up.
  worker_->Stop();
}

// Takes settings_ ownership and will be deleted in the receiving thread.
JobEventDetails::JobEventDetails(Type type,
                                 PrintedDocument* document,
                                 PrintedPage* page)
    : document_(document),
      page_(page),
      type_(type) {
}

JobEventDetails::~JobEventDetails() {
}

PrintedDocument* JobEventDetails::document() const {
  return document_;
}

PrintedPage* JobEventDetails::page() const {
  return page_;
}

}  // namespace printing
<|endoftext|>


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

#include "chrome/common/process_watcher.h"

#include "base/env_var.h"
#include "base/message_loop.h"
#include "base/object_watcher.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/result_codes.h"

// Maximum amount of time (in milliseconds) to wait for the process to exit.
static const int kWaitInterval = 2000;

namespace {

class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate {
 public:
  explicit TimerExpiredTask(base::ProcessHandle process) : process_(process) {
    watcher_.StartWatching(process_, this);
  }

  virtual ~TimerExpiredTask() {
    if (process_) {
      KillProcess();
      DCHECK(!process_) << "Make sure to close the handle.";
    }
  }

  // Task ---------------------------------------------------------------------

  virtual void Run() {
    if (process_)
      KillProcess();
  }

  // MessageLoop::Watcher -----------------------------------------------------

  virtual void OnObjectSignaled(HANDLE object) {
    // When we're called from KillProcess, the ObjectWatcher may still be
    // watching.  the process handle, so make sure it has stopped.
    watcher_.StopWatching();

    CloseHandle(process_);
    process_ = NULL;
  }

 private:
  void KillProcess() {
    scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
    if (env->HasEnv(env_vars::kHeadless)) {
     // If running the distributed tests, give the renderer a little time
     // to figure out that the channel is shutdown and unwind.
     if (WaitForSingleObject(process_, kWaitInterval) == WAIT_OBJECT_0) {
       OnObjectSignaled(process_);
       return;
     }
    }

    // OK, time to get frisky.  We don't actually care when the process
    // terminates.  We just care that it eventually terminates, and that's what
    // TerminateProcess should do for us. Don't check for the result code since
    // it fails quite often. This should be investigated eventually.
    base::KillProcess(process_, ResultCodes::HUNG, false);

    // Now, just cleanup as if the process exited normally.
    OnObjectSignaled(process_);
  }

  // The process that we are watching.
  base::ProcessHandle process_;

  base::ObjectWatcher watcher_;

  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
};

}  // namespace

// static
void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process) {
  DCHECK(process != GetCurrentProcess());

  // If already signaled, then we are done!
  if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
    CloseHandle(process);
    return;
  }

  MessageLoop::current()->PostDelayedTask(FROM_HERE,
                                          new TimerExpiredTask(process),
                                          kWaitInterval);
}
<commit_msg>Windows build fix<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/process_watcher.h"

#include "base/scoped_ptr.h"
#include "base/env_var.h"
#include "base/message_loop.h"
#include "base/object_watcher.h"
#include "chrome/common/env_vars.h"
#include "chrome/common/result_codes.h"

// Maximum amount of time (in milliseconds) to wait for the process to exit.
static const int kWaitInterval = 2000;

namespace {

class TimerExpiredTask : public Task, public base::ObjectWatcher::Delegate {
 public:
  explicit TimerExpiredTask(base::ProcessHandle process) : process_(process) {
    watcher_.StartWatching(process_, this);
  }

  virtual ~TimerExpiredTask() {
    if (process_) {
      KillProcess();
      DCHECK(!process_) << "Make sure to close the handle.";
    }
  }

  // Task ---------------------------------------------------------------------

  virtual void Run() {
    if (process_)
      KillProcess();
  }

  // MessageLoop::Watcher -----------------------------------------------------

  virtual void OnObjectSignaled(HANDLE object) {
    // When we're called from KillProcess, the ObjectWatcher may still be
    // watching.  the process handle, so make sure it has stopped.
    watcher_.StopWatching();

    CloseHandle(process_);
    process_ = NULL;
  }

 private:
  void KillProcess() {
    scoped_ptr<base::EnvVarGetter> env(base::EnvVarGetter::Create());
    if (env->HasEnv(env_vars::kHeadless)) {
     // If running the distributed tests, give the renderer a little time
     // to figure out that the channel is shutdown and unwind.
     if (WaitForSingleObject(process_, kWaitInterval) == WAIT_OBJECT_0) {
       OnObjectSignaled(process_);
       return;
     }
    }

    // OK, time to get frisky.  We don't actually care when the process
    // terminates.  We just care that it eventually terminates, and that's what
    // TerminateProcess should do for us. Don't check for the result code since
    // it fails quite often. This should be investigated eventually.
    base::KillProcess(process_, ResultCodes::HUNG, false);

    // Now, just cleanup as if the process exited normally.
    OnObjectSignaled(process_);
  }

  // The process that we are watching.
  base::ProcessHandle process_;

  base::ObjectWatcher watcher_;

  DISALLOW_COPY_AND_ASSIGN(TimerExpiredTask);
};

}  // namespace

// static
void ProcessWatcher::EnsureProcessTerminated(base::ProcessHandle process) {
  DCHECK(process != GetCurrentProcess());

  // If already signaled, then we are done!
  if (WaitForSingleObject(process, 0) == WAIT_OBJECT_0) {
    CloseHandle(process);
    return;
  }

  MessageLoop::current()->PostDelayedTask(FROM_HERE,
                                          new TimerExpiredTask(process),
                                          kWaitInterval);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkOnce.h"
#include "SkOpts.h"
#include "SkXfermode_opts.h"

#if defined(SK_CPU_X86)
    #if defined(SK_BUILD_FOR_WIN32)
        #include <intrin.h>
        static void cpuid(uint32_t abcd[4]) { __cpuid((int*)abcd, 1); }
    #else
        #include <cpuid.h>
        static void cpuid(uint32_t abcd[4]) { __get_cpuid(1, abcd+0, abcd+1, abcd+2, abcd+3); }
    #endif
#elif !defined(SK_ARM_HAS_NEON) && defined(SK_CPU_ARM32) && defined(SK_BUILD_FOR_ANDROID)
    #include <cpu-features.h>
#endif

namespace portable {  // This helps identify methods from this file when debugging / profiling.

static float rsqrt(float x) {
    // Get initial estimate.
    int i = *SkTCast<int*>(&x);
    i = 0x5F1FFFF9 - (i>>1);
    float estimate = *SkTCast<float*>(&i);

    // One step of Newton's method to refine.
    const float estimate_sq = estimate*estimate;
    estimate *= 0.703952253f*(2.38924456f-x*estimate_sq);
    return estimate;
}

template <typename T>
static void memsetT(T dst[], T val, int n) { while (n --> 0) { *dst++ = val; } }

}  // namespace portable

namespace SkOpts {
    // Define default function pointer values here...
    decltype(rsqrt)                     rsqrt = portable::rsqrt;
    decltype(memset16)               memset16 = portable::memsetT<uint16_t>;
    decltype(memset32)               memset32 = portable::memsetT<uint32_t>;
    decltype(create_xfermode) create_xfermode = SkCreate4pxXfermode;

    // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
    void Init_sse2();
    void Init_ssse3();
    void Init_sse41();
    void Init_neon();
    //TODO: _dsp2, _armv7, _armv8, _x86, _x86_64, _sse42, _avx, avx2, ... ?

    static void init() {
    #if defined(SK_CPU_X86)
        uint32_t abcd[] = {0,0,0,0};
        cpuid(abcd);
        if (abcd[3] & (1<<26)) { Init_sse2(); }
        if (abcd[2] & (1<< 9)) { Init_ssse3(); }
        if (abcd[2] & (1<<19)) { Init_sse41(); }
    #elif defined(SK_ARM_HAS_NEON)
        Init_neon();
    #elif defined(SK_CPU_ARM32) && defined(SK_BUILD_FOR_ANDROID)
        if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) { Init_neon(); }
    #endif
    }

    SK_DECLARE_STATIC_ONCE(gInitOnce);
    void Init() { SkOnce(&gInitOnce, init); }

#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    static struct AutoInit {
        AutoInit() { Init(); }
    } gAutoInit;
#endif
}
<commit_msg>disable SkOpts on x86 iOS (simulator)<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkOnce.h"
#include "SkOpts.h"
#include "SkXfermode_opts.h"

#if defined(SK_CPU_X86)
    #if defined(SK_BUILD_FOR_WIN32)
        #include <intrin.h>
        static void cpuid(uint32_t abcd[4]) { __cpuid((int*)abcd, 1); }
    #else
        #include <cpuid.h>
        static void cpuid(uint32_t abcd[4]) { __get_cpuid(1, abcd+0, abcd+1, abcd+2, abcd+3); }
    #endif
#elif !defined(SK_ARM_HAS_NEON) && defined(SK_CPU_ARM32) && defined(SK_BUILD_FOR_ANDROID)
    #include <cpu-features.h>
#endif

namespace portable {  // This helps identify methods from this file when debugging / profiling.

static float rsqrt(float x) {
    // Get initial estimate.
    int i = *SkTCast<int*>(&x);
    i = 0x5F1FFFF9 - (i>>1);
    float estimate = *SkTCast<float*>(&i);

    // One step of Newton's method to refine.
    const float estimate_sq = estimate*estimate;
    estimate *= 0.703952253f*(2.38924456f-x*estimate_sq);
    return estimate;
}

template <typename T>
static void memsetT(T dst[], T val, int n) { while (n --> 0) { *dst++ = val; } }

}  // namespace portable

namespace SkOpts {
    // Define default function pointer values here...
    decltype(rsqrt)                     rsqrt = portable::rsqrt;
    decltype(memset16)               memset16 = portable::memsetT<uint16_t>;
    decltype(memset32)               memset32 = portable::memsetT<uint32_t>;
    decltype(create_xfermode) create_xfermode = SkCreate4pxXfermode;

    // Each Init_foo() is defined in src/opts/SkOpts_foo.cpp.
    void Init_sse2();
    void Init_ssse3();
    void Init_sse41();
    void Init_neon();
    //TODO: _dsp2, _armv7, _armv8, _x86, _x86_64, _sse42, _avx, avx2, ... ?

    static void init() {
        // TODO: Chrome's not linking _sse* opts on iOS simulator builds.  Bug or feature?
    #if defined(SK_CPU_X86) && !defined(SK_BUILD_FOR_IOS)
        uint32_t abcd[] = {0,0,0,0};
        cpuid(abcd);
        if (abcd[3] & (1<<26)) { Init_sse2(); }
        if (abcd[2] & (1<< 9)) { Init_ssse3(); }
        if (abcd[2] & (1<<19)) { Init_sse41(); }
    #elif defined(SK_ARM_HAS_NEON)
        Init_neon();
    #elif defined(SK_CPU_ARM32) && defined(SK_BUILD_FOR_ANDROID)
        if (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) { Init_neon(); }
    #endif
    }

    SK_DECLARE_STATIC_ONCE(gInitOnce);
    void Init() { SkOnce(&gInitOnce, init); }

#if SK_ALLOW_STATIC_GLOBAL_INITIALIZERS
    static struct AutoInit {
        AutoInit() { Init(); }
    } gAutoInit;
#endif
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "CoreContext.h"
#include "Autowired.h"
#include "CoreThread.h"
#include "GlobalCoreContext.h"
#include "OutstandingCountTracker.h"
#include "ThreadStatusMaintainer.h"
#include <boost/thread.hpp>
#include <algorithm>
#include <memory>

using namespace boost;

thread_specific_ptr<std::shared_ptr<CoreContext> > CoreContext::s_curContext;

CoreContext::CoreContext(std::shared_ptr<CoreContext> pParent):
  Autowirer(std::static_pointer_cast<Autowirer, CoreContext>(pParent)),
  m_shouldStop(true),
  m_refCount(0)
{
  ASSERT(pParent.get() != this);
}

CoreContext::~CoreContext(void) {
  // The s_curContext pointer holds a shared_ptr to this--if we're in a ctor, and our caller
  // still holds a reference to us, then we have a serious problem.
  ASSERT(
    !s_curContext.get() ||
    !s_curContext.get()->use_count() ||
    s_curContext.get()->get() != this
  );
}

std::shared_ptr<OutstandingCountTracker> CoreContext::IncrementOutstandingThreadCount(void) {
  std::shared_ptr<OutstandingCountTracker> retVal = m_outstanding.lock();
  if(!m_outstanding.expired())
    return retVal;

  boost::lock_guard<boost::mutex> lk(m_outstandingLock);
  retVal.reset(
    new OutstandingCountTracker(
      std::static_pointer_cast<CoreContext, Autowirer>(m_self.lock())
    )
  );
  m_outstanding = retVal;
  return retVal;
}

std::shared_ptr<CoreContext> CoreContext::Create(void) {
  // Create the context, first
  CoreContext* pContext =
    new CoreContext(
      std::static_pointer_cast<CoreContext, Autowirer>(m_self.lock())
    );

  // Create the shared pointer for the context--do not add the context to itself,
  // this creates a dangerous cyclic reference.
  std::shared_ptr<CoreContext> retVal(pContext);
  pContext->m_self = retVal;
  return retVal;
}

void CoreContext::InitiateCoreThreads(void) {
  // Self-reference to ensure the context is not destroyed until all threads are gone
  std::shared_ptr<CoreContext> self = std::static_pointer_cast<CoreContext, Autowirer>(m_self.lock());

  // Because the caller was able to invoke a method on this CoreContext, it must have
  // a shared_ptr to it.  Thus, we can assert that the above lock operation succeeded.
  ASSERT(self);

  {
    lock_guard<mutex> lk(m_coreLock);
    if(m_refCount++)
      // Already running
      return;
  }

  if(m_pParent)
    // Start parent threads first
    // Parent MUST be a core context
    std::static_pointer_cast<CoreContext, Autowirer>(m_pParent)->InitiateCoreThreads();

  // Set our stop flag before kicking off any threads:
  m_shouldStop = false;

  // Hold another lock to prevent m_threads from being modified while we sit on it
  lock_guard<mutex> lk(m_coreLock);
  for(t_threadList::iterator q = m_threads.begin(); q != m_threads.end(); q++)
    (*q)->Start();
}

void CoreContext::SignalShutdown(void) {
  {
    lock_guard<mutex> lk(m_coreLock);
    if(--m_refCount)
      // Someone else still depends on this
      return;

    // Global context is now "stop":
    m_shouldStop = true;
    m_stopping.notify_all();

    // Also pass notice to all children:
    for(t_threadList::iterator q = m_threads.begin(); q != m_threads.end(); q++)
      (*q)->Stop();
  }

  if(m_pParent)
    // Signal parent that it's time to shut down
    std::static_pointer_cast<CoreContext, Autowirer>(m_pParent)->SignalShutdown();
}

std::shared_ptr<CoreContext> CoreContext::CurrentContext(void) {
  if(!s_curContext.get())
    return std::static_pointer_cast<CoreContext, GlobalCoreContext>(GetGlobalContext());

  std::shared_ptr<CoreContext>* retVal = s_curContext.get();
  ASSERT(retVal);
  ASSERT(*retVal);
  return *retVal;
}

void CoreContext::AddCoreThread(CoreThread* ptr, bool allowNotReady) {
  // We don't allow the insertion of a thread that isn't ready unless the user really
  // wants that behavior.
  ASSERT(allowNotReady || ptr->IsReady());

  // Insert into the linked list of threads first:
  lock_guard<mutex> lk(m_coreLock);
  m_threads.push_front(ptr);

  if(!m_shouldStop)
    // We're already running, this means we're late to the game and need to start _now_.
    ptr->Start();
}

std::shared_ptr<CoreContext> GetCurrentContext() {
  return CoreContext::CurrentContext();
}
<commit_msg>Fixed another bug.  Signalling shutdown on a child context should NOT terminate its parent.<commit_after>#include "stdafx.h"
#include "CoreContext.h"
#include "Autowired.h"
#include "CoreThread.h"
#include "GlobalCoreContext.h"
#include "OutstandingCountTracker.h"
#include "ThreadStatusMaintainer.h"
#include <boost/thread.hpp>
#include <algorithm>
#include <memory>

using namespace boost;

thread_specific_ptr<std::shared_ptr<CoreContext> > CoreContext::s_curContext;

CoreContext::CoreContext(std::shared_ptr<CoreContext> pParent):
  Autowirer(std::static_pointer_cast<Autowirer, CoreContext>(pParent)),
  m_shouldStop(true),
  m_refCount(0)
{
  ASSERT(pParent.get() != this);
}

CoreContext::~CoreContext(void) {
  // The s_curContext pointer holds a shared_ptr to this--if we're in a ctor, and our caller
  // still holds a reference to us, then we have a serious problem.
  ASSERT(
    !s_curContext.get() ||
    !s_curContext.get()->use_count() ||
    s_curContext.get()->get() != this
  );
}

std::shared_ptr<OutstandingCountTracker> CoreContext::IncrementOutstandingThreadCount(void) {
  std::shared_ptr<OutstandingCountTracker> retVal = m_outstanding.lock();
  if(!m_outstanding.expired())
    return retVal;

  boost::lock_guard<boost::mutex> lk(m_outstandingLock);
  retVal.reset(
    new OutstandingCountTracker(
      std::static_pointer_cast<CoreContext, Autowirer>(m_self.lock())
    )
  );
  m_outstanding = retVal;
  return retVal;
}

std::shared_ptr<CoreContext> CoreContext::Create(void) {
  // Create the context, first
  CoreContext* pContext =
    new CoreContext(
      std::static_pointer_cast<CoreContext, Autowirer>(m_self.lock())
    );

  // Create the shared pointer for the context--do not add the context to itself,
  // this creates a dangerous cyclic reference.
  std::shared_ptr<CoreContext> retVal(pContext);
  pContext->m_self = retVal;
  return retVal;
}

void CoreContext::InitiateCoreThreads(void) {
  // Self-reference to ensure the context is not destroyed until all threads are gone
  std::shared_ptr<CoreContext> self = std::static_pointer_cast<CoreContext, Autowirer>(m_self.lock());

  // Because the caller was able to invoke a method on this CoreContext, it must have
  // a shared_ptr to it.  Thus, we can assert that the above lock operation succeeded.
  ASSERT(self);

  {
    lock_guard<mutex> lk(m_coreLock);
    if(m_refCount++)
      // Already running
      return;
  }

  if(m_pParent)
    // Start parent threads first
    // Parent MUST be a core context
    std::static_pointer_cast<CoreContext, Autowirer>(m_pParent)->InitiateCoreThreads();

  // Set our stop flag before kicking off any threads:
  m_shouldStop = false;

  // Hold another lock to prevent m_threads from being modified while we sit on it
  lock_guard<mutex> lk(m_coreLock);
  for(t_threadList::iterator q = m_threads.begin(); q != m_threads.end(); q++)
    (*q)->Start();
}

void CoreContext::SignalShutdown(void) {
  lock_guard<mutex> lk(m_coreLock);
  if(--m_refCount)
    // Someone else still depends on this
    return;

  // Global context is now "stop":
  m_shouldStop = true;
  m_stopping.notify_all();

  // Also pass notice to all children:
  for(t_threadList::iterator q = m_threads.begin(); q != m_threads.end(); q++)
    (*q)->Stop();
}

std::shared_ptr<CoreContext> CoreContext::CurrentContext(void) {
  if(!s_curContext.get())
    return std::static_pointer_cast<CoreContext, GlobalCoreContext>(GetGlobalContext());

  std::shared_ptr<CoreContext>* retVal = s_curContext.get();
  ASSERT(retVal);
  ASSERT(*retVal);
  return *retVal;
}

void CoreContext::AddCoreThread(CoreThread* ptr, bool allowNotReady) {
  // We don't allow the insertion of a thread that isn't ready unless the user really
  // wants that behavior.
  ASSERT(allowNotReady || ptr->IsReady());

  // Insert into the linked list of threads first:
  lock_guard<mutex> lk(m_coreLock);
  m_threads.push_front(ptr);

  if(!m_shouldStop)
    // We're already running, this means we're late to the game and need to start _now_.
    ptr->Start();
}

std::shared_ptr<CoreContext> GetCurrentContext() {
  return CoreContext::CurrentContext();
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "BindingHandler.h"

namespace CefSharp
{

    CefRefPtr<CefV8Value> BindingHandler::ConvertToCef(Type^ type, Object^ obj)
    {
        if(type == Void::typeid)
        {
            return CefV8Value::CreateUndefined();
        }
        if(obj == nullptr)
        {
            return CefV8Value::CreateNull();
        }

        if (type == Boolean::typeid)
        {
            return CefV8Value::CreateBool(safe_cast<bool>(obj));
        }
        if (type == Int16::typeid || type == Int32::typeid)
        {
            return CefV8Value::CreateInt(safe_cast<int>(obj));
        }
        if (type == Single::typeid || type == Double::typeid)
        {
            return CefV8Value::CreateDouble(safe_cast<double>(obj));
        }
        if (type == String::typeid)
        {
            CefString str = convertFromString(safe_cast<String^>(obj));
            return CefV8Value::CreateString(str);
        }

        //TODO: What exception type?
        throw gcnew Exception("Cannot convert object from CLR to Cef " + type->ToString() + ".");
    }

    Object^ BindingHandler::ConvertFromCef(CefRefPtr<CefV8Value> obj)
    {
        if (obj->IsNull() || obj->IsUndefined())
        {
            return nullptr;
        }
        if (obj->IsBool())
            return gcnew System::Boolean(obj->GetBoolValue());
        if (obj->IsInt())
            return gcnew System::Int32(obj->GetIntValue());
        if (obj->IsDouble())
            return gcnew System::Double(obj->GetDoubleValue());
        if (obj->IsString()){
            return convertToString(obj->GetStringValue());
        }

        //TODO: What exception type?
        throw gcnew Exception("Cannot convert object from Cef to CLR.");
    }

    bool BindingHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
    {
        CefRefPtr<BindingData> bindingData = reinterpret_cast<BindingData*>(object->GetUserData().get());
        Object^ self = bindingData->Get();
        if(self == nullptr)
        {
            exception = "Binding's CLR object is null.";
            return true;
        }

        String^ memberName = convertToString(name);
        Type^ type = self->GetType();
        array<System::Reflection::MemberInfo^>^ members = type->GetMember(memberName, MemberTypes::Method,
            /* BindingFlags::IgnoreCase |*/ BindingFlags::Instance | BindingFlags::Public);

        if(members->Length == 0)
        {
            exception = convertFromString("No member named " + memberName + ".");
            return true;
        }

        array<System::Object^>^ suppliedArguments = gcnew array<Object^>(arguments.size());
        try
        {
            for(int i = 0; i < suppliedArguments->Length; i++)
            {
                    suppliedArguments[i] = ConvertFromCef(arguments[i]);
            }
        }
        catch(System::Exception^ err)
        {
            exception = convertFromString(err->Message);
            return true;
        }

        MethodInfo^ bestMethod;
        array<Object^>^ bestMethodArguments;
        int bestMethodMatchedArgs = -1;

        for (int i = 0; i < members->Length; i++)
        {
            MethodInfo^ method = (MethodInfo^) members[i];
            array<ParameterInfo^>^ parametersInfo = method->GetParameters();
            array<Object^>^ arguments;

            if (suppliedArguments->Length == parametersInfo->Length)
            {
                int match = 0;
                int failed = 0;

                arguments = gcnew array<Object^>(suppliedArguments->Length);
                for (int p = 0; p < suppliedArguments->Length; p++)
                {
                    System::Type^ paramType = parametersInfo[p]->ParameterType;

                    if (suppliedArguments[p] != nullptr)
                    {
                        System::Type^ suppliedType = suppliedArguments[p]->GetType();

                        if (suppliedType == paramType)
                        {
                            arguments[p] = suppliedArguments[p];
                            match++;
                        }
                        else
                        {
                            // TODO
                            //arguments[p] = ConvertToType(suppliedArguments[p], paramType);
                            //if (arguments[p] == nullptr)
                            //{
                            failed++;
                            break;
                            //}
                        }
                    }
                }

                if (failed > 0)
                {
                    continue;
                }

                if (match > bestMethodMatchedArgs)
                {
                    bestMethod = method;
                    bestMethodArguments = arguments;
                    bestMethodMatchedArgs = match;
                }

                if (match == arguments->Length)
                    break;
            }
        }

        if (bestMethod != nullptr)
        {
            try
            {
                Object^ result = bestMethod->Invoke(self, bestMethodArguments);
                retval = ConvertToCef(bestMethod->ReturnType, result);
                return true;
            }
            catch(System::Reflection::TargetInvocationException^ err)
            {
                exception = convertFromString(err->InnerException->Message);
            }
            catch(System::Exception^ err)
            {
                exception = convertFromString(err->Message);
            }
        }
        else
        {
            exception = convertFromString("Argument mismatch for method \"" + memberName + "\".");
        }
        return true;
    }

    void BindingHandler::Bind(String^ name, Object^ obj, CefRefPtr<CefV8Value> window)
    {
        CefRefPtr<BindingData> bindingData = new BindingData(obj);
        CefRefPtr<CefBase> userData = static_cast<CefRefPtr<CefBase>>(bindingData);
        CefRefPtr<CefV8Value> wrappedObject = window->CreateObject(userData);
        CefRefPtr<CefV8Handler> handler = static_cast<CefV8Handler*>(new BindingHandler());

        array<MethodInfo^>^ methods = obj->GetType()->GetMethods(BindingFlags::Instance | BindingFlags::Public);

        IList<String^>^ methodNames = gcnew List<String^>();
        for each(MethodInfo^ method in methods)
        {
            if(!methodNames->Contains(method->Name))
            {
                methodNames->Add(method->Name);
            }
        }

        for each(String^ methodName in methodNames)
        {
            CefString nameStr = convertFromString(methodName);
            wrappedObject->SetValue(nameStr, CefV8Value::CreateFunction(nameStr, handler));
        }

        window->SetValue(convertFromString(name), wrappedObject);
    }

}<commit_msg>Added some type handling in CLR object binding.<commit_after>#include "stdafx.h"
#include "BindingHandler.h"

namespace CefSharp
{

    CefRefPtr<CefV8Value> BindingHandler::ConvertToCef(Type^ type, Object^ obj)
    {
        if(type == Void::typeid)
        {
            return CefV8Value::CreateUndefined();
        }
        if(obj == nullptr)
        {
            return CefV8Value::CreateNull();
        }

        Type^ underlyingType = Nullable::GetUnderlyingType(type);
        if(underlyingType!=nullptr)type = underlyingType;

        if (type == Boolean::typeid)
        {
            return CefV8Value::CreateBool(safe_cast<bool>(obj));
        }
        if (type == Int32::typeid)
        {
            return CefV8Value::CreateInt(safe_cast<int>(obj));
        }
        if (type == String::typeid)
        {
            CefString str = convertFromString(safe_cast<String^>(obj));
            return CefV8Value::CreateString(str);
        }
        if (type == Double::typeid)
        {
            return CefV8Value::CreateDouble(safe_cast<double>(obj));
        }
        if (type == Decimal::typeid)
        {
            return CefV8Value::CreateDouble( Convert::ToDouble(obj) );
        }
        if (type == SByte::typeid)
        {
            return CefV8Value::CreateInt( Convert::ToInt32(obj) );
        }
        if (type == Int16::typeid)
        {
            return CefV8Value::CreateInt( Convert::ToInt32(obj) );
        }
        if (type == Int64::typeid)
        {
            return CefV8Value::CreateDouble( Convert::ToDouble(obj) );
        }
        if (type == Byte::typeid)
        {
            return CefV8Value::CreateInt( Convert::ToInt32(obj) );
        }
        if (type == UInt16::typeid)
        {
            return CefV8Value::CreateInt( Convert::ToInt32(obj) );
        }
        if (type == UInt32::typeid)
        {
            return CefV8Value::CreateDouble( Convert::ToDouble(obj) );
        }
        if (type == UInt64::typeid)
        {
            return CefV8Value::CreateDouble( Convert::ToDouble(obj) );
        }
        if (type == Single::typeid)
        {
            return CefV8Value::CreateDouble( Convert::ToDouble(obj) );
        }
        if (type == Char::typeid)
        {
            return CefV8Value::CreateInt( Convert::ToInt32(obj) );
        }

        //TODO: What exception type?
        throw gcnew Exception("Cannot convert object from CLR to Cef " + type->ToString() + ".");
    }

    Object^ BindingHandler::ConvertFromCef(CefRefPtr<CefV8Value> obj)
    {
        if (obj->IsNull() || obj->IsUndefined())
        {
            return nullptr;
        }
        if (obj->IsBool())
            return gcnew System::Boolean(obj->GetBoolValue());
        if (obj->IsInt())
            return gcnew System::Int32(obj->GetIntValue());
        if (obj->IsDouble())
            return gcnew System::Double(obj->GetDoubleValue());
        if (obj->IsString()){
            return convertToString(obj->GetStringValue());
        }

        //TODO: What exception type?
        throw gcnew Exception("Cannot convert object from Cef to CLR.");
    }

    bool BindingHandler::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
    {
        CefRefPtr<BindingData> bindingData = reinterpret_cast<BindingData*>(object->GetUserData().get());
        Object^ self = bindingData->Get();
        if(self == nullptr)
        {
            exception = "Binding's CLR object is null.";
            return true;
        }

        String^ memberName = convertToString(name);
        Type^ type = self->GetType();
        array<System::Reflection::MemberInfo^>^ members = type->GetMember(memberName, MemberTypes::Method,
            /* BindingFlags::IgnoreCase |*/ BindingFlags::Instance | BindingFlags::Public);

        if(members->Length == 0)
        {
            exception = convertFromString("No member named " + memberName + ".");
            return true;
        }

        //TODO: cache for type info here

        array<System::Object^>^ suppliedArguments = gcnew array<Object^>(arguments.size());
        try
        {
            for(int i = 0; i < suppliedArguments->Length; i++)
            {
                    suppliedArguments[i] = ConvertFromCef(arguments[i]);
            }
        }
        catch(System::Exception^ err)
        {
            exception = convertFromString(err->Message);
            return true;
        }

        // choose best method
        MethodInfo^ bestMethod;
        array<Object^>^ bestMethodArguments;
        int bestMethodMatchedArgs = -1;

        for (int i = 0; i < members->Length; i++)
        {
            MethodInfo^ method = (MethodInfo^) members[i];
            array<ParameterInfo^>^ parametersInfo = method->GetParameters();
            array<Object^>^ arguments;

            if (suppliedArguments->Length == parametersInfo->Length)
            {
                int match = 0;
                int failed = 0;

                arguments = gcnew array<Object^>(suppliedArguments->Length);
                for (int p = 0; p < suppliedArguments->Length; p++)
                {
                    System::Type^ paramType = parametersInfo[p]->ParameterType;

                    if (suppliedArguments[p] != nullptr)
                    {
                        System::Type^ suppliedType = suppliedArguments[p]->GetType();

                        if (paramType == suppliedType)
                        {
                            arguments[p] = suppliedArguments[p];
                            match++;
                        }
                        else
                        {
                            try
                            {
                                Type^ underlyingParamType = Nullable::GetUnderlyingType(paramType);
                                arguments[p] = Convert::ChangeType(suppliedArguments[p], underlyingParamType!=nullptr?underlyingParamType : paramType);
                            }
                            catch (System::Exception^)
                            {
                                failed++;
                                break;
                            }
                            match++;

                            // TODO
                            //arguments[p] = ConvertToType(suppliedArguments[p], paramType);
                            //if (arguments[p] == nullptr)
                            //{
                            // failed++;
                            // break;
                            //}
                        }
                    } else if(paramType->IsValueType == false || Nullable::GetUnderlyingType(paramType) != nullptr) {
                        arguments[p] = suppliedArguments[p];
                        match++;
                    } else {
                        failed++;
                        break;
                    }
                }

                if (failed > 0)
                {
                    continue;
                }

                if (match > bestMethodMatchedArgs)
                {
                    bestMethod = method;
                    bestMethodArguments = arguments;
                    bestMethodMatchedArgs = match;
                }

                if (match == arguments->Length)
                    break;
            }
        }

        if (bestMethod != nullptr)
        {
            try
            {
                Object^ result = bestMethod->Invoke(self, bestMethodArguments);
                retval = ConvertToCef(bestMethod->ReturnType, result);
                return true;
            }
            catch(System::Reflection::TargetInvocationException^ err)
            {
                exception = convertFromString(err->InnerException->Message);
            }
            catch(System::Exception^ err)
            {
                exception = convertFromString(err->Message);
            }
        }
        else
        {
            exception = convertFromString("Argument mismatch for method \"" + memberName + "\".");
        }
        return true;
    }

    void BindingHandler::Bind(String^ name, Object^ obj, CefRefPtr<CefV8Value> window)
    {
        CefRefPtr<BindingData> bindingData = new BindingData(obj);
        CefRefPtr<CefBase> userData = static_cast<CefRefPtr<CefBase>>(bindingData);
        CefRefPtr<CefV8Value> wrappedObject = window->CreateObject(userData);
        CefRefPtr<CefV8Handler> handler = static_cast<CefV8Handler*>(new BindingHandler());

        array<MethodInfo^>^ methods = obj->GetType()->GetMethods(BindingFlags::Instance | BindingFlags::Public);

        IList<String^>^ methodNames = gcnew List<String^>();
        for each(MethodInfo^ method in methods)
        {
            if(!methodNames->Contains(method->Name))
            {
                methodNames->Add(method->Name);
            }
        }

        for each(String^ methodName in methodNames)
        {
            CefString nameStr = convertFromString(methodName);
            wrappedObject->SetValue(nameStr, CefV8Value::CreateFunction(nameStr, handler));
        }

        window->SetValue(convertFromString(name), wrappedObject);
    }

}<|endoftext|>


<commit_before>#ifndef ALPHA_SCREENGLWIDGET_HEADER
#define ALPHA_SCREENGLWIDGET_HEADER

#include <QGLWidget>
#include "../Box2.hpp"
#include "Screen.hpp"

namespace nt {
namespace gl {

/**
 * A Qt-specific wrapper of a Screen.
 *
 * ScreenGLWidget takes care of the Qt-specific setup and behavior
 * necessary to render an OpenGL scene. As such, it is a relatively
 * light class. Most of the heavyweight behavior is contained within
 * the screen and the render layers themselves.
 *
 * @see Screen
 * @see RenderLayer
 */
class ScreenGLWidget : public QGLWidget
{
    Q_OBJECT

    const Screen* _screen;
    Box2<int> _screenArea;

protected:
    void paintGL();
    void initializeGL();
    void resizeGL(int width, int height);

public:
    ScreenGLWidget(QWidget* const parent = 0) :
        QGLWidget(parent),
        _screen(nullptr)
    {
    }

    void setScreen(const Screen* const screen);
    const Screen* getScreen() const;
};

} // namespace gl
} // namespace nt

#endif // ALPHA_SCREENGLWIDGET_HEADER
<commit_msg>Allow QGLFormat to be passed to ScreenGLWidget<commit_after>#ifndef ALPHA_SCREENGLWIDGET_HEADER
#define ALPHA_SCREENGLWIDGET_HEADER

#include <QGLWidget>
#include "../Box2.hpp"
#include "Screen.hpp"

namespace nt {
namespace gl {

/**
 * A Qt-specific wrapper of a Screen.
 *
 * ScreenGLWidget takes care of the Qt-specific setup and behavior
 * necessary to render an OpenGL scene. As such, it is a relatively
 * light class. Most of the heavyweight behavior is contained within
 * the screen and the render layers themselves.
 *
 * @see Screen
 * @see RenderLayer
 */
class ScreenGLWidget : public QGLWidget
{
    Q_OBJECT

    const Screen* _screen;
    Box2<int> _screenArea;

protected:
    void paintGL();
    void initializeGL();
    void resizeGL(int width, int height);

public:
    ScreenGLWidget(const QGLFormat& format, QWidget* const parent = 0) :
        QGLWidget(format, parent),
        _screen(nullptr)
    {
    }

    ScreenGLWidget(QWidget* const parent = 0) :
        QGLWidget(parent),
        _screen(nullptr)
    {
    }

    void setScreen(const Screen* const screen);
    const Screen* getScreen() const;
};

} // namespace gl
} // namespace nt

#endif // ALPHA_SCREENGLWIDGET_HEADER
<|endoftext|>


<commit_before>// Copyright 2013-2015 Stanford University
//
// 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.

#include <array>

#include "src/cost/latency.h"
#include "src/ext/x64asm/include/x64asm.h"

using namespace std;

namespace {

array<stoke::Cost, X64ASM_NUM_OPCODES> latencies_ {{
#include "src/cost/tables/haswell_latency.h"
  }
};

} // namespace

namespace stoke {

LatencyCost::result_type LatencyCost::operator()(const Cfg& cfg, Cost max) {
  Cost latency = 0;

  const auto& code = cfg.get_code();
  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {
    if (cfg.is_exit(*b)) {
      continue;
    }

    Cost block_latency = 0;
    const auto first = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = first, ie = first + cfg.num_instrs(*b); i < ie; ++i) {
      // Record latency for non nop instructions
      if (!code[i].is_nop()) {
        block_latency += latencies_[code[i].get_opcode()];
      }
    }

    // Increment latency by block latency scaled by nesting penalty
    // The call to pow() is expensive, so we hide it behind a faster check
    const auto nd = cfg.nesting_depth(*b);
    if (nd > 1) {
      latency += block_latency * pow(nesting_penalty_, cfg.nesting_depth(*b));
    } else {
      latency += block_latency;
    }

    if(latency >= max) {
      return result_type(true, max);
    }
  }

  return result_type(true, latency);
}

} //namespace stoke

<commit_msg>fixes nesting depth bug<commit_after>// Copyright 2013-2015 Stanford University
//
// 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.

#include <array>

#include "src/cost/latency.h"
#include "src/ext/x64asm/include/x64asm.h"

using namespace std;

namespace {

array<stoke::Cost, X64ASM_NUM_OPCODES> latencies_ {{
#include "src/cost/tables/haswell_latency.h"
  }
};

} // namespace

namespace stoke {

LatencyCost::result_type LatencyCost::operator()(const Cfg& cfg, Cost max) {
  Cost latency = 0;

  const auto& code = cfg.get_code();
  for (auto b = ++cfg.reachable_begin(), be = cfg.reachable_end(); b != be; ++b) {
    if (cfg.is_exit(*b)) {
      continue;
    }

    Cost block_latency = 0;
    const auto first = cfg.get_index(Cfg::loc_type(*b, 0));
    for (size_t i = first, ie = first + cfg.num_instrs(*b); i < ie; ++i) {
      // Record latency for non nop instructions
      if (!code[i].is_nop()) {
        block_latency += latencies_[code[i].get_opcode()];
      }
    }

    // Increment latency by block latency scaled by nesting penalty
    // The call to pow() is expensive, so we hide it behind a faster check
    const auto nd = cfg.nesting_depth(*b);
    if (nd >= 1) {
      latency += block_latency * pow(nesting_penalty_, cfg.nesting_depth(*b));
    } else {
      latency += block_latency;
    }

    if(latency >= max) {
      return result_type(true, max);
    }
  }

  return result_type(true, latency);
}

} //namespace stoke

<|endoftext|>


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

#ifndef __ARCH_ARM_REGISTERS_HH__
#define __ARCH_ARM_REGISTERS_HH__

#include "arch/arm/max_inst_regs.hh"
#include "arch/arm/intregs.hh"
#include "arch/arm/miscregs.hh"

namespace ArmISA {

using ArmISAInst::MaxInstSrcRegs;
using ArmISAInst::MaxInstDestRegs;

typedef uint16_t  RegIndex;

typedef uint64_t IntReg;

// floating point register file entry type
typedef uint32_t FloatRegBits;
typedef float FloatReg;

// cop-0/cop-1 system control register
typedef uint64_t MiscReg;

// Constants Related to the number of registers
const int NumIntArchRegs = NUM_ARCH_INTREGS;
// The number of single precision floating point registers
const int NumFloatArchRegs = 64;
const int NumFloatSpecialRegs = 8;

const int NumIntRegs = NUM_INTREGS;
const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs;

const int NumMiscRegs = NUM_MISCREGS;

// semantically meaningful register indices
const int ReturnValueReg = 0;
const int ReturnValueReg1 = 1;
const int ReturnValueReg2 = 2;
const int ArgumentReg0 = 0;
const int ArgumentReg1 = 1;
const int ArgumentReg2 = 2;
const int ArgumentReg3 = 3;
const int FramePointerReg = 11;
const int StackPointerReg = INTREG_SP;
const int ReturnAddressReg = INTREG_LR;
const int PCReg = INTREG_PC;

const int ZeroReg = INTREG_ZERO;

const int SyscallNumReg = ReturnValueReg;
const int SyscallPseudoReturnReg = ReturnValueReg;
const int SyscallSuccessReg = ReturnValueReg;

// These help enumerate all the registers for dependence tracking.
const int FP_Base_DepTag = NumIntRegs * (MODE_MAXMODE + 1);
const int Ctrl_Base_DepTag = FP_Base_DepTag + NumFloatRegs;

typedef union {
    IntReg   intreg;
    FloatReg fpreg;
    MiscReg  ctrlreg;
} AnyReg;

enum FPControlRegNums {
   FIR = NumFloatArchRegs,
   FCCR,
   FEXR,
   FENR,
   FCSR
};

enum FCSRBits {
    Inexact = 1,
    Underflow,
    Overflow,
    DivideByZero,
    Invalid,
    Unimplemented
};

enum FCSRFields {
    Flag_Field = 1,
    Enable_Field = 6,
    Cause_Field = 11
};

} // namespace ArmISA

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

#ifndef __ARCH_ARM_REGISTERS_HH__
#define __ARCH_ARM_REGISTERS_HH__

#include "arch/arm/max_inst_regs.hh"
#include "arch/arm/intregs.hh"
#include "arch/arm/miscregs.hh"

namespace ArmISA {

using ArmISAInst::MaxInstSrcRegs;
using ArmISAInst::MaxInstDestRegs;

typedef uint16_t  RegIndex;

typedef uint64_t IntReg;

// floating point register file entry type
typedef uint32_t FloatRegBits;
typedef float FloatReg;

// cop-0/cop-1 system control register
typedef uint64_t MiscReg;

// Constants Related to the number of registers
const int NumIntArchRegs = NUM_ARCH_INTREGS;
// The number of single precision floating point registers
const int NumFloatArchRegs = 64;
const int NumFloatSpecialRegs = 8;

const int NumIntRegs = NUM_INTREGS;
const int NumFloatRegs = NumFloatArchRegs + NumFloatSpecialRegs;

const int NumMiscRegs = NUM_MISCREGS;

// semantically meaningful register indices
const int ReturnValueReg = 0;
const int ReturnValueReg1 = 1;
const int ReturnValueReg2 = 2;
const int ArgumentReg0 = 0;
const int ArgumentReg1 = 1;
const int ArgumentReg2 = 2;
const int ArgumentReg3 = 3;
const int FramePointerReg = 11;
const int StackPointerReg = INTREG_SP;
const int ReturnAddressReg = INTREG_LR;
const int PCReg = INTREG_PC;

const int ZeroReg = INTREG_ZERO;

const int SyscallNumReg = ReturnValueReg;
const int SyscallPseudoReturnReg = ReturnValueReg;
const int SyscallSuccessReg = ReturnValueReg;

// These help enumerate all the registers for dependence tracking.
const int FP_Base_DepTag = NumIntRegs * (MODE_MAXMODE + 1);
const int Ctrl_Base_DepTag = FP_Base_DepTag + NumFloatRegs;

typedef union {
    IntReg   intreg;
    FloatReg fpreg;
    MiscReg  ctrlreg;
} AnyReg;

} // namespace ArmISA

#endif
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3 -*-

Copyright 2010, 2011, 2012, 2013
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

ABC is free software: you can redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

ABC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License along with ABC. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef ABC_NUMERIC_HXX
#define ABC_NUMERIC_HXX

#ifdef ABC_CXX_PRAGMA_ONCE
	#pragma once
#endif

#include <abc/core.hxx>
#include <type_traits>

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::numeric globals

namespace abc {

namespace numeric {

/** Returns true if the argument is negative. It avoids annoying compiler warnings if the argument
will never be negative (i.e. T is unsigned).

TODO: comment signature.
*/
template <typename T>
static /*constexpr*/ bool is_negative(
	typename std::enable_if<std::is_signed<T>::value, T>::type t
) {
	return t < T(0);
}
template <typename T>
static /*constexpr*/ bool is_negative(
	typename std::enable_if<!std::is_signed<T>::value, T>::type t
) {
	UNUSED_ARG(t);
	return false;
}

} //namespace numeric

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::numeric::min and abc::numeric::max

namespace abc {

namespace numeric {

/** Defines the minimum value for a numeric type. */
template <typename T>
struct min;

/** Defines the maximum value for a numeric type. */
template <typename T>
struct max;

// Specialization of min and max for UTF character types (note: wchar_t is not among these).
template <>
struct min<    char> : public std::integral_constant<    char, CHAR_MIN> {};
template <>
struct max<    char> : public std::integral_constant<    char, CHAR_MAX> {};
#ifdef ABC_CXX_CHAR16
template <>
struct min<char16_t> : public std::integral_constant<char16_t,        0> {};
template <>
struct max<char16_t> : public std::integral_constant<char16_t,
#ifdef UINT_LEAST16_MAX
		UINT_LEAST16_MAX
#else
		0xffff
#endif
	> {};
#endif //ifdef ABC_CXX_CHAR16
#ifdef ABC_CXX_CHAR32
template <>
struct min<char32_t> : public std::integral_constant<char32_t,        0> {};
template <>
struct max<char32_t> : public std::integral_constant<char32_t,
#ifdef UINT_LEAST32_MAX
		UINT_LEAST32_MAX
#else
		0xffffffff
#endif
	> {};
#endif //ifdef ABC_CXX_CHAR32

// Specialization of min and max for integer types.
template <>
struct min<  signed      char> : public std::integral_constant<  signed      char,  SCHAR_MIN> {};
template <>
struct max<  signed      char> : public std::integral_constant<  signed      char,  SCHAR_MAX> {};
template <>
struct min<unsigned      char> : public std::integral_constant<unsigned      char,          0> {};
template <>
struct max<unsigned      char> : public std::integral_constant<unsigned      char,  UCHAR_MAX> {};
template <>
struct min<             short> : public std::integral_constant<             short,   SHRT_MIN> {};
template <>
struct max<             short> : public std::integral_constant<             short,   SHRT_MAX> {};
template <>
struct min<unsigned     short> : public std::integral_constant<unsigned     short,          0> {};
template <>
struct max<unsigned     short> : public std::integral_constant<unsigned     short,  USHRT_MAX> {};
template <>
struct min<               int> : public std::integral_constant<               int,    INT_MIN> {};
template <>
struct max<               int> : public std::integral_constant<               int,    INT_MAX> {};
template <>
struct min<unsigned          > : public std::integral_constant<unsigned          ,          0> {};
template <>
struct max<unsigned          > : public std::integral_constant<unsigned          ,   UINT_MAX> {};
template <>
struct min<              long> : public std::integral_constant<              long,   LONG_MIN> {};
template <>
struct max<              long> : public std::integral_constant<              long,   LONG_MAX> {};
template <>
struct min<unsigned      long> : public std::integral_constant<unsigned      long,          0> {};
template <>
struct max<unsigned      long> : public std::integral_constant<unsigned      long,  ULONG_MAX> {};
template <>
struct min<         long long> : public std::integral_constant<         long long,  LLONG_MIN> {};
template <>
struct max<         long long> : public std::integral_constant<         long long,  LLONG_MAX> {};
template <>
struct min<unsigned long long> : public std::integral_constant<unsigned long long,          0> {};
template <>
struct max<unsigned long long> : public std::integral_constant<unsigned long long, ULLONG_MAX> {};

} //namespace numeric

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef ABC_NUMERIC_HXX

<commit_msg>Change from static to inline<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3 -*-

Copyright 2010, 2011, 2012, 2013
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

ABC is free software: you can redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

ABC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License along with ABC. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef ABC_NUMERIC_HXX
#define ABC_NUMERIC_HXX

#ifdef ABC_CXX_PRAGMA_ONCE
	#pragma once
#endif

#include <abc/core.hxx>
#include <type_traits>

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::numeric globals

namespace abc {

namespace numeric {

/** Returns true if the argument is negative. It avoids annoying compiler warnings if the argument
will never be negative (i.e. T is unsigned).

TODO: comment signature.
*/
template <typename T>
inline /*constexpr*/ bool is_negative(
	typename std::enable_if<std::is_signed<T>::value, T>::type t
) {
	return t < T(0);
}
template <typename T>
inline /*constexpr*/ bool is_negative(
	typename std::enable_if<!std::is_signed<T>::value, T>::type t
) {
	UNUSED_ARG(t);
	return false;
}

} //namespace numeric

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::numeric::min and abc::numeric::max

namespace abc {

namespace numeric {

/** Defines the minimum value for a numeric type. */
template <typename T>
struct min;

/** Defines the maximum value for a numeric type. */
template <typename T>
struct max;

// Specialization of min and max for UTF character types (note: wchar_t is not among these).
template <>
struct min<    char> : public std::integral_constant<    char, CHAR_MIN> {};
template <>
struct max<    char> : public std::integral_constant<    char, CHAR_MAX> {};
#ifdef ABC_CXX_CHAR16
template <>
struct min<char16_t> : public std::integral_constant<char16_t,        0> {};
template <>
struct max<char16_t> : public std::integral_constant<char16_t,
#ifdef UINT_LEAST16_MAX
		UINT_LEAST16_MAX
#else
		0xffff
#endif
	> {};
#endif //ifdef ABC_CXX_CHAR16
#ifdef ABC_CXX_CHAR32
template <>
struct min<char32_t> : public std::integral_constant<char32_t,        0> {};
template <>
struct max<char32_t> : public std::integral_constant<char32_t,
#ifdef UINT_LEAST32_MAX
		UINT_LEAST32_MAX
#else
		0xffffffff
#endif
	> {};
#endif //ifdef ABC_CXX_CHAR32

// Specialization of min and max for integer types.
template <>
struct min<  signed      char> : public std::integral_constant<  signed      char,  SCHAR_MIN> {};
template <>
struct max<  signed      char> : public std::integral_constant<  signed      char,  SCHAR_MAX> {};
template <>
struct min<unsigned      char> : public std::integral_constant<unsigned      char,          0> {};
template <>
struct max<unsigned      char> : public std::integral_constant<unsigned      char,  UCHAR_MAX> {};
template <>
struct min<             short> : public std::integral_constant<             short,   SHRT_MIN> {};
template <>
struct max<             short> : public std::integral_constant<             short,   SHRT_MAX> {};
template <>
struct min<unsigned     short> : public std::integral_constant<unsigned     short,          0> {};
template <>
struct max<unsigned     short> : public std::integral_constant<unsigned     short,  USHRT_MAX> {};
template <>
struct min<               int> : public std::integral_constant<               int,    INT_MIN> {};
template <>
struct max<               int> : public std::integral_constant<               int,    INT_MAX> {};
template <>
struct min<unsigned          > : public std::integral_constant<unsigned          ,          0> {};
template <>
struct max<unsigned          > : public std::integral_constant<unsigned          ,   UINT_MAX> {};
template <>
struct min<              long> : public std::integral_constant<              long,   LONG_MIN> {};
template <>
struct max<              long> : public std::integral_constant<              long,   LONG_MAX> {};
template <>
struct min<unsigned      long> : public std::integral_constant<unsigned      long,          0> {};
template <>
struct max<unsigned      long> : public std::integral_constant<unsigned      long,  ULONG_MAX> {};
template <>
struct min<         long long> : public std::integral_constant<         long long,  LLONG_MIN> {};
template <>
struct max<         long long> : public std::integral_constant<         long long,  LLONG_MAX> {};
template <>
struct min<unsigned long long> : public std::integral_constant<unsigned long long,          0> {};
template <>
struct max<unsigned long long> : public std::integral_constant<unsigned long long, ULLONG_MAX> {};

} //namespace numeric

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifndef ABC_NUMERIC_HXX

<|endoftext|>


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

#include <iomanip>

#include "arch/isa_traits.hh"
#include "arch/utility.hh"
#include "base/loader/symtab.hh"
#include "config/the_isa.hh"
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "debug/ExecAll.hh"
#include "enums/OpClass.hh"

using namespace std;
using namespace TheISA;

namespace Trace {

void
ExeTracerRecord::dumpTicks(ostream &outs)
{
    ccprintf(outs, "%7d: ", when);
}

void
Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran)
{
    ostream &outs = Trace::output();

    if (!Debug::ExecUser || !Debug::ExecKernel) {
        bool in_user_mode = TheISA::inUserMode(thread);
        if (in_user_mode && !Debug::ExecUser) return;
        if (!in_user_mode && !Debug::ExecKernel) return;
    }

    if (Debug::ExecTicks)
        dumpTicks(outs);

    outs << thread->getCpuPtr()->name() << " ";

    if (Debug::ExecSpeculative)
        outs << (misspeculating ? "-" : "+") << " ";

    if (Debug::ExecAsid)
        outs << "A" << dec << TheISA::getExecutingAsid(thread) << " ";

    if (Debug::ExecThread)
        outs << "T" << thread->threadId() << " : ";

    std::string sym_str;
    Addr sym_addr;
    Addr cur_pc = pc.instAddr();
    if (debugSymbolTable && Debug::ExecSymbol && !inUserMode(thread)
        && debugSymbolTable->findNearestSymbol(cur_pc, sym_str, sym_addr)) {
        if (cur_pc != sym_addr)
            sym_str += csprintf("+%d",cur_pc - sym_addr);
        outs << "@" << sym_str;
    } else {
        outs << "0x" << hex << cur_pc;
    }

    if (inst->isMicroop()) {
        outs << "." << setw(2) << dec << pc.microPC();
    } else {
        outs << "   ";
    }

    outs << " : ";

    //
    //  Print decoded instruction
    //

    outs << setw(26) << left;
    outs << inst->disassemble(cur_pc, debugSymbolTable);

    if (ran) {
        outs << " : ";

        if (Debug::ExecOpClass) {
            outs << Enums::OpClassStrings[inst->opClass()] << " : ";
        }

        if (Debug::ExecResult && predicate == false) {
            outs << "Predicated False";
        }

        if (Debug::ExecResult && data_status != DataInvalid) {
            ccprintf(outs, " D=%#018x", data.as_int);
        }

        if (Debug::ExecEffAddr && addr_valid)
            outs << " A=0x" << hex << addr;

        if (Debug::ExecFetchSeq && fetch_seq_valid)
            outs << "  FetchSeq=" << dec << fetch_seq;

        if (Debug::ExecCPSeq && cp_seq_valid)
            outs << "  CPSeq=" << dec << cp_seq;
    }

    //
    //  End of line...
    //
    outs << endl;
}

void
Trace::ExeTracerRecord::dump()
{
    /*
     * The behavior this check tries to achieve is that if ExecMacro is on,
     * the macroop will be printed. If it's on and microops are also on, it's
     * printed before the microops start printing to give context. If the
     * microops aren't printed, then it's printed only when the final microop
     * finishes. Macroops then behave like regular instructions and don't
     * complete/print when they fault.
     */
    if (Debug::ExecMacro && staticInst->isMicroop() &&
        ((Debug::ExecMicro &&
            macroStaticInst && staticInst->isFirstMicroop()) ||
            (!Debug::ExecMicro &&
             macroStaticInst && staticInst->isLastMicroop()))) {
        traceInst(macroStaticInst, false);
    }
    if (Debug::ExecMicro || !staticInst->isMicroop()) {
        traceInst(staticInst, true);
    }
}

} // namespace Trace

////////////////////////////////////////////////////////////////////////
//
//  ExeTracer Simulation Object
//
Trace::ExeTracer *
ExeTracerParams::create()
{
    return new Trace::ExeTracer(this);
}
<commit_msg>debug : Fixes the issue wherein Debug symbols were not getting dumped into trace files for SE mode<commit_after>/*
 * Copyright (c) 2001-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 *          Lisa Hsu
 *          Nathan Binkert
 *          Steve Raasch
 */

#include <iomanip>

#include "arch/isa_traits.hh"
#include "arch/utility.hh"
#include "base/loader/symtab.hh"
#include "config/the_isa.hh"
#include "cpu/base.hh"
#include "cpu/exetrace.hh"
#include "cpu/static_inst.hh"
#include "cpu/thread_context.hh"
#include "debug/ExecAll.hh"
#include "enums/OpClass.hh"

using namespace std;
using namespace TheISA;

namespace Trace {

void
ExeTracerRecord::dumpTicks(ostream &outs)
{
    ccprintf(outs, "%7d: ", when);
}

void
Trace::ExeTracerRecord::traceInst(StaticInstPtr inst, bool ran)
{
    ostream &outs = Trace::output();

    if (!Debug::ExecUser || !Debug::ExecKernel) {
        bool in_user_mode = TheISA::inUserMode(thread);
        if (in_user_mode && !Debug::ExecUser) return;
        if (!in_user_mode && !Debug::ExecKernel) return;
    }

    if (Debug::ExecTicks)
        dumpTicks(outs);

    outs << thread->getCpuPtr()->name() << " ";

    if (Debug::ExecSpeculative)
        outs << (misspeculating ? "-" : "+") << " ";

    if (Debug::ExecAsid)
        outs << "A" << dec << TheISA::getExecutingAsid(thread) << " ";

    if (Debug::ExecThread)
        outs << "T" << thread->threadId() << " : ";

    std::string sym_str;
    Addr sym_addr;
    Addr cur_pc = pc.instAddr();
    if (debugSymbolTable && Debug::ExecSymbol &&
            (!FullSystem || !inUserMode(thread)) &&
            debugSymbolTable->findNearestSymbol(cur_pc, sym_str, sym_addr)) {
        if (cur_pc != sym_addr)
            sym_str += csprintf("+%d",cur_pc - sym_addr);
        outs << "@" << sym_str;
    } else {
        outs << "0x" << hex << cur_pc;
    }

    if (inst->isMicroop()) {
        outs << "." << setw(2) << dec << pc.microPC();
    } else {
        outs << "   ";
    }

    outs << " : ";

    //
    //  Print decoded instruction
    //

    outs << setw(26) << left;
    outs << inst->disassemble(cur_pc, debugSymbolTable);

    if (ran) {
        outs << " : ";

        if (Debug::ExecOpClass) {
            outs << Enums::OpClassStrings[inst->opClass()] << " : ";
        }

        if (Debug::ExecResult && predicate == false) {
            outs << "Predicated False";
        }

        if (Debug::ExecResult && data_status != DataInvalid) {
            ccprintf(outs, " D=%#018x", data.as_int);
        }

        if (Debug::ExecEffAddr && addr_valid)
            outs << " A=0x" << hex << addr;

        if (Debug::ExecFetchSeq && fetch_seq_valid)
            outs << "  FetchSeq=" << dec << fetch_seq;

        if (Debug::ExecCPSeq && cp_seq_valid)
            outs << "  CPSeq=" << dec << cp_seq;
    }

    //
    //  End of line...
    //
    outs << endl;
}

void
Trace::ExeTracerRecord::dump()
{
    /*
     * The behavior this check tries to achieve is that if ExecMacro is on,
     * the macroop will be printed. If it's on and microops are also on, it's
     * printed before the microops start printing to give context. If the
     * microops aren't printed, then it's printed only when the final microop
     * finishes. Macroops then behave like regular instructions and don't
     * complete/print when they fault.
     */
    if (Debug::ExecMacro && staticInst->isMicroop() &&
        ((Debug::ExecMicro &&
            macroStaticInst && staticInst->isFirstMicroop()) ||
            (!Debug::ExecMicro &&
             macroStaticInst && staticInst->isLastMicroop()))) {
        traceInst(macroStaticInst, false);
    }
    if (Debug::ExecMicro || !staticInst->isMicroop()) {
        traceInst(staticInst, true);
    }
}

} // namespace Trace

////////////////////////////////////////////////////////////////////////
//
//  ExeTracer Simulation Object
//
Trace::ExeTracer *
ExeTracerParams::create()
{
    return new Trace::ExeTracer(this);
}
<|endoftext|>