Live data from Hacker News

Ntimed – NTPD replacement

github.com

101–109 of 109 posts

Re: Ntimed – NTPD replacement

#101

Earlier quoted context omitted.

Rust definitely allows data sharing. It just doesn't allow data races. > If you define data races to not include race conditions that your code is handling (by placement of atomics, fences, locking etc.) then maybe your points make some sense but it is exactly the code handling these that I am saying does not fit with what I have seen rust advocates claim. Its actual guarantees for atomics are not very strong and let…

> Data races are well-defined, and what you're describing aren't data races, benign or otherwise. You basically never want data races, just like you basically never to dereference a dangling pointer Lock free algorithms, or even a lock implementation, does not jive with this. You let the race happen, and you safely detect when you lost or won the race, and then you do stuff accordingly. To use your pointer analogy, i…

Lock free algorithms have to be careful to avoid dataraces by using the appropriate atomic instructions on the CPU. Using non-atomic instructions is a data race and may mean you incorrectly detect that you won the race (seeing stale data in a CPU cache or somesuch).

A data race is essentially defined as a race condition between reads and writes where at least one of those is non-atomic. Rust's type system allows one to enforce atomicity by default (e.g. using atomic instructions, or wrapping data in a mutex).

Re: Ntimed – NTPD replacement

#102
post #27

Earlier quoted context omitted.

Lifting up constants into defines/consts and DRYing up C code makes for shorter, less error-prone and easier-to-understand codebases. Eg there's no reason to continue writing code like it's 1960's because we can steal good software eng and maintainability lessons from everything that has come since. (If one must maintain absolute portability.) PS: I would like to see a toolchain for Go that emits portable C instead o…

It's not "writing like 1960's programming' gratuitous abstraction just creates a burden for the programmer to dig through, it makes reasoning a pain.

That's taking things literally too far. Common sense says take some giant unsigned long long constant used in multiple places that cannot be vertically aligned and give it the semantic meaning it deserves. The goal of reducing LoC is to not obscure meaning but to write less code that states its behavior more clearly. Abstractions are garbage if they are confusing / hide meaning, but abstractions are immensely valuable if they perform complex operations in a clear manner (say an well-designed http client lib in C.)

Re: Ntimed – NTPD replacement

#103
post #77

Earlier quoted context omitted.

That simply won't do for OP as he seems to want solely client only mode implementation of NTP. chrony supports both. He seems to think the authors of these daemons don't have his best interests at heart by adding functionality he doesn't want personally yet many other people will use.

I fully agree with him that client-only mode deserves its own program, given that less than 1% of all computers ever need to be NTP servers.

OSX uses sntp which is open source, but it sucks because it doesn't stay running so it doesn't establish a PLL feedback loop that ntimed and ntp do.

Q: Does openntpd hook into PLL infrastructure?

Re: Ntimed – NTPD replacement

#104
post #101

Earlier quoted context omitted.

> Data races are well-defined, and what you're describing aren't data races, benign or otherwise. You basically never want data races, just like you basically never to dereference a dangling pointer Lock free algorithms, or even a lock implementation, does not jive with this. You let the race happen, and you safely detect when you lost or won the race, and then you do stuff accordingly. To use your pointer analogy, i…

Lock free algorithms have to be careful to avoid dataraces by using the appropriate atomic instructions on the CPU. Using non-atomic instructions is a data race and may mean you incorrectly detect that you won the race (seeing stale data in a CPU cache or somesuch). A data race is essentially defined as a race condition between reads and writes where at least one of those is non-atomic. Rust's type system allows one…

Are you assuming that I haven't written these things in real life or something?

I said "safely" detect, so yes, the final observation that you have won or lost the race must come from an atomic op. However, a "data race" susceptible read can totally be part of the process. The most common idiom I have seen for a lock free atomic read-modify-write has been to do an "unsafe" read, then act like it was OK, then issue compare-and-swap to determine if it really was OK and do the write if successful. (A failed compare and swap means you need to re-fetch and try again.) Yes you need to make sure fences are OK and the compiler is not caching/reordering the read and you need to account for the famous "ABA problem", blah blah blah, but it's what people do and I am not making it up for the purposes of an HN discussion.

The typical RISC approach to atomics, load-link/store-conditional, also encourages what I will call "my kind of thinking" on this issue, though it does so with specialized instructions. You do a special read, then you use ordinary non-atomic register operations, then you do the special store which fails when you lose the race. I will give you that these are specialized instructions and not ordinary C assignments but I would suggest looking into them if you have not already, the semantics are very educational. (And they may just convince you that disallowing data races is an overly restrictive thing to do in some scenarios.)

Re: Ntimed – NTPD replacement

#105
post #101

Earlier quoted context omitted.

Lock free algorithms have to be careful to avoid dataraces by using the appropriate atomic instructions on the CPU. Using non-atomic instructions is a data race and may mean you incorrectly detect that you won the race (seeing stale data in a CPU cache or somesuch). A data race is essentially defined as a race condition between reads and writes where at least one of those is non-atomic. Rust's type system allows one…

Are you assuming that I haven't written these things in real life or something? I said "safely" detect, so yes, the final observation that you have won or lost the race must come from an atomic op. However, a "data race" susceptible read can totally be part of the process. The most common idiom I have seen for a lock free atomic read-modify-write has been to do an "unsafe" read, then act like it was OK, then issue co…

I was assuming you were talking about the race & detection as e.g.

  // let the "race" happen:
  old = compare_and_swap(some_shared_memory, 1);
  if old == 0 {
      // we won!
  }
This is perfectly valid data-race-free code if the CAS is atomic, but is invalid if the CAS is not (assuming no other memory fences).

But sure, if you're manually fencing then you can have data races that are benign; however, just because something has some relatively rare uses doesn't mean it's wildly unsafe for the general case, and so disallowing by default it helps the correctness of the vast majority of concurrent code.

In any case, Rust allows one to opt-in to that sort of behaviour using `unsafe` locally, e.g. one would use `unsafe` deep in the internals of the implementation of the lock-free data structure and with careful vetting to ensure it's correct, and then all users can benefit with the compiler ensuring concurrency-safety by default.

Rust tries not to completely disallow behaviour, just make memory safety the default. The programmer can override the compiler via `unsafe` if they truly know better.

Re: Ntimed – NTPD replacement

#106
post #105

Earlier quoted context omitted.

Are you assuming that I haven't written these things in real life or something? I said "safely" detect, so yes, the final observation that you have won or lost the race must come from an atomic op. However, a "data race" susceptible read can totally be part of the process. The most common idiom I have seen for a lock free atomic read-modify-write has been to do an "unsafe" read, then act like it was OK, then issue co…

I was assuming you were talking about the race & detection as e.g. // let the "race" happen: old = compare_and_swap(some_shared_memory, 1); if old == 0 { // we won! } This is perfectly valid data-race-free code if the CAS is atomic, but is invalid if the CAS is not (assuming no other memory fences). But sure, if you're manually fencing then you can have data races that are benign; however, just because something has…

Other than the address compare and swap takes two operands: expected value and new value. It does an equality check and (if equal) the swap atomically. Therefore the equality check is handy to atomically check if a previous potentially unsafe read is still valid, and if so, set a new value.

Re: Ntimed – NTPD replacement

#107
post #105

Earlier quoted context omitted.

I was assuming you were talking about the race & detection as e.g. // let the "race" happen: old = compare_and_swap(some_shared_memory, 1); if old == 0 { // we won! } This is perfectly valid data-race-free code if the CAS is atomic, but is invalid if the CAS is not (assuming no other memory fences). But sure, if you're manually fencing then you can have data races that are benign; however, just because something has…

Other than the address compare and swap takes two operands: expected value and new value. It does an equality check and (if equal) the swap atomically. Therefore the equality check is handy to atomically check if a previous potentially unsafe read is still valid, and if so, set a new value.

Too late to edit the post but maybe some code sample will help illustrate the pattern. I am typing code into a web form so I make no guarantees that it is perfect.

  // Performs some modification on the input.
  extern int f(int);

  volatile int global_var = /* ... */;

  int expected;
  int new; // assuming C and not C++, where "new" is reserved
  do
  {
     // Do a speculative read
     expected = global_var;

     // Make some (non-atomic) modification
     new = f(expected);

     // loop until the speculative read was OK. (won the race)
  } while (compare_and_swap(&global_var, expected, new) != expected);

Re: Ntimed – NTPD replacement

#108

Earlier quoted context omitted.

Other than the address compare and swap takes two operands: expected value and new value. It does an equality check and (if equal) the swap atomically. Therefore the equality check is handy to atomically check if a previous potentially unsafe read is still valid, and if so, set a new value.

Too late to edit the post but maybe some code sample will help illustrate the pattern. I am typing code into a web form so I make no guarantees that it is perfect. // Performs some modification on the input. extern int f(int); volatile int global_var = /* ... */; int expected; int new; // assuming C and not C++, where "new" is reserved do { // Do a speculative read expected = global_var; // Make some (non-atomic) mod…

Whoops, I got the signature of CAS slightly wrong. In any case, I already understood the pattern and understand why it is OK. However, as I said, it is the exception that a data race is OK, which is why Rust disallows them by default (it does not disallow them completely).

Re: Ntimed – NTPD replacement

#109
post #77

Earlier quoted context omitted.

That simply won't do for OP as he seems to want solely client only mode implementation of NTP. chrony supports both. He seems to think the authors of these daemons don't have his best interests at heart by adding functionality he doesn't want personally yet many other people will use.

I fully agree with him that client-only mode deserves its own program, given that less than 1% of all computers ever need to be NTP servers.

How is that different than running the existing code in client only mode? That configured operation is just as easy to test and verify.
Post reply on HN