<commit_before>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/scenarios/side_pass/side_pass_scenario.h"

#include <algorithm>
#include <limits>
#include <utility>

#include "cyber/common/log.h"
#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/time/time.h"
#include "modules/planning/common/frame.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/scenarios/side_pass/side_pass_stage.h"
#include "modules/planning/scenarios/side_pass/side_pass_stop_on_wait_point.h"

namespace apollo {
namespace planning {
namespace scenario {
namespace side_pass {

using apollo::common::VehicleConfigHelper;

apollo::common::util::Factory<
    ScenarioConfig::StageType, Stage,
    Stage* (*)(const ScenarioConfig::StageConfig& stage_config)>
    SidePassScenario::s_stage_factory_;

void SidePassScenario::RegisterStages() {
  s_stage_factory_.Clear();
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_APPROACH_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassApproachObstacle(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_DETECT_SAFETY,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassDetectSafety(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_GENERATE_PATH,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassGeneratePath(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_STOP_ON_WAITPOINT,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassStopOnWaitPoint(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_PASS_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassPassObstacle(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_BACKUP,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassBackup(config);
      });
}

SidePassScenario::SidePassScenario(const ScenarioConfig& config,
                                   const ScenarioContext* scenario_context)
    : Scenario(config, scenario_context) {
  side_pass_context_.scenario_config_.CopyFrom(config.side_pass_config());
}

std::unique_ptr<Stage> SidePassScenario::CreateStage(
    const ScenarioConfig::StageConfig& stage_config) {
  if (s_stage_factory_.Empty()) {
    RegisterStages();
  }
  auto ptr = s_stage_factory_.CreateObjectOrNull(stage_config.stage_type(),
                                                 stage_config);
  if (ptr == nullptr) {
    AERROR << "Failed to create stage for config: "
           << stage_config.DebugString();
    return nullptr;
  }
  ptr->SetContext(&side_pass_context_);
  return ptr;
}

bool SidePassScenario::IsTransferable(const Scenario& current_scenario,
                                      const common::TrajectoryPoint& ego_point,
                                      const Frame& frame) {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  if (current_scenario.scenario_type() == ScenarioConfig::SIDE_PASS) {
    const auto front_blocking_obstacle =
        const_cast<Frame&>(frame).Find(front_blocking_obstacle_id_);
    if (front_blocking_obstacle != nullptr &&
        !front_blocking_obstacle->IsStatic()) {
      AWARN << "obstacle: " << front_blocking_obstacle_id_
            << " starts to move and scenario changes SIDE_PASS back to default "
               "scenario.";
      return false;
    }
    return (current_scenario.GetStatus() !=
            Scenario::ScenarioStatus::STATUS_DONE);
  } else if (current_scenario.scenario_type() != ScenarioConfig::LANE_FOLLOW) {
    return false;
  } else {
    return IsSidePassScenario(frame);
  }
}

bool SidePassScenario::IsSidePassScenario(const Frame& frame) {
  return (IsFarFromIntersection(frame) && HasBlockingObstacle(frame));
}

bool SidePassScenario::IsFarFromIntersection(const Frame& frame) {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  const SLBoundary& adc_sl_boundary =
      frame.reference_line_info().front().AdcSlBoundary();
  const auto& first_encountered_overlaps =
      frame.reference_line_info().front().FirstEncounteredOverlaps();
  const double kClearDistance = 15.0;  // in meters
  for (const auto& overlap : first_encountered_overlaps) {
    ADEBUG << "AdcSL: " << adc_sl_boundary.ShortDebugString();
    ADEBUG << overlap.first << ", " << overlap.second.DebugString();
    if (overlap.first != ReferenceLineInfo::CROSSWALK &&
        overlap.first != ReferenceLineInfo::SIGNAL &&
        overlap.first != ReferenceLineInfo::STOP_SIGN) {
      continue;
    }
    if (overlap.second.start_s - adc_sl_boundary.end_s() < kClearDistance) {
      ADEBUG << "too close to overlap_type[" << overlap.first << "]";
      return false;
    }
  }
  return true;
}

bool SidePassScenario::HasBlockingObstacle(const Frame& frame) {
  // possible state change: default scenario => side_pass scenario
  front_blocking_obstacle_id_ = "";

  if (frame.reference_line_info().size() > 1) {
    return false;
  }

  const auto& reference_line_info = frame.reference_line_info().front();
  const SLBoundary& adc_sl_boundary = reference_line_info.AdcSlBoundary();
  const PathDecision& path_decision = reference_line_info.path_decision();

  // a blocking obstacle is an obstacle blocks the road when it is not blocked
  // (by other obstacles or traffic rules)
  for (const auto* obstacle : path_decision.obstacles().Items()) {
    if (obstacle->IsVirtual() || !obstacle->IsStatic()) {
      continue;
    }

    if (obstacle->speed() >
        side_pass_context_.scenario_config_.block_obstacle_min_speed()) {
      continue;
    }

    if (obstacle->PerceptionSLBoundary().start_s() <=
        adc_sl_boundary.end_s()) {  // such vehicles are behind the ego car.
      continue;
    }

    // check s distance
    constexpr double kAdcDistanceThreshold = 15.0;  // unit: m
    if (obstacle->PerceptionSLBoundary().start_s() >
        adc_sl_boundary.end_s() + kAdcDistanceThreshold) {
      // vehicles are far away
      continue;
    }

    if (adc_sl_boundary.end_s() + FLAGS_side_pass_min_front_obstacle_distance >
        obstacle->PerceptionSLBoundary().start_s()) {
      // front obstacle is too close to side pass
      continue;
    }

    // check driving_width
    constexpr double kLBufferThreshold = 0.3;  // unit: m
    const auto& reference_line = reference_line_info.reference_line();
    const double driving_width =
        reference_line.GetDrivingWidth(obstacle->PerceptionSLBoundary());
    const double adc_width =
        VehicleConfigHelper::GetConfig().vehicle_param().width();
    if (driving_width - adc_width - FLAGS_static_decision_nudge_l_buffer >
        kLBufferThreshold) {
      continue;
    }

    bool is_blocked_by_others = false;
    for (const auto* other_obstacle : path_decision.obstacles().Items()) {
      if (other_obstacle->Id() == obstacle->Id()) {
        continue;
      }
      if (other_obstacle->PerceptionSLBoundary().start_l() >
              obstacle->PerceptionSLBoundary().end_l() ||
          other_obstacle->PerceptionSLBoundary().end_l() <
              obstacle->PerceptionSLBoundary().start_l()) {
        // not blocking the backside vehicle
        continue;
      }

      double delta_s = other_obstacle->PerceptionSLBoundary().start_s() -
                       obstacle->PerceptionSLBoundary().end_s();
      if (delta_s < 0.0 || delta_s > kAdcDistanceThreshold) {
        continue;
      } else {
        // TODO(All): fixed the segmentation bug for large vehicles, otherwise
        // the follow line will be problematic.
        // is_blocked_by_others = true; break;
      }
    }

    if (!is_blocked_by_others) {
      // static obstacle id doesn't contain prediction trajectory suffix.
      front_blocking_obstacle_id_ = obstacle->Id() + "_0";
      return true;
    }
  }
  return false;
}

}  // namespace side_pass
}  // namespace scenario
}  // namespace planning
}  // namespace apollo
<commit_msg>planning: side-pass scenario: enable being blocked check on obstacles<commit_after>/******************************************************************************
 * Copyright 2018 The Apollo Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *****************************************************************************/

/**
 * @file
 **/

#include "modules/planning/scenarios/side_pass/side_pass_scenario.h"

#include <algorithm>
#include <limits>
#include <utility>

#include "cyber/common/log.h"
#include "modules/common/configs/vehicle_config_helper.h"
#include "modules/common/math/math_utils.h"
#include "modules/common/time/time.h"
#include "modules/planning/common/frame.h"
#include "modules/planning/common/planning_gflags.h"
#include "modules/planning/scenarios/side_pass/side_pass_stage.h"
#include "modules/planning/scenarios/side_pass/side_pass_stop_on_wait_point.h"

namespace apollo {
namespace planning {
namespace scenario {
namespace side_pass {

using apollo::common::VehicleConfigHelper;

apollo::common::util::Factory<
    ScenarioConfig::StageType, Stage,
    Stage* (*)(const ScenarioConfig::StageConfig& stage_config)>
    SidePassScenario::s_stage_factory_;

void SidePassScenario::RegisterStages() {
  s_stage_factory_.Clear();
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_APPROACH_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassApproachObstacle(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_DETECT_SAFETY,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassDetectSafety(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_GENERATE_PATH,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassGeneratePath(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_STOP_ON_WAITPOINT,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassStopOnWaitPoint(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_PASS_OBSTACLE,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassPassObstacle(config);
      });
  s_stage_factory_.Register(
      ScenarioConfig::SIDE_PASS_BACKUP,
      [](const ScenarioConfig::StageConfig& config) -> Stage* {
        return new SidePassBackup(config);
      });
}

SidePassScenario::SidePassScenario(const ScenarioConfig& config,
                                   const ScenarioContext* scenario_context)
    : Scenario(config, scenario_context) {
  side_pass_context_.scenario_config_.CopyFrom(config.side_pass_config());
}

std::unique_ptr<Stage> SidePassScenario::CreateStage(
    const ScenarioConfig::StageConfig& stage_config) {
  if (s_stage_factory_.Empty()) {
    RegisterStages();
  }
  auto ptr = s_stage_factory_.CreateObjectOrNull(stage_config.stage_type(),
                                                 stage_config);
  if (ptr == nullptr) {
    AERROR << "Failed to create stage for config: "
           << stage_config.DebugString();
    return nullptr;
  }
  ptr->SetContext(&side_pass_context_);
  return ptr;
}

bool SidePassScenario::IsTransferable(const Scenario& current_scenario,
                                      const common::TrajectoryPoint& ego_point,
                                      const Frame& frame) {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  if (current_scenario.scenario_type() == ScenarioConfig::SIDE_PASS) {
    const auto front_blocking_obstacle =
        const_cast<Frame&>(frame).Find(front_blocking_obstacle_id_);
    if (front_blocking_obstacle != nullptr &&
        !front_blocking_obstacle->IsStatic()) {
      AWARN << "obstacle: " << front_blocking_obstacle_id_
            << " starts to move and scenario changes SIDE_PASS back to default "
               "scenario.";
      return false;
    }
    return (current_scenario.GetStatus() !=
            Scenario::ScenarioStatus::STATUS_DONE);
  } else if (current_scenario.scenario_type() != ScenarioConfig::LANE_FOLLOW) {
    return false;
  } else {
    return IsSidePassScenario(frame);
  }
}

bool SidePassScenario::IsSidePassScenario(const Frame& frame) {
  return (IsFarFromIntersection(frame) && HasBlockingObstacle(frame));
}

bool SidePassScenario::IsFarFromIntersection(const Frame& frame) {
  if (frame.reference_line_info().size() > 1) {
    return false;
  }
  const SLBoundary& adc_sl_boundary =
      frame.reference_line_info().front().AdcSlBoundary();
  const auto& first_encountered_overlaps =
      frame.reference_line_info().front().FirstEncounteredOverlaps();
  const double kClearDistance = 15.0;  // in meters
  for (const auto& overlap : first_encountered_overlaps) {
    ADEBUG << "AdcSL: " << adc_sl_boundary.ShortDebugString();
    ADEBUG << overlap.first << ", " << overlap.second.DebugString();
    if (overlap.first != ReferenceLineInfo::CROSSWALK &&
        overlap.first != ReferenceLineInfo::SIGNAL &&
        overlap.first != ReferenceLineInfo::STOP_SIGN) {
      continue;
    }
    if (overlap.second.start_s - adc_sl_boundary.end_s() < kClearDistance) {
      ADEBUG << "too close to overlap_type[" << overlap.first << "]";
      return false;
    }
  }
  return true;
}

bool SidePassScenario::HasBlockingObstacle(const Frame& frame) {
  // possible state change: default scenario => side_pass scenario
  front_blocking_obstacle_id_ = "";

  if (frame.reference_line_info().size() > 1) {
    return false;
  }

  const auto& reference_line_info = frame.reference_line_info().front();
  const SLBoundary& adc_sl_boundary = reference_line_info.AdcSlBoundary();
  const PathDecision& path_decision = reference_line_info.path_decision();

  // a blocking obstacle is an obstacle blocks the road when it is not blocked
  // (by other obstacles or traffic rules)
  for (const auto* obstacle : path_decision.obstacles().Items()) {
    if (obstacle->IsVirtual() || !obstacle->IsStatic()) {
      continue;
    }

    if (obstacle->speed() >
        side_pass_context_.scenario_config_.block_obstacle_min_speed()) {
      continue;
    }

    if (obstacle->PerceptionSLBoundary().start_s() <=
        adc_sl_boundary.end_s()) {  // such vehicles are behind the ego car.
      continue;
    }

    // check s distance
    constexpr double kAdcDistanceThreshold = 15.0;  // unit: m
    if (obstacle->PerceptionSLBoundary().start_s() >
        adc_sl_boundary.end_s() + kAdcDistanceThreshold) {
      // vehicles are far away
      continue;
    }

    if (adc_sl_boundary.end_s() + FLAGS_side_pass_min_front_obstacle_distance >
        obstacle->PerceptionSLBoundary().start_s()) {
      // front obstacle is too close to side pass
      continue;
    }

    // check driving_width
    constexpr double kLBufferThreshold = 0.3;  // unit: m
    const auto& reference_line = reference_line_info.reference_line();
    const double driving_width =
        reference_line.GetDrivingWidth(obstacle->PerceptionSLBoundary());
    const double adc_width =
        VehicleConfigHelper::GetConfig().vehicle_param().width();
    if (driving_width - adc_width - FLAGS_static_decision_nudge_l_buffer >
        kLBufferThreshold) {
      continue;
    }

    bool is_blocked_by_others = false;
    for (const auto* other_obstacle : path_decision.obstacles().Items()) {
      if (other_obstacle->Id() == obstacle->Id()) {
        continue;
      }
      if (other_obstacle->PerceptionSLBoundary().start_l() >
              obstacle->PerceptionSLBoundary().end_l() ||
          other_obstacle->PerceptionSLBoundary().end_l() <
              obstacle->PerceptionSLBoundary().start_l()) {
        // not blocking the backside vehicle
        continue;
      }

      double delta_s = other_obstacle->PerceptionSLBoundary().start_s() -
                       obstacle->PerceptionSLBoundary().end_s();
      if (delta_s < 0.0 || delta_s > kAdcDistanceThreshold) {
        continue;
      } else {
        // TODO(All): fixed the segmentation bug for large vehicles, otherwise
        // the follow line will be problematic.
        is_blocked_by_others = true;
        break;
      }
    }

    if (!is_blocked_by_others) {
      // static obstacle id doesn't contain prediction trajectory suffix.
      front_blocking_obstacle_id_ = obstacle->Id() + "_0";
      return true;
    }
  }
  return false;
}

}  // namespace side_pass
}  // namespace scenario
}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @mss_const.H
/// @This file contains constants for the memory team.
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP

#ifndef _MSS_CONST_H_
#define _MSS_CONST_H_

namespace mss
{

enum sizes
{
    PORTS_PER_MCS = 2,
    PORTS_PER_MCBIST = 4,
    MC_PER_MODULE = 2,
    MCBIST_PER_MC = 1,
    MAX_DIMM_PER_PORT = 2,
    MAX_RANK_PER_DIMM = 4,
    RANK_MID_POINT = 4,            ///< Which rank number indicates the switch to the other DIMM
    DEFAULT_POLL_LIMIT = 10,       ///< the number of poll attempts in the event we can't calculate another
    MAX_NUM_IMP = 4,               ///< number of impedances valid per slew type
    MAX_NUM_CAL_SLEW_RATES = 4,    ///< 3V/ns, 4V/ns, 5V/ns, 6V/n
    MAX_SLEW_VALUE = 15,           ///< 4 bit value
    MAX_SUPPORTED_FREQUENCIES = 1, ///< Number of supported frequencies. Right now it's only 2400

    BYTES_PER_GB = 1000000000,      ///< Multiplier to go from GB to B
    T_PER_MT     = 1000000,          ///< Multiplier to go from MT/s to T/s

    // All need to be attributes - BRS
    // 48:51, 0b1100, (def_is_sim);       # BIG_STEP = 12 (changed from default for SIM)
    // 48:51, 0b0000, any;       # BIG_STEP = 0  SWyatt
    // #48:51, 0b0010, any;       # BIG_STEP = 2  (default)
    // 52:54,  0b000,  any;       # SMALL_STEP = 0 (default)      SWyatt
    //#52:54,  0b001,  any;       # SMALL_STEP = 1        (!! recommend setting to 0)
    // 55:60,  0b101010, any;     # WR_PRE_DLY = 42
    WR_LVL_BIG_STEP = 0b1100,
    WR_LVL_SMALL_STEP = 0b000,
    WR_LVL_PRE_DLY = 0b101010,
    WR_LVL_NUM_VALID_SAMPLES = 0x5,

    // THIS IS LIKELY INCORRECT - Should be defined in the DDR4 write centering protocol BRS
    // This field must be set to the larger of the two values in number of memory clock cycles.
    // FW_RD_WR = max(tWTR + 11, AL + tRTP + 3)
    WR_CNTR_FW_RD_WR = 0x11 + 4,
    WR_CNTR_FW_WR_RD = 0x0,

    // Attribute? BRS
    COARSE_CAL_STEP_SIZE = 0x4,
    CONSEQ_PASS = 0x8,
};

enum times
{
    CONVERT_PS_IN_A_NS      = 1000,     ///< 1000 pico in an nano
    CONVERT_PS_IN_A_US      = 1000000,  ///< 1000000 picos in a micro

    DELAY_1NS               = 1,
    DELAY_10NS              = 10 ,      ///< general purpose 10  ns delay for HW mode
    DELAY_100NS             = 100,      ///< general purpose 100 ns delay for HW mode
    DELAY_1US               = 1000,     ///< general purpose 1 usec delay for HW mode
    DELAY_100US             = 100000,   ///< general purpose 100 usec delay for HW mode
    DELAY_1MS               = 1000000,  ///< general purpose 1 ms delay for HW mode

    // From the DDR4spec 2400 speed - need to be changed to read attributes. BRS
    tWLO = 10,
    tWLOE = 2,

    SEC_IN_HOUR             = 60 * 60,  ///< seconds in an hour, used for scrub times
    BG_SCRUB_IN_HOURS       = 12,

    CMD_TIMEBASE            = 8192,     ///< Represents the timebase multiplier for the MCBIST inter cmd gap
};

enum states
{
    LOW = 0,
    HIGH = 1,
    START = 1,
    STOP = 0,
    START_N = 0,
    STOP_N = 1,
    ON = 1,
    OFF = 0,
    ON_N = 0,
    OFF_N = 1,
    YES = 1,
    NO = 0,
    YES_N = 0,
    NO_N = 1,
    INVALID = 0xFF,

    // This needs to be an attribute I think - BRS. Used as a boolean.
    CAL_ABORT_ON_ERROR = 1,
};

// Static consts describing the bits used in the cal_step_enable attribute
// These are bit positions. 0 is the left most bit.
enum cal_steps
{
    EXT_ZQCAL         = 0,
    WR_LEVEL          = 1,
    DQS_ALIGN         = 2,
    RDCLK_ALIGN       = 3,
    READ_CTR          = 4,
    READ_CTR_2D_VREF  = 5,
    WRITE_CTR         = 6,
    WRITE_CTR_2D_VREF = 7,
    COARSE_WR         = 8,
    COARSE_RD         = 9,
};

// Static consts for DDR4 voltages used in p9_mss_volt
enum voltages : uint64_t
{
    DDR4_NOMINAL_VOLTAGE = 1200,
    DDR4_VPP_VOLTAGE = 2500,
};

namespace mcbist
{
enum data_mode
{
    // MCBIST test data modes
    FIXED_DATA_MODE   = 0b000,
    RAND_FWD_MODE     = 0b001,
    RAND_REV_MODE     = 0b010,
    RAND_FWD_MAINT    = 0b011,
    RAND_REV_MAINT    = 0b100,
    DATA_EQ_ADDR      = 0b101,
    ROTATE_LEFT_MODE  = 0b110,
    ROTATE_RIGHT_MODE = 0b111,
};

// 0:3  Operation Type
enum op_type
{
    WRITE            = 0b0000, // fast, with no concurrent traffic
    READ             = 0b0001, // fast, with no concurrent traffic
    READ_WRITE       = 0b0010,
    WRITE_READ       = 0b0011,
    READ_WRITE_READ  = 0b0100,
    READ_WRITE_WRITE = 0b0101,
    RAND_SEQ         = 0b0110,
    READ_READ_WRITE  = 0b1000,
    SCRUB_RRWR       = 0b1001,
    STEER_RW         = 0b1010,
    ALTER            = 0b1011, // (W)
    DISPLAY          = 0b1100, // (R, slow)
    CCS_EXECUTE      = 0b1111,

    // if bits 9:11 (Data Mode bits)  = 000  (bits 4:8 used to specify which subtest to go to)
    // Refresh only cmd if bits 9:11 (Data Mode bits) /= 000
    GOTO_SUBTEST_N = 0b0111,
};

enum test_type
{
    USER_MODE = 0,
    CENSHMOO = 1,
    SUREFAIL = 2,
    MEMWRITE = 3,
    MEMREAD = 4,
    CBR_REFRESH = 5,
    MCBIST_SHORT = 6,
    SHORT_SEQ = 7,
    DELTA_I = 8,
    DELTA_I_LOOP = 9,
    SHORT_RAND = 10,
    LONG1 = 11,
    BUS_TAT = 12,
    SIMPLE_FIX = 13,
    SIMPLE_RAND = 14,
    SIMPLE_RAND_2W = 15,
    SIMPLE_RAND_FIXD = 16,
    SIMPLE_RA_RD_WR = 17,
    SIMPLE_RA_RD_R = 18,
    SIMPLE_RA_FD_R = 19,
    SIMPLE_RA_FD_R_INF = 20,
    SIMPLE_SA_FD_R = 21,
    SIMPLE_RA_FD_W = 22,
    INFINITE = 23,
    WR_ONLY = 24,
    W_ONLY = 25,
    R_ONLY = 26,
    W_ONLY_RAND = 27,
    R_ONLY_RAND = 28,
    R_ONLY_MULTI = 29,
    SHORT = 30,
    SIMPLE_RAND_BARI = 31,
    W_R_INFINITE = 32,
    W_R_RAND_INFINITE = 33,
    R_INFINITE1 = 34,
    R_INFINITE_RF = 35,
    MARCH = 36,
    SIMPLE_FIX_RF = 37,
    SHMOO_STRESS = 38,
    SIMPLE_RAND_RA = 39,
    SIMPLE_FIX_RA = 40,
    SIMPLE_FIX_RF_RA = 41,
    TEST_RR = 42,
    TEST_RF = 43,
    W_ONLY_INFINITE_RAND = 44,
    MCB_2D_CUP_SEQ = 45,
    MCB_2D_CUP_RAND = 46,
    SHMOO_STRESS_INFINITE = 47,
    HYNIX_1_COL = 48,
    RMWFIX = 49,
    RMWFIX_I = 50,
    W_INFINITE = 51,
    R_INFINITE = 52,
};

} // namespace mcbist

}
#endif
<commit_msg>Added shmoo data storage classes<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/shared/mss_const.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @mss_const.H
/// @This file contains constants for the memory team.
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: HB:FSP

#ifndef _MSS_CONST_H_
#define _MSS_CONST_H_

#include <cstdint>

namespace mss
{

enum sizes
{
    PORTS_PER_MCS = 2,
    PORTS_PER_MCBIST = 4,
    MC_PER_MODULE = 2,
    MCBIST_PER_MC = 1,
    MAX_DIMM_PER_PORT = 2,
    MAX_RANK_PER_DIMM = 4,
    RANK_MID_POINT = 4,            ///< Which rank number indicates the switch to the other DIMM
    DEFAULT_POLL_LIMIT = 10,       ///< the number of poll attempts in the event we can't calculate another
    MAX_NUM_IMP = 4,               ///< number of impedances valid per slew type
    MAX_NUM_CAL_SLEW_RATES = 4,    ///< 3V/ns, 4V/ns, 5V/ns, 6V/n
    MAX_SLEW_VALUE = 15,           ///< 4 bit value
    MAX_SUPPORTED_FREQUENCIES = 1, ///< Number of supported frequencies. Right now it's only 2400

    BYTES_PER_GB = 1000000000,      ///< Multiplier to go from GB to B
    T_PER_MT     = 1000000,          ///< Multiplier to go from MT/s to T/s

    // All need to be attributes - BRS
    // 48:51, 0b1100, (def_is_sim);       # BIG_STEP = 12 (changed from default for SIM)
    // 48:51, 0b0000, any;       # BIG_STEP = 0  SWyatt
    // #48:51, 0b0010, any;       # BIG_STEP = 2  (default)
    // 52:54,  0b000,  any;       # SMALL_STEP = 0 (default)      SWyatt
    //#52:54,  0b001,  any;       # SMALL_STEP = 1        (!! recommend setting to 0)
    // 55:60,  0b101010, any;     # WR_PRE_DLY = 42
    WR_LVL_BIG_STEP = 0b1100,
    WR_LVL_SMALL_STEP = 0b000,
    WR_LVL_PRE_DLY = 0b101010,
    WR_LVL_NUM_VALID_SAMPLES = 0x5,

    // THIS IS LIKELY INCORRECT - Should be defined in the DDR4 write centering protocol BRS
    // This field must be set to the larger of the two values in number of memory clock cycles.
    // FW_RD_WR = max(tWTR + 11, AL + tRTP + 3)
    WR_CNTR_FW_RD_WR = 0x11 + 4,
    WR_CNTR_FW_WR_RD = 0x0,

    // Attribute? BRS
    COARSE_CAL_STEP_SIZE = 0x4,
    CONSEQ_PASS = 0x8,
};

enum times
{
    CONVERT_PS_IN_A_NS      = 1000,     ///< 1000 pico in an nano
    CONVERT_PS_IN_A_US      = 1000000,  ///< 1000000 picos in a micro

    DELAY_1NS               = 1,
    DELAY_10NS              = 10 ,      ///< general purpose 10  ns delay for HW mode
    DELAY_100NS             = 100,      ///< general purpose 100 ns delay for HW mode
    DELAY_1US               = 1000,     ///< general purpose 1 usec delay for HW mode
    DELAY_100US             = 100000,   ///< general purpose 100 usec delay for HW mode
    DELAY_1MS               = 1000000,  ///< general purpose 1 ms delay for HW mode

    // From the DDR4spec 2400 speed - need to be changed to read attributes. BRS
    tWLO = 10,
    tWLOE = 2,

    SEC_IN_HOUR             = 60 * 60,  ///< seconds in an hour, used for scrub times
    BG_SCRUB_IN_HOURS       = 12,

    CMD_TIMEBASE            = 8192,     ///< Represents the timebase multiplier for the MCBIST inter cmd gap
};

enum states
{
    LOW = 0,
    HIGH = 1,
    START = 1,
    STOP = 0,
    START_N = 0,
    STOP_N = 1,
    ON = 1,
    OFF = 0,
    ON_N = 0,
    OFF_N = 1,
    YES = 1,
    NO = 0,
    YES_N = 0,
    NO_N = 1,
    INVALID = 0xFF,

    // This needs to be an attribute I think - BRS. Used as a boolean.
    CAL_ABORT_ON_ERROR = 1,
};

// Static consts describing the bits used in the cal_step_enable attribute
// These are bit positions. 0 is the left most bit.
enum cal_steps
{
    EXT_ZQCAL         = 0,
    WR_LEVEL          = 1,
    DQS_ALIGN         = 2,
    RDCLK_ALIGN       = 3,
    READ_CTR          = 4,
    READ_CTR_2D_VREF  = 5,
    WRITE_CTR         = 6,
    WRITE_CTR_2D_VREF = 7,
    COARSE_WR         = 8,
    COARSE_RD         = 9,
};

// Static consts for DDR4 voltages used in p9_mss_volt
enum voltages : uint64_t
{
    DDR4_NOMINAL_VOLTAGE = 1200,
    DDR4_VPP_VOLTAGE = 2500,
};

namespace mcbist
{
enum data_mode
{
    // MCBIST test data modes
    FIXED_DATA_MODE   = 0b000,
    RAND_FWD_MODE     = 0b001,
    RAND_REV_MODE     = 0b010,
    RAND_FWD_MAINT    = 0b011,
    RAND_REV_MAINT    = 0b100,
    DATA_EQ_ADDR      = 0b101,
    ROTATE_LEFT_MODE  = 0b110,
    ROTATE_RIGHT_MODE = 0b111,
};

// 0:3  Operation Type
enum op_type
{
    WRITE            = 0b0000, // fast, with no concurrent traffic
    READ             = 0b0001, // fast, with no concurrent traffic
    READ_WRITE       = 0b0010,
    WRITE_READ       = 0b0011,
    READ_WRITE_READ  = 0b0100,
    READ_WRITE_WRITE = 0b0101,
    RAND_SEQ         = 0b0110,
    READ_READ_WRITE  = 0b1000,
    SCRUB_RRWR       = 0b1001,
    STEER_RW         = 0b1010,
    ALTER            = 0b1011, // (W)
    DISPLAY          = 0b1100, // (R, slow)
    CCS_EXECUTE      = 0b1111,

    // if bits 9:11 (Data Mode bits)  = 000  (bits 4:8 used to specify which subtest to go to)
    // Refresh only cmd if bits 9:11 (Data Mode bits) /= 000
    GOTO_SUBTEST_N = 0b0111,
};

enum test_type
{
    USER_MODE = 0,
    CENSHMOO = 1,
    SUREFAIL = 2,
    MEMWRITE = 3,
    MEMREAD = 4,
    CBR_REFRESH = 5,
    MCBIST_SHORT = 6,
    SHORT_SEQ = 7,
    DELTA_I = 8,
    DELTA_I_LOOP = 9,
    SHORT_RAND = 10,
    LONG1 = 11,
    BUS_TAT = 12,
    SIMPLE_FIX = 13,
    SIMPLE_RAND = 14,
    SIMPLE_RAND_2W = 15,
    SIMPLE_RAND_FIXD = 16,
    SIMPLE_RA_RD_WR = 17,
    SIMPLE_RA_RD_R = 18,
    SIMPLE_RA_FD_R = 19,
    SIMPLE_RA_FD_R_INF = 20,
    SIMPLE_SA_FD_R = 21,
    SIMPLE_RA_FD_W = 22,
    INFINITE = 23,
    WR_ONLY = 24,
    W_ONLY = 25,
    R_ONLY = 26,
    W_ONLY_RAND = 27,
    R_ONLY_RAND = 28,
    R_ONLY_MULTI = 29,
    SHORT = 30,
    SIMPLE_RAND_BARI = 31,
    W_R_INFINITE = 32,
    W_R_RAND_INFINITE = 33,
    R_INFINITE1 = 34,
    R_INFINITE_RF = 35,
    MARCH = 36,
    SIMPLE_FIX_RF = 37,
    SHMOO_STRESS = 38,
    SIMPLE_RAND_RA = 39,
    SIMPLE_FIX_RA = 40,
    SIMPLE_FIX_RF_RA = 41,
    TEST_RR = 42,
    TEST_RF = 43,
    W_ONLY_INFINITE_RAND = 44,
    MCB_2D_CUP_SEQ = 45,
    MCB_2D_CUP_RAND = 46,
    SHMOO_STRESS_INFINITE = 47,
    HYNIX_1_COL = 48,
    RMWFIX = 49,
    RMWFIX_I = 50,
    W_INFINITE = 51,
    R_INFINITE = 52,
};

} // namespace mcbist

enum class shmoo_edge : std::size_t
{
    LEFT,
    RIGHT
};

} // namespace mss
#endif
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_chiplet_enable_ridi.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_chiplet_enable_ridi.C
///
/// @brief Enable RI/DI for all IO chiplets (excluding XBUS)
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : Sunil Kumar <skumar8j@in.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 3
// *HWP Consumed by     : HB
//------------------------------------------------------------------------------

//## auto_generated
#include "p9_chiplet_enable_ridi.H"

#include "p9_perv_scom_addresses.H"

static fapi2::ReturnCode p9_chiplet_enable_ridi_net_ctrl_action_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet);

fapi2::ReturnCode p9_chiplet_enable_ridi(const
        fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip)
{
    FAPI_DBG("Entering ...");

    for(auto l_target_cplt : i_target_chip.getChildren<fapi2::TARGET_TYPE_PERV>
        (static_cast<fapi2::TargetFilter>(fapi2::TARGET_FILTER_ALL_MC  |
                                          fapi2::TARGET_FILTER_ALL_PCI |
                                          fapi2::TARGET_FILTER_ALL_OBUS),
         fapi2::TARGET_STATE_FUNCTIONAL))
    {
        FAPI_INF("Call p9_chiplet_enable_ridi_net_ctrl_action_function");
        FAPI_TRY(p9_chiplet_enable_ridi_net_ctrl_action_function(l_target_cplt));
    }

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}

/// @brief Enable Drivers/Recievers of O, PCIE, MC chiplets
///
/// @param[in]     i_target_chiplet   Reference to TARGET_TYPE_PERV target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode p9_chiplet_enable_ridi_net_ctrl_action_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet)
{
    bool l_read_reg = false;
    fapi2::buffer<uint64_t> l_data64;
    FAPI_DBG("Entering ...");

    FAPI_INF("Check for chiplet enable");
    //Getting NET_CTRL0 register value
    FAPI_TRY(fapi2::getScom(i_target_chiplet, PERV_NET_CTRL0, l_data64));
    l_read_reg = l_data64.getBit<0>();  //l_read_reg = NET_CTRL0.CHIPLET_ENABLE

    if ( l_read_reg )
    {
        FAPI_INF("Enable Recievers, Drivers DI1 & DI2");
        //Setting NET_CTRL0 register value
        l_data64.flush<0>();
        l_data64.setBit<19>();  //NET_CTRL0.RI_N = 1
        l_data64.setBit<20>();  //NET_CTRL0.DI1_N = 1
        l_data64.setBit<21>();  //NET_CTRL0.DI2_N = 1
        FAPI_TRY(fapi2::putScom(i_target_chiplet, PERV_NET_CTRL0_WOR, l_data64));
    }

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}
<commit_msg>Temporarily fix master-p10 build<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/perv/p9_chiplet_enable_ridi.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
//------------------------------------------------------------------------------
/// @file  p9_chiplet_enable_ridi.C
///
/// @brief Enable RI/DI for all IO chiplets (excluding XBUS)
//------------------------------------------------------------------------------
// *HWP HW Owner        : Abhishek Agarwal <abagarw8@in.ibm.com>
// *HWP HW Backup Owner : Srinivas V Naga <srinivan@in.ibm.com>
// *HWP FW Owner        : Sunil Kumar <skumar8j@in.ibm.com>
// *HWP Team            : Perv
// *HWP Level           : 3
// *HWP Consumed by     : HB
//------------------------------------------------------------------------------

//## auto_generated
#include "p9_chiplet_enable_ridi.H"

#include "p9_perv_scom_addresses.H"
#include <target_filters.H>

static fapi2::ReturnCode p9_chiplet_enable_ridi_net_ctrl_action_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet);

fapi2::ReturnCode p9_chiplet_enable_ridi(const
        fapi2::Target<fapi2::TARGET_TYPE_PROC_CHIP>& i_target_chip)
{
    FAPI_DBG("Entering ...");

    for(auto l_target_cplt : i_target_chip.getChildren<fapi2::TARGET_TYPE_PERV>
        (static_cast<fapi2::TargetFilter>(fapi2::TARGET_FILTER_ALL_MC  |
                                          fapi2::TARGET_FILTER_ALL_PCI |
                                          fapi2::TARGET_FILTER_ALL_OBUS),
         fapi2::TARGET_STATE_FUNCTIONAL))
    {
        FAPI_INF("Call p9_chiplet_enable_ridi_net_ctrl_action_function");
        FAPI_TRY(p9_chiplet_enable_ridi_net_ctrl_action_function(l_target_cplt));
    }

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}

/// @brief Enable Drivers/Recievers of O, PCIE, MC chiplets
///
/// @param[in]     i_target_chiplet   Reference to TARGET_TYPE_PERV target
/// @return  FAPI2_RC_SUCCESS if success, else error code.
static fapi2::ReturnCode p9_chiplet_enable_ridi_net_ctrl_action_function(
    const fapi2::Target<fapi2::TARGET_TYPE_PERV>& i_target_chiplet)
{
    bool l_read_reg = false;
    fapi2::buffer<uint64_t> l_data64;
    FAPI_DBG("Entering ...");

    FAPI_INF("Check for chiplet enable");
    //Getting NET_CTRL0 register value
    FAPI_TRY(fapi2::getScom(i_target_chiplet, PERV_NET_CTRL0, l_data64));
    l_read_reg = l_data64.getBit<0>();  //l_read_reg = NET_CTRL0.CHIPLET_ENABLE

    if ( l_read_reg )
    {
        FAPI_INF("Enable Recievers, Drivers DI1 & DI2");
        //Setting NET_CTRL0 register value
        l_data64.flush<0>();
        l_data64.setBit<19>();  //NET_CTRL0.RI_N = 1
        l_data64.setBit<20>();  //NET_CTRL0.DI1_N = 1
        l_data64.setBit<21>();  //NET_CTRL0.DI2_N = 1
        FAPI_TRY(fapi2::putScom(i_target_chiplet, PERV_NET_CTRL0_WOR, l_data64));
    }

    FAPI_DBG("Exiting ...");

fapi_try_exit:
    return fapi2::current_err;

}
<|endoftext|>


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

#ifndef __BASE_STATS_MYSQL_HH__
#define __BASE_STATS_MYSQL_HH__

#include <cstdio>
#include <list>
#include <map>
#include <string>

#include "base/stats/output.hh"
#include "config/use_mysql.hh"

namespace MySQL { class Connection; }
namespace Stats {

class DistData;
class DistParams;
class MySqlRun;

struct SetupStat
{
    std::string name;
    std::string descr;
    std::string type;
    bool print;
    uint16_t prereq;
    int8_t prec;
    bool nozero;
    bool nonan;
    bool total;
    bool pdf;
    bool cdf;

    double min;
    double max;
    double bktsize;
    uint16_t size;

    void init();
    unsigned setup(MySqlRun *run);
};

class InsertData
{
  private:
    char *query;
    std::size_t size;
    bool first;
    static const std::size_t maxsize = 1024*1024;

  public:
    MySqlRun *run;

  public:
    uint64_t tick;
    double data;
    uint16_t stat;
    int16_t x;
    int16_t y;

  public:
    InsertData(MySqlRun *_run);
    ~InsertData();

    void flush();
    void insert();
};

class MySql : public Output
{
  protected:
    MySqlRun *run; /* Hide the implementation so we don't have a
                      #include mess */

    SetupStat stat;
    InsertData newdata;
    std::list<FormulaInfo *> formulas;
    bool configured;

  protected:
    std::map<int, int> idmap;

    void
    insert(int sim_id, int db_id)
    {
        using namespace std;
        idmap.insert(make_pair(sim_id, db_id));
    }

    int
    find(int sim_id)
    {
        using namespace std;
        map<int,int>::const_iterator i = idmap.find(sim_id);
        assert(i != idmap.end());
        return (*i).second;
    }

  public:
    MySql();
    ~MySql();

    void connect(const std::string &host, const std::string &user,
        const std::string &passwd, const std::string &db,
        const std::string &name, const std::string &sample,
        const std::string &project);
    bool connected() const;

  public:
    // Implement Visit
    virtual void visit(const ScalarInfo &info);
    virtual void visit(const VectorInfo &info);
    virtual void visit(const DistInfo &info);
    virtual void visit(const VectorDistInfo &info);
    virtual void visit(const Vector2dInfo &info);
    virtual void visit(const FormulaInfo &info);

    // Implement Output
    virtual bool valid() const;
    virtual void output();

  protected:
    // Output helper
    void output(const ScalarInfo &info);
    void output(const VectorInfo &info);
    void output(const DistInfo &info);
    void output(const VectorDistInfo &info);
    void output(const Vector2dInfo &info);
    void output(const FormulaInfo &info);
    void output(const DistData &data, const DistParams *params);

    void configure();
    bool configure(const Info &info, std::string type);
    void configure(const ScalarInfo &info);
    void configure(const VectorInfo &info);
    void configure(const DistInfo &info);
    void configure(const VectorDistInfo &info);
    void configure(const Vector2dInfo &info);
    void configure(const FormulaInfo &info);
};

bool initMySQL(std::string host, std::string database, std::string user,
    std::string passwd, std::string project, std::string name,
    std::string sample);

#if !USE_MYSQL
inline bool
initMySQL(std::string host, std::string user, std::string password,
    std::string database, std::string project, std::string name,
    std::string sample)
{
    return false;
}
#endif

} // namespace Stats

#endif // __BASE_STATS_MYSQL_HH__
<commit_msg>base: include types.hh in base/stats/mysql.hh Due to certain changes made via changeset 8229, the compilation was failing in certain cases. The compiler pointed to base/stats/mysql.hh for not naming a certain types like uint64_t. To rectify this, base/types.hh is being included in base/stats/mysql.hh.<commit_after>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Nathan Binkert
 */

#ifndef __BASE_STATS_MYSQL_HH__
#define __BASE_STATS_MYSQL_HH__

#include <cstdio>
#include <list>
#include <map>
#include <string>

#include "base/stats/output.hh"
#include "base/types.hh"
#include "config/use_mysql.hh"

namespace MySQL { class Connection; }
namespace Stats {

class DistData;
class DistParams;
class MySqlRun;

struct SetupStat
{
    std::string name;
    std::string descr;
    std::string type;
    bool print;
    uint16_t prereq;
    int8_t prec;
    bool nozero;
    bool nonan;
    bool total;
    bool pdf;
    bool cdf;

    double min;
    double max;
    double bktsize;
    uint16_t size;

    void init();
    unsigned setup(MySqlRun *run);
};

class InsertData
{
  private:
    char *query;
    std::size_t size;
    bool first;
    static const std::size_t maxsize = 1024*1024;

  public:
    MySqlRun *run;

  public:
    uint64_t tick;
    double data;
    uint16_t stat;
    int16_t x;
    int16_t y;

  public:
    InsertData(MySqlRun *_run);
    ~InsertData();

    void flush();
    void insert();
};

class MySql : public Output
{
  protected:
    MySqlRun *run; /* Hide the implementation so we don't have a
                      #include mess */

    SetupStat stat;
    InsertData newdata;
    std::list<FormulaInfo *> formulas;
    bool configured;

  protected:
    std::map<int, int> idmap;

    void
    insert(int sim_id, int db_id)
    {
        using namespace std;
        idmap.insert(make_pair(sim_id, db_id));
    }

    int
    find(int sim_id)
    {
        using namespace std;
        map<int,int>::const_iterator i = idmap.find(sim_id);
        assert(i != idmap.end());
        return (*i).second;
    }

  public:
    MySql();
    ~MySql();

    void connect(const std::string &host, const std::string &user,
        const std::string &passwd, const std::string &db,
        const std::string &name, const std::string &sample,
        const std::string &project);
    bool connected() const;

  public:
    // Implement Visit
    virtual void visit(const ScalarInfo &info);
    virtual void visit(const VectorInfo &info);
    virtual void visit(const DistInfo &info);
    virtual void visit(const VectorDistInfo &info);
    virtual void visit(const Vector2dInfo &info);
    virtual void visit(const FormulaInfo &info);

    // Implement Output
    virtual bool valid() const;
    virtual void output();

  protected:
    // Output helper
    void output(const ScalarInfo &info);
    void output(const VectorInfo &info);
    void output(const DistInfo &info);
    void output(const VectorDistInfo &info);
    void output(const Vector2dInfo &info);
    void output(const FormulaInfo &info);
    void output(const DistData &data, const DistParams *params);

    void configure();
    bool configure(const Info &info, std::string type);
    void configure(const ScalarInfo &info);
    void configure(const VectorInfo &info);
    void configure(const DistInfo &info);
    void configure(const VectorDistInfo &info);
    void configure(const Vector2dInfo &info);
    void configure(const FormulaInfo &info);
};

bool initMySQL(std::string host, std::string database, std::string user,
    std::string passwd, std::string project, std::string name,
    std::string sample);

#if !USE_MYSQL
inline bool
initMySQL(std::string host, std::string user, std::string password,
    std::string database, std::string project, std::string name,
    std::string sample)
{
    return false;
}
#endif

} // namespace Stats

#endif // __BASE_STATS_MYSQL_HH__
<|endoftext|>


<commit_before>#include <cstring>
#include <cstdlib>

#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "dinit.h"
#include "dinit-log.h"
#include "dinit-socket.h"
#include "proc-service.h"

#include "baseproc-sys.h"

/*
 * Base process implementation (base_process_service).
 *
 * See proc-service.h for interface documentation.
 */

void base_process_service::do_smooth_recovery() noexcept
{
    if (! restart_ps_process()) {
        emergency_stop();
        services->process_queues();
    }
}

bool base_process_service::bring_up() noexcept
{
    if (restarting) {
        if (pid == -1) {
            return restart_ps_process();
        }
        return true;
    }
    else {
        if (! open_socket()) {
            return false;
        }

        event_loop.get_time(restart_interval_time, clock_type::MONOTONIC);
        restart_interval_count = 0;
        if (start_ps_process(exec_arg_parts,
                onstart_flags.starts_on_console || onstart_flags.shares_console)) {
            // Note: we don't set a start timeout for PROCESS services.
            if (start_timeout != time_val(0,0) && get_type() != service_type_t::PROCESS) {
                restart_timer.arm_timer_rel(event_loop, start_timeout);
                stop_timer_armed = true;
            }
            else if (stop_timer_armed) {
                restart_timer.stop_timer(event_loop);
                stop_timer_armed = false;
            }
            return true;
        }
        return false;
    }
}

bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
{
    // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
    // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
    // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
    // is written to the pipe, and the parent can read it.

    event_loop.get_time(last_start_time, clock_type::MONOTONIC);

    int pipefd[2];
    if (bp_sys::pipe2(pipefd, O_CLOEXEC)) {
        log(loglevel_t::ERROR, get_name(), ": can't create status check pipe: ", strerror(errno));
        return false;
    }

    const char * logfile = this->logfile.c_str();
    if (*logfile == 0) {
        logfile = "/dev/null";
    }

    bool child_status_registered = false;
    control_conn_t *control_conn = nullptr;

    int control_socket[2] = {-1, -1};
    if (onstart_flags.pass_cs_fd) {
        if (dinit_socketpair(AF_UNIX, SOCK_STREAM, /* protocol */ 0, control_socket, SOCK_NONBLOCK)) {
            log(loglevel_t::ERROR, get_name(), ": can't create control socket: ", strerror(errno));
            goto out_p;
        }

        // Make the server side socket close-on-exec:
        int fdflags = bp_sys::fcntl(control_socket[0], F_GETFD);
        bp_sys::fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC);

        try {
            control_conn = new control_conn_t(event_loop, services, control_socket[0]);
        }
        catch (std::exception &exc) {
            log(loglevel_t::ERROR, get_name(), ": can't launch process; out of memory");
            goto out_cs;
        }
    }

    // Set up complete, now fork and exec:

    pid_t forkpid;

    try {
        child_status_listener.add_watch(event_loop, pipefd[0], dasynq::IN_EVENTS);
        child_status_registered = true;

        // We specify a high priority (i.e. low priority value) so that process termination is
        // handled early. This means we have always recorded that the process is terminated by the
        // time that we handle events that might otherwise cause us to signal the process, so we
        // avoid sending a signal to an invalid (and possibly recycled) process ID.
        forkpid = child_listener.fork(event_loop, reserved_child_watch, dasynq::DEFAULT_PRIORITY - 10);
        reserved_child_watch = true;
    }
    catch (std::exception &e) {
        log(loglevel_t::ERROR, get_name(), ": Could not fork: ", e.what());
        goto out_cs_h;
    }

    if (forkpid == 0) {
        const char * working_dir_c = nullptr;
        if (! working_dir.empty()) working_dir_c = working_dir.c_str();
        run_child_proc(cmd.data(), working_dir_c, logfile, on_console, pipefd[1], control_socket[1],
                socket_fd, run_as_uid, run_as_gid);
    }
    else {
        // Parent process
        bp_sys::close(pipefd[1]); // close the 'other end' fd
        if (control_socket[1] != -1) {
            bp_sys::close(control_socket[1]);
        }
        pid = forkpid;

        waiting_for_execstat = true;
        return true;
    }

    // Failure exit:

    out_cs_h:
    if (child_status_registered) {
        child_status_listener.deregister(event_loop);
    }

    if (onstart_flags.pass_cs_fd) {
        delete control_conn;

        out_cs:
        bp_sys::close(control_socket[0]);
        bp_sys::close(control_socket[1]);
    }

    out_p:
    bp_sys::close(pipefd[0]);
    bp_sys::close(pipefd[1]);

    return false;
}

base_process_service::base_process_service(service_set *sset, string name,
        service_type_t service_type_p, string &&command,
        const std::list<std::pair<unsigned,unsigned>> &command_offsets,
        const std::list<prelim_dep> &deplist_p)
     : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
       child_status_listener(this), restart_timer(this)
{
    program_name = std::move(command);
    exec_arg_parts = separate_args(program_name, command_offsets);

    restart_interval_count = 0;
    restart_interval_time = {0, 0};
    restart_timer.service = this;
    restart_timer.add_timer(event_loop);

    // By default, allow a maximum of 3 restarts within 10.0 seconds:
    restart_interval.seconds() = 10;
    restart_interval.nseconds() = 0;
    max_restart_interval_count = 3;

    waiting_restart_timer = false;
    reserved_child_watch = false;
    tracking_child = false;
    stop_timer_armed = false;
}

void base_process_service::do_restart() noexcept
{
    waiting_restart_timer = false;
    restart_interval_count++;
    auto service_state = get_state();

    if (service_state == service_state_t::STARTING) {
        // for a smooth recovery, we want to check dependencies are available before actually
        // starting:
        if (! check_deps_started()) {
            waiting_for_deps = true;
            return;
        }
    }

    if (! start_ps_process(exec_arg_parts, have_console || onstart_flags.shares_console)) {
        restarting = false;
        if (service_state == service_state_t::STARTING) {
            failed_to_start();
        }
        else {
            // desired_state = service_state_t::STOPPED;
            forced_stop();
        }
        services->process_queues();
    }
}

bool base_process_service::restart_ps_process() noexcept
{
    using time_val = dasynq::time_val;

    time_val current_time;
    event_loop.get_time(current_time, clock_type::MONOTONIC);

    if (max_restart_interval_count != 0) {
        // Check whether we're still in the most recent restart check interval:
        time_val int_diff = current_time - restart_interval_time;
        if (int_diff < restart_interval) {
            if (restart_interval_count >= max_restart_interval_count) {
                log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
                return false;
            }
        }
        else {
            restart_interval_time = current_time;
            restart_interval_count = 0;
        }
    }

    // Check if enough time has lapsed since the previous restart. If not, start a timer:
    time_val tdiff = current_time - last_start_time;
    if (restart_delay <= tdiff) {
        // > restart delay (normally 200ms)
        do_restart();
    }
    else {
        time_val timeout = restart_delay - tdiff;
        restart_timer.arm_timer_rel(event_loop, timeout);
        waiting_restart_timer = true;
    }
    return true;
}

bool base_process_service::interrupt_start() noexcept
{
    if (waiting_restart_timer) {
        restart_timer.stop_timer(event_loop);
        waiting_restart_timer = false;
        return service_record::interrupt_start();
    }
    else {
        log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
        kill_pg(SIGINT);

        if (stop_timeout != time_val(0,0)) {
            restart_timer.arm_timer_rel(event_loop, stop_timeout);
            stop_timer_armed = true;
        }
        else if (stop_timer_armed) {
            restart_timer.stop_timer(event_loop);
            stop_timer_armed = false;
        }

        set_state(service_state_t::STOPPING);
        return false;
    }
}

void base_process_service::kill_with_fire() noexcept
{
    if (pid != -1) {
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
        kill_pg(SIGKILL);
    }
}

void base_process_service::kill_pg(int signo) noexcept
{
    if (onstart_flags.signal_process_only) {
        bp_sys::kill(pid, signo);
    }
    else {
        pid_t pgid = bp_sys::getpgid(pid);
        if (pgid == -1) {
            // only should happen if pid is invalid, which should never happen...
            log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
            return;
        }
        bp_sys::kill(-pgid, signo);
    }
}

void base_process_service::timer_expired() noexcept
{
    stop_timer_armed = false;

    // Timer expires if:
    // We are stopping, including after having startup cancelled (stop timeout, state is STOPPING); We are
    // starting (start timeout, state is STARTING); We are waiting for restart timer before restarting,
    // including smooth recovery (restart timeout, state is STARTING or STARTED).
    if (get_state() == service_state_t::STOPPING) {
        kill_with_fire();
    }
    else if (pid != -1) {
        // Starting, start timed out.
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed start time; cancelling.");
        interrupt_start();
        stop_reason = stopped_reason_t::TIMEDOUT;
        failed_to_start(false, false);
    }
    else {
        // STARTING / STARTED, and we have a pid: must be restarting (smooth recovery if STARTED)
        do_restart();
    }
}

void base_process_service::emergency_stop() noexcept
{
    if (! do_auto_restart() && start_explicit) {
        start_explicit = false;
        release(false);
    }
    forced_stop();
    stop_dependents();
}

void base_process_service::becoming_inactive() noexcept
{
    if (socket_fd != -1) {
        close(socket_fd);
        socket_fd = -1;
    }
}

bool base_process_service::open_socket() noexcept
{
    if (socket_path.empty() || socket_fd != -1) {
        // No socket, or already open
        return true;
    }

    const char * saddrname = socket_path.c_str();

    // Check the specified socket path
    struct stat stat_buf;
    if (stat(saddrname, &stat_buf) == 0) {
        if ((stat_buf.st_mode & S_IFSOCK) == 0) {
            // Not a socket
            log(loglevel_t::ERROR, get_name(), ": Activation socket file exists (and is not a socket)");
            return false;
        }
    }
    else if (errno != ENOENT) {
        // Other error
        log(loglevel_t::ERROR, get_name(), ": Error checking activation socket: ", strerror(errno));
        return false;
    }

    // Remove stale socket file (if it exists).
    // We won't test the return from unlink - if it fails other than due to ENOENT, we should get an
    // error when we try to create the socket anyway.
    unlink(saddrname);

    uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + socket_path.length() + 1;
    struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
    if (name == nullptr) {
        log(loglevel_t::ERROR, get_name(), ": Opening activation socket: out of memory");
        return false;
    }

    name->sun_family = AF_UNIX;
    strcpy(name->sun_path, saddrname);

    int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (sockfd == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error creating activation socket: ", strerror(errno));
        free(name);
        return false;
    }

    if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error binding activation socket: ", strerror(errno));
        close(sockfd);
        free(name);
        return false;
    }

    free(name);

    // POSIX (1003.1, 2013) says that fchown and fchmod don't necessarily work on sockets. We have to
    // use chown and chmod instead.
    if (chown(saddrname, socket_uid, socket_gid)) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket owner/group: ", strerror(errno));
        close(sockfd);
        return false;
    }

    if (chmod(saddrname, socket_perms) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket permissions: ", strerror(errno));
        close(sockfd);
        return false;
    }

    if (listen(sockfd, 128) == -1) { // 128 "seems reasonable".
        log(loglevel_t::ERROR, ": Error listening on activation socket: ", strerror(errno));
        close(sockfd);
        return false;
    }

    socket_fd = sockfd;
    return true;
}
<commit_msg>Avoid 2nd call to get current time when starting process.<commit_after>#include <cstring>
#include <cstdlib>

#include <sys/un.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include "dinit.h"
#include "dinit-log.h"
#include "dinit-socket.h"
#include "proc-service.h"

#include "baseproc-sys.h"

/*
 * Base process implementation (base_process_service).
 *
 * See proc-service.h for interface documentation.
 */

void base_process_service::do_smooth_recovery() noexcept
{
    if (! restart_ps_process()) {
        emergency_stop();
        services->process_queues();
    }
}

bool base_process_service::bring_up() noexcept
{
    if (restarting) {
        if (pid == -1) {
            return restart_ps_process();
        }
        return true;
    }
    else {
        if (! open_socket()) {
            return false;
        }

        restart_interval_count = 0;
        if (start_ps_process(exec_arg_parts,
                onstart_flags.starts_on_console || onstart_flags.shares_console)) {
            // start_ps_process updates last_start_time, use it also for restart_interval_time:
            restart_interval_time = last_start_time;
            // Note: we don't set a start timeout for PROCESS services.
            if (start_timeout != time_val(0,0) && get_type() != service_type_t::PROCESS) {
                restart_timer.arm_timer_rel(event_loop, start_timeout);
                stop_timer_armed = true;
            }
            else if (stop_timer_armed) {
                restart_timer.stop_timer(event_loop);
                stop_timer_armed = false;
            }
            return true;
        }
        restart_interval_time = last_start_time;
        return false;
    }
}

bool base_process_service::start_ps_process(const std::vector<const char *> &cmd, bool on_console) noexcept
{
    // In general, you can't tell whether fork/exec is successful. We use a pipe to communicate
    // success/failure from the child to the parent. The pipe is set CLOEXEC so a successful
    // exec closes the pipe, and the parent sees EOF. If the exec is unsuccessful, the errno
    // is written to the pipe, and the parent can read it.

    event_loop.get_time(last_start_time, clock_type::MONOTONIC);

    int pipefd[2];
    if (bp_sys::pipe2(pipefd, O_CLOEXEC)) {
        log(loglevel_t::ERROR, get_name(), ": can't create status check pipe: ", strerror(errno));
        return false;
    }

    const char * logfile = this->logfile.c_str();
    if (*logfile == 0) {
        logfile = "/dev/null";
    }

    bool child_status_registered = false;
    control_conn_t *control_conn = nullptr;

    int control_socket[2] = {-1, -1};
    if (onstart_flags.pass_cs_fd) {
        if (dinit_socketpair(AF_UNIX, SOCK_STREAM, /* protocol */ 0, control_socket, SOCK_NONBLOCK)) {
            log(loglevel_t::ERROR, get_name(), ": can't create control socket: ", strerror(errno));
            goto out_p;
        }

        // Make the server side socket close-on-exec:
        int fdflags = bp_sys::fcntl(control_socket[0], F_GETFD);
        bp_sys::fcntl(control_socket[0], F_SETFD, fdflags | FD_CLOEXEC);

        try {
            control_conn = new control_conn_t(event_loop, services, control_socket[0]);
        }
        catch (std::exception &exc) {
            log(loglevel_t::ERROR, get_name(), ": can't launch process; out of memory");
            goto out_cs;
        }
    }

    // Set up complete, now fork and exec:

    pid_t forkpid;

    try {
        child_status_listener.add_watch(event_loop, pipefd[0], dasynq::IN_EVENTS);
        child_status_registered = true;

        // We specify a high priority (i.e. low priority value) so that process termination is
        // handled early. This means we have always recorded that the process is terminated by the
        // time that we handle events that might otherwise cause us to signal the process, so we
        // avoid sending a signal to an invalid (and possibly recycled) process ID.
        forkpid = child_listener.fork(event_loop, reserved_child_watch, dasynq::DEFAULT_PRIORITY - 10);
        reserved_child_watch = true;
    }
    catch (std::exception &e) {
        log(loglevel_t::ERROR, get_name(), ": Could not fork: ", e.what());
        goto out_cs_h;
    }

    if (forkpid == 0) {
        const char * working_dir_c = nullptr;
        if (! working_dir.empty()) working_dir_c = working_dir.c_str();
        run_child_proc(cmd.data(), working_dir_c, logfile, on_console, pipefd[1], control_socket[1],
                socket_fd, run_as_uid, run_as_gid);
    }
    else {
        // Parent process
        bp_sys::close(pipefd[1]); // close the 'other end' fd
        if (control_socket[1] != -1) {
            bp_sys::close(control_socket[1]);
        }
        pid = forkpid;

        waiting_for_execstat = true;
        return true;
    }

    // Failure exit:

    out_cs_h:
    if (child_status_registered) {
        child_status_listener.deregister(event_loop);
    }

    if (onstart_flags.pass_cs_fd) {
        delete control_conn;

        out_cs:
        bp_sys::close(control_socket[0]);
        bp_sys::close(control_socket[1]);
    }

    out_p:
    bp_sys::close(pipefd[0]);
    bp_sys::close(pipefd[1]);

    return false;
}

base_process_service::base_process_service(service_set *sset, string name,
        service_type_t service_type_p, string &&command,
        const std::list<std::pair<unsigned,unsigned>> &command_offsets,
        const std::list<prelim_dep> &deplist_p)
     : service_record(sset, name, service_type_p, deplist_p), child_listener(this),
       child_status_listener(this), restart_timer(this)
{
    program_name = std::move(command);
    exec_arg_parts = separate_args(program_name, command_offsets);

    restart_interval_count = 0;
    restart_interval_time = {0, 0};
    restart_timer.service = this;
    restart_timer.add_timer(event_loop);

    // By default, allow a maximum of 3 restarts within 10.0 seconds:
    restart_interval.seconds() = 10;
    restart_interval.nseconds() = 0;
    max_restart_interval_count = 3;

    waiting_restart_timer = false;
    reserved_child_watch = false;
    tracking_child = false;
    stop_timer_armed = false;
}

void base_process_service::do_restart() noexcept
{
    waiting_restart_timer = false;
    restart_interval_count++;
    auto service_state = get_state();

    if (service_state == service_state_t::STARTING) {
        // for a smooth recovery, we want to check dependencies are available before actually
        // starting:
        if (! check_deps_started()) {
            waiting_for_deps = true;
            return;
        }
    }

    if (! start_ps_process(exec_arg_parts, have_console || onstart_flags.shares_console)) {
        restarting = false;
        if (service_state == service_state_t::STARTING) {
            failed_to_start();
        }
        else {
            // desired_state = service_state_t::STOPPED;
            forced_stop();
        }
        services->process_queues();
    }
}

bool base_process_service::restart_ps_process() noexcept
{
    using time_val = dasynq::time_val;

    time_val current_time;
    event_loop.get_time(current_time, clock_type::MONOTONIC);

    if (max_restart_interval_count != 0) {
        // Check whether we're still in the most recent restart check interval:
        time_val int_diff = current_time - restart_interval_time;
        if (int_diff < restart_interval) {
            if (restart_interval_count >= max_restart_interval_count) {
                log(loglevel_t::ERROR, "Service ", get_name(), " restarting too quickly; stopping.");
                return false;
            }
        }
        else {
            restart_interval_time = current_time;
            restart_interval_count = 0;
        }
    }

    // Check if enough time has lapsed since the previous restart. If not, start a timer:
    time_val tdiff = current_time - last_start_time;
    if (restart_delay <= tdiff) {
        // > restart delay (normally 200ms)
        do_restart();
    }
    else {
        time_val timeout = restart_delay - tdiff;
        restart_timer.arm_timer_rel(event_loop, timeout);
        waiting_restart_timer = true;
    }
    return true;
}

bool base_process_service::interrupt_start() noexcept
{
    if (waiting_restart_timer) {
        restart_timer.stop_timer(event_loop);
        waiting_restart_timer = false;
        return service_record::interrupt_start();
    }
    else {
        log(loglevel_t::WARN, "Interrupting start of service ", get_name(), " with pid ", pid, " (with SIGINT).");
        kill_pg(SIGINT);

        if (stop_timeout != time_val(0,0)) {
            restart_timer.arm_timer_rel(event_loop, stop_timeout);
            stop_timer_armed = true;
        }
        else if (stop_timer_armed) {
            restart_timer.stop_timer(event_loop);
            stop_timer_armed = false;
        }

        set_state(service_state_t::STOPPING);
        return false;
    }
}

void base_process_service::kill_with_fire() noexcept
{
    if (pid != -1) {
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed stop time; killing.");
        kill_pg(SIGKILL);
    }
}

void base_process_service::kill_pg(int signo) noexcept
{
    if (onstart_flags.signal_process_only) {
        bp_sys::kill(pid, signo);
    }
    else {
        pid_t pgid = bp_sys::getpgid(pid);
        if (pgid == -1) {
            // only should happen if pid is invalid, which should never happen...
            log(loglevel_t::ERROR, get_name(), ": can't signal process: ", strerror(errno));
            return;
        }
        bp_sys::kill(-pgid, signo);
    }
}

void base_process_service::timer_expired() noexcept
{
    stop_timer_armed = false;

    // Timer expires if:
    // We are stopping, including after having startup cancelled (stop timeout, state is STOPPING); We are
    // starting (start timeout, state is STARTING); We are waiting for restart timer before restarting,
    // including smooth recovery (restart timeout, state is STARTING or STARTED).
    if (get_state() == service_state_t::STOPPING) {
        kill_with_fire();
    }
    else if (pid != -1) {
        // Starting, start timed out.
        log(loglevel_t::WARN, "Service ", get_name(), " with pid ", pid, " exceeded allowed start time; cancelling.");
        interrupt_start();
        stop_reason = stopped_reason_t::TIMEDOUT;
        failed_to_start(false, false);
    }
    else {
        // STARTING / STARTED, and we have a pid: must be restarting (smooth recovery if STARTED)
        do_restart();
    }
}

void base_process_service::emergency_stop() noexcept
{
    if (! do_auto_restart() && start_explicit) {
        start_explicit = false;
        release(false);
    }
    forced_stop();
    stop_dependents();
}

void base_process_service::becoming_inactive() noexcept
{
    if (socket_fd != -1) {
        close(socket_fd);
        socket_fd = -1;
    }
}

bool base_process_service::open_socket() noexcept
{
    if (socket_path.empty() || socket_fd != -1) {
        // No socket, or already open
        return true;
    }

    const char * saddrname = socket_path.c_str();

    // Check the specified socket path
    struct stat stat_buf;
    if (stat(saddrname, &stat_buf) == 0) {
        if ((stat_buf.st_mode & S_IFSOCK) == 0) {
            // Not a socket
            log(loglevel_t::ERROR, get_name(), ": Activation socket file exists (and is not a socket)");
            return false;
        }
    }
    else if (errno != ENOENT) {
        // Other error
        log(loglevel_t::ERROR, get_name(), ": Error checking activation socket: ", strerror(errno));
        return false;
    }

    // Remove stale socket file (if it exists).
    // We won't test the return from unlink - if it fails other than due to ENOENT, we should get an
    // error when we try to create the socket anyway.
    unlink(saddrname);

    uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + socket_path.length() + 1;
    struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
    if (name == nullptr) {
        log(loglevel_t::ERROR, get_name(), ": Opening activation socket: out of memory");
        return false;
    }

    name->sun_family = AF_UNIX;
    strcpy(name->sun_path, saddrname);

    int sockfd = dinit_socket(AF_UNIX, SOCK_STREAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (sockfd == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error creating activation socket: ", strerror(errno));
        free(name);
        return false;
    }

    if (bind(sockfd, (struct sockaddr *) name, sockaddr_size) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error binding activation socket: ", strerror(errno));
        close(sockfd);
        free(name);
        return false;
    }

    free(name);

    // POSIX (1003.1, 2013) says that fchown and fchmod don't necessarily work on sockets. We have to
    // use chown and chmod instead.
    if (chown(saddrname, socket_uid, socket_gid)) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket owner/group: ", strerror(errno));
        close(sockfd);
        return false;
    }

    if (chmod(saddrname, socket_perms) == -1) {
        log(loglevel_t::ERROR, get_name(), ": Error setting activation socket permissions: ", strerror(errno));
        close(sockfd);
        return false;
    }

    if (listen(sockfd, 128) == -1) { // 128 "seems reasonable".
        log(loglevel_t::ERROR, ": Error listening on activation socket: ", strerror(errno));
        close(sockfd);
        return false;
    }

    socket_fd = sockfd;
    return true;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsSelectionFunction.hxx,v $
 *
 *  $Revision: 1.12 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 18:34:04 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef SD_SLIDESORTER_SELECTION_FUNCTION_HXX
#define SD_SLIDESORTER_SELECTION_FUNCTION_HXX

#include "controller/SlsSlideFunction.hxx"
#include "model/SlsSharedPageDescriptor.hxx"

#ifndef _LIST_HXX
#include <tools/list.hxx>
#endif
#include <memory>

class SdSlideViewShell;
class SdWindow;
class SdSlideView;
class SdDrawDocument;
class Sound;

namespace sd { namespace slidesorter { namespace controller {

class SlideSorterController;

class SelectionFunction
    : public SlideFunction
{
public:
    TYPEINFO();

    static FunctionReference Create( SlideSorterController& rController, SfxRequest& rRequest );

    // Mouse- & Key-Events
    virtual BOOL KeyInput(const KeyEvent& rKEvt);
    virtual BOOL MouseMove(const MouseEvent& rMEvt);
    virtual BOOL MouseButtonUp(const MouseEvent& rMEvt);
    virtual BOOL MouseButtonDown(const MouseEvent& rMEvt);
    virtual void Paint(const Rectangle&, ::sd::Window* );

    virtual void Activate();           // Function aktivieren
    virtual void Deactivate();         // Function deaktivieren

    virtual void ScrollStart();
    virtual void ScrollEnd();

    /// Forward to the clipboard manager.
    virtual void DoCut (void);

    /// Forward to the clipboard manager.
    virtual void DoCopy (void);

    /// Forward to the clipboard manager.
    virtual void DoPaste (void);

    /** is called when the current function should be aborted.

        This is used when a function gets a KEY_ESCAPE but can also
        be called directly.

        @returns
            true if a active function was aborted
    */
    virtual bool cancel();

protected:
    SlideSorterController& mrController;

    SelectionFunction (
        SlideSorterController& rController,
        SfxRequest& rRequest);

    virtual ~SelectionFunction();

private:
    class SubstitutionHandler;
    class EventDescriptor;
    class InsertionIndicatorHandler;

    /// Set in MouseButtonDown this flag indicates that a page has been hit.
    bool mbPageHit;

    /// The rectangle of the mouse drag selection.
    Rectangle maDragSelectionRectangle;
    bool mbDragSelection;

    /// Box of the insert marker in model coordinates.
    Rectangle maInsertionMarkerBox;

    /** We use this flag to filter out the cases where MouseMotion() is called
        with a pressed mouse button but without a prior MouseButtonDown()
        call.  This is an indication that the mouse button was pressed over
        another control, e.g. the view tab bar, and that a re-layout of the
        controls moved the slide sorter under the mouse.
    */
    bool mbProcessingMouseButtonDown;

    ::std::auto_ptr<SubstitutionHandler> mpSubstitutionHandler;

    ::std::auto_ptr<InsertionIndicatorHandler> mpInsertionIndicatorHandler;

    DECL_LINK( DragSlideHdl, Timer* );
    void StartDrag (void);

    /** Set the selection to exactly the specified page and also set it as
        the current page.
    */
    void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor);

    /** When the view on which this selection function is working is the
        main view then the view is switched to the regular editing view.
    */
    void SwitchView (const model::SharedPageDescriptor& rpDescriptor);

    /** Make the slide nOffset slides away of the current one the new
        current slide.  When the new index is outside the range of valid
        page numbers it is clipped to that range.
        @param nOffset
            When nOffset is negative then go back.  When nOffset if positive go
            forward.  When it is zero then ignore the call.
    */
    void GotoNextPage (int nOffset);

    void ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent);
    void ProcessKeyEvent (const KeyEvent& rEvent);

    // What follows are a couple of helper methods that are used by
    // ProcessMouseEvent().

    /// Select the specified page and set the selection anchor.
    void SelectHitPage (const model::SharedPageDescriptor& rpDescriptor);
    /// Deselect the specified page.
    void DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor);
    /// Deselect all pages.
    void DeselectAllPages (void);

    /** for a possibly following mouse motion by starting the drag timer
        that after a short time of pressed but un-moved mouse starts a drag
        operation.
    */
    void PrepareMouseMotion (const Point& aMouseModelPosition);

    /** Select all pages between and including the selection anchor and the
        specified page.
    */
    void RangeSelect (const model::SharedPageDescriptor& rpDescriptor);

    /** Start a rectangle selection at the given position.
    */
    void StartRectangleSelection (const Point& aMouseModelPosition);

    /** Update the rectangle selection so that the given position becomes
        the new second point of the selection rectangle.
    */
    void UpdateRectangleSelection (const Point& aMouseModelPosition);

    /** Select all pages that lie completly in the selection rectangle.
    */
    void ProcessRectangleSelection (bool bToggleSelection);

    /** Hide and clear the insertion indiciator, substitution display and
        selection rectangle.
    */
    void ClearOverlays (void);

    /** Compute a numerical code that describes a mouse event and that can
        be used for fast look up of the appropriate reaction.
    */
    sal_uInt32 EncodeMouseEvent (
        const EventDescriptor& rDescriptor,
        const MouseEvent& rEvent) const;

    /** Compute a numerical code that describes a key event and that can
        be used for fast look up of the appropriate reaction.
    */
    sal_uInt32 EncodeKeyEvent (
        const EventDescriptor& rDescriptor,
        const KeyEvent& rEvent) const;

    void EventPreprocessing (const EventDescriptor& rEvent);
    bool EventProcessing (const EventDescriptor& rEvent);
    void EventPostprocessing (const EventDescriptor& rEvent);
};

} } } // end of namespace ::sd::slidesorter::controller

#endif

<commit_msg>INTEGRATION: CWS presenterview (1.12.54); FILE MERGED 2008/03/05 17:25:12 af 1.12.54.3: #i86733# Reintroduced SetCurrentPage() method that not only switches to a page but also selects it. 2007/04/26 16:03:26 af 1.12.54.2: #i75317# Using the new CurrentSlideManager class. 2007/03/12 15:35:35 af 1.12.54.1: #i75317# Remove dependecy of slide sorter on SlideSorterViewShell.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: SlsSelectionFunction.hxx,v $
 *
 *  $Revision: 1.13 $
 *
 *  last change: $Author: kz $ $Date: 2008-04-03 14:36:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef SD_SLIDESORTER_SELECTION_FUNCTION_HXX
#define SD_SLIDESORTER_SELECTION_FUNCTION_HXX

#include "controller/SlsSlideFunction.hxx"
#include "model/SlsSharedPageDescriptor.hxx"

#ifndef _LIST_HXX
#include <tools/list.hxx>
#endif
#include <memory>

class SdSlideViewShell;
class SdWindow;
class SdSlideView;
class SdDrawDocument;
class Sound;

namespace sd { namespace slidesorter {
class SlideSorter;
} }

namespace sd { namespace slidesorter { namespace controller {

class SlideSorterController;

class SelectionFunction
    : public SlideFunction
{
public:
    TYPEINFO();

    static FunctionReference Create( SlideSorter& rSlideSorter, SfxRequest& rRequest );

    // Mouse- & Key-Events
    virtual BOOL KeyInput(const KeyEvent& rKEvt);
    virtual BOOL MouseMove(const MouseEvent& rMEvt);
    virtual BOOL MouseButtonUp(const MouseEvent& rMEvt);
    virtual BOOL MouseButtonDown(const MouseEvent& rMEvt);
    virtual void Paint(const Rectangle&, ::sd::Window* );

    virtual void Activate();           // Function aktivieren
    virtual void Deactivate();         // Function deaktivieren

    virtual void ScrollStart();
    virtual void ScrollEnd();

    /// Forward to the clipboard manager.
    virtual void DoCut (void);

    /// Forward to the clipboard manager.
    virtual void DoCopy (void);

    /// Forward to the clipboard manager.
    virtual void DoPaste (void);

    /** is called when the current function should be aborted.

        This is used when a function gets a KEY_ESCAPE but can also
        be called directly.

        @returns
            true if a active function was aborted
    */
    virtual bool cancel();

protected:
    SlideSorter& mrSlideSorter;
    SlideSorterController& mrController;

    SelectionFunction (
        SlideSorter& rSlideSorter,
        SfxRequest& rRequest);

    virtual ~SelectionFunction();

private:
    class SubstitutionHandler;
    class EventDescriptor;
    class InsertionIndicatorHandler;

    /// Set in MouseButtonDown this flag indicates that a page has been hit.
    bool mbPageHit;

    /// The rectangle of the mouse drag selection.
    Rectangle maDragSelectionRectangle;
    bool mbDragSelection;

    /// Box of the insert marker in model coordinates.
    Rectangle maInsertionMarkerBox;

    /** We use this flag to filter out the cases where MouseMotion() is called
        with a pressed mouse button but without a prior MouseButtonDown()
        call.  This is an indication that the mouse button was pressed over
        another control, e.g. the view tab bar, and that a re-layout of the
        controls moved the slide sorter under the mouse.
    */
    bool mbProcessingMouseButtonDown;

    ::std::auto_ptr<SubstitutionHandler> mpSubstitutionHandler;

    ::std::auto_ptr<InsertionIndicatorHandler> mpInsertionIndicatorHandler;

    DECL_LINK( DragSlideHdl, Timer* );
    void StartDrag (void);

    /** Set the selection to exactly the specified page and also set it as
        the current page.
    */
    void SetCurrentPage (const model::SharedPageDescriptor& rpDescriptor);

    /** When the view on which this selection function is working is the
        main view then the view is switched to the regular editing view.
    */
    void SwitchView (const model::SharedPageDescriptor& rpDescriptor);

    /** Make the slide nOffset slides away of the current one the new
        current slide.  When the new index is outside the range of valid
        page numbers it is clipped to that range.
        @param nOffset
            When nOffset is negative then go back.  When nOffset if positive go
            forward.  When it is zero then ignore the call.
    */
    void GotoNextPage (int nOffset);

    void ProcessMouseEvent (sal_uInt32 nEventType, const MouseEvent& rEvent);
    void ProcessKeyEvent (const KeyEvent& rEvent);

    // What follows are a couple of helper methods that are used by
    // ProcessMouseEvent().

    /// Select the specified page and set the selection anchor.
    void SelectHitPage (const model::SharedPageDescriptor& rpDescriptor);
    /// Deselect the specified page.
    void DeselectHitPage (const model::SharedPageDescriptor& rpDescriptor);
    /// Deselect all pages.
    void DeselectAllPages (void);

    /** for a possibly following mouse motion by starting the drag timer
        that after a short time of pressed but un-moved mouse starts a drag
        operation.
    */
    void PrepareMouseMotion (const Point& aMouseModelPosition);

    /** Select all pages between and including the selection anchor and the
        specified page.
    */
    void RangeSelect (const model::SharedPageDescriptor& rpDescriptor);

    /** Start a rectangle selection at the given position.
    */
    void StartRectangleSelection (const Point& aMouseModelPosition);

    /** Update the rectangle selection so that the given position becomes
        the new second point of the selection rectangle.
    */
    void UpdateRectangleSelection (const Point& aMouseModelPosition);

    /** Select all pages that lie completly in the selection rectangle.
    */
    void ProcessRectangleSelection (bool bToggleSelection);

    /** Hide and clear the insertion indiciator, substitution display and
        selection rectangle.
    */
    void ClearOverlays (void);

    /** Compute a numerical code that describes a mouse event and that can
        be used for fast look up of the appropriate reaction.
    */
    sal_uInt32 EncodeMouseEvent (
        const EventDescriptor& rDescriptor,
        const MouseEvent& rEvent) const;

    /** Compute a numerical code that describes a key event and that can
        be used for fast look up of the appropriate reaction.
    */
    sal_uInt32 EncodeKeyEvent (
        const EventDescriptor& rDescriptor,
        const KeyEvent& rEvent) const;

    void EventPreprocessing (const EventDescriptor& rEvent);
    bool EventProcessing (const EventDescriptor& rEvent);
    void EventPostprocessing (const EventDescriptor& rEvent);
};

} } } // end of namespace ::sd::slidesorter::controller

#endif

<|endoftext|>