aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilliam Preston <wpreston@suse.de>2015-01-19 15:39:52 +0100
committerMichael Kerrisk <mtk.manpages@gmail.com>2016-03-04 12:22:46 +0100
commitf3910b47127aed970e770ff35cb6f1c8496565ce (patch)
treedb493194e93442b24b77b6e44608027c603b0bc3
parente3548e1d649fef5be0b1aae85a0b9d3fbe737368 (diff)
downloadman-pages-f3910b47127aed970e770ff35cb6f1c8496565ce.tar.gz
adjtimex.2: Update a detail in adjtimex return value description
Starting with Linux 3.4, the time_state change is now asynchronous and the call returns the time_state before it has been altered, rather than after it was altered as the previous code did. ====================================================== Notes from Petr Gajdos attached program behaves differently on 2.6 and 3.0 kernels: ******************************************************* 2.6.32.59-0.7-default Insert LS adjtimex() return code 1: insert leap second (TIME_INS) Kernel leap second flag: STA_INS Delete LS adjtimex() return code 2: delete leap second (TIME_DEL) Kernel leap second flag: STA_DEL Insert LS again adjtimex() return code 1: insert leap second (TIME_INS) Kernel leap second flag: STA_INS Delete LS again adjtimex() return code 2: delete leap second (TIME_DEL) Kernel leap second flag: STA_DEL ******************************************************* 3.0.101-0.35-default sbsvt101:~/tmp # ./adjt Insert LS adjtimex() return code 0: clock synchronized (TIME_OK) Kernel leap second flag: STA_INS Delete LS adjtimex() return code 1: insert leap second (TIME_INS) Kernel leap second flag: STA_DEL Insert LS again adjtimex() return code 2: delete leap second (TIME_DEL) Kernel leap second flag: STA_INS Delete LS again adjtimex() return code 1: insert leap second (TIME_INS) Kernel leap second flag: STA_DEL ******************************************************* The explanation provided by William Preston (in CC): """ in both cases you get the actual value of the global kernel variable time_state. The code changed between the two kernels in the way it handled this. In 2.6.32.59 the adjtimex call starts a timer immediately with the function ntp_start_leap_timer(), which sets the value of time_state before returning to the user. This means you will get the value TIME_INS / TIME_DEL back immediately. In 3.0.101, the timer has been removed and the value of time_state is set when the microsecond field overflows. The function second_overflow() handles this. This means the value of time_state will not have been set when the syscall adjtimex returns, and so you will almost certainly get the old state. Incidentally if you remove the sleep() calls in the code for 3.0.101 you may instead see the state of TIME_OK when switching between STA_INS / STA_DEL. All this is completely normal and expected behaviour, since both return the current state, however I agree it is not intuitive. I would recommend calling adjtimex without a mode to get the actual state of the system after waiting a second. At the same time, William suggests the patch in the attachement. Petr =============== adjt.c ================ void adjtm(int); int main() { printf("Insert LS\n"); adjtm(STA_INS); sleep(2); printf("\nDelete LS\n"); adjtm(STA_DEL); sleep(2); printf("\nInsert LS again\n"); adjtm(STA_INS); sleep(2); printf("\nDelete LS again\n"); adjtm(STA_DEL); printf("\nRestoring initial state\n"); adjtm(0); } /*************************************/ /* Modify LS flag and print status */ /*************************************/ void adjtm(int ls) { struct timex tx; int rc; tx.modes = ADJ_STATUS; tx.status = ls; if ((rc = adjtimex(&tx)) == -1) { perror("adjtimex()"); exit(1); } sleep(2); tx.modes = 0; rc = adjtimex(&tx); printf("adjtimex() return code %d: ", rc); switch (rc) { case TIME_OK: printf("clock synchronized (TIME_OK)\n"); break; case TIME_INS: printf("insert leap second (TIME_INS)\n"); break; case TIME_DEL: printf("delete leap second (TIME_DEL)\n"); break; case TIME_OOP: printf("leap second in progress (TIME_OOP)\n"); break; case TIME_WAIT: printf("leap second has occurred (TIME_WAIT)\n"); break; case TIME_BAD: printf("clock not synchronized (TIME_BAD)\n"); break; default: printf("Unknown return code: %i\n", rc); break; } printf("Kernel leap second flag: "); if (tx.status & STA_INS) printf("STA_INS\n"); else if (tx.status & STA_DEL) printf("STA_DEL\n"); else printf("not set\n"); } ======================================= Reported-by: Petr Gajdos <pgajdos@suse.cz> Signed-off-by: Michael Kerrisk <mtk.manpages@gmail.com>
-rw-r--r--man2/adjtimex.25
1 files changed, 5 insertions, 0 deletions
diff --git a/man2/adjtimex.2 b/man2/adjtimex.2
index 89e9abf2ef..7eeb7e3306 100644
--- a/man2/adjtimex.2
+++ b/man2/adjtimex.2
@@ -362,6 +362,11 @@ The symbolic name
is a synonym for
.BR TIME_ERROR ,
provided for backward compatibility.
+Note that starting with Linux 3.4,
+.\" commit 6b43ae8a619d17c4935c3320d2ef9e92bdeed05d changed to asynchronous
+.\" operation, so we can no longer rely on the return code.
+the call operates asynchronously and the return value usually will
+not reflect a state change caused by the call itself.
.PP
On failure,
.BR adjtimex ()