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

// <functional>

//  In C++17, the function adapters mem_fun/mem_fun_ref, etc have been removed.
//  However, for backwards compatibility, if _LIBCPP_ENABLE_CXX17_REMOVED_BINDERS
//  is defined before including <functional>, then they will be restored.

#define _LIBCPP_ENABLE_CXX17_REMOVED_BINDERS

#include <functional>
#include <cassert>

int identity(int v) { return v; }
int sum(int a, int b) { return a + b; }

struct Foo {
	int zero() const { return 0; }
	int identity(int v) const { return v; }
	int sum(int a, int b) const { return a + b; }
};

int main()
{
	typedef std::pointer_to_unary_function<int, int> PUF;
	typedef std::pointer_to_binary_function<int, int, int> PBF;
	assert((std::ptr_fun<int, int>(identity)(4) == 4));
	assert((std::ptr_fun<int, int, int>(sum)(4, 5) == 9));

	Foo f;
	assert((std::mem_fn(&Foo::identity)(f, 5) == 5));
	assert((std::mem_fn(&Foo::sum)(f, 5, 6) == 11));

    typedef std::mem_fun_ref_t<int, Foo> MFR;
    typedef std::const_mem_fun_ref_t<int, Foo> CMFR;

	assert((std::mem_fun_ref(&Foo::zero)(f) == 0));
	assert((std::mem_fun_ref(&Foo::identity)(f, 5) == 5));
}
<commit_msg>Fix another test with modules enabled<commit_after>//===----------------------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

// <functional>

//  In C++17, the function adapters mem_fun/mem_fun_ref, etc have been removed.
//  However, for backwards compatibility, if _LIBCPP_ENABLE_CXX17_REMOVED_BINDERS
//  is defined before including <functional>, then they will be restored.

// MODULES_DEFINES: _LIBCPP_ENABLE_CXX17_REMOVED_BINDERS
#define _LIBCPP_ENABLE_CXX17_REMOVED_BINDERS

#include <functional>
#include <cassert>

int identity(int v) { return v; }
int sum(int a, int b) { return a + b; }

struct Foo {
	int zero() const { return 0; }
	int identity(int v) const { return v; }
	int sum(int a, int b) const { return a + b; }
};

int main()
{
	typedef std::pointer_to_unary_function<int, int> PUF;
	typedef std::pointer_to_binary_function<int, int, int> PBF;
	assert((std::ptr_fun<int, int>(identity)(4) == 4));
	assert((std::ptr_fun<int, int, int>(sum)(4, 5) == 9));

	Foo f;
	assert((std::mem_fn(&Foo::identity)(f, 5) == 5));
	assert((std::mem_fn(&Foo::sum)(f, 5, 6) == 11));

    typedef std::mem_fun_ref_t<int, Foo> MFR;
    typedef std::const_mem_fun_ref_t<int, Foo> CMFR;

	assert((std::mem_fun_ref(&Foo::zero)(f) == 0));
	assert((std::mem_fun_ref(&Foo::identity)(f, 5) == 5));
}
<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This 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.  See file COPYING.
 *
 */

#include "Timer.h"
#include "Cond.h"

#include "config.h"
#include "include/Context.h"

#undef dout
#define dout(x)  if (x <= g_conf.debug) cout << g_clock.now() << " TIMER "
#define derr(x)  if (x <= g_conf.debug) cerr << g_clock.now() << " TIMER "

#define DBL 10

#include <signal.h>
#include <sys/time.h>
#include <math.h>

// single global instance
Timer      g_timer;

/**** thread solution *****/

bool Timer::get_next_due(utime_t& when)
{
  if (scheduled.empty()) {
    dout(10) << "get_next_due - nothing scheduled" << endl;
    return false;
  } else {
    map< utime_t, set<Context*> >::iterator it = scheduled.begin();
    when = it->first;
    dout(10) << "get_next_due - " << when << endl;
    return true;
  }
}

void Timer::timer_entry()
{
  lock.Lock();

  while (!thread_stop) {

    // now
    utime_t now = g_clock.now();

    // any events due?
    utime_t next;
    bool next_due = get_next_due(next);

    if (next_due && now >= next) {
      // move to pending list
      list<Context*> pending;

      map< utime_t, set<Context*> >::iterator it = scheduled.begin();
      while (it != scheduled.end()) {
        if (it->first > now) break;

        utime_t t = it->first;
        dout(DBL) << "queueing event(s) scheduled at " << t << endl;

        for (set<Context*>::iterator cit = it->second.begin();
             cit != it->second.end();
             cit++) {
          pending.push_back(*cit);
          event_times.erase(*cit);
          num_event--;
        }

        map< utime_t, set<Context*> >::iterator previt = it;
        it++;
        scheduled.erase(previt);
      }

      if (!pending.empty()) {
        sleeping = false;
        lock.Unlock();
        {
	  // make sure we're not holding any locks while we do callbacks
          // make the callbacks myself.
          for (list<Context*>::iterator cit = pending.begin();
               cit != pending.end();
               cit++) {
            dout(DBL) << "start callback " << *cit << endl;
            (*cit)->finish(0);
            dout(DBL) << "finish callback " << *cit << endl;
	    delete *cit;
          }
          pending.clear();
          assert(pending.empty());
        }
        lock.Lock();
      }

    }
    else {
      // sleep
      if (next_due) {
        dout(DBL) << "sleeping until " << next << endl;
        timed_sleep = true;
        sleeping = true;
        timeout_cond.WaitUntil(lock, next);  // wait for waker or time
        utime_t now = g_clock.now();
        dout(DBL) << "kicked or timed out at " << now << endl;
      } else {
        dout(DBL) << "sleeping" << endl;
        timed_sleep = false;
        sleeping = true;
        sleep_cond.Wait(lock);         // wait for waker
        utime_t now = g_clock.now();
        dout(DBL) << "kicked at " << now << endl;
      }
    }
  }

  lock.Unlock();
}

/**
 * Timer bits
 */

void Timer::register_timer()
{
  if (timer_thread.is_started()) {
    if (sleeping) {
      dout(DBL) << "register_timer kicking thread" << endl;
      if (timed_sleep)
        timeout_cond.SignalAll();
      else
        sleep_cond.SignalAll();
    } else {
      dout(DBL) << "register_timer doing nothing; thread is awake" << endl;
      // it's probably doing callbacks.
    }
  } else {
    dout(DBL) << "register_timer starting thread" << endl;
    timer_thread.create();
  }
}

void Timer::cancel_timer()
{
  // clear my callback pointers
  if (timer_thread.is_started()) {
    dout(10) << "setting thread_stop flag" << endl;
    lock.Lock();
    thread_stop = true;
    if (timed_sleep)
      timeout_cond.SignalAll();
    else
      sleep_cond.SignalAll();
    lock.Unlock();

    dout(10) << "waiting for thread to finish" << endl;
    void *ptr;
    timer_thread.join(&ptr);

    dout(10) << "thread finished, exit code " << ptr << endl;
  }
}

/*
 * schedule
 */

void Timer::add_event_after(float seconds,
                            Context *callback)
{
  utime_t when = g_clock.now();
  when.sec_ref() += (int)seconds;
  add_event_at(when, callback);
}

void Timer::add_event_at(utime_t when,
                         Context *callback)
{
  lock.Lock();

  dout(DBL) << "add_event " << callback << " at " << when << endl;

  // insert
  scheduled[when].insert(callback);
  assert(event_times.count(callback) == 0);
  event_times[callback] = when;

  num_event++;

  // make sure i wake up on time
  register_timer();

  lock.Unlock();
}

bool Timer::cancel_event(Context *callback)
{
  lock.Lock();

  dout(DBL) << "cancel_event " << callback << endl;

  if (!event_times.count(callback)) {
    dout(DBL) << "cancel_event " << callback << " isn't scheduled (probably executing in another thread?)" << endl;
    lock.Unlock();
    return false;     // wasn't scheduled.
  }

  utime_t tp = event_times[callback];
  event_times.erase(callback);

  assert(scheduled.count(tp));
  assert(scheduled[tp].count(callback));
  scheduled[tp].erase(callback);
  if (scheduled[tp].empty())
    scheduled.erase(tp);

  lock.Unlock();
  return true;
}

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

void SafeTimer::add_event_after(float seconds, Context *c)
{
  assert(lock.is_locked());
  Context *w = new EventWrapper(this, c);
  dout(DBL) << "SafeTimer.add_event_after wrapping " << c << " with " << w << endl;
  scheduled[c] = w;
  g_timer.add_event_after(seconds, w);
}

void SafeTimer::add_event_at(utime_t when, Context *c)
{
  assert(lock.is_locked());
  Context *w = new EventWrapper(this, c);
  dout(DBL) << "SafeTimer.add_event_at wrapping " << c << " with " << w << endl;
  scheduled[c] = w;
  g_timer.add_event_at(when, w);
}

void SafeTimer::EventWrapper::finish(int r)
{
  timer->lock.Lock();
  if (timer->scheduled.count(actual)) {
    // still scheduled.  execute.
    actual->finish(r);
    timer->scheduled.erase(actual);
  } else {
    // canceled.
    assert(timer->canceled.count(actual));
    timer->canceled.erase(actual);
    delete actual;
    timer->cond.Signal();
  }
  timer->lock.Unlock();
}

void SafeTimer::cancel_event(Context *c)
{
  assert(lock.is_locked());
  assert(scheduled.count(c));
  if (!g_timer.cancel_event(scheduled[c]))
    canceled[c] = scheduled[c];
  scheduled.erase(c);
}

void SafeTimer::cancel_all()
{
  assert(lock.is_locked());
  for (map<Context*,Context*>::iterator p = scheduled.begin();
       p != scheduled.end();
       ++p)
    if (!g_timer.cancel_event(p->second))
      canceled[p->first] = p->second;
  scheduled.clear();
}

void SafeTimer::join()
{
  assert(lock.is_locked());
  assert(scheduled.empty());
  while (!canceled.empty()) {
    // wait
    dout(-10) << "SafeTimer.join waiting for " << canceled.size() << " to join" << endl;
    cond.Wait(lock);
  }
}

SafeTimer::~SafeTimer()
{
  if (!scheduled.empty() && !canceled.empty()) {
    derr(0) << "SafeTimer.~SafeTimer " << scheduled.size() << " events scheduled, "
	    << canceled.size() << " canceled but unflushed"
	    << endl;
  }
}
<commit_msg>another minor SafeTimer issue<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This 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.  See file COPYING.
 *
 */

#include "Timer.h"
#include "Cond.h"

#include "config.h"
#include "include/Context.h"

#undef dout
#define dout(x)  if (x <= g_conf.debug) cout << g_clock.now() << " TIMER "
#define derr(x)  if (x <= g_conf.debug) cerr << g_clock.now() << " TIMER "

#define DBL 10

#include <signal.h>
#include <sys/time.h>
#include <math.h>

// single global instance
Timer      g_timer;

/**** thread solution *****/

bool Timer::get_next_due(utime_t& when)
{
  if (scheduled.empty()) {
    dout(10) << "get_next_due - nothing scheduled" << endl;
    return false;
  } else {
    map< utime_t, set<Context*> >::iterator it = scheduled.begin();
    when = it->first;
    dout(10) << "get_next_due - " << when << endl;
    return true;
  }
}

void Timer::timer_entry()
{
  lock.Lock();

  while (!thread_stop) {

    // now
    utime_t now = g_clock.now();

    // any events due?
    utime_t next;
    bool next_due = get_next_due(next);

    if (next_due && now >= next) {
      // move to pending list
      list<Context*> pending;

      map< utime_t, set<Context*> >::iterator it = scheduled.begin();
      while (it != scheduled.end()) {
        if (it->first > now) break;

        utime_t t = it->first;
        dout(DBL) << "queueing event(s) scheduled at " << t << endl;

        for (set<Context*>::iterator cit = it->second.begin();
             cit != it->second.end();
             cit++) {
          pending.push_back(*cit);
          event_times.erase(*cit);
          num_event--;
        }

        map< utime_t, set<Context*> >::iterator previt = it;
        it++;
        scheduled.erase(previt);
      }

      if (!pending.empty()) {
        sleeping = false;
        lock.Unlock();
        {
	  // make sure we're not holding any locks while we do callbacks
          // make the callbacks myself.
          for (list<Context*>::iterator cit = pending.begin();
               cit != pending.end();
               cit++) {
            dout(DBL) << "start callback " << *cit << endl;
            (*cit)->finish(0);
            dout(DBL) << "finish callback " << *cit << endl;
	    delete *cit;
          }
          pending.clear();
          assert(pending.empty());
        }
        lock.Lock();
      }

    }
    else {
      // sleep
      if (next_due) {
        dout(DBL) << "sleeping until " << next << endl;
        timed_sleep = true;
        sleeping = true;
        timeout_cond.WaitUntil(lock, next);  // wait for waker or time
        utime_t now = g_clock.now();
        dout(DBL) << "kicked or timed out at " << now << endl;
      } else {
        dout(DBL) << "sleeping" << endl;
        timed_sleep = false;
        sleeping = true;
        sleep_cond.Wait(lock);         // wait for waker
        utime_t now = g_clock.now();
        dout(DBL) << "kicked at " << now << endl;
      }
    }
  }

  lock.Unlock();
}

/**
 * Timer bits
 */

void Timer::register_timer()
{
  if (timer_thread.is_started()) {
    if (sleeping) {
      dout(DBL) << "register_timer kicking thread" << endl;
      if (timed_sleep)
        timeout_cond.SignalAll();
      else
        sleep_cond.SignalAll();
    } else {
      dout(DBL) << "register_timer doing nothing; thread is awake" << endl;
      // it's probably doing callbacks.
    }
  } else {
    dout(DBL) << "register_timer starting thread" << endl;
    timer_thread.create();
  }
}

void Timer::cancel_timer()
{
  // clear my callback pointers
  if (timer_thread.is_started()) {
    dout(10) << "setting thread_stop flag" << endl;
    lock.Lock();
    thread_stop = true;
    if (timed_sleep)
      timeout_cond.SignalAll();
    else
      sleep_cond.SignalAll();
    lock.Unlock();

    dout(10) << "waiting for thread to finish" << endl;
    void *ptr;
    timer_thread.join(&ptr);

    dout(10) << "thread finished, exit code " << ptr << endl;
  }
}

/*
 * schedule
 */

void Timer::add_event_after(float seconds,
                            Context *callback)
{
  utime_t when = g_clock.now();
  when.sec_ref() += (int)seconds;
  add_event_at(when, callback);
}

void Timer::add_event_at(utime_t when,
                         Context *callback)
{
  lock.Lock();

  dout(DBL) << "add_event " << callback << " at " << when << endl;

  // insert
  scheduled[when].insert(callback);
  assert(event_times.count(callback) == 0);
  event_times[callback] = when;

  num_event++;

  // make sure i wake up on time
  register_timer();

  lock.Unlock();
}

bool Timer::cancel_event(Context *callback)
{
  lock.Lock();

  dout(DBL) << "cancel_event " << callback << endl;

  if (!event_times.count(callback)) {
    dout(DBL) << "cancel_event " << callback << " isn't scheduled (probably executing)" << endl;
    lock.Unlock();
    return false;     // wasn't scheduled.
  }

  utime_t tp = event_times[callback];
  event_times.erase(callback);

  assert(scheduled.count(tp));
  assert(scheduled[tp].count(callback));
  scheduled[tp].erase(callback);
  if (scheduled[tp].empty())
    scheduled.erase(tp);

  lock.Unlock();
  return true;
}

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

void SafeTimer::add_event_after(float seconds, Context *c)
{
  assert(lock.is_locked());
  Context *w = new EventWrapper(this, c);
  dout(DBL) << "SafeTimer.add_event_after wrapping " << c << " with " << w << endl;
  scheduled[c] = w;
  g_timer.add_event_after(seconds, w);
}

void SafeTimer::add_event_at(utime_t when, Context *c)
{
  assert(lock.is_locked());
  Context *w = new EventWrapper(this, c);
  dout(DBL) << "SafeTimer.add_event_at wrapping " << c << " with " << w << endl;
  scheduled[c] = w;
  g_timer.add_event_at(when, w);
}

void SafeTimer::EventWrapper::finish(int r)
{
  timer->lock.Lock();
  if (timer->scheduled.count(actual)) {
    // still scheduled.  execute.
    actual->finish(r);
    timer->scheduled.erase(actual);
    timer->canceled.erase(actual);  // in case, say, i canceled myself
  } else {
    // canceled.
    assert(timer->canceled.count(actual));
    timer->canceled.erase(actual);
    timer->cond.Signal();
  }
  delete actual;
  timer->lock.Unlock();
}

void SafeTimer::cancel_event(Context *c)
{
  assert(lock.is_locked());
  assert(scheduled.count(c));
  if (!g_timer.cancel_event(scheduled[c]))
    canceled[c] = scheduled[c];
  scheduled.erase(c);
}

void SafeTimer::cancel_all()
{
  assert(lock.is_locked());
  for (map<Context*,Context*>::iterator p = scheduled.begin();
       p != scheduled.end();
       ++p)
    if (!g_timer.cancel_event(p->second))
      canceled[p->first] = p->second;
  scheduled.clear();
}

void SafeTimer::join()
{
  assert(lock.is_locked());
  assert(scheduled.empty());
  while (!canceled.empty()) {
    // wait
    dout(-10) << "SafeTimer.join waiting for " << canceled.size() << " to join" << endl;
    dout(-10) << canceled << endl;
    cond.Wait(lock);
  }
}

SafeTimer::~SafeTimer()
{
  if (!scheduled.empty() && !canceled.empty()) {
    derr(0) << "SafeTimer.~SafeTimer " << scheduled.size() << " events scheduled, "
	    << canceled.size() << " canceled but unflushed"
	    << endl;
  }
}
<|endoftext|>


<commit_before>/****************************************************************************
 *
 *   Copyright (c) 2017 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file task.cpp
 *
 * Main task handling the temperature calibration process
 *
 * @author Beat Küng <beat-kueng@gmx.net>
 */

#include <uORB/topics/sensor_gyro.h>
#include <mathlib/mathlib.h>
#include <px4_log.h>
#include <px4_posix.h>
#include <px4_tasks.h>
#include <drivers/drv_hrt.h>
#include <drivers/drv_led.h>

#include <unistd.h>

#include "common.h"
#include "temperature_calibration.h"
#include "accel.h"
#include "baro.h"
#include "gyro.h"

class TemperatureCalibration;

namespace temperature_calibration
{
TemperatureCalibration *instance = nullptr;
}

class TemperatureCalibration
{
public:
	/**
	 * Constructor
	 */
	TemperatureCalibration(bool accel, bool baro, bool gyro);

	/**
	 * Destructor
	 */
	~TemperatureCalibration();

	/**
	 * Start task.
	 *
	 * @return		OK on success.
	 */
	int		start();

	static void do_temperature_calibration(int argc, char *argv[]);

	void		task_main();

	void exit() { _force_task_exit = true; }

private:
	void publish_led_control(led_control_s &led_control);

	orb_advert_t _led_control_pub = nullptr;

	bool	_force_task_exit = false;
	int	_control_task = -1;		// task handle for task

	bool _accel; ///< enable accel calibration?
	bool _baro; ///< enable baro calibration?
	bool _gyro; ///< enable gyro calibration?
};

TemperatureCalibration::TemperatureCalibration(bool accel, bool baro, bool gyro)
	: _accel(accel), _baro(baro), _gyro(gyro)
{
}

TemperatureCalibration::~TemperatureCalibration()
{
}

void TemperatureCalibration::task_main()
{
	// subscribe to all gyro instances
	int gyro_sub[SENSOR_COUNT_MAX];
	px4_pollfd_struct_t fds[SENSOR_COUNT_MAX] = {};
	unsigned num_gyro = orb_group_count(ORB_ID(sensor_gyro));

	if (num_gyro > SENSOR_COUNT_MAX) {
		num_gyro = SENSOR_COUNT_MAX;
	}

	for (unsigned i = 0; i < num_gyro; i++) {
		gyro_sub[i] = orb_subscribe_multi(ORB_ID(sensor_gyro), i);
		fds[i].fd = gyro_sub[i];
		fds[i].events = POLLIN;
	}

	int32_t min_temp_rise = 24;
	param_get(param_find("SYS_CAL_TDEL"), &min_temp_rise);
	PX4_INFO("Waiting for %i degrees difference in sensor temperature", min_temp_rise);

	int32_t min_start_temp = 5;
	param_get(param_find("SYS_CAL_TMIN"), &min_start_temp);

	int32_t max_start_temp = 10;
	param_get(param_find("SYS_CAL_TMAX"), &max_start_temp);

	//init calibrators
	TemperatureCalibrationBase *calibrators[3];
	bool error_reported[3] = {};
	int num_calibrators = 0;

	if (_accel) {
		calibrators[num_calibrators] = new TemperatureCalibrationAccel(min_temp_rise, min_start_temp, max_start_temp);

		if (calibrators[num_calibrators]) {
			++num_calibrators;

		} else {
			PX4_ERR("alloc failed");
		}
	}

	if (_baro) {
		calibrators[num_calibrators] = new TemperatureCalibrationBaro(min_temp_rise, min_start_temp, max_start_temp);

		if (calibrators[num_calibrators]) {
			++num_calibrators;

		} else {
			PX4_ERR("alloc failed");
		}
	}

	if (_gyro) {
		calibrators[num_calibrators] = new TemperatureCalibrationGyro(min_temp_rise, min_start_temp, max_start_temp, gyro_sub,
				num_gyro);

		if (calibrators[num_calibrators]) {
			++num_calibrators;

		} else {
			PX4_ERR("alloc failed");
		}
	}

	// reset params
	for (int i = 0; i < num_calibrators; ++i) {
		calibrators[i]->reset_calibration();
	}

	// make sure the system updates the changed parameters
	param_notify_changes();

	usleep(300000); // wait a bit for the system to apply the parameters

	hrt_abstime next_progress_output = hrt_absolute_time() + 1e6;

	// control LED's: blink, then turn solid according to progress
	led_control_s led_control = {};
	led_control.led_mask = 0xff;
	led_control.mode = led_control_s::MODE_BLINK_NORMAL;
	led_control.priority = led_control_s::MAX_PRIORITY;
	led_control.color = led_control_s::COLOR_YELLOW;
	led_control.num_blinks = 0;
	publish_led_control(led_control);
	int leds_completed = 0;

	bool abort_calibration = false;

	while (!_force_task_exit) {
		/* we poll on the gyro(s), since this is the sensor with the highest update rate.
		 * Each individual sensor will then check on its own if there's new data.
		 */
		int ret = px4_poll(fds, num_gyro, 1000);

		if (ret < 0) {
			// Poll error, sleep and try again
			usleep(10000);
			continue;

		} else if (ret == 0) {
			// Poll timeout or no new data, do nothing
			continue;
		}

		//if gyro is not enabled: we must do an orb_copy here, so that poll() does not immediately return again
		if (!_gyro) {
			sensor_gyro_s gyro_data;

			for (int i = 0; i < num_gyro; ++i) {
				orb_copy(ORB_ID(sensor_gyro), gyro_sub[i], &gyro_data);
			}
		}

		int min_progress = 110;

		for (int i = 0; i < num_calibrators; ++i) {
			ret = calibrators[i]->update();

			if (ret == -TC_ERROR_INITIAL_TEMP_TOO_HIGH) {
				abort_calibration = true;
				PX4_ERR("Calibration won't start - sensor temperature too high");
				_force_task_exit = true;
				break;

			} else if (ret < 0 && !error_reported[i]) {
				// temperature has decreased so calibration is not being updated
				error_reported[i] = true;
				PX4_ERR("Calibration update step failed (%i)", ret);

			} else if (ret < min_progress) {
				// temperature is stable or increasing
				min_progress = ret;
			}
		}

		if (min_progress == 110 || abort_calibration) {
			break; // we are done
		}

		int led_progress = min_progress * BOARD_MAX_LEDS / 100;

		for (; leds_completed < led_progress; ++leds_completed) {
			led_control.led_mask = 1 << leds_completed;
			led_control.mode = led_control_s::MODE_ON;
			publish_led_control(led_control);
		}

		//print progress each second
		hrt_abstime now = hrt_absolute_time();

		if (now > next_progress_output) {
			PX4_INFO("Calibration progress: %i%%", min_progress);
			next_progress_output = now + 1e6;
		}
	}

	if (abort_calibration) {
		led_control.color = led_control_s::COLOR_RED;

	} else {
		PX4_INFO("Sensor Measurments completed");

		// save params immediately so that we can check the result and don't have to wait for param save timeout
		param_control_autosave(false);

		// do final calculations & parameter storage
		for (int i = 0; i < num_calibrators; ++i) {
			int ret = calibrators[i]->finish();

			if (ret < 0) {
				PX4_ERR("Failed to finish calibration process (%i)", ret);
			}
		}

		param_notify_changes();
		int ret = param_save_default();

		if (ret != 0) {
			PX4_ERR("Failed to save params (%i)", ret);
		}

		param_control_autosave(true);

		led_control.color = led_control_s::COLOR_GREEN;
	}

	// blink the LED's according to success/failure
	led_control.led_mask = 0xff;
	led_control.mode = led_control_s::MODE_BLINK_FAST;
	led_control.num_blinks = 0;
	publish_led_control(led_control);

	for (int i = 0; i < num_calibrators; ++i) {
		delete calibrators[i];
	}

	for (unsigned i = 0; i < num_gyro; i++) {
		orb_unsubscribe(gyro_sub[i]);
	}

	delete temperature_calibration::instance;
	temperature_calibration::instance = nullptr;
	PX4_INFO("Exiting temperature calibration task");
}

void TemperatureCalibration::do_temperature_calibration(int argc, char *argv[])
{
	temperature_calibration::instance->task_main();
}

int TemperatureCalibration::start()
{

	ASSERT(_control_task == -1);
	_control_task = px4_task_spawn_cmd("temperature_calib",
					   SCHED_DEFAULT,
					   SCHED_PRIORITY_MAX - 5,
					   5800,
					   (px4_main_t)&TemperatureCalibration::do_temperature_calibration,
					   nullptr);

	if (_control_task < 0) {
		delete temperature_calibration::instance;
		temperature_calibration::instance = nullptr;
		PX4_ERR("start failed");
		return -errno;
	}

	return 0;
}

void TemperatureCalibration::publish_led_control(led_control_s &led_control)
{
	led_control.timestamp = hrt_absolute_time();

	if (_led_control_pub == nullptr) {
		_led_control_pub = orb_advertise_queue(ORB_ID(led_control), &led_control, LED_UORB_QUEUE_LENGTH);

	} else {
		orb_publish(ORB_ID(led_control), _led_control_pub, &led_control);
	}
}

int run_temperature_calibration(bool accel, bool baro, bool gyro)
{
	PX4_INFO("Starting temperature calibration task (accel=%i, baro=%i, gyro=%i)", (int)accel, (int)baro, (int)gyro);
	temperature_calibration::instance = new TemperatureCalibration(accel, baro, gyro);

	if (temperature_calibration::instance == nullptr) {
		PX4_ERR("alloc failed");
		return 1;
	}

	return temperature_calibration::instance->start();
}
<commit_msg>temperature calibration coverity fix 141891<commit_after>/****************************************************************************
 *
 *   Copyright (c) 2017 PX4 Development Team. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name PX4 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.
 *
 ****************************************************************************/

/**
 * @file task.cpp
 *
 * Main task handling the temperature calibration process
 *
 * @author Beat Küng <beat-kueng@gmx.net>
 */

#include <uORB/topics/sensor_gyro.h>
#include <mathlib/mathlib.h>
#include <px4_log.h>
#include <px4_posix.h>
#include <px4_tasks.h>
#include <drivers/drv_hrt.h>
#include <drivers/drv_led.h>

#include <unistd.h>

#include "common.h"
#include "temperature_calibration.h"
#include "accel.h"
#include "baro.h"
#include "gyro.h"

class TemperatureCalibration;

namespace temperature_calibration
{
TemperatureCalibration *instance = nullptr;
}

class TemperatureCalibration
{
public:
	/**
	 * Constructor
	 */
	TemperatureCalibration(bool accel, bool baro, bool gyro);

	/**
	 * Destructor
	 */
	~TemperatureCalibration() = default;

	/**
	 * Start task.
	 *
	 * @return		OK on success.
	 */
	int		start();

	static void do_temperature_calibration(int argc, char *argv[]);

	void		task_main();

	void exit() { _force_task_exit = true; }

private:
	void publish_led_control(led_control_s &led_control);

	orb_advert_t _led_control_pub = nullptr;

	bool	_force_task_exit = false;
	int	_control_task = -1;		// task handle for task

	bool _accel; ///< enable accel calibration?
	bool _baro; ///< enable baro calibration?
	bool _gyro; ///< enable gyro calibration?
};

TemperatureCalibration::TemperatureCalibration(bool accel, bool baro, bool gyro)
	: _accel(accel), _baro(baro), _gyro(gyro)
{
}

void TemperatureCalibration::task_main()
{
	// subscribe to all gyro instances
	int gyro_sub[SENSOR_COUNT_MAX] = {};
	px4_pollfd_struct_t fds[SENSOR_COUNT_MAX] = {};
	unsigned num_gyro = orb_group_count(ORB_ID(sensor_gyro));

	if (num_gyro > SENSOR_COUNT_MAX) {
		num_gyro = SENSOR_COUNT_MAX;
	}

	for (unsigned i = 0; i < num_gyro; i++) {
		gyro_sub[i] = orb_subscribe_multi(ORB_ID(sensor_gyro), i);
		fds[i].fd = gyro_sub[i];
		fds[i].events = POLLIN;
	}

	int32_t min_temp_rise = 24;
	param_get(param_find("SYS_CAL_TDEL"), &min_temp_rise);
	PX4_INFO("Waiting for %i degrees difference in sensor temperature", min_temp_rise);

	int32_t min_start_temp = 5;
	param_get(param_find("SYS_CAL_TMIN"), &min_start_temp);

	int32_t max_start_temp = 10;
	param_get(param_find("SYS_CAL_TMAX"), &max_start_temp);

	//init calibrators
	TemperatureCalibrationBase *calibrators[3];
	bool error_reported[3] = {};
	int num_calibrators = 0;

	if (_accel) {
		calibrators[num_calibrators] = new TemperatureCalibrationAccel(min_temp_rise, min_start_temp, max_start_temp);

		if (calibrators[num_calibrators]) {
			++num_calibrators;

		} else {
			PX4_ERR("alloc failed");
		}
	}

	if (_baro) {
		calibrators[num_calibrators] = new TemperatureCalibrationBaro(min_temp_rise, min_start_temp, max_start_temp);

		if (calibrators[num_calibrators]) {
			++num_calibrators;

		} else {
			PX4_ERR("alloc failed");
		}
	}

	if (_gyro) {
		calibrators[num_calibrators] = new TemperatureCalibrationGyro(min_temp_rise, min_start_temp, max_start_temp, gyro_sub,
				num_gyro);

		if (calibrators[num_calibrators]) {
			++num_calibrators;

		} else {
			PX4_ERR("alloc failed");
		}
	}

	// reset params
	for (int i = 0; i < num_calibrators; ++i) {
		calibrators[i]->reset_calibration();
	}

	// make sure the system updates the changed parameters
	param_notify_changes();

	usleep(300000); // wait a bit for the system to apply the parameters

	hrt_abstime next_progress_output = hrt_absolute_time() + 1e6;

	// control LED's: blink, then turn solid according to progress
	led_control_s led_control = {};
	led_control.led_mask = 0xff;
	led_control.mode = led_control_s::MODE_BLINK_NORMAL;
	led_control.priority = led_control_s::MAX_PRIORITY;
	led_control.color = led_control_s::COLOR_YELLOW;
	led_control.num_blinks = 0;
	publish_led_control(led_control);
	int leds_completed = 0;

	bool abort_calibration = false;

	while (!_force_task_exit) {
		/* we poll on the gyro(s), since this is the sensor with the highest update rate.
		 * Each individual sensor will then check on its own if there's new data.
		 */
		int ret = px4_poll(fds, num_gyro, 1000);

		if (ret < 0) {
			// Poll error, sleep and try again
			usleep(10000);
			continue;

		} else if (ret == 0) {
			// Poll timeout or no new data, do nothing
			continue;
		}

		//if gyro is not enabled: we must do an orb_copy here, so that poll() does not immediately return again
		if (!_gyro) {
			sensor_gyro_s gyro_data;

			for (int i = 0; i < num_gyro; ++i) {
				orb_copy(ORB_ID(sensor_gyro), gyro_sub[i], &gyro_data);
			}
		}

		int min_progress = 110;

		for (int i = 0; i < num_calibrators; ++i) {
			ret = calibrators[i]->update();

			if (ret == -TC_ERROR_INITIAL_TEMP_TOO_HIGH) {
				abort_calibration = true;
				PX4_ERR("Calibration won't start - sensor temperature too high");
				_force_task_exit = true;
				break;

			} else if (ret < 0 && !error_reported[i]) {
				// temperature has decreased so calibration is not being updated
				error_reported[i] = true;
				PX4_ERR("Calibration update step failed (%i)", ret);

			} else if (ret < min_progress) {
				// temperature is stable or increasing
				min_progress = ret;
			}
		}

		if (min_progress == 110 || abort_calibration) {
			break; // we are done
		}

		int led_progress = min_progress * BOARD_MAX_LEDS / 100;

		for (; leds_completed < led_progress; ++leds_completed) {
			led_control.led_mask = 1 << leds_completed;
			led_control.mode = led_control_s::MODE_ON;
			publish_led_control(led_control);
		}

		//print progress each second
		hrt_abstime now = hrt_absolute_time();

		if (now > next_progress_output) {
			PX4_INFO("Calibration progress: %i%%", min_progress);
			next_progress_output = now + 1e6;
		}
	}

	if (abort_calibration) {
		led_control.color = led_control_s::COLOR_RED;

	} else {
		PX4_INFO("Sensor Measurments completed");

		// save params immediately so that we can check the result and don't have to wait for param save timeout
		param_control_autosave(false);

		// do final calculations & parameter storage
		for (int i = 0; i < num_calibrators; ++i) {
			int ret = calibrators[i]->finish();

			if (ret < 0) {
				PX4_ERR("Failed to finish calibration process (%i)", ret);
			}
		}

		param_notify_changes();
		int ret = param_save_default();

		if (ret != 0) {
			PX4_ERR("Failed to save params (%i)", ret);
		}

		param_control_autosave(true);

		led_control.color = led_control_s::COLOR_GREEN;
	}

	// blink the LED's according to success/failure
	led_control.led_mask = 0xff;
	led_control.mode = led_control_s::MODE_BLINK_FAST;
	led_control.num_blinks = 0;
	publish_led_control(led_control);

	for (int i = 0; i < num_calibrators; ++i) {
		delete calibrators[i];
	}

	for (unsigned i = 0; i < num_gyro; i++) {
		orb_unsubscribe(gyro_sub[i]);
	}

	delete temperature_calibration::instance;
	temperature_calibration::instance = nullptr;
	PX4_INFO("Exiting temperature calibration task");
}

void TemperatureCalibration::do_temperature_calibration(int argc, char *argv[])
{
	temperature_calibration::instance->task_main();
}

int TemperatureCalibration::start()
{

	ASSERT(_control_task == -1);
	_control_task = px4_task_spawn_cmd("temperature_calib",
					   SCHED_DEFAULT,
					   SCHED_PRIORITY_MAX - 5,
					   5800,
					   (px4_main_t)&TemperatureCalibration::do_temperature_calibration,
					   nullptr);

	if (_control_task < 0) {
		delete temperature_calibration::instance;
		temperature_calibration::instance = nullptr;
		PX4_ERR("start failed");
		return -errno;
	}

	return 0;
}

void TemperatureCalibration::publish_led_control(led_control_s &led_control)
{
	led_control.timestamp = hrt_absolute_time();

	if (_led_control_pub == nullptr) {
		_led_control_pub = orb_advertise_queue(ORB_ID(led_control), &led_control, LED_UORB_QUEUE_LENGTH);

	} else {
		orb_publish(ORB_ID(led_control), _led_control_pub, &led_control);
	}
}

int run_temperature_calibration(bool accel, bool baro, bool gyro)
{
	PX4_INFO("Starting temperature calibration task (accel=%i, baro=%i, gyro=%i)", (int)accel, (int)baro, (int)gyro);
	temperature_calibration::instance = new TemperatureCalibration(accel, baro, gyro);

	if (temperature_calibration::instance == nullptr) {
		PX4_ERR("alloc failed");
		return 1;
	}

	return temperature_calibration::instance->start();
}
<|endoftext|>


<commit_before>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include <string>

#include "../urbackupcommon/fileclient/FileClient.h"
#include "../urbackupcommon/fileclient/tcpstack.h"
#include "server_prepare_hash.h"

#include "../Interface/Pipe.h"
#include "../Interface/File.h"
#include "../Interface/Server.h"

#include "filedownload.h"
#include "../urbackupcommon/os_functions.h"
#include "../stringtools.h"

#include <stdlib.h>
#include "../urbackupcommon/chunk_hasher.h"

extern std::string server_identity;

bool FileDownload::copy_file_fd(IFile *fsrc, IFile *fdst)
{
	fsrc->Seek(0);
	fdst->Seek(0);
	char buf[4096];
	size_t rc;
	while( (rc=(_u32)fsrc->Read(buf, 4096))>0)
	{
		fdst->Write(buf, (_u32)rc);
	}
	return true;
}

void FileDownload::filedownload(std::string remotefn, std::string dest, int method, int predicted_filesize, SQueueStatus queueStatus)
{
	IFsFile *dstfile;
	if(queueStatus==SQueueStatus_Queue || queueStatus==SQueueStatus_NoQueue)
	{
		Server->Log("Opening destination file...");

		if(method==0)
		{
			dstfile=Server->openFile(dest, MODE_WRITE);
		}
		else
		{
			dstfile=Server->openFile(dest, MODE_RW_CREATE);
		}

		if(dstfile==NULL)
		{
			Server->Log("Cannot open file");
			return;
		}
	}

	_u32 rc=ERR_SUCCESS;
	if(method==0)
	{
		if(queueStatus==SQueueStatus_Queue)
		{
			FileDownloadQueueItemFull qi = {
				remotefn,
				predicted_filesize,
				false
			};

			dlqueueFull.push_back(qi);
		}
		else
		{
			Server->Log("Downloading file...");

			for(size_t i=0;i<dlqueueFull.size();++i)
			{
				if(dlqueueFull[i].remotefn==remotefn)
				{
					dlqueueFull.erase(dlqueueFull.begin()+i);
					break;
				}
			}

			rc=fc->GetFile(remotefn, dstfile, true, false, 0, false, 0);

			Server->destroy(dstfile);
		}
	}
	else if(method==1)
	{
		IFile *hashfile;
		IFsFile *hashfile_output;

		if(queueStatus==SQueueStatus_Queue || queueStatus==SQueueStatus_NoQueue)
		{
			hashfile=Server->openTemporaryFile();
			hashfile_output=Server->openTemporaryFile();

			Server->Log("Building hashes...");
			build_chunk_hashs(dstfile, hashfile, NULL, NULL, false, NULL, false);

			Server->Log("Downloading file...");

			if(queueStatus==SQueueStatus_Queue)
			{
				FileDownloadQueueItemChunked qi =
				{
					remotefn,
					dstfile,
					NULL,
					hashfile,
					hashfile_output,
					predicted_filesize,
					false
				};

				dlqueueChunked.push_back(qi);
			}
		}
		else
		{
			for(size_t i=0;i<dlqueueChunked.size();++i)
			{
				if(dlqueueChunked[i].remotefn==remotefn)
				{
					hashfile = dlqueueChunked[i].chunkhashes;
					hashfile_output = dlqueueChunked[i].hashoutput;

					dlqueueChunked.erase(dlqueueChunked.begin()+i);
					break;
				}
			}
		}

		int64 remote_filesize=-1;

		if(predicted_filesize>=0)
		{
			remote_filesize = predicted_filesize;
		}

		if(queueStatus==SQueueStatus_NoQueue || queueStatus==SQueueStatus_IsQueued)
		{

			rc=fc_chunked->GetFileChunked(remotefn, dstfile, hashfile, hashfile_output, remote_filesize, 0, false, NULL);

			cleanup_tmpfile(hashfile);
			cleanup_tmpfile(hashfile_output);

			_i64 fsize=dstfile->Size();
			Server->destroy(dstfile);
			if(rc==ERR_SUCCESS && fsize>remote_filesize)
			{
				os_file_truncate(dest, remote_filesize);
			}
		}

	}
	else if(method==2)
	{
		IFile *hashfile;
		IFsFile *hashfile_output;
		IFile *patchfile;

		if(queueStatus==SQueueStatus_Queue || queueStatus==SQueueStatus_NoQueue)
		{
			hashfile=Server->openTemporaryFile();
			hashfile_output=Server->openTemporaryFile();
			patchfile=Server->openTemporaryFile();

			Server->Log("Building hashes...");
			build_chunk_hashs(dstfile, hashfile, NULL, NULL, false);

			if(queueStatus==SQueueStatus_Queue)
			{
				FileDownloadQueueItemChunked qi =
				{
					remotefn,
					dstfile,
					patchfile,
					hashfile,
					hashfile_output,
					predicted_filesize,
					false
				};

				dlqueueChunked.push_back(qi);
			}

			/*int64 dstf_size = dstfile->Size();
			if(dstf_size>0)
			{
				dstfile->Remove();
				os_file_truncate(widen(dest), (dstf_size/(512*1024)) * 512*1024 + 1);
				dstfile=Server->openFile(dest, MODE_RW);
			}*/
		}
		else
		{
			for(size_t i=0;i<dlqueueChunked.size();++i)
			{
				if(dlqueueChunked[i].remotefn==remotefn)
				{
					dstfile = dlqueueChunked[i].orig_file;
					patchfile = dlqueueChunked[i].patchfile;
					hashfile = dlqueueChunked[i].chunkhashes;
					hashfile_output = dlqueueChunked[i].hashoutput;

					dlqueueChunked.erase(dlqueueChunked.begin()+i);
					break;
				}
			}
		}

		int64 remote_filesize=-1;

		if(predicted_filesize>0)
		{
			remote_filesize = predicted_filesize;
		}

		if(queueStatus==SQueueStatus_IsQueued || queueStatus==SQueueStatus_NoQueue)
		{
			Server->Log("Downloading file...");
			rc=fc_chunked->GetFilePatch(remotefn, dstfile, patchfile, hashfile, hashfile_output, remote_filesize, 0, false, NULL);

			IFile *tmpfile=Server->openTemporaryFile();
			Server->Log("Copying to temporary...");
			copy_file_fd(dstfile, tmpfile);

			tmpfile->Seek(0);
			m_chunkpatchfile=tmpfile;
			ChunkPatcher patcher;
			patcher.setCallback(this);
			chunk_patch_pos=0;
			Server->Log("Patching temporary...");
			patcher.ApplyPatch(dstfile, patchfile, NULL);

			Server->Log("Copying back...");
			copy_file_fd(tmpfile, dstfile);

			cleanup_tmpfile(hashfile);
			cleanup_tmpfile(hashfile_output);
			cleanup_tmpfile(tmpfile);

			_i64 fsize=dstfile->Size();
			Server->destroy(dstfile);
			if(remote_filesize==patcher.getFilesize() && fsize>=patcher.getFilesize())
			{
				if(rc==ERR_SUCCESS && fsize>patcher.getFilesize())
				{
					os_file_truncate(dest, patcher.getFilesize());
				}
				cleanup_tmpfile(patchfile);
			}
			else
			{
				Server->Log("Filesize is wrong...", LL_ERROR);
				Server->Log("Patchfile: "+patchfile->getFilename(), LL_ERROR);
			}
		}
	}
	else
	{
		Server->Log("File download method unknown", LL_ERROR);
		return;
	}

	if(queueStatus==SQueueStatus_NoQueue || queueStatus==SQueueStatus_IsQueued)
	{
		if(rc!=ERR_SUCCESS)
		{
			Server->Log("File download failed ec="+FileClient::getErrorString(rc));
		}
		else
		{
			Server->Log("File download succeeded");
		}
	}

}

void FileDownload::filedownload( std::string csvfile )
{
	std::string data = getFile(csvfile);

	int lines = linecount(data);

	for(int line=0;line<lines+1;++line)
	{
		std::string ldata = getline(line, data);

		std::vector<std::string> cols;
		Tokenize(ldata, cols, ",");

		if(cols.size()!=4) continue;

		filedownload(cols[0], cols[1], atoi(cols[2].c_str()), atoi(cols[3].c_str()), SQueueStatus_Queue);
	}

	for(int line=0;line<lines+1;++line)
	{
		std::string ldata = getline(line, data);

		std::vector<std::string> cols;
		Tokenize(ldata, cols, ",");

		if(cols.size()!=4) continue;

		filedownload(cols[0], cols[1], atoi(cols[2].c_str()), atoi(cols[3].c_str()), SQueueStatus_IsQueued);
	}
}

IPipe * FileDownload::new_fileclient_connection(void)
{
	for(size_t i=0;i<30;++i)
	{
		IPipe *cp=Server->ConnectStream(m_servername, m_tcpport, 10000);
		if(cp==NULL)
		{
			Server->Log("Cannot connect to server");
			Server->wait(2000);
		}
		else
		{
			Server->Log("Reconnected");
			return cp;
		}
	}
	return NULL;
}

void FileDownload::next_chunk_patcher_bytes(const char *buf, size_t bsize, bool changed, bool* is_sparse)
{
	if(changed)
	{
		if(!m_chunkpatchfile->Seek(chunk_patch_pos) || m_chunkpatchfile->Write(buf, (_u32)bsize)!=bsize)
		{
			Server->Log("Writing to file failed", LL_ERROR);
			exit(3);
		}
	}
	chunk_patch_pos+=bsize;
}

void FileDownload::next_sparse_extent_bytes(const char * buf, size_t bsize)
{
}

void FileDownload::cleanup_tmpfile(IFile *tmpfile)
{
	std::string fn=tmpfile->getFilename();
	Server->destroy(tmpfile);
	Server->deleteFile(fn);
}

bool FileDownload::getQueuedFileChunked( std::string& remotefn, IFile*& orig_file, IFile*& patchfile, IFile*& chunkhashes, IFsFile*& hashoutput, _i64& predicted_filesize, int64& file_id, bool& is_script)
{
	for(size_t i=0;i<dlqueueChunked.size();++i)
	{
		if(dlqueueChunked[i].queued==false)
		{
			remotefn = dlqueueChunked[i].remotefn;
			orig_file = dlqueueChunked[i].orig_file;
			patchfile = dlqueueChunked[i].patchfile;
			chunkhashes = dlqueueChunked[i].chunkhashes;
			hashoutput = dlqueueChunked[i].hashoutput;
			predicted_filesize = dlqueueChunked[i].predicted_filesize;
			dlqueueChunked[i].queued=true;
			file_id=0;
			is_script = false;
			return true;
		}
	}

	return false;
}

void FileDownload::unqueueFileChunked( const std::string& remotefn )
{
	for(size_t i=0;i<dlqueueChunked.size();++i)
	{
		if(dlqueueChunked[i].queued && dlqueueChunked[i].remotefn==remotefn)
		{
			dlqueueChunked[i].queued=false;
		}
	}
}

void FileDownload::resetQueueChunked()
{
	for(size_t i=0;i<dlqueueChunked.size();++i)
	{
		dlqueueChunked[i].queued=false;
	}
}

FileDownload::FileDownload( std::string servername, unsigned int tcpport )
	: fc_chunked(), m_servername(servername), m_tcpport(tcpport)
{
	IPipe *cp=NULL;
	for(size_t i=0;i<30 && cp==NULL;++i)
	{
		Server->Log("Connecting to server...");
		cp=Server->ConnectStream(servername, tcpport, 10000);
		if(cp==NULL)
		{
			Server->Log("Cannot connect to server");
			Server->wait(2000);
		}
	}

	if(cp==NULL) return;

	fc_chunked.reset(new FileClientChunked(cp, true, &tcpstack, this, NULL, server_identity, NULL));
	fc_chunked->setQueueCallback(this);
	fc_chunked->setDestroyPipe(true);

	fc.reset(new FileClient(false, server_identity, 2));

	cp=NULL;
	for(size_t i=0;i<30 && cp==NULL;++i)
	{
		Server->Log("Connecting to server...");
		cp=Server->ConnectStream(servername, tcpport, 10000);
		if(cp==NULL)
		{
			Server->Log("Cannot connect to server");
			Server->wait(2000);
		}
	}

	if(cp==NULL) return;

	fc->Connect(cp);
	fc->setQueueCallback(this);
}

std::string FileDownload::getQueuedFileFull( FileClient::MetadataQueue& metadata, size_t& folder_items, bool& finish_script, int64& file_id)
{
	for(size_t i=0;i<dlqueueFull.size();++i)
	{
		if(!dlqueueFull[i].queued)
		{
			metadata=FileClient::MetadataQueue_Data;
			folder_items=0;
			file_id=0;
			finish_script=false;
			return dlqueueFull[i].remotefn;
		}
	}
	return std::string();
}

void FileDownload::unqueueFileFull( const std::string& fn, bool finish_script)
{
	for(size_t i=0;i<dlqueueFull.size();++i)
	{
		if(dlqueueFull[i].queued && dlqueueFull[i].remotefn==fn)
		{
			dlqueueFull[i].queued=false;
		}
	}
}

void FileDownload::resetQueueFull()
{
	for(size_t i=0;i<dlqueueFull.size();++i)
	{
		dlqueueFull[i].queued=false;
	}
}
<commit_msg>Fix compile issue<commit_after>/*************************************************************************
*    UrBackup - Client/Server backup system
*    Copyright (C) 2011-2016 Martin Raiber
*
*    This program is free software: you can redistribute it and/or modify
*    it under the terms of the GNU Affero General Public License as published by
*    the Free Software Foundation, either version 3 of the License, or
*    (at your option) any later version.
*
*    This program 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 Affero General Public License for more details.
*
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
**************************************************************************/

#include <string>

#include "../urbackupcommon/fileclient/FileClient.h"
#include "../urbackupcommon/fileclient/tcpstack.h"
#include "server_prepare_hash.h"

#include "../Interface/Pipe.h"
#include "../Interface/File.h"
#include "../Interface/Server.h"

#include "filedownload.h"
#include "../urbackupcommon/os_functions.h"
#include "../stringtools.h"

#include <stdlib.h>
#include "../urbackupcommon/chunk_hasher.h"

extern std::string server_identity;

bool FileDownload::copy_file_fd(IFile *fsrc, IFile *fdst)
{
	fsrc->Seek(0);
	fdst->Seek(0);
	char buf[4096];
	size_t rc;
	while( (rc=(_u32)fsrc->Read(buf, 4096))>0)
	{
		fdst->Write(buf, (_u32)rc);
	}
	return true;
}

void FileDownload::filedownload(std::string remotefn, std::string dest, int method, int predicted_filesize, SQueueStatus queueStatus)
{
	IFsFile *dstfile;
	if(queueStatus==SQueueStatus_Queue || queueStatus==SQueueStatus_NoQueue)
	{
		Server->Log("Opening destination file...");

		if(method==0)
		{
			dstfile=Server->openFile(dest, MODE_WRITE);
		}
		else
		{
			dstfile=Server->openFile(dest, MODE_RW_CREATE);
		}

		if(dstfile==NULL)
		{
			Server->Log("Cannot open file");
			return;
		}
	}

	_u32 rc=ERR_SUCCESS;
	if(method==0)
	{
		if(queueStatus==SQueueStatus_Queue)
		{
			FileDownloadQueueItemFull qi = {
				remotefn,
				predicted_filesize,
				false
			};

			dlqueueFull.push_back(qi);
		}
		else
		{
			Server->Log("Downloading file...");

			for(size_t i=0;i<dlqueueFull.size();++i)
			{
				if(dlqueueFull[i].remotefn==remotefn)
				{
					dlqueueFull.erase(dlqueueFull.begin()+i);
					break;
				}
			}

			rc=fc->GetFile(remotefn, dstfile, true, false, 0, false, 0);

			Server->destroy(dstfile);
		}
	}
	else if(method==1)
	{
		IFile *hashfile;
		IFsFile *hashfile_output;

		if(queueStatus==SQueueStatus_Queue || queueStatus==SQueueStatus_NoQueue)
		{
			hashfile=Server->openTemporaryFile();
			hashfile_output=Server->openTemporaryFile();

			Server->Log("Building hashes...");
			build_chunk_hashs(dstfile, hashfile, NULL, NULL, false, NULL, NULL);

			Server->Log("Downloading file...");

			if(queueStatus==SQueueStatus_Queue)
			{
				FileDownloadQueueItemChunked qi =
				{
					remotefn,
					dstfile,
					NULL,
					hashfile,
					hashfile_output,
					predicted_filesize,
					false
				};

				dlqueueChunked.push_back(qi);
			}
		}
		else
		{
			for(size_t i=0;i<dlqueueChunked.size();++i)
			{
				if(dlqueueChunked[i].remotefn==remotefn)
				{
					hashfile = dlqueueChunked[i].chunkhashes;
					hashfile_output = dlqueueChunked[i].hashoutput;

					dlqueueChunked.erase(dlqueueChunked.begin()+i);
					break;
				}
			}
		}

		int64 remote_filesize=-1;

		if(predicted_filesize>=0)
		{
			remote_filesize = predicted_filesize;
		}

		if(queueStatus==SQueueStatus_NoQueue || queueStatus==SQueueStatus_IsQueued)
		{

			rc=fc_chunked->GetFileChunked(remotefn, dstfile, hashfile, hashfile_output, remote_filesize, 0, false, NULL);

			cleanup_tmpfile(hashfile);
			cleanup_tmpfile(hashfile_output);

			_i64 fsize=dstfile->Size();
			Server->destroy(dstfile);
			if(rc==ERR_SUCCESS && fsize>remote_filesize)
			{
				os_file_truncate(dest, remote_filesize);
			}
		}

	}
	else if(method==2)
	{
		IFile *hashfile;
		IFsFile *hashfile_output;
		IFile *patchfile;

		if(queueStatus==SQueueStatus_Queue || queueStatus==SQueueStatus_NoQueue)
		{
			hashfile=Server->openTemporaryFile();
			hashfile_output=Server->openTemporaryFile();
			patchfile=Server->openTemporaryFile();

			Server->Log("Building hashes...");
			build_chunk_hashs(dstfile, hashfile, NULL, NULL, false);

			if(queueStatus==SQueueStatus_Queue)
			{
				FileDownloadQueueItemChunked qi =
				{
					remotefn,
					dstfile,
					patchfile,
					hashfile,
					hashfile_output,
					predicted_filesize,
					false
				};

				dlqueueChunked.push_back(qi);
			}

			/*int64 dstf_size = dstfile->Size();
			if(dstf_size>0)
			{
				dstfile->Remove();
				os_file_truncate(widen(dest), (dstf_size/(512*1024)) * 512*1024 + 1);
				dstfile=Server->openFile(dest, MODE_RW);
			}*/
		}
		else
		{
			for(size_t i=0;i<dlqueueChunked.size();++i)
			{
				if(dlqueueChunked[i].remotefn==remotefn)
				{
					dstfile = dlqueueChunked[i].orig_file;
					patchfile = dlqueueChunked[i].patchfile;
					hashfile = dlqueueChunked[i].chunkhashes;
					hashfile_output = dlqueueChunked[i].hashoutput;

					dlqueueChunked.erase(dlqueueChunked.begin()+i);
					break;
				}
			}
		}

		int64 remote_filesize=-1;

		if(predicted_filesize>0)
		{
			remote_filesize = predicted_filesize;
		}

		if(queueStatus==SQueueStatus_IsQueued || queueStatus==SQueueStatus_NoQueue)
		{
			Server->Log("Downloading file...");
			rc=fc_chunked->GetFilePatch(remotefn, dstfile, patchfile, hashfile, hashfile_output, remote_filesize, 0, false, NULL);

			IFile *tmpfile=Server->openTemporaryFile();
			Server->Log("Copying to temporary...");
			copy_file_fd(dstfile, tmpfile);

			tmpfile->Seek(0);
			m_chunkpatchfile=tmpfile;
			ChunkPatcher patcher;
			patcher.setCallback(this);
			chunk_patch_pos=0;
			Server->Log("Patching temporary...");
			patcher.ApplyPatch(dstfile, patchfile, NULL);

			Server->Log("Copying back...");
			copy_file_fd(tmpfile, dstfile);

			cleanup_tmpfile(hashfile);
			cleanup_tmpfile(hashfile_output);
			cleanup_tmpfile(tmpfile);

			_i64 fsize=dstfile->Size();
			Server->destroy(dstfile);
			if(remote_filesize==patcher.getFilesize() && fsize>=patcher.getFilesize())
			{
				if(rc==ERR_SUCCESS && fsize>patcher.getFilesize())
				{
					os_file_truncate(dest, patcher.getFilesize());
				}
				cleanup_tmpfile(patchfile);
			}
			else
			{
				Server->Log("Filesize is wrong...", LL_ERROR);
				Server->Log("Patchfile: "+patchfile->getFilename(), LL_ERROR);
			}
		}
	}
	else
	{
		Server->Log("File download method unknown", LL_ERROR);
		return;
	}

	if(queueStatus==SQueueStatus_NoQueue || queueStatus==SQueueStatus_IsQueued)
	{
		if(rc!=ERR_SUCCESS)
		{
			Server->Log("File download failed ec="+FileClient::getErrorString(rc));
		}
		else
		{
			Server->Log("File download succeeded");
		}
	}

}

void FileDownload::filedownload( std::string csvfile )
{
	std::string data = getFile(csvfile);

	int lines = linecount(data);

	for(int line=0;line<lines+1;++line)
	{
		std::string ldata = getline(line, data);

		std::vector<std::string> cols;
		Tokenize(ldata, cols, ",");

		if(cols.size()!=4) continue;

		filedownload(cols[0], cols[1], atoi(cols[2].c_str()), atoi(cols[3].c_str()), SQueueStatus_Queue);
	}

	for(int line=0;line<lines+1;++line)
	{
		std::string ldata = getline(line, data);

		std::vector<std::string> cols;
		Tokenize(ldata, cols, ",");

		if(cols.size()!=4) continue;

		filedownload(cols[0], cols[1], atoi(cols[2].c_str()), atoi(cols[3].c_str()), SQueueStatus_IsQueued);
	}
}

IPipe * FileDownload::new_fileclient_connection(void)
{
	for(size_t i=0;i<30;++i)
	{
		IPipe *cp=Server->ConnectStream(m_servername, m_tcpport, 10000);
		if(cp==NULL)
		{
			Server->Log("Cannot connect to server");
			Server->wait(2000);
		}
		else
		{
			Server->Log("Reconnected");
			return cp;
		}
	}
	return NULL;
}

void FileDownload::next_chunk_patcher_bytes(const char *buf, size_t bsize, bool changed, bool* is_sparse)
{
	if(changed)
	{
		if(!m_chunkpatchfile->Seek(chunk_patch_pos) || m_chunkpatchfile->Write(buf, (_u32)bsize)!=bsize)
		{
			Server->Log("Writing to file failed", LL_ERROR);
			exit(3);
		}
	}
	chunk_patch_pos+=bsize;
}

void FileDownload::next_sparse_extent_bytes(const char * buf, size_t bsize)
{
}

void FileDownload::cleanup_tmpfile(IFile *tmpfile)
{
	std::string fn=tmpfile->getFilename();
	Server->destroy(tmpfile);
	Server->deleteFile(fn);
}

bool FileDownload::getQueuedFileChunked( std::string& remotefn, IFile*& orig_file, IFile*& patchfile, IFile*& chunkhashes, IFsFile*& hashoutput, _i64& predicted_filesize, int64& file_id, bool& is_script)
{
	for(size_t i=0;i<dlqueueChunked.size();++i)
	{
		if(dlqueueChunked[i].queued==false)
		{
			remotefn = dlqueueChunked[i].remotefn;
			orig_file = dlqueueChunked[i].orig_file;
			patchfile = dlqueueChunked[i].patchfile;
			chunkhashes = dlqueueChunked[i].chunkhashes;
			hashoutput = dlqueueChunked[i].hashoutput;
			predicted_filesize = dlqueueChunked[i].predicted_filesize;
			dlqueueChunked[i].queued=true;
			file_id=0;
			is_script = false;
			return true;
		}
	}

	return false;
}

void FileDownload::unqueueFileChunked( const std::string& remotefn )
{
	for(size_t i=0;i<dlqueueChunked.size();++i)
	{
		if(dlqueueChunked[i].queued && dlqueueChunked[i].remotefn==remotefn)
		{
			dlqueueChunked[i].queued=false;
		}
	}
}

void FileDownload::resetQueueChunked()
{
	for(size_t i=0;i<dlqueueChunked.size();++i)
	{
		dlqueueChunked[i].queued=false;
	}
}

FileDownload::FileDownload( std::string servername, unsigned int tcpport )
	: fc_chunked(), m_servername(servername), m_tcpport(tcpport)
{
	IPipe *cp=NULL;
	for(size_t i=0;i<30 && cp==NULL;++i)
	{
		Server->Log("Connecting to server...");
		cp=Server->ConnectStream(servername, tcpport, 10000);
		if(cp==NULL)
		{
			Server->Log("Cannot connect to server");
			Server->wait(2000);
		}
	}

	if(cp==NULL) return;

	fc_chunked.reset(new FileClientChunked(cp, true, &tcpstack, this, NULL, server_identity, NULL));
	fc_chunked->setQueueCallback(this);
	fc_chunked->setDestroyPipe(true);

	fc.reset(new FileClient(false, server_identity, 2));

	cp=NULL;
	for(size_t i=0;i<30 && cp==NULL;++i)
	{
		Server->Log("Connecting to server...");
		cp=Server->ConnectStream(servername, tcpport, 10000);
		if(cp==NULL)
		{
			Server->Log("Cannot connect to server");
			Server->wait(2000);
		}
	}

	if(cp==NULL) return;

	fc->Connect(cp);
	fc->setQueueCallback(this);
}

std::string FileDownload::getQueuedFileFull( FileClient::MetadataQueue& metadata, size_t& folder_items, bool& finish_script, int64& file_id)
{
	for(size_t i=0;i<dlqueueFull.size();++i)
	{
		if(!dlqueueFull[i].queued)
		{
			metadata=FileClient::MetadataQueue_Data;
			folder_items=0;
			file_id=0;
			finish_script=false;
			return dlqueueFull[i].remotefn;
		}
	}
	return std::string();
}

void FileDownload::unqueueFileFull( const std::string& fn, bool finish_script)
{
	for(size_t i=0;i<dlqueueFull.size();++i)
	{
		if(dlqueueFull[i].queued && dlqueueFull[i].remotefn==fn)
		{
			dlqueueFull[i].queued=false;
		}
	}
}

void FileDownload::resetQueueFull()
{
	for(size_t i=0;i<dlqueueFull.size();++i)
	{
		dlqueueFull[i].queued=false;
	}
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "abstractprocessstep.h"
#include "buildstep.h"
#include "project.h"

#include <QtCore/QProcess>
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtGui/QTextDocument>

using namespace ProjectExplorer;

AbstractProcessStep::AbstractProcessStep(Project *pro)
  : BuildStep(pro)
{
}

void AbstractProcessStep::setCommand(const QString &buildConfiguration, const QString &cmd)
{
    setValue(buildConfiguration, "abstractProcess.command", cmd);
}

QString AbstractProcessStep::command(const QString &buildConfiguration) const
{
    return value(buildConfiguration, "abstractProcess.command").toString();
}

void AbstractProcessStep::setWorkingDirectory(const QString &buildConfiguration, const QString &workingDirectory)
{
    setValue(buildConfiguration, "abstractProcess.workingDirectory", workingDirectory);
}

QString AbstractProcessStep::workingDirectory(const QString &buildConfiguration) const
{
    return value(buildConfiguration, "abstractProcess.workingDirectory").toString();
}

void AbstractProcessStep::setArguments(const QString &buildConfiguration, const QStringList &arguments)
{
    setValue(buildConfiguration, "abstractProcess.arguments", arguments);
}

QStringList AbstractProcessStep::arguments(const QString &buildConfiguration) const
{
    return value(buildConfiguration, "abstractProcess.arguments").toStringList();
}

void AbstractProcessStep::setEnabled(const QString &buildConfiguration, bool b)
{
    setValue(buildConfiguration, "abstractProcess.enabled", b);
}

bool AbstractProcessStep::enabled(const QString &buildConfiguration) const
{
    return value(buildConfiguration, "abstractProcess.enabled").toBool();
}

void AbstractProcessStep::setEnvironment(const QString &buildConfiguration, Environment env)
{
    setValue(buildConfiguration, "abstractProcess.Environment", env.toStringList());
}

Environment AbstractProcessStep::environment(const QString &buildConfiguration) const
{
    return Environment(value(buildConfiguration, "abstractProcess.Environment").toStringList());
}

bool AbstractProcessStep::init(const QString &name)
{
    m_command = value(name, "abstractProcess.command").toString();
    m_arguments = value(name, "abstractProcess.arguments").toStringList();
    QVariant var = value(name, "abstractProcess.enabled");
    m_enabled =  var.isValid() && var.toBool();
    m_workingDirectory = value(name, "abstractProcess.workingDirectory").toString();
    m_environment = Environment(value(name, "abstractProcess.Environment").toStringList());
    return true;
}

void AbstractProcessStep::run(QFutureInterface<bool> & fi)
{
    m_futureInterface = &fi;
    if (!m_enabled) {
        fi.reportResult(true);
        return;
    }
    QDir wd(m_workingDirectory);
    if (!wd.exists())
        wd.mkpath(wd.absolutePath());

    m_process = new QProcess();
    m_process->setWorkingDirectory(m_workingDirectory);
    m_process->setEnvironment(m_environment.toStringList());

    connect(m_process, SIGNAL(readyReadStandardOutput()),
            this, SLOT(processReadyReadStdOutput()),
            Qt::DirectConnection);
    connect(m_process, SIGNAL(readyReadStandardError()),
            this, SLOT(processReadyReadStdError()),
            Qt::DirectConnection);

    connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(slotProcessFinished(int, QProcess::ExitStatus)),
            Qt::DirectConnection);

    m_process->start(m_command, m_arguments);
    if (!m_process->waitForStarted()) {
        processStartupFailed();
        delete m_process;
        m_process = 0;
        fi.reportResult(false);
        return;
    }
    processStarted();

    m_timer = new QTimer();
    connect(m_timer, SIGNAL(timeout()), this, SLOT(checkForCancel()), Qt::DirectConnection);
    m_timer->start(500);
    m_eventLoop = new QEventLoop;
    m_eventLoop->exec();
    m_timer->stop();
    delete m_timer;

    // The process has finished, leftover data is read in processFinished
    bool returnValue = processFinished(m_process->exitCode(), m_process->exitStatus());

    delete m_process;
    m_process = 0;
    delete m_eventLoop;
    m_eventLoop = 0;
    fi.reportResult(returnValue);
    return;
}

void AbstractProcessStep::processStarted()
{
    emit addToOutputWindow(tr("Starting: %1 %2\n").arg(m_command, Qt::escape(m_arguments.join(" "))));
}

bool AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
    const bool ok = (status == QProcess::NormalExit && exitCode == 0);
    if (ok) {
        emit addToOutputWindow(tr("Exited with code %1.").arg(m_process->exitCode()));
    } else {
        emit addToOutputWindow(tr("Exited with code %1.").arg(m_process->exitCode()));
    }
    return ok;
}

void AbstractProcessStep::processStartupFailed()
{
   emit addToOutputWindow(tr("Could not start process %1 ").arg(m_command));
}

void AbstractProcessStep::processReadyReadStdOutput()
{
    m_process->setReadChannel(QProcess::StandardOutput);
    while (m_process->canReadLine()) {
        QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
        stdOut(line);
    }
}

void AbstractProcessStep::stdOut(const QString &line)
{
    emit addToOutputWindow(Qt::escape(line));
}

void AbstractProcessStep::processReadyReadStdError()
{
    m_process->setReadChannel(QProcess::StandardError);
    while (m_process->canReadLine()) {
        QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
        stdError(line);
    }
}

void AbstractProcessStep::stdError(const QString &line)
{
    emit addToOutputWindow(QLatin1String("") + Qt::escape(line) + QLatin1String(""));
}

void AbstractProcessStep::checkForCancel()
{
    if (m_futureInterface->isCanceled() && m_timer->isActive()) {
        m_timer->stop();
        m_process->terminate();
        m_process->waitForFinished(5000);
        m_process->kill();
    }
}

void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
{
    QString line = QString::fromLocal8Bit(m_process->readAllStandardError()).trimmed();
    if (!line.isEmpty())
        stdOut(line);

    line = QString::fromLocal8Bit(m_process->readAllStandardOutput()).trimmed();
    if (!line.isEmpty())
        stdError(line);

    m_eventLoop->exit(0);
}
<commit_msg>A bit of cleanup/unduplication<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact:  Qt Software Information (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
**
**************************************************************************/

#include "abstractprocessstep.h"
#include "buildstep.h"
#include "project.h"

#include <QtCore/QProcess>
#include <QtCore/QEventLoop>
#include <QtCore/QDebug>
#include <QtCore/QTimer>
#include <QtGui/QTextDocument>

using namespace ProjectExplorer;

static const char * const PROCESS_COMMAND          = "abstractProcess.command";
static const char * const PROCESS_WORKINGDIRECTORY = "abstractProcess.workingDirectory";
static const char * const PROCESS_ARGUMENTS        = "abstractProcess.arguments";
static const char * const PROCESS_ENABLED          = "abstractProcess.enabled";
static const char * const PROCESS_ENVIRONMENT      = "abstractProcess.Environment";

AbstractProcessStep::AbstractProcessStep(Project *pro)
  : BuildStep(pro)
{
}

void AbstractProcessStep::setCommand(const QString &buildConfiguration, const QString &cmd)
{
    setValue(buildConfiguration, PROCESS_COMMAND, cmd);
}

QString AbstractProcessStep::command(const QString &buildConfiguration) const
{
    return value(buildConfiguration, PROCESS_COMMAND).toString();
}

void AbstractProcessStep::setWorkingDirectory(const QString &buildConfiguration, const QString &workingDirectory)
{
    setValue(buildConfiguration, PROCESS_WORKINGDIRECTORY, workingDirectory);
}

QString AbstractProcessStep::workingDirectory(const QString &buildConfiguration) const
{
    return value(buildConfiguration, PROCESS_WORKINGDIRECTORY).toString();
}

void AbstractProcessStep::setArguments(const QString &buildConfiguration, const QStringList &arguments)
{
    setValue(buildConfiguration, PROCESS_ARGUMENTS, arguments);
}

QStringList AbstractProcessStep::arguments(const QString &buildConfiguration) const
{
    return value(buildConfiguration, PROCESS_ARGUMENTS).toStringList();
}

void AbstractProcessStep::setEnabled(const QString &buildConfiguration, bool b)
{
    setValue(buildConfiguration, PROCESS_ENABLED, b);
}

bool AbstractProcessStep::enabled(const QString &buildConfiguration) const
{
    return value(buildConfiguration, PROCESS_ENABLED).toBool();
}

void AbstractProcessStep::setEnvironment(const QString &buildConfiguration, Environment env)
{
    setValue(buildConfiguration, PROCESS_ENVIRONMENT, env.toStringList());
}

Environment AbstractProcessStep::environment(const QString &buildConfiguration) const
{
    return Environment(value(buildConfiguration, PROCESS_ENVIRONMENT).toStringList());
}

bool AbstractProcessStep::init(const QString &name)
{
    m_command = command(name);
    m_arguments = arguments(name);
    m_enabled = enabled(name);
    m_workingDirectory = workingDirectory(name);
    m_environment = environment(name);
    return true;
}

void AbstractProcessStep::run(QFutureInterface<bool> & fi)
{
    m_futureInterface = &fi;
    if (!m_enabled) {
        fi.reportResult(true);
        return;
    }
    QDir wd(m_workingDirectory);
    if (!wd.exists())
        wd.mkpath(wd.absolutePath());

    m_process = new QProcess();
    m_process->setWorkingDirectory(m_workingDirectory);
    m_process->setEnvironment(m_environment.toStringList());

    connect(m_process, SIGNAL(readyReadStandardOutput()),
            this, SLOT(processReadyReadStdOutput()),
            Qt::DirectConnection);
    connect(m_process, SIGNAL(readyReadStandardError()),
            this, SLOT(processReadyReadStdError()),
            Qt::DirectConnection);

    connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
            this, SLOT(slotProcessFinished(int, QProcess::ExitStatus)),
            Qt::DirectConnection);

    m_process->start(m_command, m_arguments);
    if (!m_process->waitForStarted()) {
        processStartupFailed();
        delete m_process;
        m_process = 0;
        fi.reportResult(false);
        return;
    }
    processStarted();

    m_timer = new QTimer();
    connect(m_timer, SIGNAL(timeout()), this, SLOT(checkForCancel()), Qt::DirectConnection);
    m_timer->start(500);
    m_eventLoop = new QEventLoop;
    m_eventLoop->exec();
    m_timer->stop();
    delete m_timer;

    // The process has finished, leftover data is read in processFinished
    bool returnValue = processFinished(m_process->exitCode(), m_process->exitStatus());

    delete m_process;
    m_process = 0;
    delete m_eventLoop;
    m_eventLoop = 0;
    fi.reportResult(returnValue);
    return;
}

void AbstractProcessStep::processStarted()
{
    emit addToOutputWindow(tr("Starting: %1 %2\n").arg(m_command, Qt::escape(m_arguments.join(" "))));
}

bool AbstractProcessStep::processFinished(int exitCode, QProcess::ExitStatus status)
{
    const bool ok = (status == QProcess::NormalExit && exitCode == 0);
    if (ok) {
        emit addToOutputWindow(tr("Exited with code %1.").arg(m_process->exitCode()));
    } else {
        emit addToOutputWindow(tr("Exited with code %1.").arg(m_process->exitCode()));
    }
    return ok;
}

void AbstractProcessStep::processStartupFailed()
{
   emit addToOutputWindow(tr("Could not start process %1 ").arg(m_command));
}

void AbstractProcessStep::processReadyReadStdOutput()
{
    m_process->setReadChannel(QProcess::StandardOutput);
    while (m_process->canReadLine()) {
        QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
        stdOut(line);
    }
}

void AbstractProcessStep::stdOut(const QString &line)
{
    emit addToOutputWindow(Qt::escape(line));
}

void AbstractProcessStep::processReadyReadStdError()
{
    m_process->setReadChannel(QProcess::StandardError);
    while (m_process->canReadLine()) {
        QString line = QString::fromLocal8Bit(m_process->readLine()).trimmed();
        stdError(line);
    }
}

void AbstractProcessStep::stdError(const QString &line)
{
    emit addToOutputWindow(QLatin1String("") + Qt::escape(line) + QLatin1String(""));
}

void AbstractProcessStep::checkForCancel()
{
    if (m_futureInterface->isCanceled() && m_timer->isActive()) {
        m_timer->stop();
        m_process->terminate();
        m_process->waitForFinished(5000);
        m_process->kill();
    }
}

void AbstractProcessStep::slotProcessFinished(int, QProcess::ExitStatus)
{
    QString line = QString::fromLocal8Bit(m_process->readAllStandardError()).trimmed();
    if (!line.isEmpty())
        stdOut(line);

    line = QString::fromLocal8Bit(m_process->readAllStandardOutput()).trimmed();
    if (!line.isEmpty())
        stdError(line);

    m_eventLoop->exit(0);
}
<|endoftext|>


<commit_before>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "QmitkStoreSCPLauncher.h"
#include <QDir>
#include <QMessageBox>
#include <QProcessEnvironment>
#include <mitklogmacros.h>
//#include <QStringListIterator>

QmitkStoreSCPLauncher::QmitkStoreSCPLauncher(QmitkStoreSCPLauncherBuilder* builder)
: m_StoreSCP(new QProcess())
{
    connect( m_StoreSCP, SIGNAL(error(QProcess::ProcessError)),this, SLOT(OnProcessError(QProcess::ProcessError)));
    connect( m_StoreSCP, SIGNAL(stateChanged(QProcess::ProcessState)),this, SLOT(OnStateChanged(QProcess::ProcessState)));
    SetArgumentList(builder);
}

QmitkStoreSCPLauncher::~QmitkStoreSCPLauncher()
{
    m_StoreSCP->kill();
    delete m_StoreSCP;
}

void QmitkStoreSCPLauncher::StartStoreSCP()
{
    QString storeSCP;
    storeSCP.append(GetPathToExecutable());
    storeSCP.append(QString("/storescp.exe"));
    m_StoreSCP->start(storeSCP,m_ArgumentList);
}

QString QmitkStoreSCPLauncher::GetPathToExecutable()
{
    QDir root;
    QString currentPath =  root.currentPath();
    currentPath = currentPath.split("MITK").at(0);
    currentPath.append("MITK/DCMTK-install/bin");
    return currentPath;
}

void QmitkStoreSCPLauncher::OnProcessError(QProcess::ProcessError err)
{
	switch(err)
	{
	case QProcess::FailedToStart:
        MITK_INFO << QString("Failed to start storage provider: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	case QProcess::Crashed:
        MITK_INFO << QString("Storage provider crashed: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	case QProcess::Timedout:
        MITK_INFO << QString("Storage provider timeout: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	case QProcess::WriteError:
        MITK_INFO << QString("Storage provider write error: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	case QProcess::ReadError:
        MITK_INFO << QString("Storage provider read error: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	case QProcess::UnknownError:
        MITK_INFO << QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	default:
        MITK_INFO << QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	}
}

void QmitkStoreSCPLauncher::OnStateChanged(QProcess::ProcessState status)
{
	switch(status)
	{
	case QProcess::NotRunning:
        MITK_INFO << QString("Storage provider not running: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	case QProcess::Starting:
		MITK_INFO << QString("Starting storage provider").toStdString();
		break;
	case QProcess::Running:
        MITK_INFO << QString("Running storage provider").toStdString();
		break;
	default:
		MITK_INFO << QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()).toStdString();
		break;
	}
}

void QmitkStoreSCPLauncher::SetArgumentList(QmitkStoreSCPLauncherBuilder* builder)
{
    m_ArgumentList << *builder->GetPort() << QString("-aet") <<*builder->GetAETitle() << *builder->GetTransferSyntax()
        << *builder->GetOtherNetworkOptions() << *builder->GetMode() << QString("-od") << *builder->GetOutputDirectory();
}

QString QmitkStoreSCPLauncher::ArgumentListToQString()
{
    QString argumentString;
    QStringListIterator argumentIterator(m_ArgumentList);
    while(argumentIterator.hasNext())
    {
        argumentString.append(" ");
        argumentString.append(argumentIterator.next());
    }
    return argumentString;
}<commit_msg>removed tabulators<commit_after>/*=========================================================================

Program:   Medical Imaging & Interaction Toolkit
Language:  C++
Date:      $Date$
Version:   $Revision$

Copyright (c) German Cancer Research Center, Division of Medical and
Biological Informatics. All rights reserved.
See MITKCopyright.txt or http://www.mitk.org/copyright.html for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notices for more information.

=========================================================================*/

#include "QmitkStoreSCPLauncher.h"
#include <QDir>
#include <QMessageBox>
#include <QProcessEnvironment>
#include <mitklogmacros.h>
//#include <QStringListIterator>

QmitkStoreSCPLauncher::QmitkStoreSCPLauncher(QmitkStoreSCPLauncherBuilder* builder)
: m_StoreSCP(new QProcess())
{
    connect( m_StoreSCP, SIGNAL(error(QProcess::ProcessError)),this, SLOT(OnProcessError(QProcess::ProcessError)));
    connect( m_StoreSCP, SIGNAL(stateChanged(QProcess::ProcessState)),this, SLOT(OnStateChanged(QProcess::ProcessState)));
    SetArgumentList(builder);
}

QmitkStoreSCPLauncher::~QmitkStoreSCPLauncher()
{
    m_StoreSCP->kill();
    delete m_StoreSCP;
}

void QmitkStoreSCPLauncher::StartStoreSCP()
{
    QString storeSCP;
    storeSCP.append(GetPathToExecutable());
    storeSCP.append(QString("/storescp.exe"));
    m_StoreSCP->start(storeSCP,m_ArgumentList);
}

QString QmitkStoreSCPLauncher::GetPathToExecutable()
{
    QDir root;
    QString currentPath =  root.currentPath();
    currentPath = currentPath.split("MITK").at(0);
    currentPath.append("MITK/DCMTK-install/bin");
    return currentPath;
}

void QmitkStoreSCPLauncher::OnProcessError(QProcess::ProcessError err)
{
    switch(err)
    {
    case QProcess::FailedToStart:
        MITK_INFO << QString("Failed to start storage provider: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    case QProcess::Crashed:
        MITK_INFO << QString("Storage provider crashed: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    case QProcess::Timedout:
        MITK_INFO << QString("Storage provider timeout: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    case QProcess::WriteError:
        MITK_INFO << QString("Storage provider write error: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    case QProcess::ReadError:
        MITK_INFO << QString("Storage provider read error: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    case QProcess::UnknownError:
        MITK_INFO << QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    default:
        MITK_INFO << QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    }
}

void QmitkStoreSCPLauncher::OnStateChanged(QProcess::ProcessState status)
{
    switch(status)
    {
    case QProcess::NotRunning:
        MITK_INFO << QString("Storage provider not running: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    case QProcess::Starting:
        MITK_INFO << QString("Starting storage provider").toStdString();
        break;
    case QProcess::Running:
        MITK_INFO << QString("Running storage provider").toStdString();
        break;
    default:
        MITK_INFO << QString("Storage provider unknown error: ").append(m_StoreSCP->errorString()).toStdString();
        break;
    }
}

void QmitkStoreSCPLauncher::SetArgumentList(QmitkStoreSCPLauncherBuilder* builder)
{
    m_ArgumentList << *builder->GetPort() << QString("-aet") <<*builder->GetAETitle() << *builder->GetTransferSyntax()
        << *builder->GetOtherNetworkOptions() << *builder->GetMode() << QString("-od") << *builder->GetOutputDirectory();
}

QString QmitkStoreSCPLauncher::ArgumentListToQString()
{
    QString argumentString;
    QStringListIterator argumentIterator(m_ArgumentList);
    while(argumentIterator.hasNext())
    {
        argumentString.append(" ");
        argumentString.append(argumentIterator.next());
    }
    return argumentString;
}<|endoftext|>