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

#include <math.h>
#include <stdio.h>  // FIXME(brettw) erase me.
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <time.h>

#include <algorithm>

#include "ppapi/c/dev/ppb_console_dev.h"
#include "ppapi/c/dev/ppb_cursor_control_dev.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/private/instance_private.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/private/var_private.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/cpp/url_request_info.h"
#include "ppapi/cpp/var.h"

static const int kStepsPerCircle = 800;

void FlushCallback(void* data, int32_t result);

void FillRect(pp::ImageData* image, int left, int top, int width, int height,
              uint32_t color) {
  for (int y = std::max(0, top);
       y < std::min(image->size().height() - 1, top + height);
       y++) {
    for (int x = std::max(0, left);
         x < std::min(image->size().width() - 1, left + width);
         x++)
      *image->GetAddr32(pp::Point(x, y)) = color;
  }
}

class MyScriptableObject : public pp::deprecated::ScriptableObject {
 public:
  explicit MyScriptableObject(pp::InstancePrivate* instance)
      : instance_(instance) {}

  virtual bool HasMethod(const pp::Var& method, pp::Var* exception) {
    return method.AsString() == "toString";
  }

  virtual bool HasProperty(const pp::Var& name, pp::Var* exception) {
    if (name.is_string() && name.AsString() == "blah")
      return true;
    return false;
  }

  virtual pp::Var GetProperty(const pp::Var& name, pp::Var* exception) {
    if (name.is_string() && name.AsString() == "blah")
      return pp::VarPrivate(instance_, new MyScriptableObject(instance_));
    return pp::Var();
  }

  virtual void GetAllPropertyNames(std::vector<pp::Var>* names,
                                   pp::Var* exception) {
    names->push_back("blah");
  }

  virtual pp::Var Call(const pp::Var& method,
                       const std::vector<pp::Var>& args,
                       pp::Var* exception) {
    if (method.AsString() == "toString")
      return pp::Var("hello world");
    return pp::Var();
  }

 private:
  pp::InstancePrivate* instance_;
};

class MyFetcherClient {
 public:
  virtual void DidFetch(bool success, const std::string& data) = 0;
};

class MyFetcher {
 public:
  MyFetcher() : client_(NULL) {
    callback_factory_.Initialize(this);
  }

  void Start(const pp::InstancePrivate& instance,
             const pp::Var& url,
             MyFetcherClient* client) {
    pp::URLRequestInfo request;
    request.SetURL(url);
    request.SetMethod("GET");

    loader_ = pp::URLLoader(instance);
    client_ = client;

    pp::CompletionCallback callback =
        callback_factory_.NewCallback(&MyFetcher::DidOpen);
    int rv = loader_.Open(request, callback);
    if (rv != PP_OK_COMPLETIONPENDING)
      callback.Run(rv);
  }

  void StartWithOpenedLoader(const pp::URLLoader& loader,
                             MyFetcherClient* client) {
    loader_ = loader;
    client_ = client;

    ReadMore();
  }

 private:
  void ReadMore() {
    pp::CompletionCallback callback =
        callback_factory_.NewCallback(&MyFetcher::DidRead);
    int rv = loader_.ReadResponseBody(buf_, sizeof(buf_), callback);
    if (rv != PP_OK_COMPLETIONPENDING)
      callback.Run(rv);
  }

  void DidOpen(int32_t result) {
    if (result == PP_OK) {
      ReadMore();
    } else {
      DidFinish(result);
    }
  }

  void DidRead(int32_t result) {
    if (result > 0) {
      data_.append(buf_, result);
      ReadMore();
    } else {
      DidFinish(result);
    }
  }

  void DidFinish(int32_t result) {
    if (client_)
      client_->DidFetch(result == PP_OK, data_);
  }

  pp::CompletionCallbackFactory<MyFetcher> callback_factory_;
  pp::URLLoader loader_;
  MyFetcherClient* client_;
  char buf_[4096];
  std::string data_;
};

class MyInstance : public pp::InstancePrivate, public MyFetcherClient {
 public:
  MyInstance(PP_Instance instance)
      : pp::InstancePrivate(instance),
        time_at_last_check_(0.0),
        fetcher_(NULL),
        width_(0),
        height_(0),
        animation_counter_(0),
        print_settings_valid_(false),
        showing_custom_cursor_(false) {}

  virtual ~MyInstance() {
    if (fetcher_) {
      delete fetcher_;
      fetcher_ = NULL;
    }
  }

  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
    return true;
  }

  void Log(PP_LogLevel_Dev level, const pp::Var& value) {
    const PPB_Console_Dev* console = reinterpret_cast<const PPB_Console_Dev*>(
        pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE));
    if (!console)
      return;
    console->Log(pp_instance(), level, value.pp_var());
  }

  virtual bool HandleDocumentLoad(const pp::URLLoader& loader) {
    fetcher_ = new MyFetcher();
    fetcher_->StartWithOpenedLoader(loader, this);
    return true;
  }

  virtual bool HandleInputEvent(const PP_InputEvent& event) {
    switch (event.type) {
      case PP_INPUTEVENT_TYPE_MOUSEDOWN:
        SayHello();
        ToggleCursor();
        return true;
      case PP_INPUTEVENT_TYPE_MOUSEMOVE:
        return true;
      case PP_INPUTEVENT_TYPE_KEYDOWN:
        return true;
      default:
        return false;
    }
  }

  virtual pp::Var GetInstanceObject() {
    return pp::VarPrivate(this, new MyScriptableObject(this));
  }

  pp::ImageData PaintImage(int width, int height) {
    pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
                        pp::Size(width, height), false);
    if (image.is_null()) {
      printf("Couldn't allocate the image data: %d, %d\n", width, height);
      return image;
    }

    // Fill with semitransparent gradient.
    for (int y = 0; y < image.size().height(); y++) {
      char* row = &static_cast<char*>(image.data())[y * image.stride()];
      for (int x = 0; x < image.size().width(); x++) {
        row[x * 4 + 0] = y;
        row[x * 4 + 1] = y;
        row[x * 4 + 2] = 0;
        row[x * 4 + 3] = y;
      }
    }

    // Draw the orbiting box.
    float radians = static_cast<float>(animation_counter_) / kStepsPerCircle *
        2 * 3.14159265358979F;

    float radius = static_cast<float>(std::min(width, height)) / 2.0f - 3.0f;
    int x = static_cast<int>(cos(radians) * radius + radius + 2);
    int y = static_cast<int>(sin(radians) * radius + radius + 2);

    const uint32_t box_bgra = 0x80000000;  // Alpha 50%.
    FillRect(&image, x - 3, y - 3, 7, 7, box_bgra);
    return image;
  }

  void Paint() {
    pp::ImageData image = PaintImage(width_, height_);
    if (!image.is_null()) {
      device_context_.ReplaceContents(&image);
      device_context_.Flush(pp::CompletionCallback(&FlushCallback, this));
    } else {
      printf("NullImage: %d, %d\n", width_, height_);
    }
  }

  virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
    Log(PP_LOGLEVEL_LOG, "DidChangeView");
    if (position.size().width() == width_ &&
        position.size().height() == height_)
      return;  // We don't care about the position, only the size.

    width_ = position.size().width();
    height_ = position.size().height();
    printf("DidChangeView relevant change: width=%d height:%d\n",
           width_, height_);

    device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false);
    if (!BindGraphics(device_context_)) {
      printf("Couldn't bind the device context\n");
      return;
    }

    Paint();
  }

  void UpdateFps() {
// Time code doesn't currently compile on Windows, just skip FPS for now.
#ifndef _WIN32
    pp::VarPrivate window = GetWindowObject();
    pp::VarPrivate doc = window.GetProperty("document");
    pp::VarPrivate fps = doc.Call("getElementById", "fps");

    struct timeval tv;
    struct timezone tz = {0, 0};
    gettimeofday(&tv, &tz);

    double time_now = tv.tv_sec + tv.tv_usec / 1000000.0;

    if (animation_counter_ > 0) {
      char fps_text[64];
      sprintf(fps_text, "%g fps",
              kStepsPerCircle / (time_now - time_at_last_check_));
      fps.SetProperty("innerHTML", fps_text);
    }

    time_at_last_check_ = time_now;
#endif
  }

  // Print interfaces.
  virtual PP_PrintOutputFormat_Dev* QuerySupportedPrintOutputFormats(
      uint32_t* format_count) {
    PP_PrintOutputFormat_Dev* format =
        reinterpret_cast<PP_PrintOutputFormat_Dev*>(
            pp::Module::Get()->core()->MemAlloc(
                sizeof(PP_PrintOutputFormat_Dev)));
    *format = PP_PRINTOUTPUTFORMAT_RASTER;
    *format_count = 1;
    return format;
  }

  virtual int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) {
    if (print_settings_.format != PP_PRINTOUTPUTFORMAT_RASTER)
      return 0;

    print_settings_ = print_settings;
    print_settings_valid_ = true;
    return 1;
  }

  virtual pp::Resource PrintPages(
      const PP_PrintPageNumberRange_Dev* page_ranges,
      uint32_t page_range_count) {
    if (!print_settings_valid_)
      return pp::Resource();

    if (page_range_count != 1)
      return pp::Resource();

    // Check if the page numbers are valid. We returned 1 in PrintBegin so we
    // only have 1 page to print.
    if (page_ranges[0].first_page_number || page_ranges[0].last_page_number) {
      return pp::Resource();
    }

    int width = static_cast<int>(
        (print_settings_.printable_area.size.width / 72.0) *
         print_settings_.dpi);
    int height = static_cast<int>(
        (print_settings_.printable_area.size.height / 72.0) *
         print_settings_.dpi);

    return PaintImage(width, height);
  }

  virtual void PrintEnd() {
    print_settings_valid_ = false;
  }

  void OnFlush() {
    if (animation_counter_ % kStepsPerCircle == 0)
      UpdateFps();
    animation_counter_++;
    Paint();
  }

 private:
  void SayHello() {
    pp::VarPrivate window = GetWindowObject();
    pp::VarPrivate doc = window.GetProperty("document");
    pp::VarPrivate body = doc.GetProperty("body");

    pp::VarPrivate obj(this, new MyScriptableObject(this));

    // Our object should have its toString method called.
    Log(PP_LOGLEVEL_LOG, "Testing MyScriptableObject::toString():");
    Log(PP_LOGLEVEL_LOG, obj);

    // body.appendChild(body) should throw an exception
    Log(PP_LOGLEVEL_LOG, "Calling body.appendChild(body):");
    pp::Var exception;
    body.Call("appendChild", body, &exception);
    Log(PP_LOGLEVEL_LOG, exception);

    Log(PP_LOGLEVEL_LOG, "Enumeration of window properties:");
    std::vector<pp::Var> props;
    window.GetAllPropertyNames(&props);
    for (size_t i = 0; i < props.size(); ++i)
      Log(PP_LOGLEVEL_LOG, props[i]);

    pp::Var location = window.GetProperty("location");
    pp::Var href = location.GetProperty("href");

    if (!fetcher_) {
      fetcher_ = new MyFetcher();
      fetcher_->Start(*this, href, this);
    }
  }

  void DidFetch(bool success, const std::string& data) {
    Log(PP_LOGLEVEL_LOG, "Downloaded location.href:");
    if (success) {
      Log(PP_LOGLEVEL_LOG, data);
    } else {
      Log(PP_LOGLEVEL_ERROR, "Failed to download.");
    }
    delete fetcher_;
    fetcher_ = NULL;
  }

  void ToggleCursor() {
    const PPB_CursorControl_Dev* cursor_control =
        reinterpret_cast<const PPB_CursorControl_Dev*>(
            pp::Module::Get()->GetBrowserInterface(
                PPB_CURSOR_CONTROL_DEV_INTERFACE));
    if (!cursor_control)
      return;

    if (showing_custom_cursor_) {
      cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_POINTER, 0, NULL);
    } else {
      pp::ImageData image_data(this, pp::ImageData::GetNativeImageDataFormat(),
                               pp::Size(50, 50), false);
      FillRect(&image_data, 0, 0, 50, 50,
               image_data.format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL ?
                   0x80800000 : 0x80000080);
      pp::Point hot_spot(0, 0);
      cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_CUSTOM,
                                image_data.pp_resource(), &hot_spot.pp_point());
    }

    showing_custom_cursor_ = !showing_custom_cursor_;
  }

  pp::Var console_;
  pp::Graphics2D device_context_;

  double time_at_last_check_;

  MyFetcher* fetcher_;

  int width_;
  int height_;

  // Incremented for each flush we get.
  int animation_counter_;
  bool print_settings_valid_;
  PP_PrintSettings_Dev print_settings_;

  bool showing_custom_cursor_;
};

void FlushCallback(void* data, int32_t result) {
  static_cast<MyInstance*>(data)->OnFlush();
}

class MyModule : public pp::Module {
 public:
  MyModule() : pp::Module() {}
  virtual ~MyModule() {}

  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new MyInstance(instance);
  }
};

namespace pp {

// Factory function for your specialization of the Module object.
Module* CreateModule() {
  return new MyModule();
}

}  // namespace pp
<commit_msg>Make FSP work for pepper<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <math.h>
#include <stdio.h>  // FIXME(brettw) erase me.
#ifndef _WIN32
#include <sys/time.h>
#else
#include <windows.h>
#endif
#include <time.h>

#include <algorithm>

#include "ppapi/c/dev/ppb_console_dev.h"
#include "ppapi/c/dev/ppb_cursor_control_dev.h"
#include "ppapi/c/dev/ppp_printing_dev.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/pp_input_event.h"
#include "ppapi/c/pp_rect.h"
#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/dev/scriptable_object_deprecated.h"
#include "ppapi/cpp/graphics_2d.h"
#include "ppapi/cpp/image_data.h"
#include "ppapi/cpp/private/instance_private.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/private/var_private.h"
#include "ppapi/cpp/rect.h"
#include "ppapi/cpp/url_loader.h"
#include "ppapi/cpp/url_request_info.h"
#include "ppapi/cpp/var.h"

static const int kStepsPerCircle = 800;

void FlushCallback(void* data, int32_t result);

void FillRect(pp::ImageData* image, int left, int top, int width, int height,
              uint32_t color) {
  for (int y = std::max(0, top);
       y < std::min(image->size().height() - 1, top + height);
       y++) {
    for (int x = std::max(0, left);
         x < std::min(image->size().width() - 1, left + width);
         x++)
      *image->GetAddr32(pp::Point(x, y)) = color;
  }
}

class MyScriptableObject : public pp::deprecated::ScriptableObject {
 public:
  explicit MyScriptableObject(pp::InstancePrivate* instance)
      : instance_(instance) {}

  virtual bool HasMethod(const pp::Var& method, pp::Var* exception) {
    return method.AsString() == "toString";
  }

  virtual bool HasProperty(const pp::Var& name, pp::Var* exception) {
    if (name.is_string() && name.AsString() == "blah")
      return true;
    return false;
  }

  virtual pp::Var GetProperty(const pp::Var& name, pp::Var* exception) {
    if (name.is_string() && name.AsString() == "blah")
      return pp::VarPrivate(instance_, new MyScriptableObject(instance_));
    return pp::Var();
  }

  virtual void GetAllPropertyNames(std::vector<pp::Var>* names,
                                   pp::Var* exception) {
    names->push_back("blah");
  }

  virtual pp::Var Call(const pp::Var& method,
                       const std::vector<pp::Var>& args,
                       pp::Var* exception) {
    if (method.AsString() == "toString")
      return pp::Var("hello world");
    return pp::Var();
  }

 private:
  pp::InstancePrivate* instance_;
};

class MyFetcherClient {
 public:
  virtual void DidFetch(bool success, const std::string& data) = 0;
};

class MyFetcher {
 public:
  MyFetcher() : client_(NULL) {
    callback_factory_.Initialize(this);
  }

  void Start(const pp::InstancePrivate& instance,
             const pp::Var& url,
             MyFetcherClient* client) {
    pp::URLRequestInfo request;
    request.SetURL(url);
    request.SetMethod("GET");

    loader_ = pp::URLLoader(instance);
    client_ = client;

    pp::CompletionCallback callback =
        callback_factory_.NewCallback(&MyFetcher::DidOpen);
    int rv = loader_.Open(request, callback);
    if (rv != PP_OK_COMPLETIONPENDING)
      callback.Run(rv);
  }

  void StartWithOpenedLoader(const pp::URLLoader& loader,
                             MyFetcherClient* client) {
    loader_ = loader;
    client_ = client;

    ReadMore();
  }

 private:
  void ReadMore() {
    pp::CompletionCallback callback =
        callback_factory_.NewCallback(&MyFetcher::DidRead);
    int rv = loader_.ReadResponseBody(buf_, sizeof(buf_), callback);
    if (rv != PP_OK_COMPLETIONPENDING)
      callback.Run(rv);
  }

  void DidOpen(int32_t result) {
    if (result == PP_OK) {
      ReadMore();
    } else {
      DidFinish(result);
    }
  }

  void DidRead(int32_t result) {
    if (result > 0) {
      data_.append(buf_, result);
      ReadMore();
    } else {
      DidFinish(result);
    }
  }

  void DidFinish(int32_t result) {
    if (client_)
      client_->DidFetch(result == PP_OK, data_);
  }

  pp::CompletionCallbackFactory<MyFetcher> callback_factory_;
  pp::URLLoader loader_;
  MyFetcherClient* client_;
  char buf_[4096];
  std::string data_;
};

class MyInstance : public pp::InstancePrivate, public MyFetcherClient {
 public:
  MyInstance(PP_Instance instance)
      : pp::InstancePrivate(instance),
        time_at_last_check_(0.0),
        fetcher_(NULL),
        width_(0),
        height_(0),
        animation_counter_(0),
        print_settings_valid_(false),
        showing_custom_cursor_(false) {}

  virtual ~MyInstance() {
    if (fetcher_) {
      delete fetcher_;
      fetcher_ = NULL;
    }
  }

  virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) {
    return true;
  }

  void Log(PP_LogLevel_Dev level, const pp::Var& value) {
    const PPB_Console_Dev* console = reinterpret_cast<const PPB_Console_Dev*>(
        pp::Module::Get()->GetBrowserInterface(PPB_CONSOLE_DEV_INTERFACE));
    if (!console)
      return;
    console->Log(pp_instance(), level, value.pp_var());
  }

  virtual bool HandleDocumentLoad(const pp::URLLoader& loader) {
    fetcher_ = new MyFetcher();
    fetcher_->StartWithOpenedLoader(loader, this);
    return true;
  }

  virtual bool HandleInputEvent(const PP_InputEvent& event) {
    switch (event.type) {
      case PP_INPUTEVENT_TYPE_MOUSEDOWN:
        SayHello();
        ToggleCursor();
        return true;
      case PP_INPUTEVENT_TYPE_MOUSEMOVE:
        return true;
      case PP_INPUTEVENT_TYPE_KEYDOWN:
        return true;
      default:
        return false;
    }
  }

  virtual pp::Var GetInstanceObject() {
    return pp::VarPrivate(this, new MyScriptableObject(this));
  }

  pp::ImageData PaintImage(int width, int height) {
    pp::ImageData image(this, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
                        pp::Size(width, height), false);
    if (image.is_null()) {
      printf("Couldn't allocate the image data: %d, %d\n", width, height);
      return image;
    }

    // Fill with semitransparent gradient.
    for (int y = 0; y < image.size().height(); y++) {
      char* row = &static_cast<char*>(image.data())[y * image.stride()];
      for (int x = 0; x < image.size().width(); x++) {
        row[x * 4 + 0] = y;
        row[x * 4 + 1] = y;
        row[x * 4 + 2] = 0;
        row[x * 4 + 3] = y;
      }
    }

    // Draw the orbiting box.
    float radians = static_cast<float>(animation_counter_) / kStepsPerCircle *
        2 * 3.14159265358979F;

    float radius = static_cast<float>(std::min(width, height)) / 2.0f - 3.0f;
    int x = static_cast<int>(cos(radians) * radius + radius + 2);
    int y = static_cast<int>(sin(radians) * radius + radius + 2);

    const uint32_t box_bgra = 0x80000000;  // Alpha 50%.
    FillRect(&image, x - 3, y - 3, 7, 7, box_bgra);
    return image;
  }

  void Paint() {
    pp::ImageData image = PaintImage(width_, height_);
    if (!image.is_null()) {
      device_context_.ReplaceContents(&image);
      device_context_.Flush(pp::CompletionCallback(&FlushCallback, this));
    } else {
      printf("NullImage: %d, %d\n", width_, height_);
    }
  }

  virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) {
    Log(PP_LOGLEVEL_LOG, "DidChangeView");
    if (position.size().width() == width_ &&
        position.size().height() == height_)
      return;  // We don't care about the position, only the size.

    width_ = position.size().width();
    height_ = position.size().height();
    printf("DidChangeView relevant change: width=%d height:%d\n",
           width_, height_);

    device_context_ = pp::Graphics2D(this, pp::Size(width_, height_), false);
    if (!BindGraphics(device_context_)) {
      printf("Couldn't bind the device context\n");
      return;
    }

    Paint();
  }

#if defined(_WIN32)
struct timeval {
  long tv_sec;
  long tv_usec;
};

struct timezone {
  long x;
  long y;
};

#define EPOCHFILETIME (116444736000000000i64)

int gettimeofday(struct timeval *tv, struct timezone*) {
  FILETIME ft;
  ::GetSystemTimeAsFileTime(&ft);
  LARGE_INTEGER li = {ft.dwLowDateTime, ft.dwHighDateTime};
  __int64 t = li.QuadPart - EPOCHFILETIME;
  tv->tv_sec  = static_cast<long>(t / 10000000);
  tv->tv_usec = static_cast<long>(t % 10000000);
  return 0;
}
#endif  // if defined(_WIN32)

  void UpdateFps() {
    pp::VarPrivate window = GetWindowObject();
    pp::VarPrivate doc = window.GetProperty("document");
    pp::VarPrivate fps = doc.Call("getElementById", "fps");

    struct timeval tv;
    struct timezone tz = {0, 0};
    gettimeofday(&tv, &tz);

    double time_now = tv.tv_sec + tv.tv_usec / 1000000.0;

    if (animation_counter_ > 0) {
      char fps_text[64];
      sprintf(fps_text, "%g fps",
              kStepsPerCircle / (time_now - time_at_last_check_));
      fps.SetProperty("innerHTML", fps_text);
    }

    time_at_last_check_ = time_now;
  }

  // Print interfaces.
  virtual PP_PrintOutputFormat_Dev* QuerySupportedPrintOutputFormats(
      uint32_t* format_count) {
    PP_PrintOutputFormat_Dev* format =
        reinterpret_cast<PP_PrintOutputFormat_Dev*>(
            pp::Module::Get()->core()->MemAlloc(
                sizeof(PP_PrintOutputFormat_Dev)));
    *format = PP_PRINTOUTPUTFORMAT_RASTER;
    *format_count = 1;
    return format;
  }

  virtual int32_t PrintBegin(const PP_PrintSettings_Dev& print_settings) {
    if (print_settings_.format != PP_PRINTOUTPUTFORMAT_RASTER)
      return 0;

    print_settings_ = print_settings;
    print_settings_valid_ = true;
    return 1;
  }

  virtual pp::Resource PrintPages(
      const PP_PrintPageNumberRange_Dev* page_ranges,
      uint32_t page_range_count) {
    if (!print_settings_valid_)
      return pp::Resource();

    if (page_range_count != 1)
      return pp::Resource();

    // Check if the page numbers are valid. We returned 1 in PrintBegin so we
    // only have 1 page to print.
    if (page_ranges[0].first_page_number || page_ranges[0].last_page_number) {
      return pp::Resource();
    }

    int width = static_cast<int>(
        (print_settings_.printable_area.size.width / 72.0) *
         print_settings_.dpi);
    int height = static_cast<int>(
        (print_settings_.printable_area.size.height / 72.0) *
         print_settings_.dpi);

    return PaintImage(width, height);
  }

  virtual void PrintEnd() {
    print_settings_valid_ = false;
  }

  void OnFlush() {
    if (animation_counter_ % kStepsPerCircle == 0)
      UpdateFps();
    animation_counter_++;
    Paint();
  }

 private:
  void SayHello() {
    pp::VarPrivate window = GetWindowObject();
    pp::VarPrivate doc = window.GetProperty("document");
    pp::VarPrivate body = doc.GetProperty("body");

    pp::VarPrivate obj(this, new MyScriptableObject(this));

    // Our object should have its toString method called.
    Log(PP_LOGLEVEL_LOG, "Testing MyScriptableObject::toString():");
    Log(PP_LOGLEVEL_LOG, obj);

    // body.appendChild(body) should throw an exception
    Log(PP_LOGLEVEL_LOG, "Calling body.appendChild(body):");
    pp::Var exception;
    body.Call("appendChild", body, &exception);
    Log(PP_LOGLEVEL_LOG, exception);

    Log(PP_LOGLEVEL_LOG, "Enumeration of window properties:");
    std::vector<pp::Var> props;
    window.GetAllPropertyNames(&props);
    for (size_t i = 0; i < props.size(); ++i)
      Log(PP_LOGLEVEL_LOG, props[i]);

    pp::Var location = window.GetProperty("location");
    pp::Var href = location.GetProperty("href");

    if (!fetcher_) {
      fetcher_ = new MyFetcher();
      fetcher_->Start(*this, href, this);
    }
  }

  void DidFetch(bool success, const std::string& data) {
    Log(PP_LOGLEVEL_LOG, "Downloaded location.href:");
    if (success) {
      Log(PP_LOGLEVEL_LOG, data);
    } else {
      Log(PP_LOGLEVEL_ERROR, "Failed to download.");
    }
    delete fetcher_;
    fetcher_ = NULL;
  }

  void ToggleCursor() {
    const PPB_CursorControl_Dev* cursor_control =
        reinterpret_cast<const PPB_CursorControl_Dev*>(
            pp::Module::Get()->GetBrowserInterface(
                PPB_CURSOR_CONTROL_DEV_INTERFACE));
    if (!cursor_control)
      return;

    if (showing_custom_cursor_) {
      cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_POINTER, 0, NULL);
    } else {
      pp::ImageData image_data(this, pp::ImageData::GetNativeImageDataFormat(),
                               pp::Size(50, 50), false);
      FillRect(&image_data, 0, 0, 50, 50,
               image_data.format() == PP_IMAGEDATAFORMAT_BGRA_PREMUL ?
                   0x80800000 : 0x80000080);
      pp::Point hot_spot(0, 0);
      cursor_control->SetCursor(pp_instance(), PP_CURSORTYPE_CUSTOM,
                                image_data.pp_resource(), &hot_spot.pp_point());
    }

    showing_custom_cursor_ = !showing_custom_cursor_;
  }

  pp::Var console_;
  pp::Graphics2D device_context_;

  double time_at_last_check_;

  MyFetcher* fetcher_;

  int width_;
  int height_;

  // Incremented for each flush we get.
  int animation_counter_;
  bool print_settings_valid_;
  PP_PrintSettings_Dev print_settings_;

  bool showing_custom_cursor_;
};

void FlushCallback(void* data, int32_t result) {
  static_cast<MyInstance*>(data)->OnFlush();
}

class MyModule : public pp::Module {
 public:
  MyModule() : pp::Module() {}
  virtual ~MyModule() {}

  virtual pp::Instance* CreateInstance(PP_Instance instance) {
    return new MyInstance(instance);
  }
};

namespace pp {

// Factory function for your specialization of the Module object.
Module* CreateModule() {
  return new MyModule();
}

}  // namespace pp
<|endoftext|>


<commit_before>// Copyright (c) 2009 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/chromeos/cros/network_library.h"

#include <algorithm>

#include "base/string_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "net/url_request/url_request_job.h"

// Allows InvokeLater without adding refcounting. This class is a Singleton and
// won't be deleted until it's last InvokeLater is run.
template <>
struct RunnableMethodTraits<chromeos::NetworkLibrary> {
  void RetainCallee(chromeos::NetworkLibrary* obj) {}
  void ReleaseCallee(chromeos::NetworkLibrary* obj) {}
};

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
// NetworkLibrary

// static
const int NetworkLibrary::kNetworkTrafficeTimerSecs = 1;

NetworkLibrary::NetworkLibrary()
    : traffic_type_(0),
      network_devices_(0),
      offline_mode_(false) {
  if (CrosLibrary::EnsureLoaded()) {
    Init();
  }
  g_url_request_job_tracker.AddObserver(this);
}

NetworkLibrary::~NetworkLibrary() {
  if (CrosLibrary::EnsureLoaded()) {
    chromeos::DisconnectNetworkStatus(network_status_connection_);
  }
  g_url_request_job_tracker.RemoveObserver(this);
}

// static
NetworkLibrary* NetworkLibrary::Get() {
  return Singleton<NetworkLibrary>::get();
}

// static
bool NetworkLibrary::EnsureLoaded() {
  return CrosLibrary::EnsureLoaded();
}

////////////////////////////////////////////////////////////////////////////////
// NetworkLibrary, URLRequestJobTracker::JobObserver implementation:

void NetworkLibrary::OnJobAdded(URLRequestJob* job) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnJobRemoved(URLRequestJob* job) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnJobDone(URLRequestJob* job,
                               const URLRequestStatus& status) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnJobRedirect(URLRequestJob* job, const GURL& location,
                                   int status_code) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnBytesRead(URLRequestJob* job, int byte_count) {
  CheckNetworkTraffic(true);
}

void NetworkLibrary::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void NetworkLibrary::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

static const char* GetEncryptionString(chromeos::EncryptionType encryption) {
  switch (encryption) {
    case chromeos::NONE:
      return "none";
    case chromeos::RSN:
      return "rsn";
    case chromeos::WEP:
      return "wep";
    case chromeos::WPA:
      return "wpa";
  }
  return "none";
}

void NetworkLibrary::ConnectToWifiNetwork(WifiNetwork network,
                                          const string16& password) {
  if (CrosLibrary::EnsureLoaded()) {
    // This call kicks off a request to connect to this network, the results of
    // which we'll hear about through the monitoring we've set up in Init();
    chromeos::ConnectToWifiNetwork(
        network.ssid.c_str(),
        password.empty() ? NULL : UTF16ToUTF8(password).c_str(),
        GetEncryptionString(network.encryption));
  }
}

void NetworkLibrary::ConnectToCellularNetwork(CellularNetwork network) {
  if (CrosLibrary::EnsureLoaded()) {
    // This call kicks off a request to connect to this network, the results of
    // which we'll hear about through the monitoring we've set up in Init();
    chromeos::ConnectToWifiNetwork(network.name.c_str(), NULL, NULL);
  }
}

void NetworkLibrary::EnableEthernetNetworkDevice(bool enable) {
  EnableNetworkDevice(chromeos::TYPE_ETHERNET, enable);
}

void NetworkLibrary::EnableWifiNetworkDevice(bool enable) {
  EnableNetworkDevice(chromeos::TYPE_WIFI, enable);
}

void NetworkLibrary::EnableCellularNetworkDevice(bool enable) {
  EnableNetworkDevice(chromeos::TYPE_CELLULAR, enable);
}

void NetworkLibrary::EnableOfflineMode(bool enable) {
  if (!CrosLibrary::EnsureLoaded())
    return;

  // If network device is already enabled/disabled, then don't do anything.
  if (enable && offline_mode_) {
    LOG(INFO) << "Trying to enable offline mode when it's already enabled. ";
    return;
  }
  if (!enable && !offline_mode_) {
    LOG(INFO) << "Trying to disable offline mode when it's already disabled. ";
    return;
  }

  if (chromeos::SetOfflineMode(enable)) {
    offline_mode_ = enable;
  }
}

NetworkIPConfigVector NetworkLibrary::GetIPConfigs(
    const std::string& device_path) {
  NetworkIPConfigVector ipconfig_vector;
  if (!device_path.empty()) {
    chromeos::IPConfigStatus* ipconfig_status =
        chromeos::ListIPConfigs(device_path.c_str());
    if (ipconfig_status) {
      for (int i = 0; i < ipconfig_status->size; i++) {
        chromeos::IPConfig ipconfig = ipconfig_status->ips[i];
        ipconfig_vector.push_back(
            NetworkIPConfig(device_path, ipconfig.type, ipconfig.address,
                            ipconfig.netmask, ipconfig.gateway,
                            ipconfig.name_servers));
      }
      chromeos::FreeIPConfigStatus(ipconfig_status);
      // Sort the list of ip configs by type.
      std::sort(ipconfig_vector.begin(), ipconfig_vector.end());
    }
  }
  return ipconfig_vector;
}

// static
void NetworkLibrary::NetworkStatusChangedHandler(void* object,
    const chromeos::ServiceStatus& service_status) {
  NetworkLibrary* network = static_cast<NetworkLibrary*>(object);
  EthernetNetwork ethernet;
  WifiNetworkVector wifi_networks;
  CellularNetworkVector cellular_networks;
  ParseNetworks(service_status, &ethernet, &wifi_networks, &cellular_networks);
  network->UpdateNetworkStatus(ethernet, wifi_networks, cellular_networks);
}

// static
void NetworkLibrary::ParseNetworks(
    const chromeos::ServiceStatus& service_status, EthernetNetwork* ethernet,
    WifiNetworkVector* wifi_networks,
    CellularNetworkVector* cellular_networks) {
  DLOG(INFO) << "ParseNetworks:";
  for (int i = 0; i < service_status.size; i++) {
    const chromeos::ServiceInfo& service = service_status.services[i];
    DLOG(INFO) << "  (" << service.type <<
                  ") " << service.ssid <<
                  " sta=" << service.state <<
                  " pas=" << service.needs_passphrase <<
                  " enc=" << service.encryption <<
                  " sig=" << service.signal_strength;
    bool connecting = service.state == chromeos::STATE_ASSOCIATION ||
                      service.state == chromeos::STATE_CONFIGURATION ||
                      service.state == chromeos::STATE_CARRIER;
    bool connected = service.state == chromeos::STATE_READY;
    // if connected, get ip config
    std::string ip_address;
    if (connected) {
      chromeos::IPConfigStatus* ipconfig_status =
          chromeos::ListIPConfigs(service.device_path);
      if (ipconfig_status) {
        for (int i = 0; i < ipconfig_status->size; i++) {
          chromeos::IPConfig ipconfig = ipconfig_status->ips[i];
          if (strlen(ipconfig.address) > 0)
            ip_address = ipconfig.address;
          DLOG(INFO) << "          ipconfig: " <<
                        " type=" << ipconfig.type <<
                        " address=" << ipconfig.address <<
                        " mtu=" << ipconfig.mtu <<
                        " netmask=" << ipconfig.netmask <<
                        " broadcast=" << ipconfig.broadcast <<
                        " peer_address=" << ipconfig.peer_address <<
                        " gateway=" << ipconfig.gateway <<
                        " domainname=" << ipconfig.domainname <<
                        " name_servers=" << ipconfig.name_servers;
        }
        chromeos::FreeIPConfigStatus(ipconfig_status);
      }
    }
    if (service.type == chromeos::TYPE_ETHERNET) {
      ethernet->connecting = connecting;
      ethernet->connected = connected;
      ethernet->device_path = service.device_path;
      ethernet->ip_address = ip_address;
    } else if (service.type == chromeos::TYPE_WIFI) {
      wifi_networks->push_back(WifiNetwork(service.device_path,
                                           service.ssid,
                                           service.needs_passphrase,
                                           service.encryption,
                                           service.signal_strength,
                                           connecting,
                                           connected,
                                           ip_address));
    } else if (service.type == chromeos::TYPE_CELLULAR) {
      cellular_networks->push_back(CellularNetwork(service.device_path,
                                                   service.ssid,
                                                   service.signal_strength,
                                                   connecting,
                                                   connected,
                                                   ip_address));
    }
  }
}

void NetworkLibrary::Init() {
  // First, get the currently available networks.  This data is cached
  // on the connman side, so the call should be quick.
  chromeos::ServiceStatus* service_status = chromeos::GetAvailableNetworks();
  if (service_status) {
    LOG(INFO) << "Getting initial CrOS network info.";
    EthernetNetwork ethernet;
    WifiNetworkVector wifi_networks;
    CellularNetworkVector cellular_networks;
    ParseNetworks(*service_status, &ethernet, &wifi_networks,
        &cellular_networks);
    UpdateNetworkStatus(ethernet, wifi_networks, cellular_networks);
    chromeos::FreeServiceStatus(service_status);
  }
  LOG(INFO) << "Registering for network status updates.";
  // Now, register to receive updates on network status.
  network_status_connection_ = chromeos::MonitorNetworkStatus(
      &NetworkStatusChangedHandler, this);
  // Get the enabled network devices bit flag. If we get a -1, then that means
  // offline mode is on. So all devices are disabled. This happens when offline
  // mode is persisted during a reboot and Chrome starts up with it on.
  network_devices_ = chromeos::GetEnabledNetworkDevices();
  if (network_devices_ == -1) {
    offline_mode_ = true;
    network_devices_ = 0;
  }
}

void NetworkLibrary::EnableNetworkDevice(chromeos::ConnectionType device,
                                         bool enable) {
  if (!CrosLibrary::EnsureLoaded())
    return;

  // If network device is already enabled/disabled, then don't do anything.
  if (enable && (network_devices_ & device)) {
    LOG(INFO) << "Trying to enable a network device that's already enabled: "
              << device;
    return;
  }
  if (!enable && !(network_devices_ & device)) {
    LOG(INFO) << "Trying to disable a network device that's already disabled: "
              << device;
    return;
  }

  if (chromeos::EnableNetworkDevice(device, enable)) {
    if (enable)
      network_devices_ |= device;
    else
      network_devices_ &= ~device;
  }
}

void NetworkLibrary::UpdateNetworkStatus(const EthernetNetwork& ethernet,
    const WifiNetworkVector& wifi_networks,
    const CellularNetworkVector& cellular_networks) {
  // Make sure we run on UI thread.
  if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
    ChromeThread::PostTask(
        ChromeThread::UI, FROM_HERE,
        NewRunnableMethod(this,
            &NetworkLibrary::UpdateNetworkStatus, ethernet, wifi_networks,
            cellular_networks));
    return;
  }

  ethernet_ = ethernet;
  wifi_networks_ = wifi_networks;
  // Sort the list of wifi networks by ssid.
  std::sort(wifi_networks_.begin(), wifi_networks_.end());
  wifi_ = WifiNetwork();
  for (size_t i = 0; i < wifi_networks_.size(); i++) {
    if (wifi_networks_[i].connecting || wifi_networks_[i].connected) {
      wifi_ = wifi_networks_[i];
      break;  // There is only one connected or connecting wifi network.
    }
  }
  cellular_networks_ = cellular_networks;
  std::sort(cellular_networks_.begin(), cellular_networks_.end());
  cellular_ = CellularNetwork();
  for (size_t i = 0; i < cellular_networks_.size(); i++) {
    if (cellular_networks_[i].connecting || cellular_networks_[i].connected) {
      cellular_ = cellular_networks_[i];
      break;  // There is only one connected or connecting cellular network.
    }
  }
  FOR_EACH_OBSERVER(Observer, observers_, NetworkChanged(this));
}

void NetworkLibrary::CheckNetworkTraffic(bool download) {
  // If we already have a pending upload and download notification, then
  // shortcut and return.
  if (traffic_type_ == (Observer::TRAFFIC_DOWNLOAD | Observer::TRAFFIC_UPLOAD))
    return;
  // Figure out if we are uploading and/or downloading. We are downloading
  // if download == true. We are uploading if we have upload progress.
  if (download)
    traffic_type_ |= Observer::TRAFFIC_DOWNLOAD;
  if ((traffic_type_ & Observer::TRAFFIC_UPLOAD) == 0) {
    URLRequestJobTracker::JobIterator it;
    for (it = g_url_request_job_tracker.begin();
         it != g_url_request_job_tracker.end();
         ++it) {
      URLRequestJob* job = *it;
      if (job->GetUploadProgress() > 0) {
        traffic_type_ |= Observer::TRAFFIC_UPLOAD;
        break;
      }
    }
  }
  // If we have new traffic data to send out and the timer is not currently
  // running, then start a new timer.
  if (traffic_type_ && !timer_.IsRunning()) {
    timer_.Start(base::TimeDelta::FromSeconds(kNetworkTrafficeTimerSecs), this,
                 &NetworkLibrary::NetworkTrafficTimerFired);
  }
}

void NetworkLibrary:: NetworkTrafficTimerFired() {
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &NetworkLibrary::NotifyNetworkTraffic,
                        traffic_type_));
  // Reset traffic type so that we don't send the same data next time.
  traffic_type_ = 0;
}

void NetworkLibrary::NotifyNetworkTraffic(int traffic_type) {
  FOR_EACH_OBSERVER(Observer, observers_, NetworkTraffic(this, traffic_type));
}

bool NetworkLibrary::Connected() const {
  return ethernet_connected() || wifi_connected() || cellular_connected();
}

bool NetworkLibrary::Connecting() const {
  return ethernet_connecting() || wifi_connecting() || cellular_connecting();
}

const std::string& NetworkLibrary::IPAddress() const {
  // Returns highest priority IP address.
  if (ethernet_connected())
    return ethernet_.ip_address;
  if (wifi_connected())
    return wifi_.ip_address;
  if (cellular_connected())
    return cellular_.ip_address;
  return ethernet_.ip_address;
}

}  // namespace chromeos
<commit_msg>Fix ChromeOS crash when device_path is NULL. TEST=None BUG=1698 Review URL: http://codereview.chromium.org/661230<commit_after>// Copyright (c) 2009 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/chromeos/cros/network_library.h"

#include <algorithm>

#include "base/string_util.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "net/url_request/url_request_job.h"

// Allows InvokeLater without adding refcounting. This class is a Singleton and
// won't be deleted until it's last InvokeLater is run.
template <>
struct RunnableMethodTraits<chromeos::NetworkLibrary> {
  void RetainCallee(chromeos::NetworkLibrary* obj) {}
  void ReleaseCallee(chromeos::NetworkLibrary* obj) {}
};

namespace chromeos {

////////////////////////////////////////////////////////////////////////////////
// NetworkLibrary

// static
const int NetworkLibrary::kNetworkTrafficeTimerSecs = 1;

NetworkLibrary::NetworkLibrary()
    : traffic_type_(0),
      network_devices_(0),
      offline_mode_(false) {
  if (CrosLibrary::EnsureLoaded()) {
    Init();
  }
  g_url_request_job_tracker.AddObserver(this);
}

NetworkLibrary::~NetworkLibrary() {
  if (CrosLibrary::EnsureLoaded()) {
    chromeos::DisconnectNetworkStatus(network_status_connection_);
  }
  g_url_request_job_tracker.RemoveObserver(this);
}

// static
NetworkLibrary* NetworkLibrary::Get() {
  return Singleton<NetworkLibrary>::get();
}

// static
bool NetworkLibrary::EnsureLoaded() {
  return CrosLibrary::EnsureLoaded();
}

////////////////////////////////////////////////////////////////////////////////
// NetworkLibrary, URLRequestJobTracker::JobObserver implementation:

void NetworkLibrary::OnJobAdded(URLRequestJob* job) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnJobRemoved(URLRequestJob* job) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnJobDone(URLRequestJob* job,
                               const URLRequestStatus& status) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnJobRedirect(URLRequestJob* job, const GURL& location,
                                   int status_code) {
  CheckNetworkTraffic(false);
}

void NetworkLibrary::OnBytesRead(URLRequestJob* job, int byte_count) {
  CheckNetworkTraffic(true);
}

void NetworkLibrary::AddObserver(Observer* observer) {
  observers_.AddObserver(observer);
}

void NetworkLibrary::RemoveObserver(Observer* observer) {
  observers_.RemoveObserver(observer);
}

static const char* GetEncryptionString(chromeos::EncryptionType encryption) {
  switch (encryption) {
    case chromeos::NONE:
      return "none";
    case chromeos::RSN:
      return "rsn";
    case chromeos::WEP:
      return "wep";
    case chromeos::WPA:
      return "wpa";
  }
  return "none";
}

void NetworkLibrary::ConnectToWifiNetwork(WifiNetwork network,
                                          const string16& password) {
  if (CrosLibrary::EnsureLoaded()) {
    // This call kicks off a request to connect to this network, the results of
    // which we'll hear about through the monitoring we've set up in Init();
    chromeos::ConnectToWifiNetwork(
        network.ssid.c_str(),
        password.empty() ? NULL : UTF16ToUTF8(password).c_str(),
        GetEncryptionString(network.encryption));
  }
}

void NetworkLibrary::ConnectToCellularNetwork(CellularNetwork network) {
  if (CrosLibrary::EnsureLoaded()) {
    // This call kicks off a request to connect to this network, the results of
    // which we'll hear about through the monitoring we've set up in Init();
    chromeos::ConnectToWifiNetwork(network.name.c_str(), NULL, NULL);
  }
}

void NetworkLibrary::EnableEthernetNetworkDevice(bool enable) {
  EnableNetworkDevice(chromeos::TYPE_ETHERNET, enable);
}

void NetworkLibrary::EnableWifiNetworkDevice(bool enable) {
  EnableNetworkDevice(chromeos::TYPE_WIFI, enable);
}

void NetworkLibrary::EnableCellularNetworkDevice(bool enable) {
  EnableNetworkDevice(chromeos::TYPE_CELLULAR, enable);
}

void NetworkLibrary::EnableOfflineMode(bool enable) {
  if (!CrosLibrary::EnsureLoaded())
    return;

  // If network device is already enabled/disabled, then don't do anything.
  if (enable && offline_mode_) {
    LOG(INFO) << "Trying to enable offline mode when it's already enabled. ";
    return;
  }
  if (!enable && !offline_mode_) {
    LOG(INFO) << "Trying to disable offline mode when it's already disabled. ";
    return;
  }

  if (chromeos::SetOfflineMode(enable)) {
    offline_mode_ = enable;
  }
}

NetworkIPConfigVector NetworkLibrary::GetIPConfigs(
    const std::string& device_path) {
  NetworkIPConfigVector ipconfig_vector;
  if (!device_path.empty()) {
    chromeos::IPConfigStatus* ipconfig_status =
        chromeos::ListIPConfigs(device_path.c_str());
    if (ipconfig_status) {
      for (int i = 0; i < ipconfig_status->size; i++) {
        chromeos::IPConfig ipconfig = ipconfig_status->ips[i];
        ipconfig_vector.push_back(
            NetworkIPConfig(device_path, ipconfig.type, ipconfig.address,
                            ipconfig.netmask, ipconfig.gateway,
                            ipconfig.name_servers));
      }
      chromeos::FreeIPConfigStatus(ipconfig_status);
      // Sort the list of ip configs by type.
      std::sort(ipconfig_vector.begin(), ipconfig_vector.end());
    }
  }
  return ipconfig_vector;
}

// static
void NetworkLibrary::NetworkStatusChangedHandler(void* object,
    const chromeos::ServiceStatus& service_status) {
  NetworkLibrary* network = static_cast<NetworkLibrary*>(object);
  EthernetNetwork ethernet;
  WifiNetworkVector wifi_networks;
  CellularNetworkVector cellular_networks;
  ParseNetworks(service_status, &ethernet, &wifi_networks, &cellular_networks);
  network->UpdateNetworkStatus(ethernet, wifi_networks, cellular_networks);
}

// static
void NetworkLibrary::ParseNetworks(
    const chromeos::ServiceStatus& service_status, EthernetNetwork* ethernet,
    WifiNetworkVector* wifi_networks,
    CellularNetworkVector* cellular_networks) {
  DLOG(INFO) << "ParseNetworks:";
  for (int i = 0; i < service_status.size; i++) {
    const chromeos::ServiceInfo& service = service_status.services[i];
    DLOG(INFO) << "  (" << service.type <<
                  ") " << service.ssid <<
                  " sta=" << service.state <<
                  " pas=" << service.needs_passphrase <<
                  " enc=" << service.encryption <<
                  " sig=" << service.signal_strength;
    bool connecting = service.state == chromeos::STATE_ASSOCIATION ||
                      service.state == chromeos::STATE_CONFIGURATION ||
                      service.state == chromeos::STATE_CARRIER;
    bool connected = service.state == chromeos::STATE_READY;
    // if connected, get ip config
    std::string ip_address;
    if (connected && service.device_path) {
      chromeos::IPConfigStatus* ipconfig_status =
          chromeos::ListIPConfigs(service.device_path);
      if (ipconfig_status) {
        for (int i = 0; i < ipconfig_status->size; i++) {
          chromeos::IPConfig ipconfig = ipconfig_status->ips[i];
          if (strlen(ipconfig.address) > 0)
            ip_address = ipconfig.address;
          DLOG(INFO) << "          ipconfig: " <<
                        " type=" << ipconfig.type <<
                        " address=" << ipconfig.address <<
                        " mtu=" << ipconfig.mtu <<
                        " netmask=" << ipconfig.netmask <<
                        " broadcast=" << ipconfig.broadcast <<
                        " peer_address=" << ipconfig.peer_address <<
                        " gateway=" << ipconfig.gateway <<
                        " domainname=" << ipconfig.domainname <<
                        " name_servers=" << ipconfig.name_servers;
        }
        chromeos::FreeIPConfigStatus(ipconfig_status);
      }
    }
    if (service.type == chromeos::TYPE_ETHERNET) {
      ethernet->connecting = connecting;
      ethernet->connected = connected;
      ethernet->device_path = service.device_path ? service.device_path :
                                                    std::string();
      ethernet->ip_address = ip_address;
    } else if (service.type == chromeos::TYPE_WIFI) {
      wifi_networks->push_back(WifiNetwork(service.device_path ?
                                               service.device_path :
                                               std::string(),
                                           service.ssid,
                                           service.needs_passphrase,
                                           service.encryption,
                                           service.signal_strength,
                                           connecting,
                                           connected,
                                           ip_address));
    } else if (service.type == chromeos::TYPE_CELLULAR) {
      cellular_networks->push_back(CellularNetwork(service.device_path ?
                                                       service.device_path :
                                                       std::string(),
                                                   service.ssid,
                                                   service.signal_strength,
                                                   connecting,
                                                   connected,
                                                   ip_address));
    }
  }
}

void NetworkLibrary::Init() {
  // First, get the currently available networks.  This data is cached
  // on the connman side, so the call should be quick.
  chromeos::ServiceStatus* service_status = chromeos::GetAvailableNetworks();
  if (service_status) {
    LOG(INFO) << "Getting initial CrOS network info.";
    EthernetNetwork ethernet;
    WifiNetworkVector wifi_networks;
    CellularNetworkVector cellular_networks;
    ParseNetworks(*service_status, &ethernet, &wifi_networks,
        &cellular_networks);
    UpdateNetworkStatus(ethernet, wifi_networks, cellular_networks);
    chromeos::FreeServiceStatus(service_status);
  }
  LOG(INFO) << "Registering for network status updates.";
  // Now, register to receive updates on network status.
  network_status_connection_ = chromeos::MonitorNetworkStatus(
      &NetworkStatusChangedHandler, this);
  // Get the enabled network devices bit flag. If we get a -1, then that means
  // offline mode is on. So all devices are disabled. This happens when offline
  // mode is persisted during a reboot and Chrome starts up with it on.
  network_devices_ = chromeos::GetEnabledNetworkDevices();
  if (network_devices_ == -1) {
    offline_mode_ = true;
    network_devices_ = 0;
  }
}

void NetworkLibrary::EnableNetworkDevice(chromeos::ConnectionType device,
                                         bool enable) {
  if (!CrosLibrary::EnsureLoaded())
    return;

  // If network device is already enabled/disabled, then don't do anything.
  if (enable && (network_devices_ & device)) {
    LOG(INFO) << "Trying to enable a network device that's already enabled: "
              << device;
    return;
  }
  if (!enable && !(network_devices_ & device)) {
    LOG(INFO) << "Trying to disable a network device that's already disabled: "
              << device;
    return;
  }

  if (chromeos::EnableNetworkDevice(device, enable)) {
    if (enable)
      network_devices_ |= device;
    else
      network_devices_ &= ~device;
  }
}

void NetworkLibrary::UpdateNetworkStatus(const EthernetNetwork& ethernet,
    const WifiNetworkVector& wifi_networks,
    const CellularNetworkVector& cellular_networks) {
  // Make sure we run on UI thread.
  if (!ChromeThread::CurrentlyOn(ChromeThread::UI)) {
    ChromeThread::PostTask(
        ChromeThread::UI, FROM_HERE,
        NewRunnableMethod(this,
            &NetworkLibrary::UpdateNetworkStatus, ethernet, wifi_networks,
            cellular_networks));
    return;
  }

  ethernet_ = ethernet;
  wifi_networks_ = wifi_networks;
  // Sort the list of wifi networks by ssid.
  std::sort(wifi_networks_.begin(), wifi_networks_.end());
  wifi_ = WifiNetwork();
  for (size_t i = 0; i < wifi_networks_.size(); i++) {
    if (wifi_networks_[i].connecting || wifi_networks_[i].connected) {
      wifi_ = wifi_networks_[i];
      break;  // There is only one connected or connecting wifi network.
    }
  }
  cellular_networks_ = cellular_networks;
  std::sort(cellular_networks_.begin(), cellular_networks_.end());
  cellular_ = CellularNetwork();
  for (size_t i = 0; i < cellular_networks_.size(); i++) {
    if (cellular_networks_[i].connecting || cellular_networks_[i].connected) {
      cellular_ = cellular_networks_[i];
      break;  // There is only one connected or connecting cellular network.
    }
  }
  FOR_EACH_OBSERVER(Observer, observers_, NetworkChanged(this));
}

void NetworkLibrary::CheckNetworkTraffic(bool download) {
  // If we already have a pending upload and download notification, then
  // shortcut and return.
  if (traffic_type_ == (Observer::TRAFFIC_DOWNLOAD | Observer::TRAFFIC_UPLOAD))
    return;
  // Figure out if we are uploading and/or downloading. We are downloading
  // if download == true. We are uploading if we have upload progress.
  if (download)
    traffic_type_ |= Observer::TRAFFIC_DOWNLOAD;
  if ((traffic_type_ & Observer::TRAFFIC_UPLOAD) == 0) {
    URLRequestJobTracker::JobIterator it;
    for (it = g_url_request_job_tracker.begin();
         it != g_url_request_job_tracker.end();
         ++it) {
      URLRequestJob* job = *it;
      if (job->GetUploadProgress() > 0) {
        traffic_type_ |= Observer::TRAFFIC_UPLOAD;
        break;
      }
    }
  }
  // If we have new traffic data to send out and the timer is not currently
  // running, then start a new timer.
  if (traffic_type_ && !timer_.IsRunning()) {
    timer_.Start(base::TimeDelta::FromSeconds(kNetworkTrafficeTimerSecs), this,
                 &NetworkLibrary::NetworkTrafficTimerFired);
  }
}

void NetworkLibrary:: NetworkTrafficTimerFired() {
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE,
      NewRunnableMethod(this, &NetworkLibrary::NotifyNetworkTraffic,
                        traffic_type_));
  // Reset traffic type so that we don't send the same data next time.
  traffic_type_ = 0;
}

void NetworkLibrary::NotifyNetworkTraffic(int traffic_type) {
  FOR_EACH_OBSERVER(Observer, observers_, NetworkTraffic(this, traffic_type));
}

bool NetworkLibrary::Connected() const {
  return ethernet_connected() || wifi_connected() || cellular_connected();
}

bool NetworkLibrary::Connecting() const {
  return ethernet_connecting() || wifi_connecting() || cellular_connecting();
}

const std::string& NetworkLibrary::IPAddress() const {
  // Returns highest priority IP address.
  if (ethernet_connected())
    return ethernet_.ip_address;
  if (wifi_connected())
    return wifi_.ip_address;
  if (cellular_connected())
    return cellular_.ip_address;
  return ethernet_.ip_address;
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/*
 *      Author: Vladimir Ivan
 *
 * Copyright (c) 2017, University Of Edinburgh
 * 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  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.
 *
 */

#include <exotica/Problems/UnconstrainedTimeIndexedProblem.h>
#include <exotica/Setup.h>

REGISTER_PROBLEM_TYPE("UnconstrainedTimeIndexedProblem", exotica::UnconstrainedTimeIndexedProblem)

namespace exotica
{
UnconstrainedTimeIndexedProblem::UnconstrainedTimeIndexedProblem()
    : T(0), tau(0), Q_rate(0), W_rate(0), H_rate(0)
{
    Flags = KIN_FK | KIN_J;
}

UnconstrainedTimeIndexedProblem::~UnconstrainedTimeIndexedProblem()
{
}

void UnconstrainedTimeIndexedProblem::Instantiate(UnconstrainedTimeIndexedProblemInitializer& init)
{
    init_ = init;
    setT(init_.T);
    applyStartState(false);
    reinitializeVariables();
}

void UnconstrainedTimeIndexedProblem::reinitializeVariables()
{
    if (debug_) HIGHLIGHT_NAMED("UnconstrainedTimeIndexedProblem", "Initialize problem with T=" << T);

    setTau(init_.Tau);
    Q_rate = init_.Qrate;
    H_rate = init_.Hrate;
    W_rate = init_.Wrate;

    NumTasks = Tasks.size();
    PhiN = 0;
    JN = 0;
    TaskSpaceVector yref;
    for (int i = 0; i < NumTasks; i++)
    {
        appendVector(yref.map, Tasks[i]->getLieGroupIndices());
        PhiN += Tasks[i]->Length;
        JN += Tasks[i]->LengthJ;
    }

    N = scene_->getSolver().getNumControlledJoints();

    W = Eigen::MatrixXd::Identity(N, N) * W_rate;
    if (init_.W.rows() > 0)
    {
        if (init_.W.rows() == N)
        {
            W.diagonal() = init_.W * W_rate;
        }
        else
        {
            throw_named("W dimension mismatch! Expected " << N << ", got " << init_.W.rows());
        }
    }
    H = Eigen::MatrixXd::Identity(N, N) * Q_rate;
    Q = Eigen::MatrixXd::Identity(N, N) * H_rate;

    yref.setZero(PhiN);
    Phi.assign(T, yref);
    J.assign(T, Eigen::MatrixXd(JN, N));
    x.assign(T, Eigen::VectorXd::Zero(N));
    xdiff.assign(T, Eigen::VectorXd::Zero(N));

    preupdate();

    // Set initial trajectory with current state
    InitialTrajectory.resize(T, scene_->getControlledState());

    TaskSpaceVector dummy;
    Cost.initialize(init_.Cost, shared_from_this(), dummy);
}

void UnconstrainedTimeIndexedProblem::setT(int T_in)
{
    if (T_in <= 2)
    {
        throw_named("Invalid number of timesteps: " << T_in);
    }
    T = T_in;
    reinitializeVariables();
}

void UnconstrainedTimeIndexedProblem::setTau(double tau_in)
{
    if (tau_in <= 0.) throw_pretty("tau is expected to be greater than 0. (tau=" << tau_in << ")");
    tau = tau_in;
    ct = 1.0 / tau / T;
}

void UnconstrainedTimeIndexedProblem::preupdate()
{
    PlanningProblem::preupdate();
    for (int i = 0; i < Tasks.size(); i++) Tasks[i]->isUsed = false;
    Cost.updateS();
}

void UnconstrainedTimeIndexedProblem::setInitialTrajectory(
    const std::vector<Eigen::VectorXd> q_init_in)
{
    if (q_init_in.size() != T)
        throw_pretty("Expected initial trajectory of length "
                     << T << " but got " << q_init_in.size());
    if (q_init_in[0].rows() != N)
        throw_pretty("Expected states to have " << N << " rows but got "
                                                << q_init_in[0].rows());

    InitialTrajectory = q_init_in;
    setStartState(q_init_in[0]);
}

std::vector<Eigen::VectorXd> UnconstrainedTimeIndexedProblem::getInitialTrajectory()
{
    return InitialTrajectory;
}

double UnconstrainedTimeIndexedProblem::getDuration()
{
    return tau * (double)T;
}

void UnconstrainedTimeIndexedProblem::Update(Eigen::VectorXdRefConst x_in, int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }

    x[t] = x_in;
    scene_->Update(x_in, static_cast<double>(t) * tau);
    Phi[t].setZero(PhiN);
    J[t].setZero();
    for (int i = 0; i < NumTasks; i++)
    {
        // Only update TaskMap if Rho is not 0
        if (Tasks[i]->isUsed)
            Tasks[i]->update(x_in, Phi[t].data.segment(Tasks[i]->Start, Tasks[i]->Length), J[t].middleRows(Tasks[i]->StartJ, Tasks[i]->LengthJ));
    }
    Cost.update(Phi[t], J[t], t);
    // NB: The transition cost for the 0-th time step is set to 0 in the initialiser.
    if (t > 0) xdiff[t] = x[t] - x[t - 1];

    numberOfProblemUpdates++;
}

double UnconstrainedTimeIndexedProblem::getScalarTaskCost(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    return ct * Cost.ydiff[t].transpose() * Cost.S[t] * Cost.ydiff[t];
}

Eigen::VectorXd UnconstrainedTimeIndexedProblem::getScalarTaskJacobian(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    return Cost.J[t].transpose() * Cost.S[t] * Cost.ydiff[t] * 2.0 * ct;
}

double UnconstrainedTimeIndexedProblem::getScalarTransitionCost(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    else if (t == 0)
    {
        return 0;
    }
    return ct * xdiff[t].transpose() * W * xdiff[t];
}

Eigen::VectorXd UnconstrainedTimeIndexedProblem::getScalarTransitionJacobian(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    return 2.0 * ct * W * xdiff[t];
}

void UnconstrainedTimeIndexedProblem::setGoal(const std::string& task_name, Eigen::VectorXdRefConst goal, int t)
{
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            Cost.y[t].data.segment(Cost.Indexing[i].Start, Cost.Indexing[i].Length) = goal;
            return;
        }
    }
    throw_pretty("Cannot set Goal. Task map '" << task_name << "' does not exist.");
}

void UnconstrainedTimeIndexedProblem::setRho(const std::string& task_name, const double rho, int t)
{
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            Cost.Rho[t](Cost.Indexing[i].Id) = rho;
            return;
        }
    }
    throw_pretty("Cannot set Rho. Task map '" << task_name << "' does not exist.");
}

Eigen::VectorXd UnconstrainedTimeIndexedProblem::getGoal(const std::string& task_name, int t)
{
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            return Cost.y[t].data.segment(Cost.Indexing[i].Start, Cost.Indexing[i].Length);
        }
    }
    throw_pretty("Cannot get Goal. Task map '" << task_name << "' does not exist.");
}

double UnconstrainedTimeIndexedProblem::getRho(const std::string& task_name, int t)
{
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            return Cost.Rho[t](Cost.Indexing[i].Id);
        }
    }
    throw_pretty("Cannot get Rho. Task map '" << task_name << "' does not exist.");
}
}
<commit_msg>UnconstrainedTimeIndexedProblem: re-add lost t-indexing<commit_after>/*
 *      Author: Vladimir Ivan
 *
 * Copyright (c) 2017, University Of Edinburgh
 * 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  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.
 *
 */

#include <exotica/Problems/UnconstrainedTimeIndexedProblem.h>
#include <exotica/Setup.h>

REGISTER_PROBLEM_TYPE("UnconstrainedTimeIndexedProblem", exotica::UnconstrainedTimeIndexedProblem)

namespace exotica
{
UnconstrainedTimeIndexedProblem::UnconstrainedTimeIndexedProblem()
    : T(0), tau(0), Q_rate(0), W_rate(0), H_rate(0)
{
    Flags = KIN_FK | KIN_J;
}

UnconstrainedTimeIndexedProblem::~UnconstrainedTimeIndexedProblem()
{
}

void UnconstrainedTimeIndexedProblem::Instantiate(UnconstrainedTimeIndexedProblemInitializer& init)
{
    init_ = init;
    setT(init_.T);
    applyStartState(false);
    reinitializeVariables();
}

void UnconstrainedTimeIndexedProblem::reinitializeVariables()
{
    if (debug_) HIGHLIGHT_NAMED("UnconstrainedTimeIndexedProblem", "Initialize problem with T=" << T);

    setTau(init_.Tau);
    Q_rate = init_.Qrate;
    H_rate = init_.Hrate;
    W_rate = init_.Wrate;

    NumTasks = Tasks.size();
    PhiN = 0;
    JN = 0;
    TaskSpaceVector yref;
    for (int i = 0; i < NumTasks; i++)
    {
        appendVector(yref.map, Tasks[i]->getLieGroupIndices());
        PhiN += Tasks[i]->Length;
        JN += Tasks[i]->LengthJ;
    }

    N = scene_->getSolver().getNumControlledJoints();

    W = Eigen::MatrixXd::Identity(N, N) * W_rate;
    if (init_.W.rows() > 0)
    {
        if (init_.W.rows() == N)
        {
            W.diagonal() = init_.W * W_rate;
        }
        else
        {
            throw_named("W dimension mismatch! Expected " << N << ", got " << init_.W.rows());
        }
    }
    H = Eigen::MatrixXd::Identity(N, N) * Q_rate;
    Q = Eigen::MatrixXd::Identity(N, N) * H_rate;

    yref.setZero(PhiN);
    Phi.assign(T, yref);
    J.assign(T, Eigen::MatrixXd(JN, N));
    x.assign(T, Eigen::VectorXd::Zero(N));
    xdiff.assign(T, Eigen::VectorXd::Zero(N));

    preupdate();

    // Set initial trajectory with current state
    InitialTrajectory.resize(T, scene_->getControlledState());

    TaskSpaceVector dummy;
    Cost.initialize(init_.Cost, shared_from_this(), dummy);
}

void UnconstrainedTimeIndexedProblem::setT(int T_in)
{
    if (T_in <= 2)
    {
        throw_named("Invalid number of timesteps: " << T_in);
    }
    T = T_in;
    reinitializeVariables();
}

void UnconstrainedTimeIndexedProblem::setTau(double tau_in)
{
    if (tau_in <= 0.) throw_pretty("tau is expected to be greater than 0. (tau=" << tau_in << ")");
    tau = tau_in;
    ct = 1.0 / tau / T;
}

void UnconstrainedTimeIndexedProblem::preupdate()
{
    PlanningProblem::preupdate();
    for (int i = 0; i < Tasks.size(); i++) Tasks[i]->isUsed = false;
    Cost.updateS();
}

void UnconstrainedTimeIndexedProblem::setInitialTrajectory(
    const std::vector<Eigen::VectorXd> q_init_in)
{
    if (q_init_in.size() != T)
        throw_pretty("Expected initial trajectory of length "
                     << T << " but got " << q_init_in.size());
    if (q_init_in[0].rows() != N)
        throw_pretty("Expected states to have " << N << " rows but got "
                                                << q_init_in[0].rows());

    InitialTrajectory = q_init_in;
    setStartState(q_init_in[0]);
}

std::vector<Eigen::VectorXd> UnconstrainedTimeIndexedProblem::getInitialTrajectory()
{
    return InitialTrajectory;
}

double UnconstrainedTimeIndexedProblem::getDuration()
{
    return tau * (double)T;
}

void UnconstrainedTimeIndexedProblem::Update(Eigen::VectorXdRefConst x_in, int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }

    x[t] = x_in;
    scene_->Update(x_in, static_cast<double>(t) * tau);
    Phi[t].setZero(PhiN);
    J[t].setZero();
    for (int i = 0; i < NumTasks; i++)
    {
        // Only update TaskMap if Rho is not 0
        if (Tasks[i]->isUsed)
            Tasks[i]->update(x_in, Phi[t].data.segment(Tasks[i]->Start, Tasks[i]->Length), J[t].middleRows(Tasks[i]->StartJ, Tasks[i]->LengthJ));
    }
    Cost.update(Phi[t], J[t], t);
    // NB: The transition cost for the 0-th time step is set to 0 in the initialiser.
    if (t > 0) xdiff[t] = x[t] - x[t - 1];

    numberOfProblemUpdates++;
}

double UnconstrainedTimeIndexedProblem::getScalarTaskCost(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    return ct * Cost.ydiff[t].transpose() * Cost.S[t] * Cost.ydiff[t];
}

Eigen::VectorXd UnconstrainedTimeIndexedProblem::getScalarTaskJacobian(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    return Cost.J[t].transpose() * Cost.S[t] * Cost.ydiff[t] * 2.0 * ct;
}

double UnconstrainedTimeIndexedProblem::getScalarTransitionCost(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    else if (t == 0)
    {
        return 0;
    }
    return ct * xdiff[t].transpose() * W * xdiff[t];
}

Eigen::VectorXd UnconstrainedTimeIndexedProblem::getScalarTransitionJacobian(int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    return 2.0 * ct * W * xdiff[t];
}

void UnconstrainedTimeIndexedProblem::setGoal(const std::string& task_name, Eigen::VectorXdRefConst goal, int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            Cost.y[t].data.segment(Cost.Indexing[i].Start, Cost.Indexing[i].Length) = goal;
            return;
        }
    }
    throw_pretty("Cannot set Goal. Task map '" << task_name << "' does not exist.");
}

void UnconstrainedTimeIndexedProblem::setRho(const std::string& task_name, const double rho, int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            Cost.Rho[t](Cost.Indexing[i].Id) = rho;
            return;
        }
    }
    throw_pretty("Cannot set Rho. Task map '" << task_name << "' does not exist.");
}

Eigen::VectorXd UnconstrainedTimeIndexedProblem::getGoal(const std::string& task_name, int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            return Cost.y[t].data.segment(Cost.Indexing[i].Start, Cost.Indexing[i].Length);
        }
    }
    throw_pretty("Cannot get Goal. Task map '" << task_name << "' does not exist.");
}

double UnconstrainedTimeIndexedProblem::getRho(const std::string& task_name, int t)
{
    if (t >= T || t < -1)
    {
        throw_pretty("Requested t=" << t << " out of range, needs to be 0 =< t < " << T);
    }
    else if (t == -1)
    {
        t = T - 1;
    }
    for (int i = 0; i < Cost.Indexing.size(); i++)
    {
        if (Cost.Tasks[i]->getObjectName() == task_name)
        {
            return Cost.Rho[t](Cost.Indexing[i].Id);
        }
    }
    throw_pretty("Cannot get Rho. Task map '" << task_name << "' does not exist.");
}
}
<|endoftext|>


<commit_before>#include "uspeech.h"

syllable::syllable(){
    f = 0; e = 0; o = 0; s = 0; h = 0; v = 0;
	length = 0; cf = 0; ce = 0; co = 0; cs = 0; ch = 0; cv = 0;
	modalityf = 0; modalitye = 0; modalityo = 0; modalitys = 0; modalityh = 0; modalityv = 0;
	expectSp =1; plosiveCount = 0;

}
void syllable::reset(){
    f = 0; e = 0; o = 0; s = 0; h = 0; v = 0;
	length = 0; cf = 0; ce = 0; co = 0; cs = 0; ch = 0; cv = 0;
	modalityf = 0; modalitye = 0; modalityo = 0; modalitys = 0; modalityh = 0; modalityv = 0;
	expectSp =1; plosiveCount = 0;
}
/***
 *  Classify a character into f,e,o,s,h; Call during main loop
 *  @param c    the phoneme
 */
void syllable::classify(char c){
	length++;
	if(expectSp==0){
		if(c!=' '){ //I don't trust the compiler's optimizer
			expectSp = 1;
			if((millis()-lastTime)<MAX_PLOSIVETIME){
				plosiveCount++;
			}
		}
	}
    switch (c) {
        case 'f':
            	f++;
		cf++;
            	break;
        case 'e':
            	e++;
		ce++;
            	break;
        case 'o':
            	o++;
		co++;
            	break;
        case 'v':
		v++;
		cv++;
            	break;
        case 'h':
		h++;
		ch++;
            	break;
        case 's':
		s++;
		cs++;
           	break;
	case ' ':
		if(expectSp!=0){
			expectSp = 0;
#if ARDUINO_ENVIRONMENT > 0
			lastTime = millis();
#endif
		}
		else{
		}
		break;
        default:
		break;
    	}
	//Repeat every
	if ((length&PROCESS_SKEWNESS_TIME) == 0){
		if((cf > prevf)&(prevf<PROCESS_SKEWNESS_TIME)){
			prevf = cf;
			maxf = length;
			if(currPeak != 'f'){
				currPeak = 'f';
				modalityf++;
			}
		}
		if((ce > preve)&(preve<PROCESS_SKEWNESS_TIME)){
			preve = ce;
			maxe = length;
			if(currPeak != 'e'){
				currPeak = 'e';
				modalitye++;
			}
		}
		if((co > prevo)&(prevo<PROCESS_SKEWNESS_TIME)){
			prevo = co;
			maxo = length;
			if(currPeak != 'o'){
				currPeak = 'o';
				modalityo++;
			}
		}
		if((cs > prevs)&(prevs<PROCESS_SKEWNESS_TIME)){
			prevs = cs;
			maxs = length;
			if(currPeak != 's'){
				currPeak = 's';
				modalitys++;
			}
		}
		if((ch > prevh)&(prevh<PROCESS_SKEWNESS_TIME)){
			prevh = ch;
			maxh = length;
			if(currPeak != 'h'){
				currPeak = 'h';
				modalityh++;
			}
		}
		if((cv > prevv)&(prevv<15)){
			prevv = cv;
			maxv = length;
			if(currPeak != 'v'){
				currPeak = 'v';
				modalityv++;
			}
		}
		cf = 0; ce = 0; co = 0; cs = 0; ch = 0; cv = 0;
	}
}

#if ARDUINO_ENVIRONMENT > 0
void syllable::debugPrint(){
    	Serial.print("{Accum: [ ");
    	Serial.print(f);
    	Serial.print(", ");
    	Serial.print(e);
    	Serial.print(", ");
    	Serial.print(o);
    	Serial.print(", ");
    	Serial.print(v);
    	Serial.print(", ");
    	Serial.print(h);
    	Serial.print(", ");
    	Serial.print(s);
    	Serial.print("], \n");
	Serial.print("Modality: [");
	Serial.print(modalityf);
	Serial.print(",");
	Serial.print(modalitye);
	Serial.print(",");
	Serial.print(modalityo);
	Serial.print(",");
	Serial.print(modalityv);
	Serial.print(",");
	Serial.print(modalitys);
	Serial.print(",");
	Serial.print(modalityh);
	Serial.print("],");
	Serial.print("Peak:[");
	Serial.print(maxf);
	Serial.print(",\n");
	Serial.print(maxe);
	Serial.print(",");
	Serial.print(maxo);
	Serial.print(",");
	Serial.print(maxv);
	Serial.print(",");
	Serial.print(maxs);
	Serial.print(",");
	Serial.print(maxh);
	Serial.print("],\n");
	Serial.print("length:");
	Serial.print(length);
	Serial.print(",\nplosives:");
	Serial.print(plosiveCount);
	Serial.print(" }");

}
#endif

int* syllable::tointptr(){
    	static int matrix[20];
    	matrix[0] = f;
    	matrix[1] = e;
    	matrix[2] = o;
    	matrix[3] = v;
    	matrix[4] = s;
    	matrix[5] = h;
	matrix[6] = modalityf;
        matrix[7] = modalitye;
        matrix[8] = modalityo;
        matrix[9] = modalityv;
        matrix[10] = modalitys;
        matrix[11] = modalityh;
	matrix[12] = maxf;
        matrix[13] = maxe;
        matrix[14] = maxo;
        matrix[15] = maxv;
        matrix[16] = maxs;
        matrix[17] = maxh;
	matrix[18] = length;
    	matrix[19] = plosiveCount;
	return matrix;
}
void syllable::distance(syllable s){
}
<commit_msg>Fixed some indents.<commit_after>#include "uspeech.h"

syllable::syllable(){
        f = 0; e = 0; o = 0; s = 0; h = 0; v = 0;
	length = 0; cf = 0; ce = 0; co = 0; cs = 0; ch = 0; cv = 0;
	modalityf = 0; modalitye = 0; modalityo = 0; modalitys = 0; modalityh = 0; modalityv = 0;
	expectSp =1; plosiveCount = 0;

}
void syllable::reset(){
        f = 0; e = 0; o = 0; s = 0; h = 0; v = 0;
	length = 0; cf = 0; ce = 0; co = 0; cs = 0; ch = 0; cv = 0;
	modalityf = 0; modalitye = 0; modalityo = 0; modalitys = 0; modalityh = 0; modalityv = 0;
	expectSp =1; plosiveCount = 0;
}
/***
 *  Classify a character into f,e,o,s,h; Call during main loop
 *  @param c    the phoneme
 */
void syllable::classify(char c){
	length++;
	if(expectSp==0){
		if(c!=' '){ //I don't trust the compiler's optimizer
			expectSp = 1;
			if((millis()-lastTime)<MAX_PLOSIVETIME){
				plosiveCount++;
			}
		}
	}
    switch (c) {
        case 'f':
            	f++;
		cf++;
            	break;
        case 'e':
            	e++;
		ce++;
            	break;
        case 'o':
            	o++;
		co++;
            	break;
        case 'v':
		v++;
		cv++;
            	break;
        case 'h':
		h++;
		ch++;
            	break;
        case 's':
		s++;
		cs++;
           	break;
	case ' ':
		if(expectSp!=0){
			expectSp = 0;
#if ARDUINO_ENVIRONMENT > 0
			lastTime = millis();
#endif
		}
		else{
		}
		break;
        default:
		break;
    	}
	//Repeat every
	if ((length&PROCESS_SKEWNESS_TIME) == 0){
		if((cf > prevf)&(prevf<PROCESS_SKEWNESS_TIME)){
			prevf = cf;
			maxf = length;
			if(currPeak != 'f'){
				currPeak = 'f';
				modalityf++;
			}
		}
		if((ce > preve)&(preve<PROCESS_SKEWNESS_TIME)){
			preve = ce;
			maxe = length;
			if(currPeak != 'e'){
				currPeak = 'e';
				modalitye++;
			}
		}
		if((co > prevo)&(prevo<PROCESS_SKEWNESS_TIME)){
			prevo = co;
			maxo = length;
			if(currPeak != 'o'){
				currPeak = 'o';
				modalityo++;
			}
		}
		if((cs > prevs)&(prevs<PROCESS_SKEWNESS_TIME)){
			prevs = cs;
			maxs = length;
			if(currPeak != 's'){
				currPeak = 's';
				modalitys++;
			}
		}
		if((ch > prevh)&(prevh<PROCESS_SKEWNESS_TIME)){
			prevh = ch;
			maxh = length;
			if(currPeak != 'h'){
				currPeak = 'h';
				modalityh++;
			}
		}
		if((cv > prevv)&(prevv<15)){
			prevv = cv;
			maxv = length;
			if(currPeak != 'v'){
				currPeak = 'v';
				modalityv++;
			}
		}
		cf = 0; ce = 0; co = 0; cs = 0; ch = 0; cv = 0;
	}
}

#if ARDUINO_ENVIRONMENT > 0
void syllable::debugPrint(){
    	Serial.print("{Accum: [ ");
    	Serial.print(f);
    	Serial.print(", ");
    	Serial.print(e);
    	Serial.print(", ");
    	Serial.print(o);
    	Serial.print(", ");
    	Serial.print(v);
    	Serial.print(", ");
    	Serial.print(h);
    	Serial.print(", ");
    	Serial.print(s);
    	Serial.print("], \n");
	Serial.print("Modality: [");
	Serial.print(modalityf);
	Serial.print(",");
	Serial.print(modalitye);
	Serial.print(",");
	Serial.print(modalityo);
	Serial.print(",");
	Serial.print(modalityv);
	Serial.print(",");
	Serial.print(modalitys);
	Serial.print(",");
	Serial.print(modalityh);
	Serial.print("],");
	Serial.print("Peak:[");
	Serial.print(maxf);
	Serial.print(",\n");
	Serial.print(maxe);
	Serial.print(",");
	Serial.print(maxo);
	Serial.print(",");
	Serial.print(maxv);
	Serial.print(",");
	Serial.print(maxs);
	Serial.print(",");
	Serial.print(maxh);
	Serial.print("],\n");
	Serial.print("length:");
	Serial.print(length);
	Serial.print(",\nplosives:");
	Serial.print(plosiveCount);
	Serial.print(" }");

}
#endif

int* syllable::tointptr(){
    	static int matrix[20];
    	matrix[0] = f;
    	matrix[1] = e;
    	matrix[2] = o;
    	matrix[3] = v;
    	matrix[4] = s;
    	matrix[5] = h;
	matrix[6] = modalityf;
        matrix[7] = modalitye;
        matrix[8] = modalityo;
        matrix[9] = modalityv;
        matrix[10] = modalitys;
        matrix[11] = modalityh;
	matrix[12] = maxf;
        matrix[13] = maxe;
        matrix[14] = maxo;
        matrix[15] = maxv;
        matrix[16] = maxs;
        matrix[17] = maxh;
	matrix[18] = length;
    	matrix[19] = plosiveCount;
	return matrix;
}
void syllable::distance(syllable s){
}
<|endoftext|>


<commit_before>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "kernel/userver.hh"

#include "object/urbi-exception.hh"

#include "scheduler/scheduler.hh"
#include "scheduler/job.hh"

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job (void* job)
  {
    static_cast<Job*>(job)->run();
  }

  void
  Scheduler::add_job (Job* job)
  {
    assert (job);
    assert (!libport::has (jobs_, job));
    assert (!libport::has (jobs_to_start_, job));
    jobs_to_start_.push_back (job);
  }

  libport::utime_t
  Scheduler::work ()
  {
#ifdef ENABLE_DEBUG_TRACES
    static int cycle = 0;
#endif
    ECHO ("======================================================== cycle "
	  << ++cycle);

    // Start new jobs
    to_start_.clear ();
    std::swap (to_start_, jobs_to_start_);
    foreach (Job* job, to_start_)
    {
      assert (job);
      ECHO ("will start job " << *job);
      // Job will start for a very short time and do a yield_front() to
      // be restarted below in the course of the regular cycle.
      assert (!current_job_);
      current_job_ = job;
      Coro_startCoro_ (self_, job->coro_get(), job, run_job);
      // We have to assume that a new job may have had side-effects.
      possible_side_effect_ = true;
    }

    // Start deferred jobs
    for (libport::utime_t current_time = ::urbiserver->getTime ();
	 !deferred_jobs_.empty();
	 deferred_jobs_.pop ())
    {
      deferred_job j = deferred_jobs_.top ();
      if (current_time < j.get<0>())
	break;
      jobs_.push_back (j.get<1> ());
    }

    // If something is going to happen, or if we have just started a
    // new job, add the list of jobs waiting for something to happen
    // on the pending jobs queue.
    if (!if_change_jobs_.empty() && (possible_side_effect_ || !jobs_.empty()))
    {
      foreach (Job* job, if_change_jobs_)
	jobs_.push_back (job);
      if_change_jobs_.clear ();
    }

    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    possible_side_effect_ = false;
    pending_.clear ();
    std::swap (pending_, jobs_);

    ECHO (pending_.size() << " jobs in the queue for this cycle");
    foreach (Job* job, pending_)
    {
      assert (job);
      assert (!job->terminated ());
      ECHO ("will resume job " << *job);
      possible_side_effect_ |= !job->side_effect_free_get ();
      Coro_switchTo_ (self_, job->coro_get ());
      possible_side_effect_ |= !job->side_effect_free_get ();
      ECHO ("back from job " << *job);
    }

    // Do we have some work to do now?
    if (!jobs_.empty () || !jobs_to_start_.empty())
    {
      ECHO ("scheduler: asking to be recalled ASAP, " << jobs_.size() << " jobs ready and " << jobs_to_start_.size()
	    << " to start");
      return 0;
    }

    // Do we have deferred jobs?
    if (!deferred_jobs_.empty ())
    {
      ECHO ("scheduler: asking to be recalled later");
      return deferred_jobs_.top ().get<0> ();
    }

    // Ok, let's say, we'll be called again in one hour.
    ECHO ("scheduler: asking to be recalled in a long time");
    return ::urbiserver->getTime() + 3600000000LL;
  }

  void
  Scheduler::switch_back (Job* job)
  {
    // Switch back to the scheduler.
    assert (current_job_ == job);
    current_job_ = 0;
    Coro_switchTo_ (job->coro_get (), self_);
    // We regained control, we are again in the context of the job.
    assert (!current_job_);
    current_job_ = job;
    ECHO ("job " << *job << " resumed");
    // Check that we are not near exhausting the stack space.
    if (Coro_stackSpaceAlmostGone (job->coro_get ()))
      throw object::StackExhaustedError ("stack space exhausted");
    // Execute a deferred exception if any
    job->check_for_pending_exception ();
  }

  void
  Scheduler::resume_scheduler (Job* job)
  {
    // If the job has not terminated, put it at the back of the run queue
    // so that the run queue order is preserved between work cycles.
    if (!job->terminated ())
      jobs_.push_back (job);
    ECHO (*job << " has " << (job->terminated () ? "" : "not ") << "terminated");
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_front (Job* job)
  {
    // Put the job in front of the queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    jobs_.push_front (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_until (Job* job, libport::utime_t deadline)
  {
    // Put the job in the deferred queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    deferred_jobs_.push (boost::make_tuple (deadline, job));
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_suspend (Job* job)
  {
    suspended_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_things_changed (Job* job)
  {
    if_change_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_job (Job* job)
  {
    // Suspended job may have been killed externally, in which case it
    // will not appear in the list of suspended jobs.

    if (libport::has (suspended_jobs_, job))
    {
      jobs_.push_back (job);
      suspended_jobs_.remove (job);
    }
  }

  void
  Scheduler::killall_jobs ()
  {
    ECHO ("killing all jobs!");

    // This implementation is quite inefficient because it will call
    // kill_job() for each job. But who cares? We are killing everyone
    // anyway.

    while (!jobs_to_start_.empty ())
      jobs_to_start_.pop_front ();

    while (!suspended_jobs_.empty ())
      kill_job (suspended_jobs_.front ());

    while (!if_change_jobs_.empty ())
      kill_job (if_change_jobs_.front ());

    while (!jobs_.empty ())
      kill_job (jobs_.front ());

    while (!deferred_jobs_.empty ())
      kill_job (deferred_jobs_.top ().get<1>());
  }

  void
  Scheduler::unschedule_job (Job* job)
  {
    assert (job);
    if (job == current_job_)
    {
      std::cerr << *job << " asked to unschedule itself\n";
    }
    assert (job != current_job_);

    ECHO ("unscheduling job " << *job);

    // First of all, tell the job it has been terminated unless it has
    // been registered with us but not yet started.
    if (!libport::has (jobs_to_start_, job))
      job->terminate_now ();

    // Remove the job from the queues where it could be stored.
    jobs_to_start_.remove (job);
    jobs_.remove (job);
    suspended_jobs_.remove (job);
    if_change_jobs_.remove (job);

    // Remove it from live queues as well if the job is destroyed.
    to_start_.remove (job);
    pending_.remove (job);

    // We have no remove() on a priority queue, regenerate a queue without
    // this job.
    {
      deferred_jobs old_deferred;
      std::swap (old_deferred, deferred_jobs_);
      while (!old_deferred.empty ())
      {
	deferred_job j = old_deferred.top ();
	old_deferred.pop ();
	if (j.get<1>() != job)
	  deferred_jobs_.push (j);
      }
    }
  }

  void
  Scheduler::kill_job (Job* job)
  {
    assert (job != current_job_);

    ECHO ("deleting job " << *job);
    delete job;
  }

  bool operator> (const deferred_job& left, const deferred_job& right)
  {
    return left.get<0>() > right.get<0>();
  }

} // namespace scheduler
<commit_msg>Add extra traces<commit_after>/**
 ** \file scheduler/scheduler.cc
 ** \brief Implementation of scheduler::Scheduler.
 */

//#define ENABLE_DEBUG_TRACES

#include <cassert>

#include <libport/compiler.hh>
#include <libport/containers.hh>
#include <libport/foreach.hh>

#include "kernel/userver.hh"

#include "object/urbi-exception.hh"

#include "scheduler/scheduler.hh"
#include "scheduler/job.hh"

namespace scheduler
{

  // This function is required to start a new job using the libcoroutine.
  // Its only purpose is to create the context and start the execution
  // of the new job.
  static void
  run_job (void* job)
  {
    static_cast<Job*>(job)->run();
  }

  void
  Scheduler::add_job (Job* job)
  {
    assert (job);
    assert (!libport::has (jobs_, job));
    assert (!libport::has (jobs_to_start_, job));
    jobs_to_start_.push_back (job);
  }

  libport::utime_t
  Scheduler::work ()
  {
#ifdef ENABLE_DEBUG_TRACES
    static int cycle = 0;
#endif
    ECHO ("======================================================== cycle "
	  << ++cycle);

    // Start new jobs
    to_start_.clear ();
    std::swap (to_start_, jobs_to_start_);
    foreach (Job* job, to_start_)
    {
      assert (job);
      ECHO ("will start job " << *job);
      // Job will start for a very short time and do a yield_front() to
      // be restarted below in the course of the regular cycle.
      assert (!current_job_);
      current_job_ = job;
      Coro_startCoro_ (self_, job->coro_get(), job, run_job);
      // We have to assume that a new job may have had side-effects.
      possible_side_effect_ = true;
    }

    // Start deferred jobs
    for (libport::utime_t current_time = ::urbiserver->getTime ();
	 !deferred_jobs_.empty();
	 deferred_jobs_.pop ())
    {
      deferred_job j = deferred_jobs_.top ();
      if (current_time < j.get<0>())
	break;
      jobs_.push_back (j.get<1> ());
    }

    // If something is going to happen, or if we have just started a
    // new job, add the list of jobs waiting for something to happen
    // on the pending jobs queue.
    if (!if_change_jobs_.empty() && (possible_side_effect_ || !jobs_.empty()))
    {
      foreach (Job* job, if_change_jobs_)
	jobs_.push_back (job);
      if_change_jobs_.clear ();
    }

    // Run all the jobs in the run queue once. If any job declares upon entry or
    // return that it is not side-effect free, we remember that for the next
    // cycle.
    possible_side_effect_ = false;
    pending_.clear ();
    std::swap (pending_, jobs_);

    ECHO (pending_.size() << " jobs in the queue for this cycle");
    foreach (Job* job, pending_)
    {
      assert (job);
      assert (!job->terminated ());
      ECHO ("will resume job " << *job << (job->side_effect_free_get() ? " (side-effect free)" : ""));
      possible_side_effect_ |= !job->side_effect_free_get ();
      Coro_switchTo_ (self_, job->coro_get ());
      possible_side_effect_ |= !job->side_effect_free_get ();
      ECHO ("back from job " << *job << (job->side_effect_free_get() ? " (side-effect free)" : ""));
    }

    // Do we have some work to do now?
    if (!jobs_.empty () || !jobs_to_start_.empty())
    {
      ECHO ("scheduler: asking to be recalled ASAP, " << jobs_.size() << " jobs ready and " << jobs_to_start_.size()
	    << " to start");
      return 0;
    }

    // Do we have deferred jobs?
    if (!deferred_jobs_.empty ())
    {
      ECHO ("scheduler: asking to be recalled later");
      return deferred_jobs_.top ().get<0> ();
    }

    // Ok, let's say, we'll be called again in one hour.
    ECHO ("scheduler: asking to be recalled in a long time");
    return ::urbiserver->getTime() + 3600000000LL;
  }

  void
  Scheduler::switch_back (Job* job)
  {
    // Switch back to the scheduler.
    assert (current_job_ == job);
    current_job_ = 0;
    Coro_switchTo_ (job->coro_get (), self_);
    // We regained control, we are again in the context of the job.
    assert (!current_job_);
    current_job_ = job;
    ECHO ("job " << *job << " resumed");
    // Check that we are not near exhausting the stack space.
    if (Coro_stackSpaceAlmostGone (job->coro_get ()))
      throw object::StackExhaustedError ("stack space exhausted");
    // Execute a deferred exception if any
    job->check_for_pending_exception ();
  }

  void
  Scheduler::resume_scheduler (Job* job)
  {
    // If the job has not terminated, put it at the back of the run queue
    // so that the run queue order is preserved between work cycles.
    if (!job->terminated ())
      jobs_.push_back (job);
    ECHO (*job << " has " << (job->terminated () ? "" : "not ") << "terminated");
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_front (Job* job)
  {
    // Put the job in front of the queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    jobs_.push_front (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_until (Job* job, libport::utime_t deadline)
  {
    // Put the job in the deferred queue. If the job asks to be requeued,
    // it is not terminated.
    assert (!job->terminated ());
    deferred_jobs_.push (boost::make_tuple (deadline, job));
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_suspend (Job* job)
  {
    suspended_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_scheduler_things_changed (Job* job)
  {
    if_change_jobs_.push_back (job);
    switch_back (job);
  }

  void
  Scheduler::resume_job (Job* job)
  {
    // Suspended job may have been killed externally, in which case it
    // will not appear in the list of suspended jobs.

    if (libport::has (suspended_jobs_, job))
    {
      jobs_.push_back (job);
      suspended_jobs_.remove (job);
    }
  }

  void
  Scheduler::killall_jobs ()
  {
    ECHO ("killing all jobs!");

    // This implementation is quite inefficient because it will call
    // kill_job() for each job. But who cares? We are killing everyone
    // anyway.

    while (!jobs_to_start_.empty ())
      jobs_to_start_.pop_front ();

    while (!suspended_jobs_.empty ())
      kill_job (suspended_jobs_.front ());

    while (!if_change_jobs_.empty ())
      kill_job (if_change_jobs_.front ());

    while (!jobs_.empty ())
      kill_job (jobs_.front ());

    while (!deferred_jobs_.empty ())
      kill_job (deferred_jobs_.top ().get<1>());
  }

  void
  Scheduler::unschedule_job (Job* job)
  {
    assert (job);
    if (job == current_job_)
    {
      std::cerr << *job << " asked to unschedule itself\n";
    }
    assert (job != current_job_);

    ECHO ("unscheduling job " << *job);

    // First of all, tell the job it has been terminated unless it has
    // been registered with us but not yet started.
    if (!libport::has (jobs_to_start_, job))
      job->terminate_now ();

    // Remove the job from the queues where it could be stored.
    jobs_to_start_.remove (job);
    jobs_.remove (job);
    suspended_jobs_.remove (job);
    if_change_jobs_.remove (job);

    // Remove it from live queues as well if the job is destroyed.
    to_start_.remove (job);
    pending_.remove (job);

    // We have no remove() on a priority queue, regenerate a queue without
    // this job.
    {
      deferred_jobs old_deferred;
      std::swap (old_deferred, deferred_jobs_);
      while (!old_deferred.empty ())
      {
	deferred_job j = old_deferred.top ();
	old_deferred.pop ();
	if (j.get<1>() != job)
	  deferred_jobs_.push (j);
      }
    }
  }

  void
  Scheduler::kill_job (Job* job)
  {
    assert (job != current_job_);

    ECHO ("deleting job " << *job);
    delete job;
  }

  bool operator> (const deferred_job& left, const deferred_job& right)
  {
    return left.get<0>() > right.get<0>();
  }

} // namespace scheduler
<|endoftext|>


<commit_before><commit_msg>* notify theme loading with --load-extension * fix crasher in theme parsing with no images<commit_after><|endoftext|>