1 /* $Id: time_man.cpp 530755 2017-03-17 13:19:30Z gouriano $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Pavel Ivanov
27 *
28 */
29
30 #include "task_server_pch.hpp"
31
32 #include <corelib/ncbireg.hpp>
33
34 #include "time_man.hpp"
35
36
37 BEGIN_NCBI_SCOPE;
38
39
40 class CTZAdjuster : public CSrvTask
41 {
42 public:
43 CTZAdjuster(void);
44 virtual ~CTZAdjuster(void);
45
46 private:
47 virtual void ExecuteSlice(TSrvThreadNum thr_num);
48 };
49
50
51 CSrvTime s_SrvStartTime;
52 CSrvTime s_LastJiffyTime;
53 Uint8 s_CurJiffies = 0;
54 CSrvTime s_JiffyTime;
55 static time_t s_TZAdjustment = 0;
56 static CTZAdjuster* s_Adjuster = NULL;
57
58
59 static Uint4
s_InitTZAdjustment(void)60 s_InitTZAdjustment(void)
61 {
62 #ifdef NCBI_OS_LINUX
63 CSrvTime srv_t = CSrvTime::Current();
64 struct tm t;
65 gmtime_r(&srv_t.Sec(), &t);
66 t.tm_isdst = -1;
67 time_t loc_time = mktime(&t);
68 s_TZAdjustment = srv_t.Sec() - loc_time;
69
70 // Return number of seconds until it's 1 second after the hour boundary
71 return (60 - t.tm_min) * 60 - (t.tm_sec - 1);
72 #else
73 return 0;
74 #endif
75 }
76
77 void
InitTime(void)78 InitTime(void)
79 {
80 s_LastJiffyTime = s_SrvStartTime = CSrvTime::Current();
81 s_InitTZAdjustment();
82 }
83
84 void
InitTimeMan(void)85 InitTimeMan(void)
86 {
87 s_Adjuster = new CTZAdjuster();
88 s_Adjuster->SetRunnable();
89 }
90
91 void
ConfigureTimeMan(const CNcbiRegistry * reg,CTempString section)92 ConfigureTimeMan(const CNcbiRegistry* reg, CTempString section)
93 {
94 Uint4 clock_freq = Uint4(reg->GetInt(section, "jiffies_per_sec", 100));
95 s_JiffyTime.NSec() = kUSecsPerSecond * kNSecsPerUSec / clock_freq;
96 }
97
ReConfig_TimeMan(const CTempString &,const CNcbiRegistry &,string &)98 bool ReConfig_TimeMan(const CTempString&, const CNcbiRegistry&, string&)
99 {
100 return true;
101 }
102
WriteSetup_TimeMan(CSrvSocketTask & task)103 void WriteSetup_TimeMan(CSrvSocketTask& task)
104 {
105 string is("\": "), eol(",\n\"");
106 task.WriteText(eol).WriteText("jiffies_per_sec").WriteText(is ).WriteNumber( kUSecsPerSecond * kNSecsPerUSec / s_JiffyTime.NSec());
107 }
108
109 void
IncCurJiffies(void)110 IncCurJiffies(void)
111 {
112 s_LastJiffyTime = CSrvTime::Current();
113 ++s_CurJiffies;
114 }
115
116 static inline void
s_Print1Dig(char * & buf,int num)117 s_Print1Dig(char*& buf, int num)
118 {
119 *(buf++) = char(num + '0');
120 }
121
122 static inline void
s_Print2Digs(char * & buf,int num)123 s_Print2Digs(char*& buf, int num)
124 {
125 int hi = num / 10;
126 s_Print1Dig(buf, hi);
127 s_Print1Dig(buf, num - hi * 10);
128 }
129
130 static inline void
s_Print3Digs(char * & buf,int num)131 s_Print3Digs(char*& buf, int num)
132 {
133 int hi = num / 100;
134 s_Print1Dig(buf, hi);
135 s_Print2Digs(buf, num - hi * 100);
136 }
137
138 static inline void
s_Print4Digs(char * & buf,int num)139 s_Print4Digs(char*& buf, int num)
140 {
141 int hi = num / 100;
142 s_Print2Digs(buf, hi);
143 s_Print2Digs(buf, num - hi * 100);
144 }
145
146 static inline void
s_Print6Digs(char * & buf,int num)147 s_Print6Digs(char*& buf, int num)
148 {
149 int hi = num / 100;
150 s_Print4Digs(buf, hi);
151 s_Print2Digs(buf, num - hi * 100);
152 }
153
154 Uint1
Print(char * buf,EFormatType fmt) const155 CSrvTime::Print(char* buf, EFormatType fmt) const
156 {
157 char* start_buf = buf;
158
159 #ifdef NCBI_OS_LINUX
160 time_t sec = tv_sec + s_TZAdjustment;
161 struct tm t;
162 gmtime_r(&sec, &t);
163
164 switch (fmt) {
165 default:
166 SRV_LOG(Error, "Unsupported time format: " << fmt);
167 // no break
168 case eFmtLogging:
169 s_Print4Digs(buf, t.tm_year + 1900);
170 *(buf++) = '-';
171 s_Print2Digs(buf, t.tm_mon + 1);
172 *(buf++) = '-';
173 s_Print2Digs(buf, t.tm_mday);
174 *(buf++) = 'T';
175 s_Print2Digs(buf, t.tm_hour);
176 *(buf++) = ':';
177 s_Print2Digs(buf, t.tm_min);
178 *(buf++) = ':';
179 s_Print2Digs(buf, t.tm_sec);
180 *(buf++) = '.';
181 s_Print6Digs(buf, int(tv_nsec / kNSecsPerUSec));
182 break;
183 case eFmtJson:
184 if ( tv_sec == 0 && tv_nsec == 0) {
185 *(buf++) = 'n';
186 *(buf++) = 'u';
187 *(buf++) = 'l';
188 *(buf++) = 'l';
189 break;
190 } else {
191 *(buf++) = '\"';
192 }
193 case eFmtHumanSeconds:
194 case eFmtHumanUSecs:
195 s_Print2Digs(buf, t.tm_mon + 1);
196 *(buf++) = '/';
197 s_Print2Digs(buf, t.tm_mday);
198 *(buf++) = '/';
199 s_Print4Digs(buf, t.tm_year + 1900);
200 *(buf++) = ' ';
201 s_Print2Digs(buf, t.tm_hour);
202 *(buf++) = ':';
203 s_Print2Digs(buf, t.tm_min);
204 *(buf++) = ':';
205 s_Print2Digs(buf, t.tm_sec);
206 if (fmt == eFmtHumanUSecs) {
207 *(buf++) = '.';
208 s_Print6Digs(buf, int(tv_nsec / kNSecsPerUSec));
209 }
210 if (fmt == eFmtJson) {
211 *(buf++) = '\"';
212 }
213 break;
214 }
215 #endif
216
217 *buf = '\0';
218 return Uint1(buf - start_buf);
219 }
220
221 int
TZAdjustment(void)222 CSrvTime::TZAdjustment(void)
223 {
224 return int(s_TZAdjustment);
225 }
226
227
CTZAdjuster(void)228 CTZAdjuster::CTZAdjuster(void)
229 {
230 #if __NC_TASKS_MONITOR
231 m_TaskName = "CTZAdjuster";
232 #endif
233 }
234
~CTZAdjuster(void)235 CTZAdjuster::~CTZAdjuster(void)
236 {}
237
238 void
ExecuteSlice(TSrvThreadNum)239 CTZAdjuster::ExecuteSlice(TSrvThreadNum /* thr_num */)
240 {
241 // on one second after an hour, calculates difference with GMT time
242 Uint4 delay = s_InitTZAdjustment();
243 if (!CTaskServer::IsInShutdown())
244 RunAfter(delay);
245 }
246
247 END_NCBI_SCOPE;
248