Merge ~anj/epics-base/+git/base-3.15:vxworks-tz-support into ~epics-core/epics-base/+git/epics-base: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)
Reviewer Review Type Date Requested Status
Andrew Johnson Approve
Dirk Zimoch Pending
Review via email: mp+368570@code.launchpad.net

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
mdavidsaver (mdavidsaver) wrote :

This looks like almost a no-op for RTEMS, so I see no problem. Are the changes to epicsTime.cpp a bug fix?

Revision history for this message
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
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
1diff --git a/configure/CONFIG_SITE_ENV b/configure/CONFIG_SITE_ENV
2index 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.
81diff --git a/documentation/RELEASE_NOTES.html b/documentation/RELEASE_NOTES.html
82index 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
124diff --git a/src/libCom/RTEMS/rtems_init.c b/src/libCom/RTEMS/rtems_init.c
125index 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();
159diff --git a/src/libCom/env/envDefs.h b/src/libCom/env/envDefs.h
160index 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;
172diff --git a/src/libCom/osi/Makefile b/src/libCom/osi/Makefile
173index 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)
185diff --git a/src/libCom/osi/epicsTime.cpp b/src/libCom/osi/epicsTime.cpp
186index 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;
209diff --git a/src/libCom/osi/os/vxWorks/osdTime.cpp b/src/libCom/osi/os/vxWorks/osdTime.cpp
210index 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 {
268diff --git a/src/libCom/osi/os/vxWorks/tz2timezone.c b/src/libCom/osi/os/vxWorks/tz2timezone.c
269new file mode 100644
270index 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(&current, 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, &current, start) != OK)
535+ return ERROR;
536+
537+ tz = strchr(tz + 1, ',');
538+ if (!tz)
539+ return ERROR;
540+ if (extractDate(tz, &current, 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+}
552diff --git a/src/libCom/osi/osiClockTime.c b/src/libCom/osi/osiClockTime.c
553index 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
602diff --git a/src/libCom/osi/osiClockTime.h b/src/libCom/osi/osiClockTime.h
603index 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

Subscribers

People subscribed via source and target branches