1 /*----------------------------------------------------------------------------
2 Name: Timestampc.c
3 Project: xmlBlaster.org
4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
5 Comment: Time handling and unique counter
6 Author: "Marcel Ruff" <xmlBlaster@marcelruff.info>
7 See: http://www.xmlblaster.org/xmlBlaster/doc/requirements/protocol.socket.html
8 -----------------------------------------------------------------------------*/
9 #include <stdio.h> /* snprintf */
10 #include <string.h> /* memset */
11 #include "basicDefs.h"
12 #include "helper.h"
13 #include "Timestampc.h"
14
15 #ifdef _WINDOWS
16 # if defined(WINCE)
17 /* time between jan 1, 1601 and jan 1, 1970 in units of 100 nanoseconds */
18 # if !defined(PTW32_TIMESPEC_TO_FILETIME_OFFSET)
19 # define PTW32_TIMESPEC_TO_FILETIME_OFFSET \
20 ( ((LONGLONG) 27111902 << 32) + (LONGLONG) 3577643008 )
21 # endif
22 # else
23 # include <sys/timeb.h>
24 # endif
25 # if XB_USE_PTHREADS
26 # include <pthreads/pthread.h> /* Our pthreads.h: For logging output of thread ID, for Windows and WinCE downloaded from http://sources.redhat.com/pthreads-win32 */
27 # endif
28 #else
29 # include <unistd.h> /* sleep(), only used in main */
30 # include <errno.h> /* errno */
31 # include <sys/time.h> /* sleep with select(), gettimeofday() */
32 # if XB_USE_PTHREADS
33 # include <pthread.h> /* The original pthreads.h from the OS */
34 # endif
35 # include <inttypes.h> /* PRId64 %lld format specifier */
36 #endif
37
38 #define MICRO_SECS_PER_SECOND 1000000
39 #define NANO_SECS_PER_SECOND MICRO_SECS_PER_SECOND * 1000
40
41
42 #if XB_USE_PTHREADS
43 static pthread_mutex_t tsMutex = PTHREAD_MUTEX_INITIALIZER;
44 /*pthread_mutex_init(&tsMutex, NULL); */
45 /*pthread_mutex_destroy(&tsMutex);*/
46 #endif
47
48 /**
49 * Create a timestamp in nano seconds elapsed since 1970-01-01.
50 * The timestamp is guaranteed to be ascending and unique.
51 * <p>
52 * The call is thread safe
53 */
54 Dll_Export int64_t getTimestamp() {
55 struct timespec abstime;
56 int64_t timestamp;
57 static int64_t lastNanos=0;
58
59 getAbsoluteTime(0L, &abstime);
60
61 timestamp = (int64_t)abstime.tv_sec * NANO_SECS_PER_SECOND;
62 timestamp += abstime.tv_nsec;
63 # if XB_USE_PTHREADS
64 pthread_mutex_lock(&tsMutex);
65 # endif
66 if (timestamp <= lastNanos) {
67 timestamp = lastNanos + 1;
68 }
69 lastNanos = timestamp;
70 # if XB_USE_PTHREADS
71 pthread_mutex_unlock(&tsMutex);
72 # endif
73 return timestamp;
74 }
75
76 Dll_Export char *getTimestampStr(char *buf, size_t buflen) {
77 int64_t ts = getTimestamp(); /* INT_LEAST64_MAX=9223372036854775807 */
78 SNPRINTF(buf, buflen, PRINTF_PREFIX_INT64_T, ts); /* Windows does not know "%"PRId64 (from inttypes.h) */
79 return buf;
80 }
81
82 /**
83 * Fills the given abstime with absolute time, using the given timeout relativeTimeFromNow in milliseconds
84 * On Linux < 2.5.64 does not support high resolution timers clock_gettime(),
85 * but patches are available at http://sourceforge.net/projects/high-res-timers
86 * @param relativeTimeFromNow the relative time from now in milliseconds
87 * @param abstime
88 * @return true If implemented
89 */
90 Dll_Export bool getAbsoluteTime(long relativeTimeFromNow, struct timespec *abstime)
91 {
92 # if defined(WINCE)
93 /* Copied from pthreads_win32: thank you! */
94 FILETIME ft;
95 SYSTEMTIME st;
96 GetSystemTime(&st);
97 SystemTimeToFileTime(&st, &ft);
98 /*
99 * GetSystemTimeAsFileTime(&ft); would be faster,
100 * but it does not exist on WinCE
101 */
102 /*
103 * -------------------------------------------------------------------
104 * converts FILETIME (as set by GetSystemTimeAsFileTime), where the time is
105 * expressed in 100 nanoseconds from Jan 1, 1601,
106 * into struct timespec
107 * where the time is expressed in seconds and nanoseconds from Jan 1, 1970.
108 * -------------------------------------------------------------------
109 */
110 abstime->tv_sec =
111 (int) ((*(LONGLONG *) &ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
112 abstime->tv_nsec =
113 (int) ((*(LONGLONG *) &ft - PTW32_TIMESPEC_TO_FILETIME_OFFSET -
114 ((LONGLONG) abstime->tv_sec * (LONGLONG) 10000000)) * 100);
115
116 if (relativeTimeFromNow > 0) {
117 abstime->tv_sec += relativeTimeFromNow / 1000;
118 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
119 }
120 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
121 abstime->tv_nsec -= NANO_SECS_PER_SECOND;
122 abstime->tv_sec += 1;
123 }
124 return true;
125
126 # elif defined(_WINDOWS)
127 struct _timeb tm;
128 # if _MSC_VER >= 1400 /* _WINDOWS: 1200->VC++6.0, 1310->VC++7.1 (2003), 1400->VC++8.0 (2005) */
129 errno_t err = _ftime_s(&tm);
130 if (err) return false;
131 # else
132 (void) _ftime(&tm);
133 # endif
134
135 abstime->tv_sec = (long)tm.time;
136 abstime->tv_nsec = tm.millitm * 1000 * 1000; /* TODO !!! How to get the more precise current time on Win? */
137
138 if (relativeTimeFromNow > 0) {
139 abstime->tv_sec += relativeTimeFromNow / 1000;
140 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
141 }
142 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
143 abstime->tv_nsec -= NANO_SECS_PER_SECOND;
144 abstime->tv_sec += 1;
145 }
146 return true;
147 # else /* LINUX, __sun */
148 struct timeval tv;
149
150 memset(abstime, 0, sizeof(struct timespec));
151
152 /* Better?
153 if (clock_gettime(CLOCK_REALTIME, &abstime) == -1) {
154 printf("Timeout.c clock_gettime failed%d\n", errno);
155 }
156 */
157
158 gettimeofday(&tv, 0);
159 abstime->tv_sec = tv.tv_sec;
160 abstime->tv_nsec = tv.tv_usec * 1000; /* microseconds to nanoseconds */
161
162 if (relativeTimeFromNow > 0) {
163 abstime->tv_sec += relativeTimeFromNow / 1000;
164 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
165 }
166 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
167 abstime->tv_nsec -= NANO_SECS_PER_SECOND;
168 abstime->tv_sec += 1;
169 }
170 return true;
171 # endif
172 # ifdef MORE_REALTIME
173 clock_gettime(CLOCK_REALTIME, abstime);
174
175 if (relativeTimeFromNow > 0) {
176 abstime->tv_sec += relativeTimeFromNow / 1000;
177 abstime->tv_nsec += (relativeTimeFromNow % 1000) * 1000 * 1000;
178 }
179 if (abstime->tv_nsec >= NANO_SECS_PER_SECOND) {
180 abstime->tv_nsec -= NANO_SECS_PER_SECOND;
181 abstime->tv_sec += 1;
182 }
183 return true;
184 # endif
185 }
186
187 /**
188 * Get current timestamp string in ISO 8601 notation.
189 * @param bufSize at least 26
190 * @param timeStr out parameter, filled with e.g. "1997-07-16T19:20:30.45-02:00"
191 * @return Your param timeStr for easy usage in printf() and such
192 * @see http://en.wikipedia.org/wiki/ISO_8601
193 */
194 Dll_Export const char *getCurrentLocalIsoTimestampStr(char *timeStr, int bufSize) {
195 # if defined(WINCE)
196 /*http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcekernl/html/_wcesdk_win32_systemtime_str.asp*/
197 SYSTEMTIME st;
198 GetSystemTime(&st);
199 snprintf0(timeStr, bufSize, "%hd-%hd-%hdT%hd:%hd:%hd.%hd\n", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
200 # elif _MSC_VER >= 1400
201 /* TODO */
202 /*__time64_t timer;
203 _time64(&timer);*/
204 time_t t1; /* unsigned long */
205 (void) time(&t1); /* in seconds since the Epoch. 1970 */
206 ctime_s(timeStr, bufSize-1, &t1);
207 # elif defined(_WINDOWS)
208 /* TODO */
209 time_t t1; /* unsigned long */
210 (void) time(&t1);
211 strncpy0(timeStr, ctime(&t1), bufSize);
212 # elif defined(__sun)
213 /* TODO */
214 time_t t1; /* unsigned long */
215 (void) time(&t1);
216 ctime_r(&t1, (char *)timeStr, bufSize-1);
217 # else
218 time_t t1; /* unsigned long */
219 struct tm st;
220 (void) time(&t1);
221 /*ctime_r(&t1, (char *)timeStr);*/
222 gmtime_r(&t1, &st); /* TODO: localtime_r() with zone offset*/
223 snprintf0(timeStr, (size_t)bufSize,
224 "20%0.2hd-%0.2hd-%0.2hdT%0.2hd:%0.2hd:%0.2hdZ\n", st.tm_year - 100,
225 st.tm_mon + 1, st.tm_mday, st.tm_hour, st.tm_min, st.tm_sec);
226 # endif
227 *(timeStr + strlen(timeStr) - 1) = '\0'; /* strip \n */
228 return timeStr;
229 }
230
231 /**
232 * Get a human readable time string for logging.
233 * @param timeStr out parameter, e.g. "12:34:46" or "2006-11-14 12:34:46"
234 * @param bufSize The size of timeStr
235 * @return timeStr Your parameter given (for easy usage in printf())
236 */
237 Dll_Export const char *getCurrentTimeStr(char *timeStr, int bufSize) {
238 # if defined(WINCE)
239 /*http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcekernl/html/_wcesdk_win32_systemtime_str.asp*/
240 SYSTEMTIME st;
241 GetSystemTime(&st);
242 snprintf0(timeStr, bufSize, "%hd:%hd:%hd\n", st.wHour, st.wMinute, st.wSecond);
243 /*wDay, wMilliseconds etc. */
244 # elif _MSC_VER >= 1400
245 /*__time64_t timer;
246 _time64(&timer);*/
247 time_t t1; /* unsigned long */
248 (void) time(&t1); /* in seconds since the Epoch. 1970 */
249 ctime_s(timeStr, bufSize-1, &t1);
250 # elif defined(_WINDOWS)
251 time_t t1; /* unsigned long */
252 (void) time(&t1);
253 strncpy0(timeStr, ctime(&t1), bufSize);
254 # elif defined(__sun)
255 time_t t1; /* unsigned long */
256 (void) time(&t1);
257 ctime_r(&t1, (char *)timeStr, bufSize-1);
258 # else
259 time_t t1; /* unsigned long */
260 (void) time(&t1);
261 ctime_r(&t1, (char *)timeStr);
262 if (bufSize > 0) bufSize = 0; /* to avoid compiler warning */
263 # endif
264 *(timeStr + strlen(timeStr) - 1) = '\0'; /* strip \n */
265 return timeStr;
266 }
syntax highlighted by Code2HTML, v. 0.9.1