aboutsummaryrefslogtreecommitdiffstats
path: root/src/system
diff options
context:
space:
mode:
Diffstat (limited to 'src/system')
-rw-r--r--src/system/Clock.cxx48
-rw-r--r--src/system/Clock.hxx18
-rw-r--r--src/system/EPollFD.hxx1
-rw-r--r--src/system/PeriodClock.hxx149
-rw-r--r--src/system/Resolver.cxx55
-rw-r--r--src/system/Resolver.hxx18
-rw-r--r--src/system/SignalFD.cxx1
-rw-r--r--src/system/SocketError.hxx6
8 files changed, 260 insertions, 36 deletions
diff --git a/src/system/Clock.cxx b/src/system/Clock.cxx
index 347997a44..4d89b9b89 100644
--- a/src/system/Clock.cxx
+++ b/src/system/Clock.cxx
@@ -31,6 +31,28 @@
#endif
unsigned
+MonotonicClockS(void)
+{
+#ifdef WIN32
+ return GetTickCount() / 1000;
+#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */
+ static mach_timebase_info_data_t base;
+ if (base.denom == 0)
+ (void)mach_timebase_info(&base);
+
+ return (unsigned)((mach_absolute_time() * base.numer / 1000)
+ / (1000000 * base.denom));
+#elif defined(CLOCK_MONOTONIC)
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return ts.tv_sec;
+#else
+ /* we have no monotonic clock, fall back to time() */
+ return time(nullptr);
+#endif
+}
+
+unsigned
MonotonicClockMS(void)
{
#ifdef WIN32
@@ -96,3 +118,29 @@ MonotonicClockUS(void)
#endif
}
+#ifdef WIN32
+
+gcc_const
+static unsigned
+DeltaFileTimeS(FILETIME a, FILETIME b)
+{
+ ULARGE_INTEGER a2, b2;
+ b2.LowPart = b.dwLowDateTime;
+ b2.HighPart = b.dwHighDateTime;
+ a2.LowPart = a.dwLowDateTime;
+ a2.HighPart = a.dwHighDateTime;
+ return (a2.QuadPart - b2.QuadPart) / 10000000;
+}
+
+unsigned
+GetProcessUptimeS()
+{
+ FILETIME creation_time, exit_time, kernel_time, user_time, now;
+ GetProcessTimes(GetCurrentProcess(), &creation_time,
+ &exit_time, &kernel_time, &user_time);
+ GetSystemTimeAsFileTime(&now);
+
+ return DeltaFileTimeS(now, creation_time);
+}
+
+#endif
diff --git a/src/system/Clock.hxx b/src/system/Clock.hxx
index 7be1127bf..1c3651a99 100644
--- a/src/system/Clock.hxx
+++ b/src/system/Clock.hxx
@@ -25,6 +25,13 @@
#include <stdint.h>
/**
+ * Returns the value of a monotonic clock in seconds.
+ */
+gcc_pure
+unsigned
+MonotonicClockS();
+
+/**
* Returns the value of a monotonic clock in milliseconds.
*/
gcc_pure
@@ -38,4 +45,15 @@ gcc_pure
uint64_t
MonotonicClockUS();
+#ifdef WIN32
+
+/**
+ * Returns the uptime of the current process in seconds.
+ */
+gcc_pure
+unsigned
+GetProcessUptimeS();
+
+#endif
+
#endif
diff --git a/src/system/EPollFD.hxx b/src/system/EPollFD.hxx
index 41f7ec377..a6ea51d18 100644
--- a/src/system/EPollFD.hxx
+++ b/src/system/EPollFD.hxx
@@ -23,6 +23,7 @@
#include <assert.h>
#include <sys/epoll.h>
#include <unistd.h>
+#include <stdint.h>
#include "check.h"
diff --git a/src/system/PeriodClock.hxx b/src/system/PeriodClock.hxx
new file mode 100644
index 000000000..61f52933f
--- /dev/null
+++ b/src/system/PeriodClock.hxx
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2003-2013 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_PERIOD_CLOCK_HXX
+#define MPD_PERIOD_CLOCK_HXX
+
+#include "Clock.hxx"
+
+/**
+ * This is a stopwatch which saves the timestamp of an event, and can
+ * check whether a specified time span has passed since then.
+ */
+class PeriodClock {
+protected:
+ typedef unsigned Stamp;
+
+private:
+ Stamp last;
+
+public:
+ /**
+ * Initializes the object, setting the last time stamp to "0",
+ * i.e. a Check() will always succeed. If you do not want this
+ * default behaviour, call Update() immediately after creating the
+ * object.
+ */
+ constexpr
+ PeriodClock():last(0) {}
+
+protected:
+ static Stamp GetNow() {
+ return MonotonicClockMS();
+ }
+
+ constexpr int Elapsed(Stamp now) const {
+ return last == 0
+ ? -1
+ : now - last;
+ }
+
+ constexpr bool Check(Stamp now, unsigned duration) const {
+ return now >= last + duration;
+ }
+
+ void Update(Stamp now) {
+ last = now;
+ }
+
+public:
+ bool IsDefined() const {
+ return last != 0;
+ }
+
+ /**
+ * Resets the clock.
+ */
+ void Reset() {
+ last = 0;
+ }
+
+ /**
+ * Returns the number of milliseconds elapsed since the last
+ * update(). Returns -1 if update() was never called.
+ */
+ int Elapsed() const {
+ return Elapsed(GetNow());
+ }
+
+ /**
+ * Combines a call to Elapsed() and Update().
+ */
+ int ElapsedUpdate() {
+ const auto now = GetNow();
+ int result = Elapsed(now);
+ Update(now);
+ return result;
+ }
+
+ /**
+ * Checks whether the specified duration has passed since the last
+ * update.
+ *
+ * @param duration the duration in milliseconds
+ */
+ bool Check(unsigned duration) const {
+ return Check(GetNow(), duration);
+ }
+
+ /**
+ * Updates the time stamp, setting it to the current clock.
+ */
+ void Update() {
+ Update(GetNow());
+ }
+
+ /**
+ * Updates the time stamp, setting it to the current clock plus the
+ * specified offset.
+ */
+ void UpdateWithOffset(int offset) {
+ Update(GetNow() + offset);
+ }
+
+ /**
+ * Checks whether the specified duration has passed since the last
+ * update. If yes, it updates the time stamp.
+ *
+ * @param duration the duration in milliseconds
+ */
+ bool CheckUpdate(unsigned duration) {
+ Stamp now = GetNow();
+ if (Check(now, duration)) {
+ Update(now);
+ return true;
+ } else
+ return false;
+ }
+
+ /**
+ * Checks whether the specified duration has passed since the last
+ * update. After that, it updates the time stamp.
+ *
+ * @param duration the duration in milliseconds
+ */
+ bool CheckAlwaysUpdate(unsigned duration) {
+ Stamp now = GetNow();
+ bool ret = Check(now, duration);
+ Update(now);
+ return ret;
+ }
+};
+
+#endif
diff --git a/src/system/Resolver.cxx b/src/system/Resolver.cxx
index 5e6ea590b..0cfb754ec 100644
--- a/src/system/Resolver.cxx
+++ b/src/system/Resolver.cxx
@@ -22,11 +22,12 @@
#include "util/Error.hxx"
#include "util/Domain.hxx"
-#include <glib.h>
-
#ifndef WIN32
#include <sys/socket.h>
#include <netdb.h>
+#ifdef HAVE_TCP
+#include <netinet/in.h>
+#endif
#else
#include <ws2tcpip.h>
#include <winsock.h>
@@ -41,17 +42,17 @@
const Domain resolver_domain("resolver");
-char *
-sockaddr_to_string(const struct sockaddr *sa, size_t length, Error &error)
+std::string
+sockaddr_to_string(const struct sockaddr *sa, size_t length)
{
#ifdef HAVE_UN
if (sa->sa_family == AF_UNIX) {
/* return path of UNIX domain sockets */
const sockaddr_un &s_un = *(const sockaddr_un *)sa;
if (length < sizeof(s_un) || s_un.sun_path[0] == 0)
- return g_strdup("local");
+ return "local";
- return g_strdup(s_un.sun_path);
+ return s_un.sun_path;
}
#endif
@@ -80,17 +81,23 @@ sockaddr_to_string(const struct sockaddr *sa, size_t length, Error &error)
ret = getnameinfo(sa, length, host, sizeof(host), serv, sizeof(serv),
NI_NUMERICHOST|NI_NUMERICSERV);
- if (ret != 0) {
- error.Set(resolver_domain, ret, gai_strerror(ret));
- return NULL;
- }
+ if (ret != 0)
+ return "unknown";
#ifdef HAVE_IPV6
- if (strchr(host, ':') != NULL)
- return g_strconcat("[", host, "]:", serv, NULL);
+ if (strchr(host, ':') != NULL) {
+ std::string result("[");
+ result.append(host);
+ result.append("]:");
+ result.append(serv);
+ return result;
+ }
#endif
- return g_strconcat(host, ":", serv, NULL);
+ std::string result(host);
+ result.push_back(':');
+ result.append(serv);
+ return result;
}
struct addrinfo *
@@ -98,19 +105,19 @@ resolve_host_port(const char *host_port, unsigned default_port,
int flags, int socktype,
Error &error)
{
- char *p = g_strdup(host_port);
- const char *host = p, *port = NULL;
+ std::string p(host_port);
+ const char *host = p.c_str(), *port = nullptr;
if (host_port[0] == '[') {
/* IPv6 needs enclosing square braces, to
differentiate between IP colons and the port
separator */
- char *q = strchr(p + 1, ']');
- if (q != NULL && q[1] == ':' && q[2] != 0) {
- *q = 0;
+ size_t q = p.find(']', 1);
+ if (q != p.npos && p[q + 1] == ':' && p[q + 2] != 0) {
+ p[q] = 0;
+ port = host + q + 2;
++host;
- port = q + 2;
}
}
@@ -118,10 +125,11 @@ resolve_host_port(const char *host_port, unsigned default_port,
/* port is after the colon, but only if it's the only
colon (don't split IPv6 addresses) */
- char *q = strchr(p, ':');
- if (q != NULL && q[1] != 0 && strchr(q + 1, ':') == NULL) {
- *q = 0;
- port = q + 1;
+ auto q = p.find(':');
+ if (q != p.npos && p[q + 1] != 0 &&
+ p.find(':', q + 1) == p.npos) {
+ p[q] = 0;
+ port = host + q + 1;
}
}
@@ -142,7 +150,6 @@ resolve_host_port(const char *host_port, unsigned default_port,
struct addrinfo *ai;
int ret = getaddrinfo(host, port, &hints, &ai);
- g_free(p);
if (ret != 0) {
error.Format(resolver_domain, ret,
"Failed to look up '%s': %s",
diff --git a/src/system/Resolver.hxx b/src/system/Resolver.hxx
index 62ef455a1..044d3f96a 100644
--- a/src/system/Resolver.hxx
+++ b/src/system/Resolver.hxx
@@ -22,27 +22,27 @@
#include "Compiler.h"
+#include <string>
+
#include <stddef.h>
struct sockaddr;
struct addrinfo;
class Error;
+class Domain;
-extern const class Domain resolver_domain;
+extern const Domain resolver_domain;
/**
* Converts the specified socket address into a string in the form
- * "IP:PORT". The return value must be freed with g_free() when you
- * don't need it anymore.
+ * "IP:PORT".
*
* @param sa the sockaddr struct
* @param length the length of #sa in bytes
- * @param error location to store the error occurring, or NULL to
- * ignore errors
*/
-gcc_malloc
-char *
-sockaddr_to_string(const struct sockaddr *sa, size_t length, Error &error);
+gcc_pure
+std::string
+sockaddr_to_string(const sockaddr *sa, size_t length);
/**
* Resolve a specification in the form "host", "host:port",
@@ -54,7 +54,7 @@ sockaddr_to_string(const struct sockaddr *sa, size_t length, Error &error);
* @return an #addrinfo linked list that must be freed with
* freeaddrinfo(), or NULL on error
*/
-struct addrinfo *
+addrinfo *
resolve_host_port(const char *host_port, unsigned default_port,
int flags, int socktype,
Error &error);
diff --git a/src/system/SignalFD.cxx b/src/system/SignalFD.cxx
index b89775dcd..d5953056d 100644
--- a/src/system/SignalFD.cxx
+++ b/src/system/SignalFD.cxx
@@ -20,7 +20,6 @@
#include "config.h"
#ifdef USE_SIGNALFD
#include "SignalFD.hxx"
-#include "fd_util.h"
#include "FatalError.hxx"
#include <assert.h>
diff --git a/src/system/SocketError.hxx b/src/system/SocketError.hxx
index 22fbd2441..28e1bace0 100644
--- a/src/system/SocketError.hxx
+++ b/src/system/SocketError.hxx
@@ -21,7 +21,7 @@
#define MPD_SOCKET_ERROR_HXX
#include "Compiler.h"
-#include "util/Error.hxx"
+#include "util/Error.hxx" // IWYU pragma: export
#ifdef WIN32
#include <winsock2.h>
@@ -31,11 +31,13 @@ typedef DWORD socket_error_t;
typedef int socket_error_t;
#endif
+class Domain;
+
/**
* A #Domain for #Error for socket I/O errors. The code is an errno
* value (or WSAGetLastError() on Windows).
*/
-extern const class Domain socket_domain;
+extern const Domain socket_domain;
gcc_pure
static inline socket_error_t