mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-15 06:32:31 +00:00
* Remove stale lock files if it is held by the same hostname and the
pid is not running. * Added rak::timer::from_seconds(uint32_t) and converted all uses to this to avoid overflows etc. * For each cycle through the tracker list without any successfull connections, increase the timeout by 20 seconds. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@635 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
@@ -57,6 +57,7 @@ class timer {
|
||||
timeval tval() const { return (timeval) { m_time / 1000000, m_time % 1000000}; }
|
||||
|
||||
static timer current();
|
||||
static timer from_seconds(uint32_t seconds) { return rak::timer((uint64_t)seconds * 1000000); }
|
||||
|
||||
bool operator < (const timer& t) const { return m_time < t.m_time; }
|
||||
bool operator > (const timer& t) const { return m_time > t.m_time; }
|
||||
|
||||
@@ -133,7 +133,7 @@ CommandScheduler::parse(const std::string& arg) {
|
||||
item->set_command(rak::trim(std::string(command)));
|
||||
item->set_interval(interval);
|
||||
|
||||
item->enable((cachedTime + rak::timer(absolute) * 1000000).round_seconds());
|
||||
item->enable((cachedTime + rak::timer::from_seconds(absolute)).round_seconds());
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
||||
@@ -77,7 +77,7 @@ CommandSchedulerItem::next_time_scheduled() const {
|
||||
|
||||
// This should be done in a non-looping manner.
|
||||
do {
|
||||
next += rak::timer(m_interval) * 1000000;
|
||||
next += rak::timer::from_seconds(m_interval);
|
||||
} while (next <= cachedTime.round_seconds());
|
||||
|
||||
return next;
|
||||
|
||||
+1
-1
@@ -128,7 +128,7 @@ Control::handle_shutdown() {
|
||||
m_core->shutdown(false);
|
||||
|
||||
if (!m_taskShutdown.is_queued())
|
||||
priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + 5 * 1000000);
|
||||
priority_queue_insert(&taskScheduler, &m_taskShutdown, cachedTime + rak::timer::from_seconds(5));
|
||||
|
||||
} else {
|
||||
m_core->shutdown(true);
|
||||
|
||||
@@ -65,7 +65,7 @@ DownloadStore::enable(bool lock) {
|
||||
m_lockfile.set_path(std::string());
|
||||
|
||||
if (!m_lockfile.try_lock())
|
||||
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", held by \"" + m_lockfile.locked_by() + "\".");
|
||||
throw torrent::input_error("Could not lock session directory: \"" + m_path + "\", held by \"" + m_lockfile.locked_by_as_string() + "\".");
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -60,7 +60,7 @@ WindowDownloadList::~WindowDownloadList() {
|
||||
|
||||
void
|
||||
WindowDownloadList::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
|
||||
m_canvas->erase();
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ WindowDownloadStatusbar::WindowDownloadStatusbar(core::Download* d) :
|
||||
|
||||
void
|
||||
WindowDownloadStatusbar::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
|
||||
m_canvas->erase();
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ hack_wstring(const std::string& src) {
|
||||
|
||||
void
|
||||
WindowFileList::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 10 * 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(10)).round_seconds());
|
||||
m_canvas->erase();
|
||||
|
||||
if (m_download->get_download().size_file_entries() == 0 ||
|
||||
|
||||
@@ -58,7 +58,7 @@ WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) :
|
||||
|
||||
void
|
||||
WindowHttpQueue::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
|
||||
cleanup_list();
|
||||
|
||||
@@ -147,7 +147,7 @@ WindowHttpQueue::receive_erase(core::CurlGet* h) {
|
||||
throw std::logic_error("WindowHttpQueue::receive_erase(...) tried to remove an object we don't have");
|
||||
|
||||
itr->m_http = NULL;
|
||||
itr->m_timer = cachedTime + 10000000;
|
||||
itr->m_timer = cachedTime + rak::timer::from_seconds(1);
|
||||
|
||||
mark_dirty();
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ WindowLog::~WindowLog() {
|
||||
|
||||
WindowLog::iterator
|
||||
WindowLog::find_older() {
|
||||
return m_log->find_older(cachedTime - 60*1000000);
|
||||
return m_log->find_older(cachedTime - rak::timer::from_seconds(60));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -58,7 +58,7 @@ WindowLogComplete::~WindowLogComplete() {
|
||||
|
||||
WindowLogComplete::iterator
|
||||
WindowLogComplete::find_older() {
|
||||
return m_log->find_older(cachedTime - 60*1000000);
|
||||
return m_log->find_older(cachedTime - rak::timer::from_seconds(60));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -57,7 +57,7 @@ WindowPeerInfo::WindowPeerInfo(core::Download* d, PList* l, PList::iterator* f)
|
||||
|
||||
void
|
||||
WindowPeerInfo::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
m_canvas->erase();
|
||||
|
||||
int y = 0;
|
||||
|
||||
@@ -56,7 +56,7 @@ WindowPeerList::WindowPeerList(core::Download* d, PList* l, PList::iterator* f)
|
||||
|
||||
void
|
||||
WindowPeerList::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
m_canvas->erase();
|
||||
|
||||
int x = 2;
|
||||
|
||||
@@ -54,7 +54,7 @@ WindowStatusbar::WindowStatusbar(Control* c) :
|
||||
|
||||
void
|
||||
WindowStatusbar::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
|
||||
m_canvas->erase();
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ WindowTitle::WindowTitle(const std::string& s) :
|
||||
|
||||
void
|
||||
WindowTitle::redraw() {
|
||||
m_slotSchedule(this, (cachedTime + 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
m_canvas->erase();
|
||||
|
||||
m_canvas->print(std::max(0, (m_canvas->get_width() - (int)m_title.size()) / 2 - 4), 0,
|
||||
|
||||
@@ -55,7 +55,7 @@ WindowTrackerList::WindowTrackerList(core::Download* d, unsigned int* focus) :
|
||||
void
|
||||
WindowTrackerList::redraw() {
|
||||
// TODO: Make this depend on tracker signal.
|
||||
m_slotSchedule(this, (cachedTime + 10 * 1000000).round_seconds());
|
||||
m_slotSchedule(this, (cachedTime + rak::timer::from_seconds(10)).round_seconds());
|
||||
m_canvas->erase();
|
||||
|
||||
int pos = 0;
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ load_arg_torrents(Control* c, char** first, char** last) {
|
||||
rak::timer
|
||||
client_next_timeout() {
|
||||
if (taskScheduler.empty())
|
||||
return 60 * 1000000;
|
||||
return rak::timer::from_seconds(60);
|
||||
else if (taskScheduler.top()->time() <= cachedTime)
|
||||
return 0;
|
||||
else
|
||||
|
||||
@@ -160,7 +160,7 @@ initialize_option_handler(Control* c) {
|
||||
variables->insert("use_udp_trackers", new utils::VariableAny("yes"));
|
||||
variables->insert("port_random", new utils::VariableAny("yes"));
|
||||
variables->insert("session", new utils::VariableSlotString<>(NULL, rak::mem_fn(&control->core()->download_store(), &core::DownloadStore::set_path)));
|
||||
variables->insert("session_lock", new utils::VariableAny("no"));
|
||||
variables->insert("session_lock", new utils::VariableAny("yes"));
|
||||
variables->insert("session_on_completion", new utils::VariableAny("yes"));
|
||||
|
||||
variables->insert("connection_leech", new utils::VariableAny("leech"));
|
||||
|
||||
@@ -359,7 +359,7 @@ void
|
||||
DownloadList::task_update() {
|
||||
m_windowLog->receive_update();
|
||||
|
||||
priority_queue_insert(&taskScheduler, &m_taskUpdate, (cachedTime + 1000000).round_seconds());
|
||||
priority_queue_insert(&taskScheduler, &m_taskUpdate, (cachedTime + rak::timer::from_seconds(1)).round_seconds());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
+63
-11
@@ -37,8 +37,11 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -47,6 +50,31 @@
|
||||
|
||||
namespace utils {
|
||||
|
||||
struct lockfile_valid_char {
|
||||
bool operator () (char c) {
|
||||
return !std::isgraph(c);
|
||||
}
|
||||
};
|
||||
|
||||
struct lockfile_valid_hostname {
|
||||
bool operator () (char c) {
|
||||
return !std::isgraph(c) || c == ':';
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
Lockfile::is_stale() {
|
||||
process_type process = locked_by();
|
||||
|
||||
char buf[256];
|
||||
|
||||
if (process.second <= 0 ||
|
||||
::gethostname(buf, 255) != 0 || buf != process.first)
|
||||
return false;
|
||||
|
||||
return ::kill(process.second, 0) != 0 && errno != EPERM;
|
||||
}
|
||||
|
||||
bool
|
||||
Lockfile::try_lock() {
|
||||
if (m_path.empty()) {
|
||||
@@ -54,6 +82,9 @@ Lockfile::try_lock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_stale())
|
||||
::unlink(m_path.c_str());
|
||||
|
||||
// Just do a simple locking for now that isn't safe for network
|
||||
// devices.
|
||||
int fd = ::open(m_path.c_str(), O_RDWR | O_CREAT | O_EXCL, 0444);
|
||||
@@ -85,25 +116,46 @@ Lockfile::unlock() {
|
||||
return ::unlink(m_path.c_str()) != -1;
|
||||
}
|
||||
|
||||
struct lockfile_valid_char {
|
||||
bool operator () (char c) {
|
||||
return !std::isgraph(c);
|
||||
}
|
||||
};
|
||||
|
||||
std::string
|
||||
Lockfile::process_type
|
||||
Lockfile::locked_by() const {
|
||||
int fd = ::open(m_path.c_str(), O_RDONLY);
|
||||
|
||||
if (fd < 0)
|
||||
return "<error>";
|
||||
return process_type(std::string(), 0);
|
||||
|
||||
char buf[256];
|
||||
int pos = read(fd, buf, 255);
|
||||
char first[256];
|
||||
char* last = first + std::max(read(fd, first, 255), 0);
|
||||
|
||||
*last = '\0';
|
||||
::close(fd);
|
||||
|
||||
return std::string(buf, std::find_if(buf, buf + std::max(pos, 0), lockfile_valid_char()));
|
||||
char* endHostname = std::find_if(first, last, lockfile_valid_hostname());
|
||||
char* beginPid = endHostname;
|
||||
char* endPid;
|
||||
|
||||
long long int pid;
|
||||
|
||||
if (beginPid + 2 >= last ||
|
||||
*(beginPid++) != ':' ||
|
||||
*(beginPid++) != '+' ||
|
||||
(pid = strtoll(beginPid, &endPid, 10)) == 0 ||
|
||||
endPid == NULL)
|
||||
return process_type(std::string(), 0);
|
||||
|
||||
return process_type(std::string(first, endHostname), pid);
|
||||
}
|
||||
|
||||
std::string
|
||||
Lockfile::locked_by_as_string() const {
|
||||
process_type p = locked_by();
|
||||
|
||||
if (p.first.empty())
|
||||
return "<error>";
|
||||
|
||||
std::stringstream str;
|
||||
str << p.first << ":+" << p.second;
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,14 +44,18 @@
|
||||
#define RTORRENT_UTILS_LOCKFILE_H
|
||||
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace utils {
|
||||
|
||||
class Lockfile {
|
||||
public:
|
||||
typedef std::pair<std::string, pid_t> process_type;
|
||||
|
||||
Lockfile() : m_locked(false) {}
|
||||
|
||||
bool is_locked() const { return m_locked; }
|
||||
bool is_stale();
|
||||
|
||||
// If the path is empty no lock file will be created, although
|
||||
// is_locked() will return true.
|
||||
@@ -61,7 +65,8 @@ public:
|
||||
const std::string& path() const { return m_path; }
|
||||
void set_path(const std::string& path) { m_path = path; }
|
||||
|
||||
std::string locked_by() const;
|
||||
std::string locked_by_as_string() const;
|
||||
process_type locked_by() const;
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
|
||||
Reference in New Issue
Block a user