Wrapping java-systemd for Clojure: CLOCK_MONOTONIC and CLOCK_REALTIME interpretation problem

clojure

#1

Dear Clojureverse,

having to talk with systemd in one of my projects, with only [dgellow/systemd "0.1.0-SNAPSHOT"] being just a wrapper around shell commands, I’ve decided to build valid systemd interface for Clojure based on Java’s java-systemd [1] library to let me work with systemd over DBus.

I am not 100% sure if this is really Clojure question, or Java question, or even systemd question (probably not, though).

Problem I am facing right now is CLOCK_MONOTONIC and CLOCK_REALTIME interpretation. See my timer.clj:

The goal here is to convert systemd-reported times into something Clojure-readable. The documentation says:

NextElapseUSecRealtime contains the next elapsation point on the CLOCK_REALTIME clock in usec since the epoch, or 0 if this timer event does not include at least one calendar event.

Similar, NextElapseUSecMonotonic contains the next elapsation point on the CLOCK_MONOTONIC clock in usec since the epoch, or 0 if this timer event does not include at least one monotonic event.

And here is how it looks like from my library perspective:

;; user> (manager/get-timer :system "dnf-makecache.timer")
;; {:active-state :active, :load-state :loaded, :id "dnf-makecache.timer", :unit "dnf-makecache.service", :next-elapse-time-monotonic 7809313353, :next-elapse-time-realtime 0, :last-trigger-time 1533557490161681, :last-trigger-time-monotonic 4208989347}

While times reported by command-line utility are:

NEXT                          LEFT       LAST                          PASSED       UNIT                         ACTIVATES
Mon 2018-08-06 15:11:30 CEST  39min left Mon 2018-08-06 14:11:30 CEST  20min ago    dnf-makecache.timer          dnf-makecache.service

Please note that those two outputs were not captured in exactly the same moment, but should be few-minute accurate at least.

So looking at those two values:

  • next-elapse-time-monotonic 7809313353
  • NEXT: Mon 2018-08-06 15:11:30 CEST

I don’t really have a clue how to parse it:

user> (clj-time.coerce/from-long 7809313353)
#object[org.joda.time.DateTime 0x3fa92b5d "1970-04-01T09:15:13.353Z"]
user> (clj-time.coerce/from-epoch 7809313353)
#object[org.joda.time.DateTime 0x7ceeb5ef "2217-06-20T13:42:33.000Z"]

I believe CLOCK_REALTIME and CLOCK_MONOTONIC might involve some kind of offset. This is UNIX specific, and as far as I know there is C interface to handle those values, but is there any alternative for Java/Clojure? How to handle such values? See [2] for more info about clocks, monotonic and realtime.

Thanks,
Slawek

[1] https://github.com/thjomnx/java-systemd
[2] https://stackoverflow.com/a/3527632


#2

Totally stabbing in the dark here but this at least gets close. Made the following observations:

  • usec refers to microseconds but cli-time’s coercer functions take milliseconds — so you’ll have to divide by 1000 first

  • in the documentation it says

    since the epoch, or 0 if this timer event does not include at least one calendar event

    Usually epoch refers to UNIX epoch but then why would it be 0 of there is no calendar event? Made me think maybe epoch means something different here. No idea if this is true but it brought me closer to the dates you were expecting to see:

(def x {:next-elapse-time-monotonic 7809313353
        :next-elapse-time-realtime 0
        :last-trigger-time 1533557490161681,
        :last-trigger-time-monotonic 4208989347})

(clj-time.coerce/from-long 
  (long (/ (+ (:last-trigger-time x) (:next-elapse-time-monotonic x)) 
           1000)))

;; => #object[org.joda.time.DateTime 0x10db6131 "2018-08-06T14:21:39.475Z"]

EDIT Searching Google for getNextElapseUSecMonotonic brings up exactly one result which is the code where it’s defined. I think that’s almost a little fascinating. :smile: Maybe you’re best off asking the author directly.

Also it’s 6300 lines of Java code and the project doesn’t seem to be used by many (at least judging by GitHub stars which may be misleading) so it seems likely that there is an occasional bug that only gets discovered with more usage.