+#endif /* HAVE_GETMNTENT_R && HAVE_STATVFS */
+}
+\f
+#define SYSTEM_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
+
+/* Whether the client wants us to report system stats. */
+static bool enabled;
+
+static enum {
+ S_DISABLED, /* Not enabled, nothing going on. */
+ S_WAITING, /* Sleeping for SYSTEM_STATS_INTERVAL ms. */
+ S_REQUEST_SENT, /* Sent a request to worker. */
+ S_REPLY_RECEIVED /* Received a reply from worker. */
+} state;
+
+/* In S_WAITING state: the next time to wake up.
+ * In other states: not meaningful. */
+static long long int next_refresh;
+
+/* In S_REPLY_RECEIVED: the stats that have just been received.
+ * In other states: not meaningful. */
+static struct smap *received_stats;
+
+static worker_request_func system_stats_request_cb;
+static worker_reply_func system_stats_reply_cb;
+
+/* Enables or disables system stats collection, according to 'new_enable'.
+ *
+ * Even if system stats are disabled, the caller should still periodically call
+ * system_stats_run(). */
+void
+system_stats_enable(bool new_enable)
+{
+ if (new_enable != enabled) {
+ if (new_enable) {
+ if (state == S_DISABLED) {
+ state = S_WAITING;
+ next_refresh = time_msec();
+ }
+ } else {
+ if (state == S_WAITING) {
+ state = S_DISABLED;
+ }
+ }
+ enabled = new_enable;
+ }
+}
+
+/* Tries to obtain a new snapshot of system stats every SYSTEM_STATS_INTERVAL
+ * milliseconds.
+ *
+ * When a new snapshot is available (which only occurs if system stats are
+ * enabled), returns it as an smap owned by the caller. The caller must use
+ * both smap_destroy() and free() to complete free the returned data.
+ *
+ * When no new snapshot is available, returns NULL. */
+struct smap *
+system_stats_run(void)
+{
+ switch (state) {
+ case S_DISABLED:
+ break;
+
+ case S_WAITING:
+ if (time_msec() >= next_refresh) {
+ worker_request(NULL, 0, NULL, 0, system_stats_request_cb,
+ system_stats_reply_cb, NULL);
+ state = S_REQUEST_SENT;
+ }
+ break;
+
+ case S_REQUEST_SENT:
+ break;
+
+ case S_REPLY_RECEIVED:
+ if (enabled) {
+ state = S_WAITING;
+ next_refresh = time_msec() + SYSTEM_STATS_INTERVAL;
+ return received_stats;
+ } else {
+ smap_destroy(received_stats);
+ free(received_stats);
+ state = S_DISABLED;
+ }
+ break;
+ }
+
+ return NULL;