<commit_before>/*******************************************************************************
 *
 * X testing environment - Google Test helper class to communicate with the
 * server
 *
 * Copyright (C) 2012 Red Hat, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 ******************************************************************************/

#include "xorg/gtest/xorg-gtest-xserver.h"
#include "defines.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <algorithm>
#include <cerrno>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <vector>
#include <map>
#include <fstream>

#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>

struct xorg::testing::XServer::Private {
  Private()
      : display_number(DEFAULT_DISPLAY),
        path_to_server(DEFAULT_XORG_SERVER) {

    options["-config"] = DUMMY_CONF_PATH;
    options["-logfile"] = DEFAULT_XORG_LOGFILE;
  }

  unsigned int display_number;
  std::string display_string;
  std::string path_to_server;
  std::map<std::string, std::string> options;
  std::string version;
};

xorg::testing::XServer::XServer() : d_(new Private) {
  d_->display_number = DEFAULT_DISPLAY;
  SetDisplayNumber(d_->display_number);
}

xorg::testing::XServer::~XServer() {
  if (Pid() > 0)
    if (!Terminate(3000))
      Kill(300);
}

void xorg::testing::XServer::SetDisplayNumber(unsigned int display_number) {
    d_->display_number = display_number;

    std::stringstream s;
    s << ":" << display_number;
    d_->display_string = s.str();
}

unsigned int xorg::testing::XServer::GetDisplayNumber(void) {
  return d_->display_number;
}

const std::string& xorg::testing::XServer::GetDisplayString(void) {
  return d_->display_string;
}

void xorg::testing::XServer::SetServerPath(const std::string &path_to_server) {
  d_->path_to_server = path_to_server;
}

bool xorg::testing::XServer::WaitForEvent(::Display *display, time_t timeout)
{
    fd_set fds;
    FD_ZERO(&fds);

    int display_fd = ConnectionNumber(display);

    XSync(display, False);

    if (XPending(display))
        return true;
    else {
        FD_SET(display_fd, &fds);

        struct timeval timeval = {
            static_cast<time_t>(timeout / 1000),
            static_cast<time_t>(timeout % 1000),
        };

        int ret;
        if (timeout)
            ret = select(display_fd + 1, &fds, NULL, NULL, &timeval);
        else
            ret = select(display_fd + 1, &fds, NULL, NULL, NULL);

        if (ret < 0)
            throw std::runtime_error("Failed to select on X fd");

        if (ret == 0)
            return false;

        return XPending(display);
    }
}

bool xorg::testing::XServer::WaitForEventOfType(::Display *display, int type, int extension,
                                                int evtype, time_t timeout)
{
    while (WaitForEvent(display, timeout)) {
        XEvent event;
        if (!XPeekEvent(display, &event))
            throw std::runtime_error("Failed to peek X event");

        if (event.type != type) {
            if (XNextEvent(display, &event) != Success)
                throw std::runtime_error("Failed to remove X event");
            continue;
        }

        if (event.type != GenericEvent || extension == -1)
            return true;

        XGenericEvent *generic_event = reinterpret_cast<XGenericEvent*>(&event);

        if (generic_event->extension != extension) {
            if (XNextEvent(display, &event) != Success)
                throw std::runtime_error("Failed to remove X event");
            continue;
        }

        if (evtype == -1 || generic_event->evtype == evtype)
            return true;

        if (XNextEvent(display, &event) != Success)
            throw std::runtime_error("Failed to remove X event");
    }

    return false;
}

bool xorg::testing::XServer::WaitForDevice(::Display *display, const std::string &name,
                                           time_t timeout)
{
    int opcode;
    int event_start;
    int error_start;

    if (!XQueryExtension(display, "XInputExtension", &opcode, &event_start,
                         &error_start))
        throw std::runtime_error("Failed to query XInput extension");

    while (WaitForEventOfType(display, GenericEvent, opcode,
                              XI_HierarchyChanged, timeout)) {
        XEvent event;
        if (XNextEvent(display, &event) != Success)
            throw std::runtime_error("Failed to get X event");

        XGenericEventCookie *xcookie =
            reinterpret_cast<XGenericEventCookie*>(&event.xcookie);
        if (!XGetEventData(display, xcookie))
            throw std::runtime_error("Failed to get X event data");

        XIHierarchyEvent *hierarchy_event =
            reinterpret_cast<XIHierarchyEvent*>(xcookie->data);

        if (!(hierarchy_event->flags & XIDeviceEnabled)) {
            XFreeEventData(display, xcookie);
            continue;
        }

        bool device_found = false;
        for (int i = 0; i < hierarchy_event->num_info; i++) {
            if (!(hierarchy_event->info[i].flags & XIDeviceEnabled))
                continue;

            int num_devices;
            XIDeviceInfo *device_info =
                XIQueryDevice(display, hierarchy_event->info[i].deviceid,
                              &num_devices);
            if (num_devices != 1 || !device_info)
                throw std::runtime_error("Failed to query device");

            if (name.compare(device_info[0].name) == 0) {
                device_found = true;
                break;
            }
        }

        XFreeEventData(display, xcookie);

        if (device_found)
            return true;
    }

    return false;
}

void xorg::testing::XServer::WaitForConnections(void) {
  for (int i = 0; i < 100; ++i) {
    Display *test_display = XOpenDisplay(GetDisplayString().c_str());

    if (test_display) {
      XCloseDisplay(test_display);
      return;
    }

    int status;
    int pid = waitpid(Pid(), &status, WNOHANG);
    if (pid == Pid()) {
      std::string message;
      message += "X server failed to start on display ";
      message +=  GetDisplayString();
      message += ". Ensure that the correct video driver is installed.\n"
                 "If the X.org server is older than 1.12, "
                 "tests will need to be run as root.\nCheck ";
      message += d_->options["-logfile"];
      message += " for any errors";
      throw std::runtime_error(message);
    } else if (pid == 0) {
      usleep(100);
    } else if (pid == -1) {
      throw std::runtime_error("Could not get status of X server process");
    } else {
      throw std::runtime_error("Invalid child PID returned by Process::Wait()");
    }
  }

  throw std::runtime_error("Unable to open connection to X server");
}

void xorg::testing::XServer::TestStartup(void) {
  Display* test_display = XOpenDisplay(GetDisplayString().c_str());
  if (test_display) {
    XCloseDisplay(test_display);
    std::string message;
    message += "A server is already running on ";
    message += GetDisplayString();
    message += ".";
    throw std::runtime_error(message);
  }

  std::string log = d_->options["-logfile"];

  /* The Xorg server won't start unless the log file and the old log file are
   * writable. */
  bool logfile_was_present;
  std::ifstream file_test;
  file_test.open(log.c_str());
  logfile_was_present = file_test.good();

  std::ofstream log_test;
  log_test.open(log.c_str(), std::ofstream::out);
  log_test.close();
  if (log_test.fail()) {
    throw std::runtime_error("X.org server log file " + log + " is not writable.");
  } else if (!logfile_was_present)
    unlink(log.c_str());

  std::string old_log_file = log + ".old";

  file_test.open(old_log_file.c_str());
  logfile_was_present = file_test.good();

  log_test.open(old_log_file.c_str(), std::ofstream::out);
  log_test.close();
  if (log_test.fail()) {
    throw std::runtime_error("X.org old server log file " + old_log_file + " is not writable.");
  } else if (!logfile_was_present)
    unlink(old_log_file.c_str());
}

const std::string& xorg::testing::XServer::GetVersion(void) {
  if (Pid() == -1 || !d_->version.empty())
    return d_->version;

  std::ifstream logfile;
  logfile.open(d_->options["-logfile"].c_str());

  std::string prefix = "X.Org X Server ";

  if (logfile.is_open()) {
    std::string line;
    while (getline(logfile, line)) {
      size_t start = line.find(prefix);
      if (start == line.npos)
        continue;

      line = line.substr(prefix.size());
      /* RCs have the human-readable version after the version */
      size_t end = line.find(" ");
      if (end == line.npos)
        end = line.size();

      d_->version = line.substr(0, end);
      break;
    }
  }

  return d_->version;
}

void xorg::testing::XServer::Start(const std::string &program) {
  TestStartup();

  std::vector<std::string> args;
  std::map<std::string, std::string>::iterator it;

  args.push_back(std::string(GetDisplayString()));

  for (it = d_->options.begin(); it != d_->options.end(); it++) {
    args.push_back(it->first);
    if (!it->second.empty())
      args.push_back(it->second);
  }

  Process::Start(program.empty() ? d_->path_to_server : program, args);

  if (Pid() > 0) {
    char *sleepwait = getenv("XORG_GTEST_XSERVER_SIGSTOP");
    if (sleepwait)
      raise(SIGSTOP);
  }
}

bool xorg::testing::XServer::Terminate(unsigned int timeout) {
  if (!Process::Terminate(timeout)) {
    std::cerr << "Warning: Failed to terminate Xorg server: "
              << std::strerror(errno) << "\n";
    return false;
  } else
    return true;
}

bool xorg::testing::XServer::Kill(unsigned int timeout) {
  if (!Process::Kill(timeout)) {
    std::cerr << "Warning: Failed to kill Xorg server: "
              << std::strerror(errno) << "\n";
    return false;
  } else
    return true;
}

void xorg::testing::XServer::RemoveLogFile(bool force) {
  enum Process::State state = GetState();
  if (force || state == Process::TERMINATED || state == Process::FINISHED_SUCCESS)
    unlink(d_->options["-logfile"].c_str());
}

void xorg::testing::XServer::SetOption(const std::string &key, const std::string &value) {
  d_->options[key] = value;
}

const std::string& xorg::testing::XServer::GetLogFilePath() {
  return d_->options["-logfile"];
}

const std::string& xorg::testing::XServer::GetConfigPath() {
  return d_->options["-config"];
}
<commit_msg>xserver: use SIGUSR1 to wait for XServer startup<commit_after>/*******************************************************************************
 *
 * X testing environment - Google Test helper class to communicate with the
 * server
 *
 * Copyright (C) 2012 Red Hat, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 ******************************************************************************/

#include "xorg/gtest/xorg-gtest-xserver.h"
#include "defines.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <algorithm>
#include <cerrno>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <vector>
#include <map>
#include <fstream>

#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>

struct xorg::testing::XServer::Private {
  Private()
      : display_number(DEFAULT_DISPLAY),
        path_to_server(DEFAULT_XORG_SERVER) {

    options["-config"] = DUMMY_CONF_PATH;
    options["-logfile"] = DEFAULT_XORG_LOGFILE;
  }

  unsigned int display_number;
  std::string display_string;
  std::string path_to_server;
  std::map<std::string, std::string> options;
  std::string version;
};

xorg::testing::XServer::XServer() : d_(new Private) {
  d_->display_number = DEFAULT_DISPLAY;
  SetDisplayNumber(d_->display_number);
}

xorg::testing::XServer::~XServer() {
  if (Pid() > 0)
    if (!Terminate(3000))
      Kill(300);
}

void xorg::testing::XServer::SetDisplayNumber(unsigned int display_number) {
    d_->display_number = display_number;

    std::stringstream s;
    s << ":" << display_number;
    d_->display_string = s.str();
}

unsigned int xorg::testing::XServer::GetDisplayNumber(void) {
  return d_->display_number;
}

const std::string& xorg::testing::XServer::GetDisplayString(void) {
  return d_->display_string;
}

void xorg::testing::XServer::SetServerPath(const std::string &path_to_server) {
  d_->path_to_server = path_to_server;
}

bool xorg::testing::XServer::WaitForEvent(::Display *display, time_t timeout)
{
    fd_set fds;
    FD_ZERO(&fds);

    int display_fd = ConnectionNumber(display);

    XSync(display, False);

    if (XPending(display))
        return true;
    else {
        FD_SET(display_fd, &fds);

        struct timeval timeval = {
            static_cast<time_t>(timeout / 1000),
            static_cast<time_t>(timeout % 1000),
        };

        int ret;
        if (timeout)
            ret = select(display_fd + 1, &fds, NULL, NULL, &timeval);
        else
            ret = select(display_fd + 1, &fds, NULL, NULL, NULL);

        if (ret < 0)
            throw std::runtime_error("Failed to select on X fd");

        if (ret == 0)
            return false;

        return XPending(display);
    }
}

bool xorg::testing::XServer::WaitForEventOfType(::Display *display, int type, int extension,
                                                int evtype, time_t timeout)
{
    while (WaitForEvent(display, timeout)) {
        XEvent event;
        if (!XPeekEvent(display, &event))
            throw std::runtime_error("Failed to peek X event");

        if (event.type != type) {
            if (XNextEvent(display, &event) != Success)
                throw std::runtime_error("Failed to remove X event");
            continue;
        }

        if (event.type != GenericEvent || extension == -1)
            return true;

        XGenericEvent *generic_event = reinterpret_cast<XGenericEvent*>(&event);

        if (generic_event->extension != extension) {
            if (XNextEvent(display, &event) != Success)
                throw std::runtime_error("Failed to remove X event");
            continue;
        }

        if (evtype == -1 || generic_event->evtype == evtype)
            return true;

        if (XNextEvent(display, &event) != Success)
            throw std::runtime_error("Failed to remove X event");
    }

    return false;
}

bool xorg::testing::XServer::WaitForDevice(::Display *display, const std::string &name,
                                           time_t timeout)
{
    int opcode;
    int event_start;
    int error_start;

    if (!XQueryExtension(display, "XInputExtension", &opcode, &event_start,
                         &error_start))
        throw std::runtime_error("Failed to query XInput extension");

    while (WaitForEventOfType(display, GenericEvent, opcode,
                              XI_HierarchyChanged, timeout)) {
        XEvent event;
        if (XNextEvent(display, &event) != Success)
            throw std::runtime_error("Failed to get X event");

        XGenericEventCookie *xcookie =
            reinterpret_cast<XGenericEventCookie*>(&event.xcookie);
        if (!XGetEventData(display, xcookie))
            throw std::runtime_error("Failed to get X event data");

        XIHierarchyEvent *hierarchy_event =
            reinterpret_cast<XIHierarchyEvent*>(xcookie->data);

        if (!(hierarchy_event->flags & XIDeviceEnabled)) {
            XFreeEventData(display, xcookie);
            continue;
        }

        bool device_found = false;
        for (int i = 0; i < hierarchy_event->num_info; i++) {
            if (!(hierarchy_event->info[i].flags & XIDeviceEnabled))
                continue;

            int num_devices;
            XIDeviceInfo *device_info =
                XIQueryDevice(display, hierarchy_event->info[i].deviceid,
                              &num_devices);
            if (num_devices != 1 || !device_info)
                throw std::runtime_error("Failed to query device");

            if (name.compare(device_info[0].name) == 0) {
                device_found = true;
                break;
            }
        }

        XFreeEventData(display, xcookie);

        if (device_found)
            return true;
    }

    return false;
}

void xorg::testing::XServer::WaitForConnections(void) {
  for (int i = 0; i < 100; ++i) {
    Display *test_display = XOpenDisplay(GetDisplayString().c_str());

    if (test_display) {
      XCloseDisplay(test_display);
      return;
    }

    int status;
    int pid = waitpid(Pid(), &status, WNOHANG);
    if (pid == Pid()) {
      std::string message;
      message += "X server failed to start on display ";
      message +=  GetDisplayString();
      message += ". Ensure that the correct video driver is installed.\n"
                 "If the X.org server is older than 1.12, "
                 "tests will need to be run as root.\nCheck ";
      message += d_->options["-logfile"];
      message += " for any errors";
      throw std::runtime_error(message);
    } else if (pid == 0) {
      usleep(100);
    } else if (pid == -1) {
      throw std::runtime_error("Could not get status of X server process");
    } else {
      throw std::runtime_error("Invalid child PID returned by Process::Wait()");
    }
  }

  throw std::runtime_error("Unable to open connection to X server");
}

void xorg::testing::XServer::TestStartup(void) {
  Display* test_display = XOpenDisplay(GetDisplayString().c_str());
  if (test_display) {
    XCloseDisplay(test_display);
    std::string message;
    message += "A server is already running on ";
    message += GetDisplayString();
    message += ".";
    throw std::runtime_error(message);
  }

  std::string log = d_->options["-logfile"];

  /* The Xorg server won't start unless the log file and the old log file are
   * writable. */
  bool logfile_was_present;
  std::ifstream file_test;
  file_test.open(log.c_str());
  logfile_was_present = file_test.good();

  std::ofstream log_test;
  log_test.open(log.c_str(), std::ofstream::out);
  log_test.close();
  if (log_test.fail()) {
    throw std::runtime_error("X.org server log file " + log + " is not writable.");
  } else if (!logfile_was_present)
    unlink(log.c_str());

  std::string old_log_file = log + ".old";

  file_test.open(old_log_file.c_str());
  logfile_was_present = file_test.good();

  log_test.open(old_log_file.c_str(), std::ofstream::out);
  log_test.close();
  if (log_test.fail()) {
    throw std::runtime_error("X.org old server log file " + old_log_file + " is not writable.");
  } else if (!logfile_was_present)
    unlink(old_log_file.c_str());
}

const std::string& xorg::testing::XServer::GetVersion(void) {
  if (Pid() == -1 || !d_->version.empty())
    return d_->version;

  std::ifstream logfile;
  logfile.open(d_->options["-logfile"].c_str());

  std::string prefix = "X.Org X Server ";

  if (logfile.is_open()) {
    std::string line;
    while (getline(logfile, line)) {
      size_t start = line.find(prefix);
      if (start == line.npos)
        continue;

      line = line.substr(prefix.size());
      /* RCs have the human-readable version after the version */
      size_t end = line.find(" ");
      if (end == line.npos)
        end = line.size();

      d_->version = line.substr(0, end);
      break;
    }
  }

  return d_->version;
}

void xorg::testing::XServer::Start(const std::string &program) {
  TestStartup();

  std::vector<std::string> args;
  std::map<std::string, std::string>::iterator it;
  std::string err_msg;

  sigset_t sig_mask;
  struct timespec sig_timeout = {1, 0}; /* 1 sec + 0 nsec */

  /* add SIGUSR1 to the signal mask */
  sigemptyset(&sig_mask);
  sigaddset(&sig_mask, SIGUSR1);
  if (sigprocmask(SIG_BLOCK, &sig_mask, NULL)) {
    err_msg.append("Failed to set signal mask: ");
    err_msg.append(std::strerror(errno));
    throw std::runtime_error(err_msg);
  }
  /* set SIGUSR1 handler to SIG_IGN, XServer tests for this and will
   * send SIGUSR1 when ready */
  if (SIG_ERR == signal(SIGUSR1, SIG_IGN)) {
    err_msg.append("Failed to set signal handler: ");
    err_msg.append(std::strerror(errno));
    throw std::runtime_error(err_msg);
  }

  args.push_back(std::string(GetDisplayString()));

  for (it = d_->options.begin(); it != d_->options.end(); it++) {
    args.push_back(it->first);
    if (!it->second.empty())
      args.push_back(it->second);
  }

  Process::Start(program.empty() ? d_->path_to_server : program, args);

  if (Pid() > 0) {
    char *sleepwait = getenv("XORG_GTEST_XSERVER_SIGSTOP");
    if (sleepwait)
      raise(SIGSTOP);

    /* wait for SIGUSR1 from XServer */
    if (SIGUSR1 != sigtimedwait(&sig_mask, NULL, &sig_timeout)) {
      if (errno == EAGAIN) {
        err_msg.append("XServer startup timed out: ");
      } else {
        err_msg.append("Error while waiting for XServer startup: ");
      }
      err_msg.append(std::strerror(errno));
      throw std::runtime_error(err_msg);
    }
  }
}

bool xorg::testing::XServer::Terminate(unsigned int timeout) {
  if (!Process::Terminate(timeout)) {
    std::cerr << "Warning: Failed to terminate Xorg server: "
              << std::strerror(errno) << "\n";
    return false;
  } else
    return true;
}

bool xorg::testing::XServer::Kill(unsigned int timeout) {
  if (!Process::Kill(timeout)) {
    std::cerr << "Warning: Failed to kill Xorg server: "
              << std::strerror(errno) << "\n";
    return false;
  } else
    return true;
}

void xorg::testing::XServer::RemoveLogFile(bool force) {
  enum Process::State state = GetState();
  if (force || state == Process::TERMINATED || state == Process::FINISHED_SUCCESS)
    unlink(d_->options["-logfile"].c_str());
}

void xorg::testing::XServer::SetOption(const std::string &key, const std::string &value) {
  d_->options[key] = value;
}

const std::string& xorg::testing::XServer::GetLogFilePath() {
  return d_->options["-logfile"];
}

const std::string& xorg::testing::XServer::GetConfigPath() {
  return d_->options["-config"];
}
<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	NTC サーミスタ 温度計算 クラス @n
			Copyright 2017 Kunihito Hiramatsu
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cmath>

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  サーミスタ型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	enum class thermistor {
		NT103_34G,	///< THB:3435, TR25:10K
		NT103_41G,	///< THB:4126, TR25:10K
		HX103_3380,	///< THB:3380, TR25:10K (25C to 50C)
	};

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  NTCTH テンプレートクラス
		@param[in]	ADNUM	A/D 変換値の量子化最大値（１２ビットの場合４０９５ @n
							１０ビットの場合、１０２３）
		@param[in]	THM		サーミスタの型
		@param[in]	REFR	分圧抵抗値（単位オーム）
		@param[in]	thup	サーミスタが VCC 側の場合「true」、GND 側の場合「false」
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t ADNUM, thermistor THM, uint32_t REFR, bool thup>
	class NTCTH {

		// サーミスタの型に応じたパラメーター
		// THB:  B 定数
		// TR25: ２５度における基準抵抗値
		static void get_para_(float& THB, float& TR25)
		{
			switch(THM) {
			case thermistor::NT103_34G:
				THB  = 3435.0f;  ///< サーミスタＢ定数
				TR25 = 10e3;     ///< R25 サーミスタ２５℃基準抵抗値
				break;
			case thermistor::NT103_41G:
				THB  = 4126.0f;  ///< サーミスタＢ定数
				TR25 = 10e3;     ///< R25 サーミスタ２５℃基準抵抗値
				break;
			case thermistor::HX103_3380:
				THB  = 3380.0f;  ///< サーミスタＢ定数
				TR25 = 10e3;     ///< R25 サーミスタ２５℃基準抵抗値
				break;
			default:
				break;
			}
		}

		// サーミスターが VCC 側
		static float thermistor_upper_(uint32_t raw)
		{
			if(raw == 0) return 0.0f;  // 零除算を避ける
			float thr = (static_cast<float>(REFR * ADNUM) / static_cast<float>(raw)) - static_cast<float>(REFR);
			return thr;
		}

		// サーミスターが GND 側
		static float thermistor_lower_(uint32_t raw)
		{
			float thr = static_cast<float>(REFR * raw) / static_cast<float>(ADNUM - raw);
			return thr;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	() オペレーター
			@param[in]	adn		A/D 変換値
		 */
		//-----------------------------------------------------------------//
		float operator () (uint16_t adn) const
		{
			float thr;
			if(thup) {
				thr = thermistor_upper_(adn);
			} else {
				thr = thermistor_lower_(adn);
			}
			float THB;
			float TR25;
			get_para_(THB, TR25);
			static const float T0 = 298.15f;   ///< 絶対温度
			float t = 1.0f / (std::log(thr / TR25) / THB + (1.0f / T0));
			return t - 273.15f;
		}
	};
}
<commit_msg>fix zero divide exceptions<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	NTC サーミスタ 温度計算 クラス @n
			Copyright 2017 Kunihito Hiramatsu
	@copyright	Copyright (C) 2017 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RL78/blob/master/LICENSE
*/
//=====================================================================//
#include <cmath>

namespace chip {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  サーミスタ型
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	enum class thermistor {
		NT103_34G,	///< THB:3435, TR25:10K
		NT103_41G,	///< THB:4126, TR25:10K
		HX103_3380,	///< THB:3380, TR25:10K (25C to 50C)
	};

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  NTCTH テンプレートクラス
		@param[in]	ADNUM	A/D 変換値の量子化最大値（１２ビットの場合４０９５ @n
							１０ビットの場合、１０２３）
		@param[in]	THM		サーミスタの型
		@param[in]	REFR	分圧抵抗値（単位オーム）
		@param[in]	thup	サーミスタが VCC 側の場合「true」、GND 側の場合「false」
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <uint32_t ADNUM, thermistor THM, uint32_t REFR, bool thup>
	class NTCTH {

		// サーミスタの型に応じたパラメーター
		// THB:  B 定数
		// TR25: ２５度における基準抵抗値
		static void get_para_(float& THB, float& TR25)
		{
			switch(THM) {
			case thermistor::NT103_34G:
				THB  = 3435.0f;  ///< サーミスタＢ定数
				TR25 = 10e3;     ///< R25 サーミスタ２５℃基準抵抗値
				break;
			case thermistor::NT103_41G:
				THB  = 4126.0f;  ///< サーミスタＢ定数
				TR25 = 10e3;     ///< R25 サーミスタ２５℃基準抵抗値
				break;
			case thermistor::HX103_3380:
				THB  = 3380.0f;  ///< サーミスタＢ定数
				TR25 = 10e3;     ///< R25 サーミスタ２５℃基準抵抗値
				break;
			default:
				break;
			}
		}

		// サーミスターが VCC 側
		static float thermistor_upper_(uint32_t raw)
		{
			if(raw == 0) return 0.0f;  // 零除算を避ける
			float thr = (static_cast<float>(REFR * ADNUM) / static_cast<float>(raw)) - static_cast<float>(REFR);
			return thr;
		}

		// サーミスターが GND 側
		static float thermistor_lower_(uint32_t raw)
		{
			float thr = static_cast<float>(REFR * raw) / static_cast<float>(ADNUM - raw);
			return thr;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	() オペレーター
			@param[in]	adn		A/D 変換値
		 */
		//-----------------------------------------------------------------//
		float operator () (uint16_t adn) const
		{
			float thr;
			if(thup) {
				thr = thermistor_upper_(adn);
			} else {
				thr = thermistor_lower_(adn);
			}
			float THB;
			float TR25;
			get_para_(THB, TR25);
			static const float T0 = 298.15f;   ///< 絶対温度
			float t = 1.0f / (std::log(thr / TR25) / THB + (1.0f / T0));
			return t - 273.15f;
		}
	};
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/thread.hpp"
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/extensions/ut_metadata.hpp"

using boost::tuples::ignore;

void test_transfer(bool clear_files, bool disconnect
	, boost::shared_ptr<libtorrent::torrent_plugin> (*constructor)(libtorrent::torrent*, void*))
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48100, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49100, 50000), "0.0.0.0", 0);
	ses1.add_extension(constructor);
	ses2.add_extension(constructor);
	torrent_handle tor1;
	torrent_handle tor2;
#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
#endif

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0, clear_files, true, true, "_meta");

	for (int i = 0; i < 50; ++i)
	{
		// make sure this function can be called on
		// torrents without metadata
		if (!disconnect) tor2.status();
		print_alerts(ses1, "ses1", false, true);
		print_alerts(ses2, "ses2", false, true);

		if (disconnect && tor2.is_valid()) ses2.remove_torrent(tor2);
		if (!disconnect && tor2.has_metadata()) break;
		test_sleep(100);
	}

	if (disconnect) return;

	TEST_CHECK(tor2.has_metadata());
	std::cerr << "waiting for transfer to complete\n";

	for (int i = 0; i < 30; ++i)
	{
		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers
			<< std::endl;
		if (tor2.is_seed()) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	if (tor2.is_seed()) std::cerr << "done\n";

	error_code ec;
	remove_all("./tmp1_meta", ec);
	remove_all("./tmp2_meta", ec);
	remove_all("./tmp3_meta", ec);
}

int test_main()
{
	using namespace libtorrent;

	// test to disconnect one client prematurely
	test_transfer(true, true, &create_metadata_plugin);
	// test where one has data and one doesn't
	test_transfer(true, false, &create_metadata_plugin);
	// test where both have data (to trigger the file check)
	test_transfer(false, false, &create_metadata_plugin);

	// test to disconnect one client prematurely
	test_transfer(true, true, &create_ut_metadata_plugin);
	// test where one has data and one doesn't
	test_transfer(true, false, &create_ut_metadata_plugin);
	// test where both have data (to trigger the file check)
	test_transfer(false, false, &create_ut_metadata_plugin);

	error_code ec;
	remove_all("./tmp1", ec);
	remove_all("./tmp2", ec);

	return 0;
}

<commit_msg>fix for metadata extension test<commit_after>/*

Copyright (c) 2008, Arvid Norberg
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 author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/thread.hpp"
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/extensions/ut_metadata.hpp"

using boost::tuples::ignore;

void test_transfer(bool clear_files, bool disconnect
	, boost::shared_ptr<libtorrent::torrent_plugin> (*constructor)(libtorrent::torrent*, void*))
{
	using namespace libtorrent;

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48100, 49000), "0.0.0.0", 0);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49100, 50000), "0.0.0.0", 0);
	ses1.add_extension(constructor);
	ses2.add_extension(constructor);
	torrent_handle tor1;
	torrent_handle tor2;
#ifndef TORRENT_DISABLE_ENCRYPTION
	pe_settings pes;
	pes.out_enc_policy = pe_settings::forced;
	pes.in_enc_policy = pe_settings::forced;
	ses1.set_pe_settings(pes);
	ses2.set_pe_settings(pes);
#endif

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0, clear_files, true, true, "_meta");

	for (int i = 0; i < 80; ++i)
	{
		// make sure this function can be called on
		// torrents without metadata
		if (!disconnect) tor2.status();
		print_alerts(ses1, "ses1", false, true);
		print_alerts(ses2, "ses2", false, true);

		if (disconnect && tor2.is_valid()) ses2.remove_torrent(tor2);
		if (!disconnect && tor2.has_metadata()) break;
		test_sleep(100);
	}

	if (disconnect) return;

	TEST_CHECK(tor2.has_metadata());
	std::cerr << "waiting for transfer to complete\n";

	for (int i = 0; i < 30; ++i)
	{
		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		std::cerr
			<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
			<< st1.num_peers << ": "
			<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
			<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
			<< "\033[0m" << int(st2.progress * 100) << "% "
			<< st2.num_peers
			<< std::endl;
		if (tor2.is_seed()) break;
		test_sleep(1000);
	}

	TEST_CHECK(tor2.is_seed());
	if (tor2.is_seed()) std::cerr << "done\n";

	error_code ec;
	remove_all("./tmp1_meta", ec);
	remove_all("./tmp2_meta", ec);
	remove_all("./tmp3_meta", ec);
}

int test_main()
{
	using namespace libtorrent;

	// test to disconnect one client prematurely
	test_transfer(true, true, &create_metadata_plugin);
	// test where one has data and one doesn't
	test_transfer(true, false, &create_metadata_plugin);
	// test where both have data (to trigger the file check)
	test_transfer(false, false, &create_metadata_plugin);

	// test to disconnect one client prematurely
	test_transfer(true, true, &create_ut_metadata_plugin);
	// test where one has data and one doesn't
	test_transfer(true, false, &create_ut_metadata_plugin);
	// test where both have data (to trigger the file check)
	test_transfer(false, false, &create_ut_metadata_plugin);

	error_code ec;
	remove_all("./tmp1", ec);
	remove_all("./tmp2", ec);

	return 0;
}

<|endoftext|>


<commit_before>#include <DuiLocale>
#include <DuiTheme>

#include <QDBusConnection>
#include <QDebug>

#include "sysuid.h"
#include "systemuigconf.h"
#include "pincodequerybusinesslogic.h"
#include "batterybusinesslogic.h"
#include "batterybusinesslogicadaptor.h"
#include "displaybusinesslogic.h"
#include "displaybusinesslogicadaptor.h"
#include "phonenetworkbusinesslogic.h"
#include "phonenetworkbusinesslogicadaptor.h"
#include "lockscreenbusinesslogic.h"
#include "shutdownbusinesslogic.h"
#include "eventhandler.h"
#include "notifier.h"

namespace {
    const QString themeDir = "/usr/share/sysuid/themes/";
    const QString styleDir = themeDir + "style/";
    const QString svgDir = themeDir + "svg/";
}

Sysuid::Sysuid() :
        QObject()
{
    qDebug() << "starting sysuidaemon";

    /* themes */
    DuiTheme::addPixmapDirectory(svgDir); // or ..(themeDir, true); ?
    DuiTheme::loadCSS(styleDir + "sysuid.css");
    DuiTheme::loadCSS(styleDir + "unlocksliderstyle.css");

    /* GConf interface */
    systemUIGConf = new SystemUIGConf(this);

    /* Pincode query variables */
    pinCodeQueryLogic = new PinCodeQueryBusinessLogic(this);

    /* Display */
    displayLogic = new DisplayBusinessLogic(this);
    displayLogicAdaptor = new DisplayBusinessLogicAdaptor(dbusObject(), displayLogic);

    /* Network */
    networkLogic = new PhoneNetworkBusinessLogic(systemUIGConf, this);
    networkLogicAdaptor = new PhoneNetworkBusinessLogicAdaptor(dbusObject(), networkLogic);

    /* Event handler */
    eventHandler = new EventHandler(this);

    /* Shutdown */
    shutdownLogic = new ShutdownBusinessLogic(this);
    connect(eventHandler, SIGNAL(longPowerKeyPressOccured(bool)),
            shutdownLogic, SLOT(openDialog(bool)));
    connect(eventHandler, SIGNAL(powerKeyDownOccured()),
            shutdownLogic, SLOT(powerKeyDown()));
    connect(eventHandler, SIGNAL(powerKeyUpOccured()),
            shutdownLogic, SLOT(powerKeyUp()));

    /* Lockscreen */
    lockScreenLogic = new LockScreenBusinessLogic(this);
    connect(eventHandler, SIGNAL(shortPowerKeyPressOccured()), lockScreenLogic, SLOT(shortPowerKeyPressOccured()));
    connect(displayLogic, SIGNAL(displayOff()), lockScreenLogic, SLOT(displayOff()));
    connect(displayLogic, SIGNAL(displayOn()), lockScreenLogic, SLOT(displayOn()));
    connect(lockScreenLogic, SIGNAL(toggleDisplay(bool)), displayLogic, SLOT(toggleDisplay(bool)));

    /* Battery */
    batteryLogic = new BatteryBusinessLogic(systemUIGConf, lockScreenLogic, this);
    batteryLogicAdaptor = new BatteryBusinessLogicAdaptor(dbusObject(), batteryLogic);

    // D-Bus registration and stuff.
    QDBusConnection bus = QDBusConnection::sessionBus();
    if(!bus.registerService(dbusService())) {
        qDebug() << "failed to register dbus service";
        abort();
    }
    if(!bus.registerObject(dbusPath(), dbusObject())) {
        qDebug() << "failed to register dbus objects";
        abort();
    }
}

QPointer<QObject> Sysuid::dbusObject()
{
    static QPointer<QObject> o = NULL;
    if(o.isNull())
    {
        o = new QObject();
    }
    return o;
}

QPointer<Notifier> Sysuid::notifier()
{
    static QPointer<Notifier> n = NULL;
    if(n.isNull())
    {
        n = new Notifier();
    }
    return n;
}

QString Sysuid::dbusService()
{
    return QString("com.nokia.systemui");
}

QString Sysuid::dbusPath()
{
    return QString("/");
}

Sysuid::~Sysuid()
{
    if(NULL != notifier())
        delete notifier();
    if(NULL != dbusObject())
        delete dbusObject();
}
<commit_msg>Removed shutdown logic because it's broken<commit_after>#include <DuiLocale>
#include <DuiTheme>

#include <QDBusConnection>
#include <QDebug>

#include "sysuid.h"
#include "systemuigconf.h"
#include "pincodequerybusinesslogic.h"
#include "batterybusinesslogic.h"
#include "batterybusinesslogicadaptor.h"
#include "displaybusinesslogic.h"
#include "displaybusinesslogicadaptor.h"
#include "phonenetworkbusinesslogic.h"
#include "phonenetworkbusinesslogicadaptor.h"
#include "lockscreenbusinesslogic.h"
//#include "shutdownbusinesslogic.h"
#include "eventhandler.h"
#include "notifier.h"

namespace {
    const QString themeDir = "/usr/share/sysuid/themes/";
    const QString styleDir = themeDir + "style/";
    const QString svgDir = themeDir + "svg/";
}

Sysuid::Sysuid() :
        QObject()
{
    qDebug() << "starting sysuidaemon";

    /* themes */
    DuiTheme::addPixmapDirectory(svgDir); // or ..(themeDir, true); ?
    DuiTheme::loadCSS(styleDir + "sysuid.css");
    DuiTheme::loadCSS(styleDir + "unlocksliderstyle.css");

    /* GConf interface */
    systemUIGConf = new SystemUIGConf(this);

    /* Pincode query variables */
    pinCodeQueryLogic = new PinCodeQueryBusinessLogic(this);

    /* Display */
    displayLogic = new DisplayBusinessLogic(this);
    displayLogicAdaptor = new DisplayBusinessLogicAdaptor(dbusObject(), displayLogic);

    /* Network */
    networkLogic = new PhoneNetworkBusinessLogic(systemUIGConf, this);
    networkLogicAdaptor = new PhoneNetworkBusinessLogicAdaptor(dbusObject(), networkLogic);

    /* Event handler */
    eventHandler = new EventHandler(this);

    /* Shutdown */
/*
    shutdownLogic = new ShutdownBusinessLogic(this);

    connect(eventHandler, SIGNAL(longPowerKeyPressOccured(bool)),
            shutdownLogic, SLOT(openDialog(bool)));
    connect(eventHandler, SIGNAL(powerKeyDownOccured()),
            shutdownLogic, SLOT(powerKeyDown()));
    connect(eventHandler, SIGNAL(powerKeyUpOccured()),
            shutdownLogic, SLOT(powerKeyUp()));
*/
    /* Lockscreen */
    lockScreenLogic = new LockScreenBusinessLogic(this);
    connect(eventHandler, SIGNAL(shortPowerKeyPressOccured()), lockScreenLogic, SLOT(shortPowerKeyPressOccured()));
    connect(displayLogic, SIGNAL(displayOff()), lockScreenLogic, SLOT(displayOff()));
    connect(displayLogic, SIGNAL(displayOn()), lockScreenLogic, SLOT(displayOn()));
    connect(lockScreenLogic, SIGNAL(toggleDisplay(bool)), displayLogic, SLOT(toggleDisplay(bool)));

    /* Battery */
    batteryLogic = new BatteryBusinessLogic(systemUIGConf, lockScreenLogic, this);
    batteryLogicAdaptor = new BatteryBusinessLogicAdaptor(dbusObject(), batteryLogic);

    // D-Bus registration and stuff.
    QDBusConnection bus = QDBusConnection::sessionBus();
    if(!bus.registerService(dbusService())) {
        qDebug() << "failed to register dbus service";
        abort();
    }
    if(!bus.registerObject(dbusPath(), dbusObject())) {
        qDebug() << "failed to register dbus objects";
        abort();
    }
}

QPointer<QObject> Sysuid::dbusObject()
{
    static QPointer<QObject> o = NULL;
    if(o.isNull())
    {
        o = new QObject();
    }
    return o;
}

QPointer<Notifier> Sysuid::notifier()
{
    static QPointer<Notifier> n = NULL;
    if(n.isNull())
    {
        n = new Notifier();
    }
    return n;
}

QString Sysuid::dbusService()
{
    return QString("com.nokia.systemui");
}

QString Sysuid::dbusPath()
{
    return QString("/");
}

Sysuid::~Sysuid()
{
    if(NULL != notifier())
        delete notifier();
    if(NULL != dbusObject())
        delete dbusObject();
}
<|endoftext|>


<commit_before>#include <unistd.h>

#include <mzx/logger.h>
#include <mzx/thread.h>

namespace mzx
{

Thread::Thread()
{
}

Thread::Thread(std::function<void()> run_cb)
    : run_cb_(run_cb)
{
    MZX_CHECK(run_cb != nullptr);
}

Thread::~Thread()
{
    MZX_CHECK(!joinable_);
}

ThreadID Thread::ID() const
{
    return thread_id_;
}

bool Thread::Joinable() const
{
    return joinable_;
}

bool Thread::Start()
{
    if (Joinable())
    {
        MZX_WARN("thread:", thread_id_, " is running");
        return false;
    }
    joinable_ = true;
    auto err = pthread_create(&thread_id_, nullptr, &Thread::Run, this);
    if (err != 0)
    {
        MZX_WARN("create thread failed:", err);
        joinable_ = false;
        return false;
    }
    return true;
}

bool Thread::Join()
{
    if (!Joinable())
    {
        return true;
    }
    int err = pthread_join(thread_id_, nullptr);
    if (err != 0)
    {
        MZX_WARN("thread:", thread_id_, " join failed:", err);
        return false;
    }
    return true;
}

bool Thread::Cancel()
{
    return Cancel(thread_id_);
}

void Thread::Sleep(unsigned ms)
{
    usleep(ms * 1000);
}

ThreadID Thread::CurrentID()
{
    return pthread_self();
}

void Thread::CheckCancelPoint()
{
    pthread_testcancel();
}

bool Thread::Cancel(ThreadID id)
{
    int err = pthread_cancel(id);
    if (err != 0)
    {
        MZX_WARN("thread:", id, " cancel failed:", err);
        return false;
    }
    return true;
}

void *Thread::Run(void *param)
{
    auto *th = static_cast<Thread *>(param);
    MZX_CHECK(th != nullptr);
    pthread_cleanup_push(&Thread::CleanUp, param);
    th->_Run();
    if (th->run_cb_)
    {
        (th->run_cb_)();
    }
    pthread_cleanup_pop(1);
}

void Thread::CleanUp(void *param)
{
    auto *th = static_cast<Thread *>(param);
    MZX_CHECK(th != nullptr);
    th->joinable_ = false;
}

} // namespace mzx
<commit_msg>modify thread<commit_after>#include <unistd.h>

#include <mzx/logger.h>
#include <mzx/thread.h>

namespace mzx
{

Thread::Thread()
{
}

Thread::Thread(std::function<void()> run_cb)
    : run_cb_(run_cb)
{
    MZX_CHECK(run_cb != nullptr);
}

Thread::~Thread()
{
    MZX_CHECK(!joinable_);
}

ThreadID Thread::ID() const
{
    return thread_id_;
}

bool Thread::Joinable() const
{
    return joinable_;
}

bool Thread::Start()
{
    if (Joinable())
    {
        MZX_WARN("thread:", thread_id_, " is running");
        return false;
    }
    joinable_ = true;
    auto err = pthread_create(&thread_id_, nullptr, &Thread::Run, this);
    if (err != 0)
    {
        MZX_WARN("create thread failed:", err);
        joinable_ = false;
        return false;
    }
    return true;
}

bool Thread::Join()
{
    if (!Joinable())
    {
        return true;
    }
    int err = pthread_join(thread_id_, nullptr);
    if (err != 0)
    {
        MZX_WARN("thread:", thread_id_, " join failed:", err);
        return false;
    }
    return true;
}

bool Thread::Cancel()
{
    return Cancel(thread_id_);
}

void Thread::Sleep(unsigned ms)
{
    usleep(ms * 1000);
}

ThreadID Thread::CurrentID()
{
    return pthread_self();
}

void Thread::CheckCancelPoint()
{
    pthread_testcancel();
}

bool Thread::Cancel(ThreadID id)
{
    int err = pthread_cancel(id);
    if (err != 0)
    {
        MZX_WARN("thread:", id, " cancel failed:", err);
        return false;
    }
    return true;
}

void *Thread::Run(void *param)
{
    auto *th = static_cast<Thread *>(param);
    MZX_CHECK(th != nullptr);
    pthread_cleanup_push(&Thread::CleanUp, param);
    th->_Run();
    if (th->run_cb_)
    {
        (th->run_cb_)();
    }
    pthread_cleanup_pop(1);
    return nullptr;
}

void Thread::CleanUp(void *param)
{
    auto *th = static_cast<Thread *>(param);
    MZX_CHECK(th != nullptr);
    th->joinable_ = false;
}

} // namespace mzx
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <fcntl.h>

#include "publish/cmd_util.h"
#include "publish/except.h"
#include "publish/repository_util.h"
#include "util/posix.h"

using namespace std;  // NOLINT

namespace publish {

class T_Util : public ::testing::Test {
 protected:
  virtual void SetUp() {
  }

 protected:
};

TEST_F(T_Util, CheckoutMarker3) {
  EXPECT_EQ(NULL, CheckoutMarker::CreateFrom("/no/such/path"));

  shash::Any hash = shash::MkFromHexPtr(
    shash::HexPtr("0123456789abcdef0123456789abcdef01234567"),
    shash::kSuffixCatalog);
  CheckoutMarker m("tag", "branch", hash, "");
  m.SaveAs("cvmfs_test_checkout_marker");

  CheckoutMarker *l = CheckoutMarker::CreateFrom("cvmfs_test_checkout_marker");
  ASSERT_TRUE(l != NULL);
  EXPECT_EQ(m.tag(), l->tag());
  EXPECT_EQ(m.branch(), l->branch());
  EXPECT_EQ(m.hash(), l->hash());
  EXPECT_EQ(m.previous_branch(), l->previous_branch());
  delete l;
}

TEST_F(T_Util, CheckoutMarker4) {
  EXPECT_EQ(NULL, CheckoutMarker::CreateFrom("/no/such/path"));

  shash::Any hash = shash::MkFromHexPtr(
    shash::HexPtr("0123456789abcdef0123456789abcdef01234567"),
    shash::kSuffixCatalog);
  CheckoutMarker m("tag", "branch", hash, "prev");
  m.SaveAs("cvmfs_test_checkout_marker");

  CheckoutMarker *l = CheckoutMarker::CreateFrom("cvmfs_test_checkout_marker");
  ASSERT_TRUE(l != NULL);
  EXPECT_EQ(m.tag(), l->tag());
  EXPECT_EQ(m.branch(), l->branch());
  EXPECT_EQ(m.hash(), l->hash());
  EXPECT_EQ(m.previous_branch(), l->previous_branch());
  delete l;
}

TEST_F(T_Util, ServerLockFile) {
  EXPECT_FALSE(ServerLockFile::IsLocked("foo", true));
  EXPECT_TRUE(ServerLockFile::Acquire("foo", true));
  EXPECT_FALSE(ServerLockFile::Acquire("foo", true));
  EXPECT_TRUE(ServerLockFile::IsLocked("foo", true));
  ServerLockFile::Release("foo");
  EXPECT_FALSE(ServerLockFile::IsLocked("foo", true));

  pid_t pid_child = fork();
  ASSERT_GE(pid_child, 0);
  if (pid_child == 0) {
    EXPECT_TRUE(ServerLockFile::Acquire("foo", true));
    exit(0);
  }
  EXPECT_EQ(0, WaitForChild(pid_child));

  EXPECT_TRUE(ServerLockFile::IsLocked("foo", true));
  EXPECT_FALSE(ServerLockFile::IsLocked("foo", false));
  EXPECT_FALSE(ServerLockFile::Acquire("foo", true));
  EXPECT_TRUE(ServerLockFile::Acquire("foo", false));
  EXPECT_TRUE(ServerLockFile::IsLocked("foo", false));
  ServerLockFile::Release("foo");
}

TEST_F(T_Util, SetInConfig) {
  EXPECT_THROW(SetInConfig("/no/such/file", "x", "y"), EPublish);
  EXPECT_FALSE(FileExists("test_publish_config"));
  SetInConfig("test_publish_config", "X", "y");
  EXPECT_TRUE(FileExists("test_publish_config"));

  int fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  std::string content;
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("X=y\n", content);

  SetInConfig("test_publish_config", "X", "z");
  fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("X=z\n", content);

  SetInConfig("test_publish_config", "A", "b");
  fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("X=z\nA=b\n", content);

  SetInConfig("test_publish_config", "X", "");
  fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("A=b\n", content);
}

TEST_F(T_Util, CallServerHook) {
  EXPECT_EQ(0, CallServerHook("hookX", "t.cvmfs.io", "no/such/file"));

  EXPECT_TRUE(SafeWriteToFile(
    "hookY() { if [ $1 = \"t.cvmfs.io\" ]; then return 0; fi; return 42; }\n",
    "cvmfs_test_hooks.sh", 0644));

  EXPECT_EQ(0, CallServerHook("hookX", "t.cvmfs.io",
                              "./cvmfs_test_hooks.sh"));
  EXPECT_EQ(0, CallServerHook("hookY", "t.cvmfs.io",
                              "./cvmfs_test_hooks.sh"));
  EXPECT_EQ(42, CallServerHook("hookY", "x.cvmfs.io",
                               "./cvmfs_test_hooks.sh"));
}

}  // namespace publish
<commit_msg>[publish] add unit test for SendTalkCommand<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include <fcntl.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>

#include <cassert>
#include <cstring>

#include "publish/cmd_util.h"
#include "publish/except.h"
#include "publish/repository_util.h"
#include "util/posix.h"

using namespace std;  // NOLINT

namespace publish {

class T_Util : public ::testing::Test {
 protected:
  virtual void SetUp() {
  }

 protected:
};

TEST_F(T_Util, CheckoutMarker3) {
  EXPECT_EQ(NULL, CheckoutMarker::CreateFrom("/no/such/path"));

  shash::Any hash = shash::MkFromHexPtr(
    shash::HexPtr("0123456789abcdef0123456789abcdef01234567"),
    shash::kSuffixCatalog);
  CheckoutMarker m("tag", "branch", hash, "");
  m.SaveAs("cvmfs_test_checkout_marker");

  CheckoutMarker *l = CheckoutMarker::CreateFrom("cvmfs_test_checkout_marker");
  ASSERT_TRUE(l != NULL);
  EXPECT_EQ(m.tag(), l->tag());
  EXPECT_EQ(m.branch(), l->branch());
  EXPECT_EQ(m.hash(), l->hash());
  EXPECT_EQ(m.previous_branch(), l->previous_branch());
  delete l;
}

TEST_F(T_Util, CheckoutMarker4) {
  EXPECT_EQ(NULL, CheckoutMarker::CreateFrom("/no/such/path"));

  shash::Any hash = shash::MkFromHexPtr(
    shash::HexPtr("0123456789abcdef0123456789abcdef01234567"),
    shash::kSuffixCatalog);
  CheckoutMarker m("tag", "branch", hash, "prev");
  m.SaveAs("cvmfs_test_checkout_marker");

  CheckoutMarker *l = CheckoutMarker::CreateFrom("cvmfs_test_checkout_marker");
  ASSERT_TRUE(l != NULL);
  EXPECT_EQ(m.tag(), l->tag());
  EXPECT_EQ(m.branch(), l->branch());
  EXPECT_EQ(m.hash(), l->hash());
  EXPECT_EQ(m.previous_branch(), l->previous_branch());
  delete l;
}

TEST_F(T_Util, ServerLockFile) {
  EXPECT_FALSE(ServerLockFile::IsLocked("foo", true));
  EXPECT_TRUE(ServerLockFile::Acquire("foo", true));
  EXPECT_FALSE(ServerLockFile::Acquire("foo", true));
  EXPECT_TRUE(ServerLockFile::IsLocked("foo", true));
  ServerLockFile::Release("foo");
  EXPECT_FALSE(ServerLockFile::IsLocked("foo", true));

  pid_t pid_child = fork();
  ASSERT_GE(pid_child, 0);
  if (pid_child == 0) {
    EXPECT_TRUE(ServerLockFile::Acquire("foo", true));
    exit(0);
  }
  EXPECT_EQ(0, WaitForChild(pid_child));

  EXPECT_TRUE(ServerLockFile::IsLocked("foo", true));
  EXPECT_FALSE(ServerLockFile::IsLocked("foo", false));
  EXPECT_FALSE(ServerLockFile::Acquire("foo", true));
  EXPECT_TRUE(ServerLockFile::Acquire("foo", false));
  EXPECT_TRUE(ServerLockFile::IsLocked("foo", false));
  ServerLockFile::Release("foo");
}

TEST_F(T_Util, SetInConfig) {
  EXPECT_THROW(SetInConfig("/no/such/file", "x", "y"), EPublish);
  EXPECT_FALSE(FileExists("test_publish_config"));
  SetInConfig("test_publish_config", "X", "y");
  EXPECT_TRUE(FileExists("test_publish_config"));

  int fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  std::string content;
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("X=y\n", content);

  SetInConfig("test_publish_config", "X", "z");
  fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("X=z\n", content);

  SetInConfig("test_publish_config", "A", "b");
  fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("X=z\nA=b\n", content);

  SetInConfig("test_publish_config", "X", "");
  fd = open("test_publish_config", O_RDONLY);
  EXPECT_GE(fd, 0);
  EXPECT_TRUE(SafeReadToString(fd, &content));
  close(fd);
  EXPECT_EQ("A=b\n", content);
}

TEST_F(T_Util, CallServerHook) {
  EXPECT_EQ(0, CallServerHook("hookX", "t.cvmfs.io", "no/such/file"));

  EXPECT_TRUE(SafeWriteToFile(
    "hookY() { if [ $1 = \"t.cvmfs.io\" ]; then return 0; fi; return 42; }\n",
    "cvmfs_test_hooks.sh", 0644));

  EXPECT_EQ(0, CallServerHook("hookX", "t.cvmfs.io",
                              "./cvmfs_test_hooks.sh"));
  EXPECT_EQ(0, CallServerHook("hookY", "t.cvmfs.io",
                              "./cvmfs_test_hooks.sh"));
  EXPECT_EQ(42, CallServerHook("hookY", "x.cvmfs.io",
                               "./cvmfs_test_hooks.sh"));
}

namespace {

void *MainTalkCommandAnswer(void *data) {
  int socket_fd = *reinterpret_cast<int *>(data);
  struct sockaddr_un remote;
  socklen_t socket_size = sizeof(remote);
  int con_fd = accept(socket_fd, (struct sockaddr *)&remote, &socket_size);
  assert(con_fd > 0);
  char buf[32];
  int nbytes = recv(con_fd, buf, sizeof(buf) - 1, 0);
  buf[nbytes] = '\0';
  assert(strcmp("command", buf) == 0);
  std::string answer = "answer";
  (void)send(con_fd, &answer[0], answer.length(), MSG_NOSIGNAL);
  shutdown(con_fd, SHUT_RDWR);
  close(con_fd);
  return NULL;
}

}  // anonymous namespace

TEST_F(T_Util, SendTalkCommand) {
  EXPECT_THROW(SendTalkCommand("/no/such/file", "command"), EPublish);
  int socket_fd = MakeSocket("cvmfs_test_socket", 0600);
  ASSERT_GE(socket_fd, 0);
  ASSERT_EQ(0, listen(socket_fd, 1));
  pthread_t thread;
  int retval = pthread_create(&thread, NULL, MainTalkCommandAnswer, &socket_fd);
  ASSERT_EQ(0, retval);

  std::string answer = SendTalkCommand("cvmfs_test_socket", "command");
  pthread_join(thread, NULL);
  EXPECT_STREQ("answer", answer.c_str());

  close(socket_fd);
  unlink("cvmfs_test_socket");
}

}  // namespace publish
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include "../../cvmfs/util.h"
#include "testutil.h"

class T_ManagedExec : public ::testing::Test {
 protected:
  std::string GetDebugger() const {
    // check if we have a GDB installed
    const std::string gdb = GetExecutablePath("gdb");
    if (!gdb.empty()) {
      return gdb;
    }

    // maybe we are on a recent OS X and we find LLDB?
    return GetExecutablePath("lldb");
  }
};

TEST_F(T_ManagedExec, RunShell) {
  int fd_stdin;
  int fd_stdout;
  int fd_stderr;
  bool retval = Shell(&fd_stdin, &fd_stdout, &fd_stderr);
  EXPECT_TRUE(retval);

  Pipe shell_pipe(fd_stdout, fd_stdin);
  const char *command = "echo \"Hello World\"\n";
  retval = shell_pipe.Write(command, strlen(command));
  EXPECT_TRUE(retval);

  char buffer[20];
  retval = shell_pipe.Read(&buffer, 11);
  EXPECT_TRUE(retval);
  buffer[11] = '\0';

  EXPECT_EQ(0, strncmp("Hello World", buffer, 12));
}

TEST_F(T_ManagedExec, ExecuteBinaryDoubleFork) {
  int fd_stdin, fd_stdout, fd_stderr;
  pid_t child_pid;

  // find gdb in the $PATH of this system
  const std::string gdb = GetDebugger();
  ASSERT_NE("", gdb) << "no debugger found, but needed by this test case";

  // spawn detached (double forked) child process
  const bool double_fork = true;
  bool retval = ExecuteBinary(&fd_stdin,
                              &fd_stdout,
                              &fd_stderr,
                               gdb,
                               std::vector<std::string>(),
                               double_fork,
                              &child_pid);
  // check if process is running
  ASSERT_TRUE(retval);
  EXPECT_EQ(0, kill(child_pid, 0));

  // check that the PPID of the process is 1 (belongs to init)
  pid_t child_parent_pid = GetParentPid(child_pid);
  EXPECT_EQ(1, child_parent_pid);

  // tell the process to terminate
  Pipe shell_pipe(fd_stdout, fd_stdin);
  const char *quit = "quit\n";
  retval = shell_pipe.Write(quit, strlen(quit));
  EXPECT_TRUE(retval);
  shell_pipe.Close();
  close(fd_stderr);

  // wait for the child process to terminate
  const unsigned int timeout = 1000;
  unsigned int counter = 0;
  while (counter < timeout && kill(child_pid, 0) == 0) {
    usleep(5000);
    ++counter;
  }
  EXPECT_LT(counter, timeout) << "detached process did not terminate in time";
}

TEST_F(T_ManagedExec, ExecuteBinaryAsChild) {
  int fd_stdin, fd_stdout, fd_stderr;
  pid_t child_pid;
  pid_t my_pid = getpid();

  // spawn a child process (not double forked)
  const bool double_fork = false;
  bool retval = ExecuteBinary(&fd_stdin,
                              &fd_stdout,
                              &fd_stderr,
                               "gdb",
                               std::vector<std::string>(),
                               double_fork,
                              &child_pid);

  // check that the process is running
  ASSERT_TRUE(retval);
  EXPECT_EQ(0, kill(child_pid, 0));

  // check that we are the parent of the spawned process
  pid_t child_parent_pid = GetParentPid(child_pid);
  EXPECT_EQ(my_pid, child_parent_pid);

  // tell the process to terminate
  Pipe shell_pipe(fd_stdout, fd_stdin);
  const char *quit = "quit\n";
  retval = shell_pipe.Write(quit, strlen(quit));
  EXPECT_TRUE(retval);
  shell_pipe.Close();
  close(fd_stderr);

  // wait for the child process to terminate
  int statloc;
  retval = waitpid(child_pid, &statloc, 0);
  EXPECT_NE(-1, retval);
}
<commit_msg>FIX: use ::GetDebugger() in ExecuteBinaryAsChild<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include <gtest/gtest.h>

#include "../../cvmfs/util.h"
#include "testutil.h"

class T_ManagedExec : public ::testing::Test {
 protected:
  std::string GetDebugger() const {
    // check if we have a GDB installed
    const std::string gdb = GetExecutablePath("gdb");
    if (!gdb.empty()) {
      return gdb;
    }

    // maybe we are on a recent OS X and we find LLDB?
    return GetExecutablePath("lldb");
  }
};

TEST_F(T_ManagedExec, RunShell) {
  int fd_stdin;
  int fd_stdout;
  int fd_stderr;
  bool retval = Shell(&fd_stdin, &fd_stdout, &fd_stderr);
  EXPECT_TRUE(retval);

  Pipe shell_pipe(fd_stdout, fd_stdin);
  const char *command = "echo \"Hello World\"\n";
  retval = shell_pipe.Write(command, strlen(command));
  EXPECT_TRUE(retval);

  char buffer[20];
  retval = shell_pipe.Read(&buffer, 11);
  EXPECT_TRUE(retval);
  buffer[11] = '\0';

  EXPECT_EQ(0, strncmp("Hello World", buffer, 12));
}

TEST_F(T_ManagedExec, ExecuteBinaryDoubleFork) {
  int fd_stdin, fd_stdout, fd_stderr;
  pid_t child_pid;

  // find gdb in the $PATH of this system
  const std::string gdb = GetDebugger();
  ASSERT_NE("", gdb) << "no debugger found, but needed by this test case";

  // spawn detached (double forked) child process
  const bool double_fork = true;
  bool retval = ExecuteBinary(&fd_stdin,
                              &fd_stdout,
                              &fd_stderr,
                               gdb,
                               std::vector<std::string>(),
                               double_fork,
                              &child_pid);
  // check if process is running
  ASSERT_TRUE(retval);
  EXPECT_EQ(0, kill(child_pid, 0));

  // check that the PPID of the process is 1 (belongs to init)
  pid_t child_parent_pid = GetParentPid(child_pid);
  EXPECT_EQ(1, child_parent_pid);

  // tell the process to terminate
  Pipe shell_pipe(fd_stdout, fd_stdin);
  const char *quit = "quit\n";
  retval = shell_pipe.Write(quit, strlen(quit));
  EXPECT_TRUE(retval);
  shell_pipe.Close();
  close(fd_stderr);

  // wait for the child process to terminate
  const unsigned int timeout = 1000;
  unsigned int counter = 0;
  while (counter < timeout && kill(child_pid, 0) == 0) {
    usleep(5000);
    ++counter;
  }
  EXPECT_LT(counter, timeout) << "detached process did not terminate in time";
}

TEST_F(T_ManagedExec, ExecuteBinaryAsChild) {
  int fd_stdin, fd_stdout, fd_stderr;
  pid_t child_pid;
  pid_t my_pid = getpid();

  // find gdb in the $PATH of this system
  const std::string gdb = GetDebugger();
  ASSERT_NE("", gdb) << "no debugger found, but needed by this test case";

  // spawn a child process (not double forked)
  const bool double_fork = false;
  bool retval = ExecuteBinary(&fd_stdin,
                              &fd_stdout,
                              &fd_stderr,
                               gdb,
                               std::vector<std::string>(),
                               double_fork,
                              &child_pid);

  // check that the process is running
  ASSERT_TRUE(retval);
  EXPECT_EQ(0, kill(child_pid, 0));

  // check that we are the parent of the spawned process
  pid_t child_parent_pid = GetParentPid(child_pid);
  EXPECT_EQ(my_pid, child_parent_pid);

  // tell the process to terminate
  Pipe shell_pipe(fd_stdout, fd_stdin);
  const char *quit = "quit\n";
  retval = shell_pipe.Write(quit, strlen(quit));
  EXPECT_TRUE(retval);
  shell_pipe.Close();
  close(fd_stderr);

  // wait for the child process to terminate
  int statloc;
  retval = waitpid(child_pid, &statloc, 0);
  EXPECT_NE(-1, retval);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2018, John Wiegley.  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 New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <system.hh>

#include "timelog.h"
#include "xact.h"
#include "post.h"
#include "account.h"
#include "journal.h"
#include "context.h"

namespace ledger {

namespace {
  void create_timelog_xact(const time_xact_t& in_event,
                           const time_xact_t& out_event,
                           parse_context_t&   context)
  {
    unique_ptr<xact_t> curr(new xact_t);
    curr->_date = in_event.checkin.date();
    curr->code  = out_event.desc; // if it wasn't used above
    curr->payee = in_event.desc;
    curr->pos   = in_event.position;

    if (! in_event.note.empty())
      curr->append_note(in_event.note.c_str(), *context.scope);

    char buf[32];
    std::sprintf(buf, "%lds", long((out_event.checkin - in_event.checkin)
                                   .total_seconds()));
    amount_t amt;
    amt.parse(buf);
    VERIFY(amt.valid());

    post_t * post = new post_t(in_event.account, amt, POST_VIRTUAL);
    post->set_state(out_event.completed ? item_t::CLEARED : item_t::UNCLEARED);
    post->pos = in_event.position;
    post->checkin = in_event.checkin;
    post->checkout = out_event.checkin;
    curr->add_post(post);
    in_event.account->add_post(post);

    if (! context.journal->add_xact(curr.get()))
      throw parse_error(_("Failed to record 'out' timelog transaction"));
    else
      curr.release();
  }

  std::size_t clock_out_from_timelog(std::list<time_xact_t>& time_xacts,
                                     time_xact_t             out_event,
                                     parse_context_t&        context)
  {
    time_xact_t event;

    if (time_xacts.size() == 1) {
      event = time_xacts.back();
      time_xacts.clear();
    }
    else if (time_xacts.empty()) {
      throw parse_error(_("Timelog check-out event without a check-in"));
    }
    else if (! out_event.account) {
      throw parse_error
        (_("When multiple check-ins are active, checking out requires an account"));
    }
    else {
      bool found = false;

      for (std::list<time_xact_t>::iterator i = time_xacts.begin();
           i != time_xacts.end();
           i++)
        if (out_event.account == (*i).account) {
          event = *i;
          found = true;
          time_xacts.erase(i);
          break;
        }

      if (! found)
        throw parse_error
          (_("Timelog check-out event does not match any current check-ins"));
    }

    if (event.checkin.is_not_a_date_time())
        throw parse_error(_("Timelog check-in has no corresponding check-out"));
    if (out_event.checkin.is_not_a_date_time())
        throw parse_error(_("Timelog check-out has no corresponding check-in"));

    if (out_event.checkin < event.checkin)
      throw parse_error
        (_("Timelog check-out date less than corresponding check-in"));

    if (! out_event.desc.empty() && event.desc.empty()) {
      event.desc = out_event.desc;
      out_event.desc = empty_string;
    }

    if (! out_event.note.empty() && event.note.empty())
      event.note = out_event.note;

    if (! context.journal->day_break) {
      create_timelog_xact(event, out_event, context);
      return 1;
    } else {
      time_xact_t begin(event);
      std::size_t xact_count = 0;

      while (begin.checkin < out_event.checkin) {
        DEBUG("timelog", "begin.checkin: " << begin.checkin);
        datetime_t days_end(begin.checkin.date(), time_duration_t(23, 59, 59));
        days_end += seconds(1);
        DEBUG("timelog", "days_end: " << days_end);

        if (out_event.checkin <= days_end) {
          create_timelog_xact(begin, out_event, context);
          ++xact_count;
          break;
        } else {
          time_xact_t end(out_event);
          end.checkin = days_end;
          DEBUG("timelog", "end.checkin: " << end.checkin);
          create_timelog_xact(begin, end, context);
          ++xact_count;

          begin.checkin = end.checkin;
        }
      }
      return xact_count;
    }
  }
} // unnamed namespace

void time_log_t::close()
{
  if (! time_xacts.empty()) {
    std::list<account_t *> accounts;

    foreach (time_xact_t& time_xact, time_xacts)
      accounts.push_back(time_xact.account);

    foreach (account_t * account, accounts) {
      DEBUG("timelog", "Clocking out from account " << account->fullname());
      context.count += clock_out_from_timelog
        (time_xacts, time_xact_t(none, CURRENT_TIME(), account), context);
    }
    assert(time_xacts.empty());
  }
}

void time_log_t::clock_in(time_xact_t event)
{
  if (! time_xacts.empty()) {
    foreach (time_xact_t& time_xact, time_xacts) {
      if (event.account == time_xact.account)
        throw parse_error(_("Cannot double check-in to the same account"));
    }
  }

  time_xacts.push_back(event);
}

std::size_t time_log_t::clock_out(time_xact_t event)
{
  if (time_xacts.empty())
    throw std::logic_error(_("Timelog check-out event without a check-in"));

  return clock_out_from_timelog(time_xacts, event, context);
}

} // namespace ledger
<commit_msg>Timelog: Not able to check-in to multiple accounts at a time<commit_after>/*
 * Copyright (c) 2003-2018, John Wiegley.  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 New Artisans LLC nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <system.hh>

#include "timelog.h"
#include "xact.h"
#include "post.h"
#include "account.h"
#include "journal.h"
#include "context.h"

namespace ledger {

namespace {
  void create_timelog_xact(const time_xact_t& in_event,
                           const time_xact_t& out_event,
                           parse_context_t&   context)
  {
    unique_ptr<xact_t> curr(new xact_t);
    curr->_date = in_event.checkin.date();
    curr->code  = out_event.desc; // if it wasn't used above
    curr->payee = in_event.desc;
    curr->pos   = in_event.position;

    if (! in_event.note.empty())
      curr->append_note(in_event.note.c_str(), *context.scope);

    char buf[32];
    std::sprintf(buf, "%lds", long((out_event.checkin - in_event.checkin)
                                   .total_seconds()));
    amount_t amt;
    amt.parse(buf);
    VERIFY(amt.valid());

    post_t * post = new post_t(in_event.account, amt, POST_VIRTUAL);
    post->set_state(out_event.completed ? item_t::CLEARED : item_t::UNCLEARED);
    post->pos = in_event.position;
    post->checkin = in_event.checkin;
    post->checkout = out_event.checkin;
    curr->add_post(post);
    in_event.account->add_post(post);

    if (! context.journal->add_xact(curr.get()))
      throw parse_error(_("Failed to record 'out' timelog transaction"));
    else
      curr.release();
  }

  std::size_t clock_out_from_timelog(std::list<time_xact_t>& time_xacts,
                                     time_xact_t             out_event,
                                     parse_context_t&        context)
  {
    time_xact_t event;

    if (time_xacts.size() == 1) {
      event = time_xacts.back();
      time_xacts.clear();
    }
    else if (time_xacts.empty()) {
      throw parse_error(_("Timelog check-out event without a check-in"));
    }
    else if (! out_event.account) {
      throw parse_error
        (_("When multiple check-ins are active, checking out requires an account"));
    }
    else {
      bool found = false;

      for (std::list<time_xact_t>::iterator i = time_xacts.begin();
           i != time_xacts.end();
           i++)
        if (out_event.account == (*i).account) {
          event = *i;
          found = true;
          time_xacts.erase(i);
          break;
        }

      if (! found)
        throw parse_error
          (_("Timelog check-out event does not match any current check-ins"));
    }

    if (event.checkin.is_not_a_date_time())
        throw parse_error(_("Timelog check-in has no corresponding check-out"));
    if (out_event.checkin.is_not_a_date_time())
        throw parse_error(_("Timelog check-out has no corresponding check-in"));

    if (out_event.checkin < event.checkin)
      throw parse_error
        (_("Timelog check-out date less than corresponding check-in"));

    if (! out_event.desc.empty() && event.desc.empty()) {
      event.desc = out_event.desc;
      out_event.desc = empty_string;
    }

    if (! out_event.note.empty() && event.note.empty())
      event.note = out_event.note;

    if (! context.journal->day_break) {
      create_timelog_xact(event, out_event, context);
      return 1;
    } else {
      time_xact_t begin(event);
      std::size_t xact_count = 0;

      while (begin.checkin < out_event.checkin) {
        DEBUG("timelog", "begin.checkin: " << begin.checkin);
        datetime_t days_end(begin.checkin.date(), time_duration_t(23, 59, 59));
        days_end += seconds(1);
        DEBUG("timelog", "days_end: " << days_end);

        if (out_event.checkin <= days_end) {
          create_timelog_xact(begin, out_event, context);
          ++xact_count;
          break;
        } else {
          time_xact_t end(out_event);
          end.checkin = days_end;
          DEBUG("timelog", "end.checkin: " << end.checkin);
          create_timelog_xact(begin, end, context);
          ++xact_count;

          begin.checkin = end.checkin;
        }
      }
      return xact_count;
    }
  }
} // unnamed namespace

void time_log_t::close()
{
  if (! time_xacts.empty()) {
    std::list<account_t *> accounts;

    foreach (time_xact_t& time_xact, time_xacts)
      accounts.push_back(time_xact.account);

    foreach (account_t * account, accounts) {
      DEBUG("timelog", "Clocking out from account " << account->fullname());
      context.count += clock_out_from_timelog
        (time_xacts, time_xact_t(none, CURRENT_TIME(), false, account), context);
    }
    assert(time_xacts.empty());
  }
}

void time_log_t::clock_in(time_xact_t event)
{
  if (! time_xacts.empty()) {
    foreach (time_xact_t& time_xact, time_xacts) {
      if (event.account == time_xact.account)
        throw parse_error(_("Cannot double check-in to the same account"));
    }
  }

  time_xacts.push_back(event);
}

std::size_t time_log_t::clock_out(time_xact_t event)
{
  if (time_xacts.empty())
    throw std::logic_error(_("Timelog check-out event without a check-in"));

  return clock_out_from_timelog(time_xacts, event, context);
}

} // namespace ledger
<|endoftext|>