1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2015-2018. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24 #include "erl_os_monotonic_time_extender.h"
25 
26 
os_monotonic_time_extender(void * vstatep)27 static void *os_monotonic_time_extender(void *vstatep)
28 {
29     ErtsOsMonotonicTimeExtendState *state = (ErtsOsMonotonicTimeExtendState *) vstatep;
30     long sleep_time = state->check_interval*1000;
31     Uint32 (*raw_os_mtime)(void) = state->raw_os_monotonic_time;
32     Uint32 last_msb = 0;
33 
34     while (1) {
35 	Uint32 msb = (*raw_os_mtime)() & (((Uint32) 1) << 31);
36 
37 	if (msb != last_msb) {
38 	    int ix = ((int) (last_msb >> 31)) & 1;
39 	    Uint32 xtnd = (Uint32) erts_atomic32_read_nob(&state->extend[ix]);
40 	    erts_atomic32_set_nob(&state->extend[ix], (erts_aint32_t) (xtnd + 1));
41 	    last_msb = msb;
42 	}
43 	erts_milli_sleep(sleep_time);
44     }
45 
46     erts_exit(ERTS_ABORT_EXIT, "os_monotonic_time_extender thread terminating");
47     return NULL;
48 }
49 
50 static erts_tid_t os_monotonic_extender_tid;
51 
52 void
erts_init_os_monotonic_time_extender(ErtsOsMonotonicTimeExtendState * statep,Uint32 (* raw_os_monotonic_time)(void),int check_seconds)53 erts_init_os_monotonic_time_extender(ErtsOsMonotonicTimeExtendState *statep,
54 				     Uint32 (*raw_os_monotonic_time)(void),
55 				     int check_seconds)
56 {
57     statep->raw_os_monotonic_time = raw_os_monotonic_time;
58     erts_atomic32_init_nob(&statep->extend[0], (erts_aint32_t) 0);
59     erts_atomic32_init_nob(&statep->extend[1], (erts_aint32_t) 0);
60     statep->check_interval = check_seconds;
61 
62 }
63 
64 void
erts_late_init_os_monotonic_time_extender(ErtsOsMonotonicTimeExtendState * statep)65 erts_late_init_os_monotonic_time_extender(ErtsOsMonotonicTimeExtendState *statep)
66 {
67     erts_thr_opts_t thr_opts = ERTS_THR_OPTS_DEFAULT_INITER;
68     thr_opts.detached = 1;
69     thr_opts.suggested_stack_size = 4;
70 
71 #if 0
72     thr_opts.name = "os_monotonic_time_extender";
73 #endif
74 
75     erts_thr_create(&os_monotonic_extender_tid,
76 		    os_monotonic_time_extender,
77 		    (void*) statep,
78 		    &thr_opts);
79 }
80