Merge ~anj/epics-base/+git/base-3.15:vxworks-tz-support into ~epics-core/epics-base/+git/epics-base:3.15
- Git
- lp:~anj/epics-base/+git/base-3.15
- vxworks-tz-support
- Merge into 3.15
Proposed by
Andrew Johnson
Status: | Merged |
---|---|
Approved by: | Andrew Johnson |
Approved revision: | d3a8a49552ca7930aa9a5ab34ceb1de9cd25ccf4 |
Merged at revision: | 3881328f2f7a0ad9853ed14c3d0fd5e97d02fafe |
Proposed branch: | ~anj/epics-base/+git/base-3.15:vxworks-tz-support |
Merge into: | ~epics-core/epics-base/+git/epics-base:3.15 |
Diff against target: |
618 lines (+397/-68) 10 files modified
configure/CONFIG_SITE_ENV (+35/-34) documentation/RELEASE_NOTES.html (+32/-0) src/libCom/RTEMS/rtems_init.c (+5/-19) src/libCom/env/envDefs.h (+1/-1) src/libCom/osi/Makefile (+1/-1) src/libCom/osi/epicsTime.cpp (+4/-2) src/libCom/osi/os/vxWorks/osdTime.cpp (+24/-8) src/libCom/osi/os/vxWorks/tz2timezone.c (+278/-0) src/libCom/osi/osiClockTime.c (+11/-3) src/libCom/osi/osiClockTime.h (+6/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrew Johnson | Approve | ||
Dirk Zimoch | Pending | ||
Review via email:
|
Commit message
Description of the change
Integrate some code Larry Hoff sent me 10 years ago that avoids the need to adjust the value of TIMEZONE every year...
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
mdavidsaver (mdavidsaver) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
MAD: The RTEMS code will need adjusting when merging up to 7.0, try to add the tzset() as suggested.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Johnson (anj) wrote : | # |
Group 10/4: No major issues.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV |
2 | index 49331f9..0084679 100644 |
3 | --- a/configure/CONFIG_SITE_ENV |
4 | +++ b/configure/CONFIG_SITE_ENV |
5 | @@ -24,40 +24,41 @@ |
6 | |
7 | # Site-specific environment settings |
8 | |
9 | -# Time service: |
10 | -# EPICS_TIMEZONE |
11 | -# Local timezone info for vxWorks and RTEMS. The format is |
12 | -# <name>::<minutesWest>:<startDST>:<endDST> |
13 | -# where <name> is only used by strftime() for %Z conversions, |
14 | -# and <startDST> and <endDST> are mmddhh - that is month,day,hour |
15 | -# e.g. for ANL in 2018: EPICS_TIMEZONE=CUS::360:031102:110402 |
16 | -# The future dates below assume the rules don't get changed; |
17 | -# see http://www.timeanddate.com/time/dst/2018.html to check. |
18 | -# |
19 | -# DST for 2018 US: Mar 11 - Nov 04 |
20 | -# EU: Mar 25 - Oct 28 |
21 | -EPICS_TIMEZONE = CUS::360:031102:110402 |
22 | -#EPICS_TIMEZONE = MET::-60:032502:102803 |
23 | -# |
24 | -# DST for 2019 US: Mar 10 - Nov 03 |
25 | -# EU: Mar 31 - Oct 27 |
26 | -#EPICS_TIMEZONE = CUS::360:031002:110302 |
27 | -#EPICS_TIMEZONE = MET::-60:033102:102703 |
28 | -# |
29 | -# DST for 2020 US: Mar 08 - Nov 01 |
30 | -# EU: Mar 29 - Oct 25 |
31 | -#EPICS_TIMEZONE = CUS::360:030802:110102 |
32 | -#EPICS_TIMEZONE = MET::-60:032902:102503 |
33 | -# |
34 | -# DST for 2021 US: Mar 14 - Nov 07 |
35 | -# EU: Mar 28 - Oct 31 |
36 | -#EPICS_TIMEZONE = CUS::360:031402:110702 |
37 | -#EPICS_TIMEZONE = MET::-60:032802:103103 |
38 | -# |
39 | -# DST for 2022 US: Mar 13 - Nov 06 |
40 | -# EU: Mar 27 - Oct 30 |
41 | -#EPICS_TIMEZONE = CUS::360:031302:110602 |
42 | -#EPICS_TIMEZONE = MET::-60:032702:103003 |
43 | +## Time service: |
44 | +# EPICS_TZ |
45 | +# Local timezone rules for vxWorks and RTEMS. The value follows the Posix |
46 | +# TZ environment variable's Mm.n.d/h format (see the IBM link below for |
47 | +# details). If TZ hasn't already been set when the osdTime timeRegister() |
48 | +# C++ static constructor runs, this parameter will be copied into the TZ |
49 | +# environment variable. Once the OS clock has been synchronized to NTP the |
50 | +# routine tz2timezone() will be run to convert TZ into the TIMEZONE |
51 | +# variable format that VxWorks needs. |
52 | +# https://developer.ibm.com/articles/au-aix-posix/ |
53 | + |
54 | +# Japan Standard Time, no DST: |
55 | +#EPICS_TZ = "JST-9" |
56 | + |
57 | +# Central European (Summer) Time: |
58 | +#EPICS_TZ = "CET-1CEST,M3.5.0/2,M10.5.0/3" |
59 | + |
60 | +# Greenwich Mean/British Summer Time: |
61 | +#EPICS_TZ = "GMT0BST,M3.5.0/1,M10.5.0/2" |
62 | + |
63 | +# US Eastern Standard/Daylight Time: |
64 | +#EPICS_TZ = "EST5EDT,M3.2.0/2,M11.1.0/2" |
65 | + |
66 | +# US Central Standard/Daylight Time: |
67 | +EPICS_TZ = "CST6CDT,M3.2.0/2,M11.1.0/2" |
68 | + |
69 | +# US Mountain Standard/Daylight Time: |
70 | +#EPICS_TZ = "MST7MDT,M3.2.0/2,M11.1.0/2" |
71 | + |
72 | +# US Pacific Standard/Daylight Time: |
73 | +#EPICS_TZ = "PST8PDT,M3.2.0/2,M11.1.0/2" |
74 | + |
75 | +# US Hawaiian Standard Time, no DST: |
76 | +#EPICS_TZ = "HST10" |
77 | + |
78 | |
79 | # EPICS_TS_NTP_INET |
80 | # NTP time server ip address for VxWorks and RTEMS. |
81 | diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html |
82 | index 8ed4e04..f6daa49 100644 |
83 | --- a/documentation/RELEASE_NOTES.html |
84 | +++ b/documentation/RELEASE_NOTES.html |
85 | @@ -16,6 +16,38 @@ |
86 | |
87 | <!-- Insert new items immediately below here ... --> |
88 | |
89 | +<h3>Replace EPICS_TIMEZONE with EPICS_TZ</h3> |
90 | + |
91 | +<p>The <tt>EPICS_TIMEZONE</tt> environment parameter provided time-zone |
92 | +information for the IOC's locale in the old ANSI format expected by VxWorks for |
93 | +its <tt>TIMEZONE</tt> environment variable, and can also used by RTEMS to set |
94 | +its <tt>TZ</tt> environment variable. However the <tt>TIMEZONE</tt> value has to |
95 | +be updated every year since it contains the exact dates of the daylight-savings |
96 | +time changes. The Posix TZ format that RTEMS uses contains rules that for |
97 | +calculating those dates, thus its value would only need updating if the rules |
98 | +(or the locale) are changed.</p> |
99 | + |
100 | +<p>This release contains changes that replace the <tt>EPICS_TIMEZONE</tt> |
101 | +environment parameter with one called <tt>EPICS_TZ</tt> and a routine for |
102 | +VxWorks that calculates the <tt>TIMEZONE</tt> environment variable from the |
103 | +current <tt>TZ</tt> value. This routine will be run once at start-up, when the |
104 | +EPICS clock has synchronized to its NTP server. The calculations it contains |
105 | +were worked out and donated to EPICS by Larry Hoff in 2009; it is unforunate |
106 | +that it has taken 10 years for them to be integrated into Base.</p> |
107 | + |
108 | +<p>The default value for the <tt>EPICS_TZ</tt> environment parameter is set in |
109 | +the Base configure/CONFIG_SITE_ENV file, which contains example settings for |
110 | +most EPICS sites that use VxWorks, and a link to a page describing the Posix TZ |
111 | +format for any locations that I missed.</p> |
112 | + |
113 | +<p>If a VxWorks IOC runs continuously without being rebooted from December 31st |
114 | +to the start of daylight savings time the following year, its <tt>TIMEZONE</tt> |
115 | +value will be wrong as it was calculated for the previous year. This only |
116 | +affects times that are converted to a string on the IOC however and is easily |
117 | +fixed; just run the command <tt>tz2timezone()</tt> on the VxWorks shell and the |
118 | +calculation will be redone for the current year. IOCs that get rebooted at least |
119 | +once before the start of summer time will not need this to be done.</p> |
120 | + |
121 | <h3>Cleaning up with Multiple CA contexts in a Process</h3> |
122 | |
123 | <p>Bruno Martins reported a problem with the CA client library at shutdown in a |
124 | diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c |
125 | index 2b909ab..dcb6daa 100644 |
126 | --- a/src/libCom/RTEMS/rtems_init.c |
127 | +++ b/src/libCom/RTEMS/rtems_init.c |
128 | @@ -581,25 +581,11 @@ Init (rtems_task_argument ignored) |
129 | printf ("***** Can't set time: %s\n", rtems_status_text (sc)); |
130 | } |
131 | if (getenv("TZ") == NULL) { |
132 | - const char *tzp = envGetConfigParamPtr(&EPICS_TIMEZONE); |
133 | - if (tzp == NULL) { |
134 | - printf("Warning -- no timezone information available -- times will be displayed as GMT.\n"); |
135 | - } |
136 | - else { |
137 | - char tz[10]; |
138 | - int minWest, toDst = 0, fromDst = 0; |
139 | - if(sscanf(tzp, "%9[^:]::%d:%d:%d", tz, &minWest, &toDst, &fromDst) < 2) { |
140 | - printf("Warning: EPICS_TIMEZONE (%s) unrecognizable -- times will be displayed as GMT.\n", tzp); |
141 | - } |
142 | - else { |
143 | - char posixTzBuf[40]; |
144 | - char *p = posixTzBuf; |
145 | - p += sprintf(p, "%cST%d:%.2d", tz[0], minWest/60, minWest%60); |
146 | - if (toDst != fromDst) |
147 | - p += sprintf(p, "%cDT", tz[0]); |
148 | - epicsEnvSet("TZ", posixTzBuf); |
149 | - } |
150 | - } |
151 | + const char *tzp = envGetConfigParamPtr(&EPICS_TZ); |
152 | + if (!tzp || *tzp) |
153 | + printf("Warning: No timezone information, times will be displayed in UTC.\n"); |
154 | + else |
155 | + epicsEnvSet("TZ", tzp); |
156 | } |
157 | tzset(); |
158 | osdTimeRegister(); |
159 | diff --git a/src/libCom/env/envDefs.h b/src/libCom/env/envDefs.h |
160 | index 20f0eb2..588cecd 100644 |
161 | --- a/src/libCom/env/envDefs.h |
162 | +++ b/src/libCom/env/envDefs.h |
163 | @@ -61,7 +61,7 @@ epicsShareExtern const ENV_PARAM EPICS_CAS_BEACON_PORT; |
164 | epicsShareExtern const ENV_PARAM EPICS_BUILD_COMPILER_CLASS; |
165 | epicsShareExtern const ENV_PARAM EPICS_BUILD_OS_CLASS; |
166 | epicsShareExtern const ENV_PARAM EPICS_BUILD_TARGET_ARCH; |
167 | -epicsShareExtern const ENV_PARAM EPICS_TIMEZONE; |
168 | +epicsShareExtern const ENV_PARAM EPICS_TZ; |
169 | epicsShareExtern const ENV_PARAM EPICS_TS_NTP_INET; |
170 | epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_PORT; |
171 | epicsShareExtern const ENV_PARAM EPICS_IOC_LOG_INET; |
172 | diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile |
173 | index c06a862..e05aec3 100644 |
174 | --- a/src/libCom/osi/Makefile |
175 | +++ b/src/libCom/osi/Makefile |
176 | @@ -77,7 +77,7 @@ Com_SRCS += epicsGeneralTime.c |
177 | |
178 | # Time providers |
179 | Com_SRCS += osiClockTime.c |
180 | -Com_SRCS_vxWorks += osiNTPTime.c |
181 | +Com_SRCS_vxWorks += osiNTPTime.c tz2timezone.c |
182 | Com_SRCS_RTEMS += osiNTPTime.c |
183 | |
184 | ifeq ($(OS_CLASS),vxWorks) |
185 | diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp |
186 | index af4fae2..9f54427 100644 |
187 | --- a/src/libCom/osi/epicsTime.cpp |
188 | +++ b/src/libCom/osi/epicsTime.cpp |
189 | @@ -955,7 +955,8 @@ extern "C" { |
190 | try { |
191 | local_tm_nano_sec tmns = epicsTime (*pSrc); |
192 | *pDest = tmns.ansi_tm; |
193 | - *pNSecDest = tmns.nSec; |
194 | + if (pNSecDest) |
195 | + *pNSecDest = tmns.nSec; |
196 | } |
197 | catch (...) { |
198 | return epicsTimeERROR; |
199 | @@ -967,7 +968,8 @@ extern "C" { |
200 | try { |
201 | gm_tm_nano_sec gmtmns = epicsTime (*pSrc); |
202 | *pDest = gmtmns.ansi_tm; |
203 | - *pNSecDest = gmtmns.nSec; |
204 | + if (pNSecDest) |
205 | + *pNSecDest = gmtmns.nSec; |
206 | } |
207 | catch (...) { |
208 | return epicsTimeERROR; |
209 | diff --git a/src/libCom/osi/os/vxWorks/osdTime.cpp b/src/libCom/osi/os/vxWorks/osdTime.cpp |
210 | index 4db375f..eb144c1 100644 |
211 | --- a/src/libCom/osi/os/vxWorks/osdTime.cpp |
212 | +++ b/src/libCom/osi/os/vxWorks/osdTime.cpp |
213 | @@ -24,22 +24,38 @@ |
214 | |
215 | #define NTP_REQUEST_TIMEOUT 4 /* seconds */ |
216 | |
217 | +extern "C" { |
218 | + int tz2timezone(void); |
219 | +} |
220 | + |
221 | static char sntp_sync_task[] = "ipsntps"; |
222 | static char ntp_daemon[] = "ipntpd"; |
223 | |
224 | static const char *pserverAddr = NULL; |
225 | +static CLOCKTIME_SYNCHOOK prevHook; |
226 | + |
227 | extern char* sysBootLine; |
228 | |
229 | +static void timeSync(int synchronized) { |
230 | + if (!tz2timezone()) |
231 | + ClockTime_syncHook = prevHook; /* Don't call me again */ |
232 | +} |
233 | + |
234 | static int timeRegister(void) |
235 | { |
236 | - /* If TIMEZONE not defined, set it from EPICS_TIMEZONE */ |
237 | - if (getenv("TIMEZONE") == NULL) { |
238 | - const char *timezone = envGetConfigParamPtr(&EPICS_TIMEZONE); |
239 | - if (timezone == NULL) { |
240 | - printf("timeRegister: No Time Zone Information\n"); |
241 | - } else { |
242 | - epicsEnvSet("TIMEZONE", timezone); |
243 | + /* If TZ not defined, set it from EPICS_TZ */ |
244 | + if (getenv("TZ") == NULL) { |
245 | + const char *tz = envGetConfigParamPtr(&EPICS_TZ); |
246 | + |
247 | + if (tz && *tz) { |
248 | + epicsEnvSet("TZ", tz); |
249 | + |
250 | + /* Call tz2timezone() once we know what year it is */ |
251 | + prevHook = ClockTime_syncHook; |
252 | + ClockTime_syncHook = timeSync; |
253 | } |
254 | + else if (getenv("TIMEZONE") == NULL) |
255 | + printf("timeRegister: No Time Zone Information available\n"); |
256 | } |
257 | |
258 | // Define EPICS_TS_FORCE_NTPTIME to force use of NTPTime provider |
259 | @@ -57,7 +73,7 @@ static int timeRegister(void) |
260 | } |
261 | |
262 | if (useNTP) { |
263 | - // Start NTP first so it can be used to sync SysTime |
264 | + // Start NTP first so it can be used to sync ClockTime |
265 | NTPTime_Init(100); |
266 | ClockTime_Init(CLOCKTIME_SYNC); |
267 | } else { |
268 | diff --git a/src/libCom/osi/os/vxWorks/tz2timezone.c b/src/libCom/osi/os/vxWorks/tz2timezone.c |
269 | new file mode 100644 |
270 | index 0000000..df8db85 |
271 | --- /dev/null |
272 | +++ b/src/libCom/osi/os/vxWorks/tz2timezone.c |
273 | @@ -0,0 +1,278 @@ |
274 | +/*************************************************************************\ |
275 | +* Copyright (c) 2009 Brookhaven Science Associates, as Operator of |
276 | +* Brookhaven National Laboratory. |
277 | +* Copyright (c) 2019 UChicago Argonne LLC, as Operator of Argonne |
278 | +* National Laboratory. |
279 | +* EPICS BASE is distributed subject to a Software License Agreement found |
280 | +* in file LICENSE that is included with this distribution. |
281 | +\*************************************************************************/ |
282 | +/* |
283 | + * Authors: Larry Hoff, Andrew Johnson <anj@anl.gov> |
284 | + */ |
285 | + |
286 | +/* |
287 | + * This file exports a single function "int tz2timezone(void)" which reads |
288 | + * the TZ environment variable (defined by POSIX) and converts it to the |
289 | + * TIMEZONE environment variable defined by ANSI. The latter is used by |
290 | + * VxWorks "time" functions, is largely deprecated in other computing |
291 | + * environments, has limitations, and is difficult to maintain. This holds |
292 | + * out the possibility of "pretending" that VxWorks supports "TZ" - until |
293 | + * such time as it actually does. |
294 | + * |
295 | + * For simplicity, only the "POSIX standard form" of TZ will be supported. |
296 | + * Even that is complicated enough (see following spec). Furthermore, |
297 | + * only the "M" form of DST start and stop dates are supported. |
298 | + * |
299 | + * TZ = zone[-]offset[dst[offset],start[/time],end[/time]] |
300 | + * |
301 | + * zone |
302 | + * A three or more letter name for the timezone in normal (winter) time. |
303 | + * |
304 | + * [-]offset |
305 | + * A signed time giving the offset of the time zone westwards from |
306 | + * Greenwich. The time has the form hh[:mm[:ss]] with a one of two |
307 | + * digit hour, and optional two digit minutes and seconds. |
308 | + * |
309 | + * dst |
310 | + * The name of the time zone when daylight saving is in effect. It may |
311 | + * be followed by an offset giving how big the adjustment is, required |
312 | + * if different than the default of 1 hour. |
313 | + * |
314 | + * start/time,end/time |
315 | + * Specify the start and end of the daylight saving period. The start |
316 | + * and end fields indicate on what day the changeover occurs, and must |
317 | + * be in this format: |
318 | + * |
319 | + * Mm.n.d |
320 | + * This indicates month m, the n-th occurrence of day d, where |
321 | + * 1 <= m <= 12, 1 <= n <= 5, 0 <= d <= 6, 0=Sunday |
322 | + * The 5th occurrence means the last occurrence of that day in a |
323 | + * month. So M4.1.0 is the first Sunday in April, M9.5.0 is the |
324 | + * last Sunday in September. |
325 | + * |
326 | + * The time field indicates what hour the changeover occurs on the given |
327 | + * day (TIMEZONE only supports switching on the hour). |
328 | + * |
329 | + */ |
330 | + |
331 | +#include <vxWorks.h> |
332 | +#include <envLib.h> /* getenv() */ |
333 | +#include <stdio.h> /* printf() */ |
334 | +#include <string.h> /* strchr() */ |
335 | +#include <ctype.h> /* isalpha() */ |
336 | + |
337 | +#include <epicsTime.h> |
338 | + |
339 | +/* for reference: TZ syntax, example, and TIMEZONE example |
340 | + * std offset dst [offset],start[/time],end[/time] |
341 | + * CST6CDT5,M3.2.0,M11.1.0 |
342 | + * EST+5EDT,M4.1.0/2,M10.5.0/2 |
343 | + * |
344 | + * std <unused> offset start stop |
345 | + * TIMEZONE=EST::300:030802:110102 |
346 | + */ |
347 | + |
348 | +static int extractDate(const char *tz, struct tm *current, char *s) |
349 | +{ |
350 | + static const int startdays[] = { |
351 | + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 |
352 | + }; |
353 | + static const int molengths[] = { |
354 | + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
355 | + }; |
356 | + |
357 | + int month, week, weekday, hour=2; /* default=2AM */ |
358 | + int jan1wday, wday, mday; |
359 | + |
360 | + /* Require 'M' format */ |
361 | + if (*++tz != 'M') { |
362 | + printf("tz2timezone: Unsupported date type, need 'M' format\n"); |
363 | + return ERROR; |
364 | + } |
365 | + tz++; |
366 | + |
367 | + if (sscanf(tz, "%d.%d.%d/%d", &month, &week, &weekday, &hour) < 3) |
368 | + return ERROR; /* something important missing */ |
369 | + |
370 | + if (month == 0 || month>12 || |
371 | + week < 1 || week > 5 || |
372 | + weekday < 0 || weekday > 6 || |
373 | + hour < 0 || hour > 23) |
374 | + return ERROR; |
375 | + |
376 | + /* Now for some brute-force calendar calculations... */ |
377 | + /* start month is in "month", and the day is "weekday", but |
378 | + we need to know when that weekday first occurs in that month */ |
379 | + /* Let's start with weekday on Jan. 1 */ |
380 | + jan1wday = (7 + current->tm_wday - (current->tm_yday % 7)) % 7; |
381 | + |
382 | + /* We need to know if it is a leap year (and if it matters) */ |
383 | + /* Let's assume that we're working with a date between 1901 and 2099, |
384 | + that way we don't have to think about the "century exception". |
385 | + If this code is still running (unchanged) in 2100, I'll be stunned |
386 | + (and 139 years old) */ |
387 | + wday = (jan1wday + startdays[month-1] + |
388 | + ((month > 2 && (current->tm_year % 4 == 0)) ? 1 : 0)) % 7; |
389 | + |
390 | + /* Let's see on what day-of-the-month the first target weekday occurs |
391 | + (counting from 1). The result is a number between 1 and 7, inclusive. */ |
392 | + mday = 1 + ((7 + weekday - wday) % 7); |
393 | + |
394 | + /* Next, we add the week offset. If we overflow the month, we subtract |
395 | + one week */ |
396 | + mday += 7 * (week - 1); |
397 | + if (mday > molengths[month-1]) |
398 | + mday -= 7; |
399 | + |
400 | + /* Should I handle Feb 29? I'm willing to gamble that no one in their right |
401 | + mind would schedule a time change to occur on Feb. 29. If so, we'll be a |
402 | + week early */ |
403 | + sprintf(s, "%02d%02d%02d", month, mday, hour); |
404 | + |
405 | + return OK; |
406 | +} |
407 | + |
408 | + |
409 | +static const char *getTime(const char *s, int *time) |
410 | +{ |
411 | + /* Time format is [+/-]hh[:mm][:ss] followed by the next zone name */ |
412 | + |
413 | + *time = 0; |
414 | + |
415 | + if (!isdigit((int) s[0])) |
416 | + return s; /* no number here... */ |
417 | + |
418 | + if (!isdigit((int) s[1])) { /* single digit form */ |
419 | + *time = s[0] - '0'; |
420 | + return s + 1; |
421 | + } |
422 | + |
423 | + if (isdigit((int) s[1])) { /* two digit form */ |
424 | + *time = 10 * (s[0] - '0') + (s[1] - '0'); |
425 | + return s + 2; |
426 | + } |
427 | + |
428 | + return s; /* does not follow supported form */ |
429 | +} |
430 | + |
431 | +int tz2timezone(void) |
432 | +{ |
433 | + const char *tz = getenv("TZ"); |
434 | + /* Spec. says that zone names must be at least 3 chars. |
435 | + * I've never seen a longer zone name, but I'll allocate |
436 | + * 40 chars. If you live in a zone with a longer name, |
437 | + * you may want to think about the benefits of relocation. |
438 | + */ |
439 | + char zone[40]; |
440 | + char start[10], stop[10]; /* only really need 7 bytes now */ |
441 | + int hours = 0, minutes = 0, sign = 1; |
442 | + /* This is more than enough, even with a 40-char zone |
443 | + * name, and 4-char offset. |
444 | + */ |
445 | + char timezone[100]; |
446 | + int i = 0; /* You *always need an "i" :-) */ |
447 | + epicsTimeStamp now; |
448 | + struct tm current; |
449 | + |
450 | + /* First let's get the current time. We need the year to |
451 | + * compute the start/stop dates for DST. |
452 | + */ |
453 | + if (epicsTimeGetCurrent(&now) || |
454 | + epicsTimeToTM(¤t, NULL, &now)) |
455 | + return ERROR; |
456 | + |
457 | + /* Make sure TZ exists. |
458 | + * Spec. says that ZONE must be at least 3 chars. |
459 | + */ |
460 | + if ((!tz) || (strlen(tz) < 3)) |
461 | + return ERROR; |
462 | + |
463 | + /* OK, now a bunch of brute-force parsing. My brain hurts if |
464 | + * I try to think of an elegant regular expression for the |
465 | + * string. |
466 | + */ |
467 | + |
468 | + /* Start extracting zone name, must be alpha */ |
469 | + while ((i < sizeof(zone) - 1) && isalpha((int) *tz)) { |
470 | + zone[i++] = *tz++; |
471 | + } |
472 | + if (i < 3) |
473 | + return ERROR; /* Too short, not a real zone name? */ |
474 | + |
475 | + zone[i] = 0; /* Nil-terminate (for now) */ |
476 | + |
477 | + /* Now extract offset time. The format is [+/-]hh[:mm[:ss]] |
478 | + * Recall that TIMEZONE doesn't support seconds.... |
479 | + */ |
480 | + if (*tz == '-') { |
481 | + sign = -1; |
482 | + tz++; |
483 | + } |
484 | + else if (*tz == '+') { |
485 | + tz++; |
486 | + } |
487 | + |
488 | + /* Need a digit now */ |
489 | + if (!isdigit((int) *tz)) |
490 | + return ERROR; |
491 | + |
492 | + /* First get the hours */ |
493 | + tz = getTime(tz, &hours); |
494 | + if (hours > 24) |
495 | + return ERROR; |
496 | + |
497 | + if (*tz == ':') { /* There is a minutes part */ |
498 | + /* Need another digit now */ |
499 | + if (!isdigit((int) *++tz)) |
500 | + return ERROR; |
501 | + |
502 | + /* Extract the minutes */ |
503 | + tz = getTime(tz, &minutes); |
504 | + if (minutes > 60) |
505 | + return ERROR; |
506 | + |
507 | + /* Skip any seconds part */ |
508 | + if (*tz == ':') { |
509 | + int seconds; |
510 | + tz = getTime(tz + 1, &seconds); |
511 | + } |
512 | + } |
513 | + |
514 | + /* Extract any DST zone name, must be alpha */ |
515 | + if (isalpha((int) *tz)) { |
516 | + zone[i++] = '/'; /* Separate the names */ |
517 | + |
518 | + while ((i < sizeof(zone) - 1) && isalpha((int) *tz)) { |
519 | + zone[i++] = *tz++; |
520 | + } |
521 | + zone[i] = 0; /* Nil-terminate */ |
522 | + } |
523 | + |
524 | + minutes += hours * 60; |
525 | + minutes *= sign; |
526 | + |
527 | + /* Look for start/stop dates - require neither or both */ |
528 | + tz = strchr(tz, ','); |
529 | + if (!tz) { /* No daylight savings time here */ |
530 | + /* Format the env. variable */ |
531 | + sprintf(timezone, "TIMEZONE=%s::%d", zone, minutes); |
532 | + } |
533 | + else { |
534 | + if (extractDate(tz, ¤t, start) != OK) |
535 | + return ERROR; |
536 | + |
537 | + tz = strchr(tz + 1, ','); |
538 | + if (!tz) |
539 | + return ERROR; |
540 | + if (extractDate(tz, ¤t, stop) != OK) |
541 | + return ERROR; |
542 | + |
543 | + /* Format the env. variable */ |
544 | + sprintf(timezone, "TIMEZONE=%s::%d:%s:%s", zone, minutes, start, stop); |
545 | + } |
546 | + |
547 | + /* Make it live! */ |
548 | + putenv(timezone); |
549 | + |
550 | + return OK; |
551 | +} |
552 | diff --git a/src/libCom/osi/osiClockTime.c b/src/libCom/osi/osiClockTime.c |
553 | index fb9d153..01958b2 100644 |
554 | --- a/src/libCom/osi/osiClockTime.c |
555 | +++ b/src/libCom/osi/osiClockTime.c |
556 | @@ -23,7 +23,8 @@ |
557 | #include "taskwd.h" |
558 | |
559 | #define NSEC_PER_SEC 1000000000 |
560 | -#define ClockTimeSyncInterval_value 60.0 |
561 | +#define ClockTimeSyncInterval_initial 1.0 |
562 | +#define ClockTimeSyncInterval_normal 60.0 |
563 | |
564 | |
565 | static struct { |
566 | @@ -79,7 +80,7 @@ static void ClockTime_InitOnce(void *pfirst) |
567 | |
568 | ClockTimePvt.loopEvent = epicsEventMustCreate(epicsEventEmpty); |
569 | ClockTimePvt.lock = epicsMutexCreate(); |
570 | - ClockTimePvt.ClockTimeSyncInterval = 1.0; /* First sync */ |
571 | + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_initial; |
572 | |
573 | epicsAtExit(ClockTime_Shutdown, NULL); |
574 | |
575 | @@ -148,6 +149,8 @@ void ClockTime_GetProgramStart(epicsTimeStamp *pDest) |
576 | /* Synchronization thread */ |
577 | |
578 | #if defined(vxWorks) || defined(__rtems__) |
579 | +CLOCKTIME_SYNCHOOK ClockTime_syncHook = NULL; |
580 | + |
581 | static void ClockTimeSync(void *dummy) |
582 | { |
583 | taskwdInsert(0, NULL, NULL); |
584 | @@ -179,11 +182,16 @@ static void ClockTimeSync(void *dummy) |
585 | ClockTimePvt.syncTime = timeNow; |
586 | epicsMutexUnlock(ClockTimePvt.lock); |
587 | |
588 | - ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_value; |
589 | + if (ClockTime_syncHook) |
590 | + ClockTime_syncHook(1); |
591 | + |
592 | + ClockTimePvt.ClockTimeSyncInterval = ClockTimeSyncInterval_normal; |
593 | } |
594 | } |
595 | |
596 | ClockTimePvt.synchronized = 0; |
597 | + if (ClockTime_syncHook) |
598 | + ClockTime_syncHook(0); |
599 | taskwdRemove(0); |
600 | } |
601 | #endif |
602 | diff --git a/src/libCom/osi/osiClockTime.h b/src/libCom/osi/osiClockTime.h |
603 | index 17eacab..2359888 100644 |
604 | --- a/src/libCom/osi/osiClockTime.h |
605 | +++ b/src/libCom/osi/osiClockTime.h |
606 | @@ -19,6 +19,12 @@ void ClockTime_Init(int synchronize); |
607 | void ClockTime_Shutdown(void *dummy); |
608 | int ClockTime_Report(int level); |
609 | |
610 | +#if defined(vxWorks) || defined(__rtems__) |
611 | +typedef void (* CLOCKTIME_SYNCHOOK)(int synchronized); |
612 | + |
613 | +extern CLOCKTIME_SYNCHOOK ClockTime_syncHook; |
614 | +#endif |
615 | + |
616 | #ifdef __cplusplus |
617 | } |
618 | #endif |
This looks like almost a no-op for RTEMS, so I see no problem. Are the changes to epicsTime.cpp a bug fix?