<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "ProguardReporting.h"
#include "DexClass.h"
#include "ReachableClasses.h"

std::string extract_suffix(std::string class_name) {
  auto i = class_name.find_last_of(".");
  if (i == std::string::npos) {
    // This is a class name with no package prefix.
    return class_name;
  }
  return class_name.substr(i + 1);
}

std::string redex::dexdump_name_to_dot_name(const std::string& dexdump_name) {
  assert(!dexdump_name.empty());
  std::string s;
  for (const char& ch : dexdump_name.substr(1)) {
    if (ch == '/') {
      s += '.';
      continue;
    }
    if (ch == ';') {
      continue;
    }
    s += ch;
  }
  return s;
}

std::string type_descriptor_to_java(const std::string& descriptor) {
  assert(!descriptor.empty());
  if (descriptor[0] == '[') {
    return type_descriptor_to_java(descriptor.substr(1)) + "[]";
  }
  if (descriptor == "B") {
    return "byte";
  }
  if (descriptor == "S") {
    return "short";
  }
  if (descriptor == "I") {
    return "int";
  }
  if (descriptor == "J") {
    return "long";
  }
  if (descriptor == "C") {
    return "char";
  }
  if (descriptor == "F") {
    return "float";
  }
  if (descriptor == "D") {
    return "double";
  }
  if (descriptor == "Z") {
    return "boolean";
  }
  if (descriptor == "V") {
    return "void";
  }
  if (descriptor[0] == 'L') {
    return redex::dexdump_name_to_dot_name(descriptor);
  }
  std::cerr
      << "type_descriptor_to_java: unexpected type descriptor " << descriptor
      << std::endl;
  exit(2);
}

std::string extract_field_name(std::string qualified) {
  auto semicolon = qualified.find(";");
  auto colon = qualified.find(":");
  return qualified.substr(semicolon + 2, colon - semicolon - 2);
}

std::string extract_method_name(std::string qualified) {
  auto dot = qualified.find(".");
  auto open = qualified.find(":");
  return qualified.substr(dot + 1, open - dot - 1);
}

// Convert a type descriptor that may contain obfuscated class names
// into the corresponding type descriptor with the class types deobfuscated.
// The incomming type descriptor is a chain of types which may be primitive
// types, array types or class types. For example [[A; -> [[Lcom.wombat.Numbat;
std::string deobfuscate_type_descriptor(const ProguardMap& pg_map,
                                        const std::string& desc) {
  assert(!desc.empty());
  std::string deob;
  size_t i = 0;
  while (i < desc.size()) {
    if (desc[i] == 'L') {
      auto colon = desc.find(";");
      assert(colon != std::string::npos);
      auto class_type = desc.substr(i, colon + 1);
      auto deob_class = pg_map.deobfuscate_class(class_type);
      if (deob_class.empty()) {
        std::cerr << "Warning: failed to deobfuscate class " << class_type
                  << std::endl;
        deob_class = class_type;
      }
      deob += deob_class;
      i = colon + 1;
      continue;
    }
    deob += desc[i];
    i++;
  }
  return deob;
}

std::string form_java_args(const ProguardMap& pg_map,
                           const std::list<DexType*>& args) {
  std::string s;
  unsigned long i = 0;
  for (const auto& arg : args) {
    auto desc = arg->get_name()->c_str();
    auto deobfu_desc = deobfuscate_type_descriptor(pg_map, desc);
    s += type_descriptor_to_java(deobfu_desc);
    if (i < args.size() - 1) {
      s += ",";
    }
    i++;
  }
  return s;
}

std::string java_args(const ProguardMap& pg_map, std::list<DexType*>& args) {
  std::string str = "(";
  str += form_java_args(pg_map, args);
  str += ")";
  return str;
}

void redex::print_method(std::ostream& output,
                         const ProguardMap& pg_map,
                         const std::string& class_name,
                         const DexMethod* method) {
  std::string method_name = extract_method_name(method->get_name()->c_str());
  // Record if this is a constriuctor to supress return value printing
  // beforer the method name.
  bool is_constructor{false};
  if (is_any_init(method)) {
    method_name = extract_suffix(class_name);
    is_constructor = true;
  } else {
    auto deob = method->get_deobfuscated_name();
    if (deob.empty()) {
      std::cerr << "WARNING: method has no deobfu: " << method_name
                << std::endl;
    } else {
      method_name = extract_method_name(deob);
    }
  }
  auto proto = method->get_proto();
  auto args = proto->get_args()->get_type_list();
  auto return_type = proto->get_rtype();
  output << class_name << ": ";
  if (!is_constructor) {
    auto return_type_desc = return_type->get_name()->c_str();
    auto deobfu_return_type =
        deobfuscate_type_descriptor(pg_map, return_type_desc);
    output << type_descriptor_to_java(deobfu_return_type) << " ";
  }
  output << method_name << java_args(pg_map, args) << std::endl;
}

void redex::print_methods(std::ostream& output,
                          const ProguardMap& pg_map,
                          const std::string& class_name,
                          const std::list<DexMethod*>& methods) {
  for (const auto& method : methods) {
    redex::print_method(output, pg_map, class_name, method);
  }
}

void redex::print_field(std::ostream& output,
                        const ProguardMap& pg_map,
                        const std::string& class_name,
                        const DexField* field) {
  auto field_name = field->get_deobfuscated_name();
  auto field_type = field->get_type()->get_name()->c_str();
  std::string deobfu_field_type = field_type;
  if (field_type[0] == 'L') {
    deobfu_field_type = pg_map.deobfuscate_class(field_type);
  }
  output << class_name << ": " << type_descriptor_to_java(deobfu_field_type)
         << " " << extract_field_name(field->get_deobfuscated_name())
         << std::endl;
}

void redex::print_fields(std::ostream& output,
                         const ProguardMap& pg_map,
                         const std::string& class_name,
                         const std::list<DexField*>& fields) {
  for (const auto& field : fields) {
    redex::print_field(output, pg_map, class_name, field);
  }
}

void redex::print_class(std::ostream& output,
                        const ProguardMap& pg_map,
                        const DexClass* cls) {
  auto deob = cls->get_deobfuscated_name();
  if (deob.empty()) {
    std::cerr << "WARNING: this class has no deobu name: "
              << cls->get_name()->c_str() << std::endl;
    deob = cls->get_name()->c_str();
  }
  std::string name = redex::dexdump_name_to_dot_name(deob);
  output << name << std::endl;
  print_fields(output, pg_map, name, cls->get_ifields());
  print_fields(output, pg_map, name, cls->get_sfields());
  print_methods(output, pg_map, name, cls->get_dmethods());
  print_methods(output, pg_map, name, cls->get_vmethods());
}

void redex::print_classes(std::ostream& output,
                          const ProguardMap& pg_map,
                          const Scope& classes) {
  for (const auto& cls : classes) {
    if (!cls->is_external()) {
      redex::print_class(output, pg_map, cls);
    }
  }
}

void alert_seeds(std::ostream& output, const DexClass* cls) {
  if (is_seed(cls) && !keep(cls)) {
    output << "SEEDS CLASS ERROR: " << cls->get_deobfuscated_name()
           << std::endl;
  }
}

void redex::alert_seeds(std::ostream& output, const Scope& classes) {
  for (const auto& cls : classes) {
    if (!cls->is_external()) {
      alert_seeds(output, cls);
    }
  }
}
<commit_msg>Fix field type deobfuscation in reporting code<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "ProguardReporting.h"
#include "DexClass.h"
#include "ReachableClasses.h"

std::string extract_suffix(std::string class_name) {
  auto i = class_name.find_last_of(".");
  if (i == std::string::npos) {
    // This is a class name with no package prefix.
    return class_name;
  }
  return class_name.substr(i + 1);
}

std::string redex::dexdump_name_to_dot_name(const std::string& dexdump_name) {
  assert(!dexdump_name.empty());
  std::string s;
  for (const char& ch : dexdump_name.substr(1)) {
    if (ch == '/') {
      s += '.';
      continue;
    }
    if (ch == ';') {
      continue;
    }
    s += ch;
  }
  return s;
}

std::string type_descriptor_to_java(const std::string& descriptor) {
  assert(!descriptor.empty());
  if (descriptor[0] == '[') {
    return type_descriptor_to_java(descriptor.substr(1)) + "[]";
  }
  if (descriptor == "B") {
    return "byte";
  }
  if (descriptor == "S") {
    return "short";
  }
  if (descriptor == "I") {
    return "int";
  }
  if (descriptor == "J") {
    return "long";
  }
  if (descriptor == "C") {
    return "char";
  }
  if (descriptor == "F") {
    return "float";
  }
  if (descriptor == "D") {
    return "double";
  }
  if (descriptor == "Z") {
    return "boolean";
  }
  if (descriptor == "V") {
    return "void";
  }
  if (descriptor[0] == 'L') {
    return redex::dexdump_name_to_dot_name(descriptor);
  }
  std::cerr << "type_descriptor_to_java: unexpected type descriptor "
            << descriptor << std::endl;
  exit(2);
}

std::string extract_member_name(std::string qualified) {
  auto dot = qualified.find(".");
  auto colon = qualified.find(":");
  return qualified.substr(dot + 1, colon - dot - 1);
}

// Convert a type descriptor that may contain obfuscated class names
// into the corresponding type descriptor with the class types deobfuscated.
// The incomming type descriptor is a chain of types which may be primitive
// types, array types or class types. For example [[A; -> [[Lcom.wombat.Numbat;
std::string deobfuscate_type_descriptor(const ProguardMap& pg_map,
                                        const std::string& desc) {
  assert(!desc.empty());
  std::string deob;
  size_t i = 0;
  while (i < desc.size()) {
    if (desc[i] == 'L') {
      auto colon = desc.find(";");
      assert(colon != std::string::npos);
      auto class_type = desc.substr(i, colon + 1);
      auto deob_class = pg_map.deobfuscate_class(class_type);
      if (deob_class.empty()) {
        std::cerr << "Warning: failed to deobfuscate class " << class_type
                  << std::endl;
        deob_class = class_type;
      }
      deob += deob_class;
      i = colon + 1;
      continue;
    }
    deob += desc[i];
    i++;
  }
  return deob;
}

std::string form_java_args(const ProguardMap& pg_map,
                           const std::list<DexType*>& args) {
  std::string s;
  unsigned long i = 0;
  for (const auto& arg : args) {
    auto desc = arg->get_name()->c_str();
    auto deobfu_desc = deobfuscate_type_descriptor(pg_map, desc);
    s += type_descriptor_to_java(deobfu_desc);
    if (i < args.size() - 1) {
      s += ",";
    }
    i++;
  }
  return s;
}

std::string java_args(const ProguardMap& pg_map, std::list<DexType*>& args) {
  std::string str = "(";
  str += form_java_args(pg_map, args);
  str += ")";
  return str;
}

void redex::print_method(std::ostream& output,
                         const ProguardMap& pg_map,
                         const std::string& class_name,
                         const DexMethod* method) {
  std::string method_name = extract_member_name(method->get_name()->c_str());
  // Record if this is a constructor to supress return value printing
  // before the method name.
  bool is_constructor = is_init(method);
  if (is_constructor) {
    method_name = extract_suffix(class_name);
    is_constructor = true;
  } else {
    auto deob = method->get_deobfuscated_name();
    if (deob.empty()) {
      std::cerr << "WARNING: method has no deobfu: " << method_name
                << std::endl;
    } else {
      method_name = extract_member_name(deob);
    }
  }
  auto proto = method->get_proto();
  auto args = proto->get_args()->get_type_list();
  auto return_type = proto->get_rtype();
  output << class_name << ": ";
  if (!is_constructor) {
    auto return_type_desc = return_type->get_name()->c_str();
    auto deobfu_return_type =
        deobfuscate_type_descriptor(pg_map, return_type_desc);
    output << type_descriptor_to_java(deobfu_return_type) << " ";
  }
  output << method_name << java_args(pg_map, args) << std::endl;
}

void redex::print_methods(std::ostream& output,
                          const ProguardMap& pg_map,
                          const std::string& class_name,
                          const std::list<DexMethod*>& methods) {
  for (const auto& method : methods) {
    redex::print_method(output, pg_map, class_name, method);
  }
}

void redex::print_field(std::ostream& output,
                        const ProguardMap& pg_map,
                        const std::string& class_name,
                        const DexField* field) {
  auto field_name = field->get_deobfuscated_name();
  auto field_type = field->get_type()->get_name()->c_str();
  std::string deobfu_field_type =
      deobfuscate_type_descriptor(pg_map, field_type);
  output << class_name << ": " << type_descriptor_to_java(deobfu_field_type)
         << " " << extract_member_name(field->get_deobfuscated_name())
         << std::endl;
}

void redex::print_fields(std::ostream& output,
                         const ProguardMap& pg_map,
                         const std::string& class_name,
                         const std::list<DexField*>& fields) {
  for (const auto& field : fields) {
    redex::print_field(output, pg_map, class_name, field);
  }
}

void redex::print_class(std::ostream& output,
                        const ProguardMap& pg_map,
                        const DexClass* cls) {
  auto deob = cls->get_deobfuscated_name();
  if (deob.empty()) {
    std::cerr << "WARNING: this class has no deobu name: "
              << cls->get_name()->c_str() << std::endl;
    deob = cls->get_name()->c_str();
  }
  std::string name = redex::dexdump_name_to_dot_name(deob);
  output << name << std::endl;
  print_fields(output, pg_map, name, cls->get_ifields());
  print_fields(output, pg_map, name, cls->get_sfields());
  print_methods(output, pg_map, name, cls->get_dmethods());
  print_methods(output, pg_map, name, cls->get_vmethods());
}

void redex::print_classes(std::ostream& output,
                          const ProguardMap& pg_map,
                          const Scope& classes) {
  for (const auto& cls : classes) {
    if (!cls->is_external()) {
      redex::print_class(output, pg_map, cls);
    }
  }
}

void alert_seeds(std::ostream& output, const DexClass* cls) {
  if (is_seed(cls) && !keep(cls)) {
    output << "SEEDS CLASS ERROR: " << cls->get_deobfuscated_name()
           << std::endl;
  }
}

void redex::alert_seeds(std::ostream& output, const Scope& classes) {
  for (const auto& cls : classes) {
    if (!cls->is_external()) {
      alert_seeds(output, cls);
    }
  }
}
<|endoftext|>


<commit_before>//===-------------------------- cxa_virtual.cpp ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "cxxabi.h"

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

namespace __cxxabiv1
{

extern "C"
{

LIBCXXABI_NORETURN
void __cxa_pure_virtual(void) {
    fputs("Pure virtual function called!\n", stderr);
    abort();
}

LIBCXXABI_NORETURN
void __cxa_deleted_virtual(void) {
    fputs("Deleted virtual function called!\n", stderr);
    abort();
}

}  // extern "C"

}  // abi
<commit_msg>use abort_message()<commit_after>//===-------------------------- cxa_virtual.cpp ---------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "cxxabi.h"
#include "abort_message.h"

namespace __cxxabiv1
{

extern "C"
{

LIBCXXABI_NORETURN
void __cxa_pure_virtual(void) {
    abort_message("Pure virtual function called!");
}

LIBCXXABI_NORETURN
void __cxa_deleted_virtual(void) {
    abort_message("Deleted virtual function called!");
}

}  // extern "C"

}  // abi
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2017 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2014 - 2017)
//   Rene Milk       (2016)

#ifndef DUNE_GDT_EXCEPTIONS_HH
#define DUNE_GDT_EXCEPTIONS_HH

#include <dune/xt/common/exceptions.hh>

namespace Dune {
namespace GDT {

class operator_error : public Dune::Exception
{
};

class prolongation_error : public operator_error
{
};

class projection_error : public operator_error
{
};

class space_error : public Dune::Exception
{
};

class restricted_space_error : public space_error
{
};

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_EXCEPTIONS_HH
<commit_msg>[exceptions] add space_error<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2017 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2014 - 2017)
//   Rene Milk       (2016)

#ifndef DUNE_GDT_EXCEPTIONS_HH
#define DUNE_GDT_EXCEPTIONS_HH

#include <dune/xt/common/exceptions.hh>

namespace Dune {
namespace GDT {

class operator_error : public Dune::Exception
{
};

class prolongation_error : public operator_error
{
};

class projection_error : public operator_error
{
};

class space_error : public Dune::Exception
{
};

class restricted_space_error : public space_error
{
};

class mapper_error : public space_error
{
};

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_EXCEPTIONS_HH
<|endoftext|>


<commit_before>#include<iostream>
using namespace std;
int main()
{
    int a[10],n;
    int l=0, r=9;
    int temp;
    for(int i = 0;i < 10;i ++){
        cin >> a[i];
    }
    while(l <= r){
        int leftisOdd = a[l] % 2 == 1;
        int rightisEven = a[r] % 2 == 0;
        if(leftisOdd){
            l++;
        }
        if(rightisEven){
            r--;
        }
        if(!leftisOdd && !rightisEven){
            temp = a[l];
            a[l] = a[r];
            a[r] = temp;
            l++; r--;
        }
    }
    int start = 0, end = l;
    for(int i = start;i < end;i ++){
        for(int j = start+1;j < end;j ++){
            if(a[i] > a[j]){
                temp = a[j];
                a[j] = a[i];
                a[i] = temp;
            }
        }
    }
    start = l; end = 10;
    for(int i = start;i < end;i ++){
        for(int j = start+1;j < end;j ++){
            if(a[i] > a[j]){
                temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }
    for(int i = 0;i < 10;i ++){
        cout << a[i] << endl;
    }
    return 0;
}
  <commit_msg>奇偶排序(1)<commit_after>#include<iostream>
using namespace std;
int main()
{
    int a[10];
    int l=0, r=9;
    int temp;
    for(int i = 0;i < 10;i ++){
        cin >> a[i];
    }
    while(l <= r){
        int leftisOdd = a[l] % 2 == 1;
        int rightisEven = a[r] % 2 == 0;
        if(leftisOdd){
            l++;
        }
        if(rightisEven){
            r--;
        }
        if(!leftisOdd && !rightisEven){
            temp = a[l];
            a[l] = a[r];
            a[r] = temp;
            l++; r--;
        }
    }
    for(int i = 0;i < 10;i ++){
        cout << a[i] << " ";
    }
    int start = 0, end = l;
    for(int i = start;i < end;i ++){
        for(int j = i+1;j < end;j ++){
            if(a[i] > a[j]){
                temp = a[j];
                a[j] = a[i];
                a[i] = temp;
            }
        }
        cout << endl;
    }
    start = l; end = 10;
    for(int i = start;i < end;i ++){
        for(int j = i+1;j < end;j ++){
            if(a[i] > a[j]){
                temp = a[i];
                a[i] = a[j];
                a[j] = temp;
            }
        }
    }
    for(int i = 0;i < 10;i ++){
        cout << a[i] << " ";
    }
    return 0;
}
  <|endoftext|>


<commit_before>/*
    Copyright (C) 2002 by Norman Krmer

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// make sure this is before all other things!
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include "cssysdef.h"
#include "cspthrd.h"
#include <sys/time.h>

// Depending upon the platform, one of these headers declares strerror().
#include <errno.h>
#include <stdio.h>
#include <string.h>

#ifdef CS_DEBUG
#define CS_SHOW_ERROR if (lasterr) printf ("%s\n", GetLastError ())
#else
#define CS_SHOW_ERROR
#endif

csRef<csMutex> csMutex::Create (bool needrecursive)
{
#ifdef CS_PTHREAD_MUTEX_RECURSIVE
  if (needrecursive)
  {
    pthread_mutexattr_t attr;
    pthread_mutexattr_init (&attr);
    pthread_mutexattr_settype (&attr, CS_PTHREAD_MUTEX_RECURSIVE);

    return csPtr<csMutex> (new csPosixMutex (&attr));
  }

  return csPtr<csMutex> (new csPosixMutex (NULL));
#else
  return csPtr<csMutex>(new csPosixMutexRecursive (NULL));
#endif
}

csPosixMutex::csPosixMutex (pthread_mutexattr_t* attr)
  : lasterr (0)
{
  pthread_mutex_init (&mutex, attr);
}

csPosixMutex::~csPosixMutex ()
{
  lasterr = pthread_mutex_destroy (&mutex);

  CS_SHOW_ERROR;
}

bool csPosixMutex::LockWait()
{
  lasterr = pthread_mutex_lock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}

bool csPosixMutex::LockTry ()
{
  lasterr = pthread_mutex_trylock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}

bool csPosixMutex::Release ()
{
  lasterr = pthread_mutex_unlock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}

char const* csPosixMutex::GetLastError ()
{
  switch (lasterr)
  {
    case EINVAL:
      return "Mutex not initialized";
    case EPERM:
      return "No permission";
    case 0:
      return "";
    default:
      return "Unknown error";
  }
}

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

#ifndef CS_PTHREAD_MUTEX_RECURSIVE
csPosixMutexRecursive::csPosixMutexRecursive (pthread_mutexattr_t* attr)
  : csPosixMutex(attr), count(0), owner(0)
{
}

csPosixMutexRecursive::~csPosixMutexRecursive ()
{
  CS_ASSERT (count==0);
}

bool csPosixMutexRecursive::LockWait ()
{
  pthread_t self = pthread_self ();

  if (owner != self)
  {
    lasterr = pthread_mutex_lock(&mutex);
    owner = self;
  }
  else
    lasterr = 0;
  count += 1;

  CS_SHOW_ERROR;
}

bool csPosixMutexRecursive::LockTry ()
{
  int rc = pthread_mutex_trylock (&mutex);

  pthread_t self = pthread_self ();
  if (rc == 0)
  {
    owner = self;
    count = 1;
    return true;
  }
  else if (owner == self)
  {
    count += 1;
    return true;
  }

  lasterr = rc;
  CS_SHOW_ERROR;
  return false;
}

bool csPosixMutexRecursive::Release ()
{
  pthread_t self = pthread_self ();

  if (owner != self)
  {
    lasterr = EPERM;
    CS_SHOW_ERROR;
    return false;
  }

  count -= 1;
  if (count == 0)
    lasterr = pthread_mutex_unlock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}
#endif

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

csRef<csSemaphore> csSemaphore::Create (uint32 value)
{
  return csPtr<csSemaphore>(new csPosixSemaphore (value));
}

csPosixSemaphore::csPosixSemaphore (uint32 value)
{
  int rc = sem_init (&sem, 0, (unsigned int)value);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
}

csPosixSemaphore::~csPosixSemaphore ()
{
  Destroy ();
}

bool csPosixSemaphore::LockWait ()
{
  sem_wait (&sem);
  return true;
}

bool csPosixSemaphore::LockTry ()
{
  int rc = sem_trywait (&sem);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
  return rc == 0;
}

bool csPosixSemaphore::Release ()
{
  int rc = sem_post (&sem);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
  return rc == 0;
}

uint32 csPosixSemaphore::Value ()
{
  int val;
  sem_getvalue (&sem, &val);
  return (uint32)val;
}

bool csPosixSemaphore::Destroy ()
{
  int rc = sem_destroy (&sem);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
  return rc == 0;
}

char const* csPosixSemaphore::GetLastError ()
{
  return lasterr;
}

csRef<csCondition> csCondition::Create (uint32 conditionAttributes)
{
  return csPtr<csCondition>(new csPosixCondition (conditionAttributes));
}

csPosixCondition::csPosixCondition (uint32 /*conditionAttributes*/)
{
  pthread_cond_init (&cond, NULL);
  lasterr = NULL;
}

csPosixCondition::~csPosixCondition ()
{
  Destroy ();
}

void csPosixCondition::Signal (bool WakeAll)
{
  if (WakeAll)
    pthread_cond_broadcast (&cond);
  else
    pthread_cond_signal (&cond);
}

bool csPosixCondition::Wait (csMutex* mutex, csTicks timeout)
{
  int rc = 0;
  if (timeout > 0)
  {
    struct timeval now;
    struct timezone tz;
    struct timespec to;
    gettimeofday (&now, &tz);
    to.tv_sec = now.tv_sec + (timeout / 1000);
    to.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000;
    rc = pthread_cond_timedwait (&cond, &((csPosixMutex*)mutex)->mutex, &to);
    switch (rc)
    {
    case ETIMEDOUT:
      lasterr = "Timeout";
      break;
    case EINTR:
      lasterr = "Wait interrupted";
      break;
    case 0:
      lasterr = NULL;
      break;
    default:
      lasterr = "Unknown error while timed waiting for condition";
      break;
    }
  }
  else
    pthread_cond_wait (&cond, &((csPosixMutex*)mutex)->mutex);
  CS_SHOW_ERROR;
  return rc == 0;
}

bool csPosixCondition::Destroy ()
{
  int rc = pthread_cond_destroy (&cond);
  switch (rc)
  {
  case EBUSY:
    lasterr = "Condition busy";
    break;
  case 0:
    lasterr = NULL;
    break;
  default:
    lasterr = "Unknown error while destroying condition";
    break;
  }
  CS_SHOW_ERROR;
  return rc == 0;
}

char const* csPosixCondition::GetLastError ()
{
  return lasterr;
}

csRef<csThread> csThread::Create (csRunnable* r, uint32 options)
{
  return csPtr<csThread>(new csPosixThread (r, options));
}

csPosixThread::csPosixThread (csRunnable* r, uint32 /*options*/)
{
  runnable = r;
  running = false;
  created = false;
  lasterr = NULL;
}

csPosixThread::~csPosixThread ()
{
  if (running)
    Stop ();
//if (created)
//  pthread_join (thread, NULL); // clean up resources
}

bool csPosixThread::Start ()
{
  if (!running && runnable)
  {
    if (created)
    {
      pthread_join (thread, NULL); // clean up resources
      created = false;
    }
    pthread_attr_t attr;
    int rc;

    // Force thread to be joinable, in later pthread implementations this
    // is default already Thread cancellation state is _assumed_ to be
    // PTHREAD_CANCEL_ENABLE and cancellation type is
    // PTHREAD_CANCEL_DEFERRED
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    rc = pthread_create(&thread, &attr, ThreadRun, (void*)this);

    switch (rc)
    {
    case EAGAIN:
      lasterr = "Out of system resources.";
      break;
    case EINVAL:
      lasterr = "Tried to create thread with wrong attributes";
      break;
    case EPERM:
      lasterr = "No permission to create thread";
      break;
    case 0:
      lasterr = NULL;
      running = true;
      created = true;
      break;
    default:
      lasterr = "Unknown error while creating thread";
      break;
    }
    pthread_attr_destroy(&attr);
  }
  CS_SHOW_ERROR;
  return running;
}

bool csPosixThread::Stop ()
{
  if (running)
  {
    int rc = pthread_cancel (thread);
    switch (rc)
    {
    case ESRCH:
      lasterr = "Trying to stop unknown thread";
      break;
    case 0:
      lasterr = NULL;
      running = false;
      break;
    default:
      lasterr = "Unknown error while cancelling thread";
      break;
    }
  }
  CS_SHOW_ERROR;
  return !running;
}

bool csPosixThread::Wait ()
{
  if (running)
  {
    int rc = pthread_join (thread,NULL);
    switch (rc)
    {
    case ESRCH:
      lasterr = "Trying to wait for unknown thread";
      break;
    case 0:
      lasterr = NULL;
      running = false;
      created=false;
      break;
    default:
      //      lasterr = "Unknown error while waiting for thread";
      lasterr = strerror(errno);
      break;
    }
  }
  CS_SHOW_ERROR;
  return !running;
}

char const* csPosixThread::GetLastError ()
{
  return lasterr;
}

void* csPosixThread::ThreadRun (void* param)
{
  csPosixThread* thread = (csPosixThread*)param;
  thread->runnable->Run ();
  thread->running = false;
  pthread_exit (NULL);
  return NULL;
}

#undef CS_SHOW_ERROR
<commit_msg>modified csPosixCondition::Wait() to not pass through CS_SHOW_ERROR when a timeout is specified and expires.<commit_after>/*
    Copyright (C) 2002 by Norman Krmer

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

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

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
// make sure this is before all other things!
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include "cssysdef.h"
#include "cspthrd.h"
#include <sys/time.h>

// Depending upon the platform, one of these headers declares strerror().
#include <errno.h>
#include <stdio.h>
#include <string.h>

#ifdef CS_DEBUG
#define CS_SHOW_ERROR if (lasterr) printf ("%s\n", GetLastError ())
#else
#define CS_SHOW_ERROR
#endif

csRef<csMutex> csMutex::Create (bool needrecursive)
{
#ifdef CS_PTHREAD_MUTEX_RECURSIVE
  if (needrecursive)
  {
    pthread_mutexattr_t attr;
    pthread_mutexattr_init (&attr);
    pthread_mutexattr_settype (&attr, CS_PTHREAD_MUTEX_RECURSIVE);

    return csPtr<csMutex> (new csPosixMutex (&attr));
  }

  return csPtr<csMutex> (new csPosixMutex (NULL));
#else
  return csPtr<csMutex>(new csPosixMutexRecursive (NULL));
#endif
}

csPosixMutex::csPosixMutex (pthread_mutexattr_t* attr)
  : lasterr (0)
{
  pthread_mutex_init (&mutex, attr);
}

csPosixMutex::~csPosixMutex ()
{
  lasterr = pthread_mutex_destroy (&mutex);

  CS_SHOW_ERROR;
}

bool csPosixMutex::LockWait()
{
  lasterr = pthread_mutex_lock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}

bool csPosixMutex::LockTry ()
{
  lasterr = pthread_mutex_trylock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}

bool csPosixMutex::Release ()
{
  lasterr = pthread_mutex_unlock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}

char const* csPosixMutex::GetLastError ()
{
  switch (lasterr)
  {
    case EINVAL:
      return "Mutex not initialized";
    case EPERM:
      return "No permission";
    case 0:
      return "";
    default:
      return "Unknown error";
  }
}

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

#ifndef CS_PTHREAD_MUTEX_RECURSIVE
csPosixMutexRecursive::csPosixMutexRecursive (pthread_mutexattr_t* attr)
  : csPosixMutex(attr), count(0), owner(0)
{
}

csPosixMutexRecursive::~csPosixMutexRecursive ()
{
  CS_ASSERT (count==0);
}

bool csPosixMutexRecursive::LockWait ()
{
  pthread_t self = pthread_self ();

  if (owner != self)
  {
    lasterr = pthread_mutex_lock(&mutex);
    owner = self;
  }
  else
    lasterr = 0;
  count += 1;

  CS_SHOW_ERROR;
}

bool csPosixMutexRecursive::LockTry ()
{
  int rc = pthread_mutex_trylock (&mutex);

  pthread_t self = pthread_self ();
  if (rc == 0)
  {
    owner = self;
    count = 1;
    return true;
  }
  else if (owner == self)
  {
    count += 1;
    return true;
  }

  lasterr = rc;
  CS_SHOW_ERROR;
  return false;
}

bool csPosixMutexRecursive::Release ()
{
  pthread_t self = pthread_self ();

  if (owner != self)
  {
    lasterr = EPERM;
    CS_SHOW_ERROR;
    return false;
  }

  count -= 1;
  if (count == 0)
    lasterr = pthread_mutex_unlock (&mutex);

  CS_SHOW_ERROR;
  return lasterr == 0;
}
#endif

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

csRef<csSemaphore> csSemaphore::Create (uint32 value)
{
  return csPtr<csSemaphore>(new csPosixSemaphore (value));
}

csPosixSemaphore::csPosixSemaphore (uint32 value)
{
  int rc = sem_init (&sem, 0, (unsigned int)value);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
}

csPosixSemaphore::~csPosixSemaphore ()
{
  Destroy ();
}

bool csPosixSemaphore::LockWait ()
{
  sem_wait (&sem);
  return true;
}

bool csPosixSemaphore::LockTry ()
{
  int rc = sem_trywait (&sem);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
  return rc == 0;
}

bool csPosixSemaphore::Release ()
{
  int rc = sem_post (&sem);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
  return rc == 0;
}

uint32 csPosixSemaphore::Value ()
{
  int val;
  sem_getvalue (&sem, &val);
  return (uint32)val;
}

bool csPosixSemaphore::Destroy ()
{
  int rc = sem_destroy (&sem);
  if (rc)
    lasterr = strerror(errno);
  else
    lasterr = NULL;
  CS_SHOW_ERROR;
  return rc == 0;
}

char const* csPosixSemaphore::GetLastError ()
{
  return lasterr;
}

csRef<csCondition> csCondition::Create (uint32 conditionAttributes)
{
  return csPtr<csCondition>(new csPosixCondition (conditionAttributes));
}

csPosixCondition::csPosixCondition (uint32 /*conditionAttributes*/)
{
  pthread_cond_init (&cond, NULL);
  lasterr = NULL;
}

csPosixCondition::~csPosixCondition ()
{
  Destroy ();
}

void csPosixCondition::Signal (bool WakeAll)
{
  if (WakeAll)
    pthread_cond_broadcast (&cond);
  else
    pthread_cond_signal (&cond);
}

bool csPosixCondition::Wait (csMutex* mutex, csTicks timeout)
{
  int rc = 0;
  if (timeout > 0)
  {
    struct timeval now;
    struct timezone tz;
    struct timespec to;
    gettimeofday (&now, &tz);
    to.tv_sec = now.tv_sec + (timeout / 1000);
    to.tv_nsec = (now.tv_usec + (timeout % 1000) * 1000) * 1000;
    rc = pthread_cond_timedwait (&cond, &((csPosixMutex*)mutex)->mutex, &to);
    switch (rc)
    {
    case ETIMEDOUT:
      lasterr = "Timeout";
      return false;
    case EINTR:
      lasterr = "Wait interrupted";
      break;
    case 0:
      lasterr = NULL;
      break;
    default:
      lasterr = "Unknown error while timed waiting for condition";
      break;
    }
  }
  else
    pthread_cond_wait (&cond, &((csPosixMutex*)mutex)->mutex);
  CS_SHOW_ERROR;
  return rc == 0;
}

bool csPosixCondition::Destroy ()
{
  int rc = pthread_cond_destroy (&cond);
  switch (rc)
  {
  case EBUSY:
    lasterr = "Condition busy";
    break;
  case 0:
    lasterr = NULL;
    break;
  default:
    lasterr = "Unknown error while destroying condition";
    break;
  }
  CS_SHOW_ERROR;
  return rc == 0;
}

char const* csPosixCondition::GetLastError ()
{
  return lasterr;
}

csRef<csThread> csThread::Create (csRunnable* r, uint32 options)
{
  return csPtr<csThread>(new csPosixThread (r, options));
}

csPosixThread::csPosixThread (csRunnable* r, uint32 /*options*/)
{
  runnable = r;
  running = false;
  created = false;
  lasterr = NULL;
}

csPosixThread::~csPosixThread ()
{
  if (running)
    Stop ();
//if (created)
//  pthread_join (thread, NULL); // clean up resources
}

bool csPosixThread::Start ()
{
  if (!running && runnable)
  {
    if (created)
    {
      pthread_join (thread, NULL); // clean up resources
      created = false;
    }
    pthread_attr_t attr;
    int rc;

    // Force thread to be joinable, in later pthread implementations this
    // is default already Thread cancellation state is _assumed_ to be
    // PTHREAD_CANCEL_ENABLE and cancellation type is
    // PTHREAD_CANCEL_DEFERRED
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
    rc = pthread_create(&thread, &attr, ThreadRun, (void*)this);

    switch (rc)
    {
    case EAGAIN:
      lasterr = "Out of system resources.";
      break;
    case EINVAL:
      lasterr = "Tried to create thread with wrong attributes";
      break;
    case EPERM:
      lasterr = "No permission to create thread";
      break;
    case 0:
      lasterr = NULL;
      running = true;
      created = true;
      break;
    default:
      lasterr = "Unknown error while creating thread";
      break;
    }
    pthread_attr_destroy(&attr);
  }
  CS_SHOW_ERROR;
  return running;
}

bool csPosixThread::Stop ()
{
  if (running)
  {
    int rc = pthread_cancel (thread);
    switch (rc)
    {
    case ESRCH:
      lasterr = "Trying to stop unknown thread";
      break;
    case 0:
      lasterr = NULL;
      running = false;
      break;
    default:
      lasterr = "Unknown error while cancelling thread";
      break;
    }
  }
  CS_SHOW_ERROR;
  return !running;
}

bool csPosixThread::Wait ()
{
  if (running)
  {
    int rc = pthread_join (thread,NULL);
    switch (rc)
    {
    case ESRCH:
      lasterr = "Trying to wait for unknown thread";
      break;
    case 0:
      lasterr = NULL;
      running = false;
      created=false;
      break;
    default:
      //      lasterr = "Unknown error while waiting for thread";
      lasterr = strerror(errno);
      break;
    }
  }
  CS_SHOW_ERROR;
  return !running;
}

char const* csPosixThread::GetLastError ()
{
  return lasterr;
}

void* csPosixThread::ThreadRun (void* param)
{
  csPosixThread* thread = (csPosixThread*)param;
  thread->runnable->Run ();
  thread->running = false;
  pthread_exit (NULL);
  return NULL;
}

#undef CS_SHOW_ERROR
<|endoftext|>


<commit_before>#include "sail.hpp"
#include <algorithm>
#include <array>
#include "base/BitWriter.hpp"
#include "base/writer.h"
#include "gpio/gpio.h"
#include "gyro/gyro.h"
#include "gyro/telemetry.hpp"
#include "logger/logger.h"
#include "mission/sail.hpp"
#include "photo/photo_service.hpp"
#include "power/power.h"
#include "time/ICurrentTime.hpp"

using services::fs::File;
using services::fs::IFileSystem;
using services::fs::FileOpen;
using services::fs::FileAccess;

namespace experiment
{
    namespace sail
    {
        using namespace std::chrono_literals;

        using namespace services::photo;

        SailExperiment::SailExperiment(IFileSystem& fileSystem,
            ::adcs::IAdcsCoordinator& adcsCoordinator,
            devices::gyro::IGyroscopeDriver& gyroDriver,
            devices::payload::IPayloadDeviceDriver& payloadDriver,
            services::power::IPowerControl& powerController,
            services::photo::IPhotoService& photoService,
            const drivers::gpio::Pin& sailState,
            services::time::ICurrentTime& timeProvider)
            : _file(&timeProvider),                        //
              _photoNumber(0),                             //
              _lastCamera(services::photo::Camera::Nadir), //
              _fileSystem(fileSystem),                     //
              _adcsCoordinator(adcsCoordinator),           //
              _gyroDriver(gyroDriver),                     //
              _payloadDriver(payloadDriver),               //
              _powerController(powerController),           //
              _photoService(photoService),                 //
              _timeProvider(timeProvider),                 //
              _sailState(sailState)
        {
        }

        experiments::ExperimentCode SailExperiment::Type()
        {
            return Code;
        }

        experiments::StartResult SailExperiment::Start()
        {
            do
            {
                if (!this->_file.Open(this->_fileSystem, "/sail.exp", FileOpen::CreateAlways, FileAccess::WriteOnly))
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to open experiment file");
                    break;
                }

                if (OS_RESULT_FAILED(this->_adcsCoordinator.Disable()))
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to disable adcs");
                    break;
                }

                if (!this->_powerController.SensPower(true))
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to enable SENS lcl");
                    break;
                }

                this->_photoService.Schedule(Reset());
                this->_photoService.Schedule(EnableCamera(Camera::Nadir));
                this->_photoService.Schedule(EnableCamera(Camera::Wing));
                this->_photoService.WaitForFinish(InfiniteTimeout);

                this->_experimentBegin = this->_timeProvider.GetCurrentTime();
                if (!this->_experimentBegin.HasValue)
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to acquire current time");
                    break;
                }

                this->_sailController->OpenSail();
                return experiments::StartResult::Success;
            } while (false);

            Stop(experiments::IterationResult::Failure);
            return experiments::StartResult::Failure;
        }

        experiments::IterationResult SailExperiment::Iteration()
        {
            const auto time = this->_timeProvider.GetCurrentTime();
            if (NeedToGetTelemetry(time))
            {
                GetTelemetry(time);
            }

            if (NeedToTakePhoto(time))
            {
                TakePhoto(time);
            }

            if (NeedToEnd(time))
            {
                return experiments::IterationResult::Finished;
            }
            else
            {
                System::SleepTask(TimeToNextEvent(time));
                return experiments::IterationResult::LoopImmediately;
            }
        }

        void SailExperiment::Stop(experiments::IterationResult lastResult)
        {
            UNREFERENCED_PARAMETER(lastResult);
            this->_file.Close();
            if (OS_RESULT_FAILED(this->_adcsCoordinator.EnableBuiltinDetumbling()))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to restore adcs mode");
            }

            if (!this->_powerController.SensPower(false))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to disable SENS lcl");
            }

            this->_photoService.Schedule(DisableCamera(Camera::Nadir));
            this->_photoService.Schedule(DisableCamera(Camera::Wing));
            SavePhotos();
            this->_photoService.Schedule(Reset());
            this->_photoService.WaitForFinish(InfiniteTimeout);
        }

        std::chrono::milliseconds SailExperiment::TimeToGetTelemetry(const Option<std::chrono::milliseconds>& time) const
        {
            if (!time.HasValue || !this->_lastTelemetryAcquisition.HasValue)
            {
                return 1000ms;
            }

            return (time.Value - this->_lastTelemetryAcquisition.Value);
        }

        std::chrono::milliseconds SailExperiment::TimeToTakePhoto(const Option<std::chrono::milliseconds>& time) const
        {
            if (!time.HasValue || !this->_lastPhotoTaken.HasValue)
            {
                return 1000ms;
            }

            return (time.Value - this->_lastPhotoTaken.Value);
        }

        std::chrono::milliseconds SailExperiment::TimeToEnd(const Option<std::chrono::milliseconds>& time) const
        {
            if (!time.HasValue || !this->_experimentBegin.HasValue)
            {
                return 1000ms;
            }

            return (time.Value - this->_experimentBegin.Value);
        }

        bool SailExperiment::NeedToGetTelemetry(const Option<std::chrono::milliseconds>& time) const
        {
            return TimeToGetTelemetry(time) > 1000ms;
        }

        bool SailExperiment::NeedToTakePhoto(const Option<std::chrono::milliseconds>& time) const
        {
            return TimeToTakePhoto(time) >= 2500ms;
        }

        bool SailExperiment::NeedToEnd(const Option<std::chrono::milliseconds>& time) const
        {
            return TimeToEnd(time) >= (4 * 60s + 1s);
        }

        void SailExperiment::GetTelemetry(const Option<std::chrono::milliseconds>& time)
        {
            const auto gyroTelemetry = this->_gyroDriver.read();
            const auto sailIndicator = this->_sailState.Input();
            devices::payload::PayloadTelemetry::Temperatures temperatures;
            if (OS_RESULT_FAILED(this->_payloadDriver.MeasureTemperatures(temperatures)))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to sail temperature");
            }

            if (!gyroTelemetry.HasValue || !Save(gyroTelemetry.Value))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to acquire/save gyro telemetry");
            }

            if (!Save(sailIndicator, temperatures.sail))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to save sail temperature");
            }

            this->_lastTelemetryAcquisition = time;
        }

        void SailExperiment::TakePhoto(const Option<std::chrono::milliseconds>& time)
        {
            this->_lastCamera = GetNextCamera();
            this->_photoService.Schedule(services::photo::TakePhoto(this->_lastCamera, services::photo::PhotoResolution::p128));
            this->_photoService.Schedule(services::photo::DownloadPhoto(this->_lastCamera, this->_photoNumber++));
            this->_lastPhotoTaken = time;
        }

        std::chrono::milliseconds SailExperiment::TimeToNextEvent(const Option<std::chrono::milliseconds>& time) const
        {
            const auto timeLeft = std::min(TimeToGetTelemetry(time), TimeToTakePhoto(time));
            return std::min(TimeToEnd(time), timeLeft);
        }

        bool SailExperiment::Save(const devices::gyro::GyroscopeTelemetry& gyroTelemetry)
        {
            std::array<std::uint8_t, (devices::gyro::GyroscopeTelemetry::BitSize() + 7) / 8> buffer;
            BitWriter writer{buffer};
            gyroTelemetry.Write(writer);
            if (!writer.Status())
            {
                return false;
            }

            return OS_RESULT_SUCCEEDED(this->_file.Write(experiments::fs::ExperimentFile::PID::Gyro, writer.Capture()));
        }

        bool SailExperiment::Save(bool sailIndicator, std::uint16_t sailTemperature)
        {
            std::array<std::uint8_t, 3> buffer;
            Writer writer{buffer};
            writer.WriteWordLE(sailTemperature);
            writer.WriteByte(sailIndicator ? 1 : 0);
            if (!writer.Status())
            {
                return false;
            }

            return OS_RESULT_SUCCEEDED(this->_file.Write(experiments::fs::ExperimentFile::PID::Sail, writer.Capture()));
        }

        void SailExperiment::SavePhotos()
        {
            for (std::uint8_t index = 0; !this->_photoService.IsEmpty(index); ++index)
            {
                this->_photoService.Schedule(services::photo::SavePhoto(index, "/sail.photo_%d", index));
            }
        }
    }
}
<commit_msg>[experiment][sail] Take two big photos at the end of the experiment.<commit_after>#include "sail.hpp"
#include <algorithm>
#include <array>
#include "base/BitWriter.hpp"
#include "base/writer.h"
#include "gpio/gpio.h"
#include "gyro/gyro.h"
#include "gyro/telemetry.hpp"
#include "logger/logger.h"
#include "mission/sail.hpp"
#include "photo/photo_service.hpp"
#include "power/power.h"
#include "time/ICurrentTime.hpp"

using services::fs::File;
using services::fs::IFileSystem;
using services::fs::FileOpen;
using services::fs::FileAccess;

namespace experiment
{
    namespace sail
    {
        using namespace std::chrono_literals;

        using namespace services::photo;

        SailExperiment::SailExperiment(IFileSystem& fileSystem,
            ::adcs::IAdcsCoordinator& adcsCoordinator,
            devices::gyro::IGyroscopeDriver& gyroDriver,
            devices::payload::IPayloadDeviceDriver& payloadDriver,
            services::power::IPowerControl& powerController,
            services::photo::IPhotoService& photoService,
            const drivers::gpio::Pin& sailState,
            services::time::ICurrentTime& timeProvider)
            : _file(&timeProvider),                        //
              _photoNumber(0),                             //
              _lastCamera(services::photo::Camera::Nadir), //
              _fileSystem(fileSystem),                     //
              _adcsCoordinator(adcsCoordinator),           //
              _gyroDriver(gyroDriver),                     //
              _payloadDriver(payloadDriver),               //
              _powerController(powerController),           //
              _photoService(photoService),                 //
              _timeProvider(timeProvider),                 //
              _sailState(sailState)
        {
        }

        experiments::ExperimentCode SailExperiment::Type()
        {
            return Code;
        }

        experiments::StartResult SailExperiment::Start()
        {
            do
            {
                if (!this->_file.Open(this->_fileSystem, "/sail.exp", FileOpen::CreateAlways, FileAccess::WriteOnly))
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to open experiment file");
                    break;
                }

                if (OS_RESULT_FAILED(this->_adcsCoordinator.Disable()))
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to disable adcs");
                    break;
                }

                if (!this->_powerController.SensPower(true))
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to enable SENS lcl");
                    break;
                }

                this->_photoService.Schedule(Reset());
                this->_photoService.Schedule(EnableCamera(Camera::Nadir));
                this->_photoService.Schedule(EnableCamera(Camera::Wing));
                this->_photoService.WaitForFinish(InfiniteTimeout);

                this->_experimentBegin = this->_timeProvider.GetCurrentTime();
                if (!this->_experimentBegin.HasValue)
                {
                    LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to acquire current time");
                    break;
                }

                this->_sailController->OpenSail();
                return experiments::StartResult::Success;
            } while (false);

            Stop(experiments::IterationResult::Failure);
            return experiments::StartResult::Failure;
        }

        experiments::IterationResult SailExperiment::Iteration()
        {
            const auto time = this->_timeProvider.GetCurrentTime();
            if (NeedToGetTelemetry(time))
            {
                GetTelemetry(time);
            }

            if (NeedToTakePhoto(time))
            {
                TakePhoto(time);
            }

            if (NeedToEnd(time))
            {
                FinalizeExperiment();
                return experiments::IterationResult::Finished;
            }
            else
            {
                System::SleepTask(TimeToNextEvent(time));
                return experiments::IterationResult::LoopImmediately;
            }
        }

        void SailExperiment::Stop(experiments::IterationResult lastResult)
        {
            UNREFERENCED_PARAMETER(lastResult);
            this->_file.Close();
            if (OS_RESULT_FAILED(this->_adcsCoordinator.EnableBuiltinDetumbling()))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to restore adcs mode");
            }

            if (!this->_powerController.SensPower(false))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to disable SENS lcl");
            }

            this->_photoService.Schedule(DisableCamera(Camera::Nadir));
            this->_photoService.Schedule(DisableCamera(Camera::Wing));
            SavePhotos();
            this->_photoService.Schedule(Reset());
            this->_photoService.WaitForFinish(InfiniteTimeout);
        }

        std::chrono::milliseconds SailExperiment::TimeToGetTelemetry(const Option<std::chrono::milliseconds>& time) const
        {
            if (!time.HasValue || !this->_lastTelemetryAcquisition.HasValue)
            {
                return 1000ms;
            }

            return (time.Value - this->_lastTelemetryAcquisition.Value);
        }

        std::chrono::milliseconds SailExperiment::TimeToTakePhoto(const Option<std::chrono::milliseconds>& time) const
        {
            if (!time.HasValue || !this->_lastPhotoTaken.HasValue)
            {
                return 1000ms;
            }

            return (time.Value - this->_lastPhotoTaken.Value);
        }

        std::chrono::milliseconds SailExperiment::TimeToEnd(const Option<std::chrono::milliseconds>& time) const
        {
            if (!time.HasValue || !this->_experimentBegin.HasValue)
            {
                return 1000ms;
            }

            return (time.Value - this->_experimentBegin.Value);
        }

        bool SailExperiment::NeedToGetTelemetry(const Option<std::chrono::milliseconds>& time) const
        {
            return TimeToGetTelemetry(time) > 1000ms;
        }

        bool SailExperiment::NeedToTakePhoto(const Option<std::chrono::milliseconds>& time) const
        {
            return TimeToTakePhoto(time) >= 2500ms;
        }

        bool SailExperiment::NeedToEnd(const Option<std::chrono::milliseconds>& time) const
        {
            return TimeToEnd(time) >= (4 * 60s + 1s);
        }

        void SailExperiment::GetTelemetry(const Option<std::chrono::milliseconds>& time)
        {
            const auto gyroTelemetry = this->_gyroDriver.read();
            const auto sailIndicator = this->_sailState.Input();
            devices::payload::PayloadTelemetry::Temperatures temperatures;
            if (OS_RESULT_FAILED(this->_payloadDriver.MeasureTemperatures(temperatures)))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to sail temperature");
            }

            if (!gyroTelemetry.HasValue || !Save(gyroTelemetry.Value))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to acquire/save gyro telemetry");
            }

            if (!Save(sailIndicator, temperatures.sail))
            {
                LOG(LOG_LEVEL_ERROR, "[exp_sail] Unable to save sail temperature");
            }

            this->_lastTelemetryAcquisition = time;
        }

        void SailExperiment::TakePhoto(const Option<std::chrono::milliseconds>& time)
        {
            this->_lastCamera = GetNextCamera();
            TakePhoto(this->_lastCamera, services::photo::PhotoResolution::p128);
            this->_lastPhotoTaken = time;
        }

        std::chrono::milliseconds SailExperiment::TimeToNextEvent(const Option<std::chrono::milliseconds>& time) const
        {
            const auto timeLeft = std::min(TimeToGetTelemetry(time), TimeToTakePhoto(time));
            return std::min(TimeToEnd(time), timeLeft);
        }

        bool SailExperiment::Save(const devices::gyro::GyroscopeTelemetry& gyroTelemetry)
        {
            std::array<std::uint8_t, (devices::gyro::GyroscopeTelemetry::BitSize() + 7) / 8> buffer;
            BitWriter writer{buffer};
            gyroTelemetry.Write(writer);
            if (!writer.Status())
            {
                return false;
            }

            return OS_RESULT_SUCCEEDED(this->_file.Write(experiments::fs::ExperimentFile::PID::Gyro, writer.Capture()));
        }

        bool SailExperiment::Save(bool sailIndicator, std::uint16_t sailTemperature)
        {
            std::array<std::uint8_t, 3> buffer;
            Writer writer{buffer};
            writer.WriteWordLE(sailTemperature);
            writer.WriteByte(sailIndicator ? 1 : 0);
            if (!writer.Status())
            {
                return false;
            }

            return OS_RESULT_SUCCEEDED(this->_file.Write(experiments::fs::ExperimentFile::PID::Sail, writer.Capture()));
        }

        void SailExperiment::TakePhoto(services::photo::Camera camera, services::photo::PhotoResolution resolution)
        {
            this->_photoService.Schedule(services::photo::TakePhoto(camera, resolution));
            this->_photoService.Schedule(services::photo::DownloadPhoto(camera, this->_photoNumber++));
        }

        void SailExperiment::FinalizeExperiment()
        {
            TakePhoto(services::photo::Camera::Wing, services::photo::PhotoResolution::p480);
            TakePhoto(services::photo::Camera::Nadir, services::photo::PhotoResolution::p480);
        }

        void SailExperiment::SavePhotos()
        {
            for (std::uint8_t index = 0; !this->_photoService.IsEmpty(index); ++index)
            {
                this->_photoService.Schedule(services::photo::SavePhoto(index, "/sail.photo_%d", index));
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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 "ui/ozone/platform/egl/egl_surface_factory.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/ozone/public/surface_ozone_egl.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
#include "base/logging.h"

#include "egl_wrapper.h"

#ifndef GL_BGRA_EXT
 #define GL_BGRA_EXT 0x80E1
#endif

#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h>   /* For open(), creat() */
#include <linux/fb.h>
#include <sys/ioctl.h>

#define OZONE_EGL_WINDOW_WIDTH 1024
#define OZONE_EGL_WINDOW_HEIGTH 768

namespace ui {

class EglOzoneCanvas: public ui::SurfaceOzoneCanvas {
 public:
  EglOzoneCanvas();
  ~EglOzoneCanvas() override  ;
  // SurfaceOzoneCanvas overrides:
  void ResizeCanvas(const gfx::Size& viewport_size) override;
  //virtual skia::RefPtr<SkCanvas> GetCanvas() override {
  //  return skia::SharePtr<SkCanvas>(surface_->getCanvas());
  //}
  void PresentCanvas(const gfx::Rect& damage) override;

  scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }
  skia::RefPtr<SkSurface> GetSurface() override { return surface_; }

 private:
  skia::RefPtr<SkSurface> surface_;
  ozone_egl_UserData userDate_;
};

EglOzoneCanvas::EglOzoneCanvas()
{
    memset(&userDate_,0,sizeof(userDate_));
}
EglOzoneCanvas::~EglOzoneCanvas()
{
    ozone_egl_textureShutDown (&userDate_);
}

void EglOzoneCanvas::ResizeCanvas(const gfx::Size& viewport_size)
{
  if(userDate_.width == viewport_size.width() && userDate_.height==viewport_size.height())
  {
      return;
  }
  else if(userDate_.width != 0 && userDate_.height !=0)
  {
      ozone_egl_textureShutDown (&userDate_);
  }
  surface_ = skia::AdoptRef(SkSurface::NewRaster(
        SkImageInfo::Make(viewport_size.width(),
                                   viewport_size.height(),
                                   kN32_SkColorType,
                                   kPremul_SkAlphaType)));
  userDate_.width = viewport_size.width();
  userDate_.height = viewport_size.height();
  userDate_.colorType = GL_BGRA_EXT;
  ozone_egl_textureInit ( &userDate_);
}

void EglOzoneCanvas::PresentCanvas(const gfx::Rect& damage)
{
    SkImageInfo info;
    size_t row_bytes;
    userDate_.data = (char *) surface_->peekPixels(&info, &row_bytes);
    ozone_egl_textureDraw(&userDate_);
    ozone_egl_swap();
}

class OzoneEgl : public ui::SurfaceOzoneEGL {
 public:
  OzoneEgl(gfx::AcceleratedWidget window_id){
     native_window_ = window_id;
  }
  ~OzoneEgl() override {
     native_window_=0;
  }

  intptr_t GetNativeWindow() override
  {
    return native_window_;
  }

  bool OnSwapBuffers() override
  {
    return true;
  }

  bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override
  {
    return true;
  }

  bool ResizeNativeWindow(const gfx::Size& viewport_size) override {
    return true;
  }

  scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }

 private:
  intptr_t native_window_;
};

SurfaceFactoryEgl::SurfaceFactoryEgl():init_(false)
{

}

SurfaceFactoryEgl::~SurfaceFactoryEgl()
{
    DestroySingleWindow();
}

EGLint g_width;
EGLint g_height;
bool SurfaceFactoryEgl::CreateSingleWindow()
{
  struct fb_var_screeninfo fb_var;

  int fb_fd =  open("/dev/fb0", O_RDWR);

  if(init_)
  {
     return true;
  }

  if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var)) {
        LOG(FATAL) << "failed to get fb var info errno: " << errno;
        g_width = 640;
	g_height = 480;
  } else {
    g_width = fb_var.xres;
    g_height = fb_var.yres;
  }

 close(fb_fd);

 if(!ozone_egl_setup(0, 0, g_width, g_height))
  {
      LOG(FATAL) << "CreateSingleWindow";
      return false;
  }
  init_ = true;
  return true;
}

void SurfaceFactoryEgl::DestroySingleWindow() {
  ozone_egl_destroy();
  init_ = false;
}

intptr_t SurfaceFactoryEgl::GetNativeDisplay() {
  return (intptr_t)ozone_egl_getNativedisp();
}

//gfx::AcceleratedWidget SurfaceFactoryEgl::GetAcceleratedWidget() {
//  if (!CreateSingleWindow())
//    LOG(FATAL) << "failed to create window";
//  return (gfx::AcceleratedWidget)GetNativeDisplay();
//}

scoped_ptr<ui::SurfaceOzoneEGL>
SurfaceFactoryEgl::CreateEGLSurfaceForWidget(
    gfx::AcceleratedWidget widget) {
  return make_scoped_ptr<ui::SurfaceOzoneEGL>(
      new OzoneEgl(widget));
}

bool SurfaceFactoryEgl::LoadEGLGLES2Bindings(
    AddGLLibraryCallback add_gl_library,
    SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
  return false;
}

const int32* SurfaceFactoryEgl::GetEGLSurfaceProperties(
    const int32* desired_list) {
  return ozone_egl_getConfigAttribs();
}

scoped_ptr<ui::SurfaceOzoneCanvas> SurfaceFactoryEgl::CreateCanvasForWidget(
      gfx::AcceleratedWidget widget){
    LOG(ERROR) << "-CreateCanvasForWidget-";
  return make_scoped_ptr<SurfaceOzoneCanvas>(new EglOzoneCanvas());
}

}  // namespace ui
<commit_msg>implementing LoadEGLGLES2Bindings<commit_after>// Copyright 2014 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 "ui/ozone/platform/egl/egl_surface_factory.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkSurface.h"
#include "ui/ozone/public/surface_ozone_egl.h"
#include "ui/ozone/public/surface_ozone_canvas.h"
#include "ui/ozone/public/surface_factory_ozone.h"
#include "ui/gfx/skia_util.h"
#include "ui/gfx/vsync_provider.h"
#include "base/logging.h"
#include "ui/ozone/common/egl_util.h"

#include "egl_wrapper.h"

#ifndef GL_BGRA_EXT
 #define GL_BGRA_EXT 0x80E1
#endif

#include <fcntl.h>    /* For O_RDWR */
#include <unistd.h>   /* For open(), creat() */
#include <linux/fb.h>
#include <sys/ioctl.h>

#define OZONE_EGL_WINDOW_WIDTH 1024
#define OZONE_EGL_WINDOW_HEIGTH 768

namespace ui {

class EglOzoneCanvas: public ui::SurfaceOzoneCanvas {
 public:
  EglOzoneCanvas();
  ~EglOzoneCanvas() override  ;
  // SurfaceOzoneCanvas overrides:
  void ResizeCanvas(const gfx::Size& viewport_size) override;
  //virtual skia::RefPtr<SkCanvas> GetCanvas() override {
  //  return skia::SharePtr<SkCanvas>(surface_->getCanvas());
  //}
  void PresentCanvas(const gfx::Rect& damage) override;

  scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }
  skia::RefPtr<SkSurface> GetSurface() override { return surface_; }

 private:
  skia::RefPtr<SkSurface> surface_;
  ozone_egl_UserData userDate_;
};

EglOzoneCanvas::EglOzoneCanvas()
{
    memset(&userDate_,0,sizeof(userDate_));
}
EglOzoneCanvas::~EglOzoneCanvas()
{
    ozone_egl_textureShutDown (&userDate_);
}

void EglOzoneCanvas::ResizeCanvas(const gfx::Size& viewport_size)
{
  if(userDate_.width == viewport_size.width() && userDate_.height==viewport_size.height())
  {
      return;
  }
  else if(userDate_.width != 0 && userDate_.height !=0)
  {
      ozone_egl_textureShutDown (&userDate_);
  }
  surface_ = skia::AdoptRef(SkSurface::NewRaster(
        SkImageInfo::Make(viewport_size.width(),
                                   viewport_size.height(),
                                   kN32_SkColorType,
                                   kPremul_SkAlphaType)));
  userDate_.width = viewport_size.width();
  userDate_.height = viewport_size.height();
  userDate_.colorType = GL_BGRA_EXT;
  ozone_egl_textureInit ( &userDate_);
}

void EglOzoneCanvas::PresentCanvas(const gfx::Rect& damage)
{
    SkImageInfo info;
    size_t row_bytes;
    userDate_.data = (char *) surface_->peekPixels(&info, &row_bytes);
    ozone_egl_textureDraw(&userDate_);
    ozone_egl_swap();
}

class OzoneEgl : public ui::SurfaceOzoneEGL {
 public:
  OzoneEgl(gfx::AcceleratedWidget window_id){
     native_window_ = window_id;
  }
  ~OzoneEgl() override {
     native_window_=0;
  }

  intptr_t GetNativeWindow() override
  {
    return native_window_;
  }

  bool OnSwapBuffers() override
  {
    return true;
  }

  bool OnSwapBuffersAsync(const SwapCompletionCallback& callback) override
  {
    return true;
  }

  bool ResizeNativeWindow(const gfx::Size& viewport_size) override {
    return true;
  }

  scoped_ptr<gfx::VSyncProvider> CreateVSyncProvider() override {
    return scoped_ptr<gfx::VSyncProvider>();
  }

 private:
  intptr_t native_window_;
};

SurfaceFactoryEgl::SurfaceFactoryEgl():init_(false)
{

}

SurfaceFactoryEgl::~SurfaceFactoryEgl()
{
    DestroySingleWindow();
}

EGLint g_width;
EGLint g_height;
bool SurfaceFactoryEgl::CreateSingleWindow()
{
  struct fb_var_screeninfo fb_var;

  int fb_fd =  open("/dev/fb0", O_RDWR);

  if(init_)
  {
     return true;
  }

  if (ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var)) {
        LOG(FATAL) << "failed to get fb var info errno: " << errno;
        g_width = 640;
	g_height = 480;
  } else {
    g_width = fb_var.xres;
    g_height = fb_var.yres;
  }

 close(fb_fd);

 if(!ozone_egl_setup(0, 0, g_width, g_height))
  {
      LOG(FATAL) << "CreateSingleWindow";
      return false;
  }
  init_ = true;
  return true;
}

void SurfaceFactoryEgl::DestroySingleWindow() {
  ozone_egl_destroy();
  init_ = false;
}

intptr_t SurfaceFactoryEgl::GetNativeDisplay() {
  return (intptr_t)ozone_egl_getNativedisp();
}

//gfx::AcceleratedWidget SurfaceFactoryEgl::GetAcceleratedWidget() {
//  if (!CreateSingleWindow())
//    LOG(FATAL) << "failed to create window";
//  return (gfx::AcceleratedWidget)GetNativeDisplay();
//}

scoped_ptr<ui::SurfaceOzoneEGL>
SurfaceFactoryEgl::CreateEGLSurfaceForWidget(
    gfx::AcceleratedWidget widget) {
  return make_scoped_ptr<ui::SurfaceOzoneEGL>(
      new OzoneEgl(widget));
}

bool SurfaceFactoryEgl::LoadEGLGLES2Bindings(
    AddGLLibraryCallback add_gl_library,
    SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
  return LoadDefaultEGLGLES2Bindings(add_gl_library, set_gl_get_proc_address);
  //return false;
}

const int32* SurfaceFactoryEgl::GetEGLSurfaceProperties(
    const int32* desired_list) {
  return ozone_egl_getConfigAttribs();
}

scoped_ptr<ui::SurfaceOzoneCanvas> SurfaceFactoryEgl::CreateCanvasForWidget(
      gfx::AcceleratedWidget widget){
  return make_scoped_ptr<SurfaceOzoneCanvas>(new EglOzoneCanvas());
}

}  // namespace ui
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/si_literals.hpp"
#include "vast/concept/printable/stream.hpp"
#include "vast/concept/printable/vast/compression.hpp"

#include "vast/detail/compressedbuf.hpp"

#define SUITE streambuf
#include "test.hpp"

using namespace std::string_literals;
using namespace vast;
using namespace vast::binary_byte_literals;
using namespace vast::detail;

TEST(compressedbuf - two blocks) {
  // Create a compressed buffer with an internal block size of 8 bytes. A
  // compressed buffer can either be used for writing or reading, but not both
  // at the same time.
  std::stringbuf buf;
  compressedbuf sink{buf, compression::null, 8};
  MESSAGE("put area");
  CHECK_EQUAL(sink.sputn("", 0), 0);      // nop
  CHECK_EQUAL(sink.sputn("foo", 3), 3);   // 5 bytes left
  CHECK_EQUAL(sink.sputn("bar", 3), 3);   // 2 bytes left
  CHECK_EQUAL(sink.sputn("##", 2), 2);    // 0 bytes left
  CHECK_EQUAL(sink.sputc('*'), '*');      // trigger overflow()
  CHECK_EQUAL(sink.pubsync(), 3);         // flush (3: 2 for head, 1 for data)
  // Read from the compressed sequence of blocks in the underlying stringbuf.
  MESSAGE("get area");
  compressedbuf source{buf, compression::null, 8};
  CHECK_EQUAL(source.in_avail(), 0);
  CHECK_EQUAL(source.sgetn(nullptr, 0), 0); // nop
  auto c = source.sgetc();                // trigger underflow()
  CHECK_EQUAL(source.in_avail(), 8);      // get area filled with block data
  CHECK_EQUAL(c, 'f');
  std::string str;
  str.resize(8);
  auto n = source.sgetn(&str[0], 8);
  CHECK_EQUAL(n, 8);
  CHECK_EQUAL(str, "foobar##");
  CHECK_EQUAL(source.in_avail(), 0);
  c = source.sbumpc();                    // trigger underflow again()
  CHECK_EQUAL(c, '*');
  c = source.sgetc();                     // input exhausted
  CHECK_EQUAL(c, compressedbuf::traits_type::eof());
}

TEST(compressedbuf - iostream interface) {
  std::vector<compression> methods = {compression::null, compression::lz4};
#ifdef VAST_HAVE_SNAPPY
  methods.push_back(compression::snappy);
#endif
  std::vector<size_t> block_sizes = {1, 2, 64, 256, 1_KiB, 16_MiB};
  auto data = "Im Kampf zwischen dir und der Welt sekundiere der Welt."s;
  auto inflation = 1000;
  for (auto block_size : block_sizes) {
    for (auto method : methods) {
      MESSAGE("block size " << block_size << ", method " << method);
      std::stringbuf buf;
      // Compress in full with std::ostream.
      compressedbuf sink{buf, method, block_size};
      std::ostream os{&sink};
      for (auto i = 0; i < inflation; ++i)
        os << data;
      os.flush(); // calls pubsync() on the contained stream buffer
      // Uncompress in full via std::istream into another std::stringstream.
      compressedbuf source{buf, method, block_size};
      std::istream is{&source};
      std::stringstream ss;
      ss << is.rdbuf();
      auto reassembled = ss.str();
      // Ensure correctness
      CHECK_EQUAL(reassembled.size(), data.size() * inflation);
      CHECK(reassembled.compare(0, data.size() + 1, data));
    }
  }
}

TEST(compressedbuf - xsgetn) {
  auto data = "Alle Wege bahnen sich vor mir"s;
  std::stringbuf buf;
  compressedbuf sink{buf};
  std::ostream os{&sink};
  os << data;
  os.flush();
  // Uncompress manually.
  compressedbuf source{buf, compression::null, 4};
  std::string str;
  str.resize(data.size());
  auto n = source.sgetn(&str[0], 5);
  CHECK_EQUAL(n, 5);
  CHECK(data.compare(0, 5 + 1, str));
  n += source.sgetn(&str[5], 20);
  CHECK_EQUAL(n, 5 + 20);
  CHECK(data.compare(0, 25 + 1, str));
  n += source.sgetn(&str[25], 42);  // only 4 more available
  CHECK_EQUAL(n, static_cast<std::streamsize>(data.size()));
  CHECK_EQUAL(str, data);
}
<commit_msg>Restore inadvertently enlarged block size<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#include "vast/si_literals.hpp"
#include "vast/concept/printable/stream.hpp"
#include "vast/concept/printable/vast/compression.hpp"

#include "vast/detail/compressedbuf.hpp"

#define SUITE streambuf
#include "test.hpp"

using namespace std::string_literals;
using namespace vast;
using namespace vast::binary_byte_literals;
using namespace vast::detail;

TEST(compressedbuf - two blocks) {
  // Create a compressed buffer with an internal block size of 8 bytes. A
  // compressed buffer can either be used for writing or reading, but not both
  // at the same time.
  std::stringbuf buf;
  compressedbuf sink{buf, compression::null, 8};
  MESSAGE("put area");
  CHECK_EQUAL(sink.sputn("", 0), 0);      // nop
  CHECK_EQUAL(sink.sputn("foo", 3), 3);   // 5 bytes left
  CHECK_EQUAL(sink.sputn("bar", 3), 3);   // 2 bytes left
  CHECK_EQUAL(sink.sputn("##", 2), 2);    // 0 bytes left
  CHECK_EQUAL(sink.sputc('*'), '*');      // trigger overflow()
  CHECK_EQUAL(sink.pubsync(), 3);         // flush (3: 2 for head, 1 for data)
  // Read from the compressed sequence of blocks in the underlying stringbuf.
  MESSAGE("get area");
  compressedbuf source{buf, compression::null, 8};
  CHECK_EQUAL(source.in_avail(), 0);
  CHECK_EQUAL(source.sgetn(nullptr, 0), 0); // nop
  auto c = source.sgetc();                // trigger underflow()
  CHECK_EQUAL(source.in_avail(), 8);      // get area filled with block data
  CHECK_EQUAL(c, 'f');
  std::string str;
  str.resize(8);
  auto n = source.sgetn(&str[0], 8);
  CHECK_EQUAL(n, 8);
  CHECK_EQUAL(str, "foobar##");
  CHECK_EQUAL(source.in_avail(), 0);
  c = source.sbumpc();                    // trigger underflow again()
  CHECK_EQUAL(c, '*');
  c = source.sgetc();                     // input exhausted
  CHECK_EQUAL(c, compressedbuf::traits_type::eof());
}

TEST(compressedbuf - iostream interface) {
  std::vector<compression> methods = {compression::null, compression::lz4};
#ifdef VAST_HAVE_SNAPPY
  methods.push_back(compression::snappy);
#endif
  std::vector<size_t> block_sizes = {1, 2, 64, 256, 1_KiB, 16_KiB};
  auto data = "Im Kampf zwischen dir und der Welt sekundiere der Welt."s;
  auto inflation = 1000;
  for (auto block_size : block_sizes) {
    for (auto method : methods) {
      MESSAGE("block size " << block_size << ", method " << method);
      std::stringbuf buf;
      // Compress in full with std::ostream.
      compressedbuf sink{buf, method, block_size};
      std::ostream os{&sink};
      for (auto i = 0; i < inflation; ++i)
        os << data;
      os.flush(); // calls pubsync() on the contained stream buffer
      // Uncompress in full via std::istream into another std::stringstream.
      compressedbuf source{buf, method, block_size};
      std::istream is{&source};
      std::stringstream ss;
      ss << is.rdbuf();
      auto reassembled = ss.str();
      // Ensure correctness
      CHECK_EQUAL(reassembled.size(), data.size() * inflation);
      CHECK(reassembled.compare(0, data.size() + 1, data));
    }
  }
}

TEST(compressedbuf - xsgetn) {
  auto data = "Alle Wege bahnen sich vor mir"s;
  std::stringbuf buf;
  compressedbuf sink{buf};
  std::ostream os{&sink};
  os << data;
  os.flush();
  // Uncompress manually.
  compressedbuf source{buf, compression::null, 4};
  std::string str;
  str.resize(data.size());
  auto n = source.sgetn(&str[0], 5);
  CHECK_EQUAL(n, 5);
  CHECK(data.compare(0, 5 + 1, str));
  n += source.sgetn(&str[5], 20);
  CHECK_EQUAL(n, 5 + 20);
  CHECK(data.compare(0, 25 + 1, str));
  n += source.sgetn(&str[25], 42);  // only 4 more available
  CHECK_EQUAL(n, static_cast<std::streamsize>(data.size()));
  CHECK_EQUAL(str, data);
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#ifndef VAST_SYSTEM_SOURCE_HPP
#define VAST_SYSTEM_SOURCE_HPP

#include <unordered_map>

#include "vast/logger.hpp"

#include <caf/actor_pool.hpp>
#include <caf/stateful_actor.hpp>

#include "vast/concept/printable/stream.hpp"
#include "vast/concept/printable/std/chrono.hpp"
#include "vast/concept/printable/vast/error.hpp"
#include "vast/concept/printable/vast/expression.hpp"
#include "vast/detail/assert.hpp"
#include "vast/error.hpp"
#include "vast/event.hpp"
#include "vast/expected.hpp"
#include "vast/expression.hpp"
#include "vast/expression_visitors.hpp"
#include "vast/schema.hpp"

#include "vast/system/accountant.hpp"
#include "vast/system/atoms.hpp"

namespace vast::system {

#if 0
/// The *Reader* concept.
struct Reader {
  Reader();

  expected<result> read();

  expected<void> schema(vast::schema&);

  expected<vast::schema> schema() const;

  const char* name() const;
};
#endif

/// The source state.
/// @tparam Reader The reader type, which must model the *Reader* concept.
template <class Reader>
struct source_state {
  static constexpr size_t max_batch_size = 1 << 20;
  uint64_t batch_size = 65536;
  std::vector<event> events;
  expression filter;
  std::unordered_map<type, expression> checkers;
  std::chrono::steady_clock::time_point start;
  accountant_type accountant;
  caf::actor sink;
  Reader reader;
  const char* name;
};

/// An event producer.
/// @tparam Reader The concrete source implementation.
/// @param self The actor handle.
/// @param reader The reader instance.
template <class Reader>
caf::behavior
source(caf::stateful_actor<source_state<Reader>>* self, Reader&& reader) {
  using namespace caf;
  using namespace std::chrono;
  self->state.reader = std::move(reader);
  self->state.name = self->state.reader.name();
  auto eu = self->system().dummy_execution_unit();
  self->state.sink = actor_pool::make(eu, actor_pool::round_robin());
  if (auto acc = self->system().registry().get(accountant_atom::value))
    self->state.accountant = actor_cast<accountant_type>(acc);
  self->set_exit_handler(
    [=](const exit_msg& msg) {
      if (self->state.accountant) {
        timestamp now = system_clock::now();
        self->send(self->state.accountant, "source.end", now);
      }
      self->send(self->state.sink, sys_atom::value, delete_atom::value);
      self->send_exit(self->state.sink, msg.reason);
      self->quit(msg.reason);
    }
  );
  return {
    [=](run_atom) {
      if (self->state.accountant && self->current_sender() != self) {
        timestamp now = system_clock::now();
        self->send(self->state.accountant, "source.start", now);
      }
      // Extract events until the source has exhausted its input or until we
      // have completed a batch.
      auto start = steady_clock::now();
      auto done = false;
      while (self->state.events.size() < self->state.batch_size) {
        auto e = self->state.reader.read();
        if (e) {
          if (!is<none>(self->state.filter)) {
            auto& checker = self->state.checkers[e->type()];
            if (is<none>(checker)) {
              auto x = tailor(self->state.filter, e->type());
              VAST_ASSERT(x);
              checker = std::move(*x);
            }
            if (!visit(event_evaluator{*e}, checker))
              continue;
          }
          self->state.events.push_back(std::move(*e));
        } else if (!e.error()) {
          continue; // Try again.
        } else {
          if (e.error() == ec::parse_error) {
            VAST_WARNING(self->system().render(e.error()));
            continue; // Just skip bogous events.
          } else if (e.error() == ec::end_of_input) {
            VAST_INFO(self->system().render(e.error()));
          } else {
            VAST_ERROR(self->system().render(e.error()));
          }
          done = true;
          break;
        }
      }
      auto stop = steady_clock::now();
      // Ship the current batch.
      if (!self->state.events.empty()) {
        auto runtime = stop - start;
        auto unit = duration_cast<microseconds>(runtime).count();
        auto rate = self->state.events.size() * 1e6 / unit;
        auto events = uint64_t{self->state.events.size()};
        VAST_INFO(self, "produced", events, "events in", runtime,
                  '(' << size_t(rate), "events/sec)");
        if (self->state.accountant) {
          auto rt = duration_cast<timespan>(runtime);
          self->send(self->state.accountant, "source.batch.runtime", rt);
          self->send(self->state.accountant, "source.batch.events", events);
          self->send(self->state.accountant, "source.batch.rate", rate);
        }
        self->send(self->state.sink, std::move(self->state.events));
        self->state.events = {};
        self->state.events.reserve(self->state.batch_size);
        // FIXME: if we do not give the stdlib implementation a hint to yield
        // here, this actor can monopolize all available resources. In
        // particular, we encountered a scenario where it prevented the BASP
        // broker from a getting a chance to operate, thereby queuing up
        // all event batches locally and running out of memory, as opposed to
        // sending them out as soon as possible. This yield fix temporarily
        // works around a deeper issue in CAF, which needs to be addressed in
        // the future.
        std::this_thread::yield();
      }
      if (done)
        self->send_exit(self, exit_reason::normal);
      else
        self->send(self, run_atom::value);
    },
    [=](batch_atom, uint64_t batch_size) {
      if (batch_size > source_state<Reader>::max_batch_size) {
        VAST_WARNING(self, "ignores too large batch size:", batch_size);
        return;
      }
      VAST_DEBUG(self, "sets batch size to", batch_size);
      self->state.batch_size = batch_size;
      self->state.events.reserve(batch_size);
    },
    [=](get_atom, schema_atom) -> result<schema> {
      auto sch = self->state.reader.schema();
      if (sch)
        return *sch;
      return sch.error();
    },
    [=](put_atom, const schema& sch) -> result<void> {
      auto r = self->state.reader.schema(sch);
      if (r)
        return {};
      return r.error();
    },
    [=](expression& expr) {
      VAST_DEBUG(self, "sets filter expression to:", expr);
      self->state.filter = std::move(expr);
    },
    [=](sink_atom, const actor& sink) {
      VAST_ASSERT(sink);
      VAST_DEBUG(self, "registers sink", sink);
      self->send(self->state.sink, sys_atom::value, put_atom::value, sink);
    },
  };
}

} // namespace vast::system

#endif
<commit_msg>Fix uninitialized actor state<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#ifndef VAST_SYSTEM_SOURCE_HPP
#define VAST_SYSTEM_SOURCE_HPP

#include <unordered_map>

#include "vast/logger.hpp"

#include <caf/actor_pool.hpp>
#include <caf/stateful_actor.hpp>

#include "vast/concept/printable/stream.hpp"
#include "vast/concept/printable/std/chrono.hpp"
#include "vast/concept/printable/vast/error.hpp"
#include "vast/concept/printable/vast/expression.hpp"
#include "vast/detail/assert.hpp"
#include "vast/error.hpp"
#include "vast/event.hpp"
#include "vast/expected.hpp"
#include "vast/expression.hpp"
#include "vast/expression_visitors.hpp"
#include "vast/schema.hpp"

#include "vast/system/accountant.hpp"
#include "vast/system/atoms.hpp"

namespace vast::system {

#if 0
/// The *Reader* concept.
struct Reader {
  Reader();

  expected<result> read();

  expected<void> schema(vast::schema&);

  expected<vast::schema> schema() const;

  const char* name() const;
};
#endif

/// The source state.
/// @tparam Reader The reader type, which must model the *Reader* concept.
template <class Reader>
struct source_state {
  static constexpr size_t max_batch_size = 1 << 20;
  uint64_t batch_size = 65536;
  std::vector<event> events;
  expression filter;
  std::unordered_map<type, expression> checkers;
  std::chrono::steady_clock::time_point start;
  accountant_type accountant;
  caf::actor sink;
  Reader reader;
  const char* name = "source";
};

/// An event producer.
/// @tparam Reader The concrete source implementation.
/// @param self The actor handle.
/// @param reader The reader instance.
template <class Reader>
caf::behavior
source(caf::stateful_actor<source_state<Reader>>* self, Reader&& reader) {
  using namespace caf;
  using namespace std::chrono;
  self->state.reader = std::move(reader);
  self->state.name = self->state.reader.name();
  auto eu = self->system().dummy_execution_unit();
  self->state.sink = actor_pool::make(eu, actor_pool::round_robin());
  if (auto acc = self->system().registry().get(accountant_atom::value))
    self->state.accountant = actor_cast<accountant_type>(acc);
  self->set_exit_handler(
    [=](const exit_msg& msg) {
      if (self->state.accountant) {
        timestamp now = system_clock::now();
        self->send(self->state.accountant, "source.end", now);
      }
      self->send(self->state.sink, sys_atom::value, delete_atom::value);
      self->send_exit(self->state.sink, msg.reason);
      self->quit(msg.reason);
    }
  );
  return {
    [=](run_atom) {
      if (self->state.accountant && self->current_sender() != self) {
        timestamp now = system_clock::now();
        self->send(self->state.accountant, "source.start", now);
      }
      // Extract events until the source has exhausted its input or until we
      // have completed a batch.
      auto start = steady_clock::now();
      auto done = false;
      while (self->state.events.size() < self->state.batch_size) {
        auto e = self->state.reader.read();
        if (e) {
          if (!is<none>(self->state.filter)) {
            auto& checker = self->state.checkers[e->type()];
            if (is<none>(checker)) {
              auto x = tailor(self->state.filter, e->type());
              VAST_ASSERT(x);
              checker = std::move(*x);
            }
            if (!visit(event_evaluator{*e}, checker))
              continue;
          }
          self->state.events.push_back(std::move(*e));
        } else if (!e.error()) {
          continue; // Try again.
        } else {
          if (e.error() == ec::parse_error) {
            VAST_WARNING(self->system().render(e.error()));
            continue; // Just skip bogous events.
          } else if (e.error() == ec::end_of_input) {
            VAST_INFO(self->system().render(e.error()));
          } else {
            VAST_ERROR(self->system().render(e.error()));
          }
          done = true;
          break;
        }
      }
      auto stop = steady_clock::now();
      // Ship the current batch.
      if (!self->state.events.empty()) {
        auto runtime = stop - start;
        auto unit = duration_cast<microseconds>(runtime).count();
        auto rate = self->state.events.size() * 1e6 / unit;
        auto events = uint64_t{self->state.events.size()};
        VAST_INFO(self, "produced", events, "events in", runtime,
                  '(' << size_t(rate), "events/sec)");
        if (self->state.accountant) {
          auto rt = duration_cast<timespan>(runtime);
          self->send(self->state.accountant, "source.batch.runtime", rt);
          self->send(self->state.accountant, "source.batch.events", events);
          self->send(self->state.accountant, "source.batch.rate", rate);
        }
        self->send(self->state.sink, std::move(self->state.events));
        self->state.events = {};
        self->state.events.reserve(self->state.batch_size);
        // FIXME: if we do not give the stdlib implementation a hint to yield
        // here, this actor can monopolize all available resources. In
        // particular, we encountered a scenario where it prevented the BASP
        // broker from a getting a chance to operate, thereby queuing up
        // all event batches locally and running out of memory, as opposed to
        // sending them out as soon as possible. This yield fix temporarily
        // works around a deeper issue in CAF, which needs to be addressed in
        // the future.
        std::this_thread::yield();
      }
      if (done)
        self->send_exit(self, exit_reason::normal);
      else
        self->send(self, run_atom::value);
    },
    [=](batch_atom, uint64_t batch_size) {
      if (batch_size > source_state<Reader>::max_batch_size) {
        VAST_WARNING(self, "ignores too large batch size:", batch_size);
        return;
      }
      VAST_DEBUG(self, "sets batch size to", batch_size);
      self->state.batch_size = batch_size;
      self->state.events.reserve(batch_size);
    },
    [=](get_atom, schema_atom) -> result<schema> {
      auto sch = self->state.reader.schema();
      if (sch)
        return *sch;
      return sch.error();
    },
    [=](put_atom, const schema& sch) -> result<void> {
      auto r = self->state.reader.schema(sch);
      if (r)
        return {};
      return r.error();
    },
    [=](expression& expr) {
      VAST_DEBUG(self, "sets filter expression to:", expr);
      self->state.filter = std::move(expr);
    },
    [=](sink_atom, const actor& sink) {
      VAST_ASSERT(sink);
      VAST_DEBUG(self, "registers sink", sink);
      self->send(self->state.sink, sys_atom::value, put_atom::value, sink);
    },
  };
}

} // namespace vast::system

#endif
<|endoftext|>