mbgtools-lx  4.2.8
mbgsystm.h
Go to the documentation of this file.
1 
2 /**************************************************************************
3  *
4  * $Id: mbgsystm.h 1.5 2019/02/08 11:05:48 martin TRASH $
5  *
6  * Copyright (c) Meinberg Funkuhren, Bad Pyrmont, Germany
7  *
8  * Description:
9  * Generic functions and definitions to deal with the computer's
10  * system time, and prototypes for mbgsystm.c.
11  *
12  * -----------------------------------------------------------------------
13  * $Log: mbgsystm.h $
14  * Revision 1.5 2019/02/08 11:05:48 martin
15  * Commonly use int64_t for MBG_SYS_TIME on Windows, rather than
16  * FILETIME in user space and LARGE_INTEGER in kernel space.
17  * Also use a function pointer to read the Windows system time
18  * depending on whether the precise time API calls are supported
19  * by the running Windows system, or not.
20  * Revision 1.4 2018/07/16 12:32:58 martin
21  * Fixed do_div() for 32 bit ARM Linux kernel.
22  * Include another header file on NetBSD.
23  * Revision 1.3 2017/07/26 14:26:17 martin
24  * Fixed build for NetBSD.
25  * Revision 1.2 2017/07/04 12:26:57 martin
26  * More detailed control of inclusion of other headers.
27  * Made mbg_delta_sys_time_ms() as inline function here.
28  * Updated function prototypes.
29  * Cleanup.
30  * Revision 1.1 2015/09/15 13:21:00Z martin
31  * Initial revision.
32  * Moved existing code from different modules here.
33  *
34  **************************************************************************/
35 
36 #ifndef _MBGSYSTM_H
37 #define _MBGSYSTM_H
38 
39 
40 /* Other headers to be included */
41 
42 #include <mbg_tgt.h>
43 #include <words.h>
44 
45 #if defined( MBG_TGT_POSIX )
46 
47  #if defined( MBG_TGT_KERNEL )
48 
49  #if defined( MBG_TGT_LINUX )
50 
51  #define LINUX_KERNEL_HAS_MSLEEP ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 16 ) )
52  #define LINUX_KERNEL_HAS_GETNSTIMEOFDAY ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 22 ) )
53  #define LINUX_KERNEL_HAS_KTIME_H ( LINUX_VERSION_CODE >= KERNEL_VERSION( 2, 6, 16 ) )
54 
55  #if !LINUX_KERNEL_HAS_MSLEEP
56  #include <linux/wait.h>
57  #include <linux/sched.h>
58  #endif
59 
60  // We need the prototype for getnstimeofday(). In newer kernels
61  // (e.g. 4.x) this is available via linux/ktime.h, which in turn
62  // includes linux/timekeeping.h, which declares the prototype.
63  #if LINUX_KERNEL_HAS_KTIME_H
64  #include <linux/ktime.h>
65  #endif
66 
67  // In older kernel versions the prototype for getnstimeofday()
68  // is declared in linux/time.h, so we include that one anyway.
69  #include <linux/time.h>
70 
71  #include <linux/delay.h>
72  #include <linux/jiffies.h>
73 
74  #elif defined( MBG_TGT_BSD )
75 
76  #if defined( MBG_TGT_FREEBSD )
77  #include <sys/libkern.h>
78  #endif
79 
80  #if defined( MBG_TGT_NETBSD )
81  #include <sys/param.h> // mstohz
82  #include <sys/kernel.h> // hz
83  #include <sys/proc.h> // kpause
84  #endif
85 
86  #include <sys/time.h>
87 
88  #endif
89 
90  #else // POSIX user space
91 
92  #include <time.h>
93 
94  #if defined( MBG_TGT_LINUX )
95  #include <sys/sysinfo.h>
96  #endif
97 
98  #endif
99 
100 #elif defined( MBG_TGT_WIN32 )
101 
102  #if defined( MBG_TGT_KERNEL )
103  #include <mbg_w32.h> // ke_query_system_time_fnc
104  #else
105  #include <timeutil.h> // gstaft_fnc
106  #endif
107 
108  #include <mbgtime.h>
109 
110 #elif defined( MBG_TGT_DOS )
111 
112  #include <dos.h>
113 
114 #endif
115 
116 
117 #ifdef _MBGSYSTM
118  #define _ext
119  #define _DO_INIT
120 #else
121  #define _ext extern
122 #endif
123 
124 
125 /* Start of header body */
126 
127 #ifdef __cplusplus
128 extern "C" {
129 #endif
130 
131 
132 /*
133  * Generic types to hold system timestamps and values for the system uptime..
134  */
135 #if defined( MBG_TGT_POSIX )
136 
138  typedef int64_t MBG_SYS_UPTIME; // [s]
139 
140 #elif defined( MBG_TGT_WIN32 )
141 
142  typedef int64_t MBG_SYS_TIME; // Number of 100ns units
143  typedef int64_t MBG_SYS_UPTIME; // [s]
144 
145 #elif defined( MBG_TGT_OS2 )
146 
147  typedef uint32_t MBG_SYS_TIME; //## dummy
148  typedef long MBG_SYS_UPTIME; //## dummy
149 
150 #elif defined( MBG_TGT_DOS )
151 
152  typedef uint32_t MBG_SYS_TIME; //## dummy
153  typedef long MBG_SYS_UPTIME; //## dummy
154 
155 #else // other target OSs which access the hardware directly
156 
157  typedef uint32_t MBG_SYS_TIME; //## dummy
158  typedef long MBG_SYS_UPTIME; //## dummy
159 
160 #endif
161 
162 //### TODO
163 // MBG_SYS_TIME is always read in native machine endianess,
164 // so no need to convert endianess.
165 #define _mbg_swab_mbg_sys_time( _p ) \
166  _nop_macro_fnc()
167 
168 
169 
170 static __mbg_inline
171 void mbg_get_sys_time( MBG_SYS_TIME *p )
172 {
173  #if defined( MBG_TGT_POSIX )
174 
175  #if defined( MBG_TGT_KERNEL ) // kernel space functions even differ for POSIX systems
176 
177  #if defined( MBG_TGT_LINUX ) // Linux kernel space
178 
179  #if ( LINUX_KERNEL_HAS_GETNSTIMEOFDAY )
180  {
181  // getnstimeofday() supported
182  struct timespec ts;
183 
184  getnstimeofday( &ts );
185 
186  p->secs = ts.tv_sec;
187  p->nano_secs = ts.tv_nsec;
188  }
189  #else
190  {
191  // getnstimeofday() *not* supported
192  struct timeval tv;
193 
194  do_gettimeofday( &tv );
195 
196  p->secs = tv.tv_sec;
197  p->nano_secs = tv.tv_usec * 1000;
198  }
199  #endif
200 
201  #elif defined( MBG_TGT_BSD ) // BSD kernel space
202  {
203  struct timespec ts;
204 
205  nanotime( &ts );
206 
207  p->secs = ts.tv_sec;
208  p->nano_secs = ts.tv_nsec;
209  }
210  #endif
211 
212  #else // POSIX user space
213  {
214  struct timespec ts;
215 
216  #if defined( CLOCK_REALTIME_PRECISE ) // at least available in FreeBSD
217  clock_gettime( CLOCK_REALTIME_PRECISE, &ts );
218  #else
219  clock_gettime( CLOCK_REALTIME, &ts );
220  #endif
221 
222  p->secs = ts.tv_sec;
223  p->nano_secs = ts.tv_nsec;
224  }
225  #endif
226 
227  #elif defined( MBG_TGT_WIN32 )
228 
229  #if defined( MBG_TGT_KERNEL ) // Windows kernel space
230  ke_query_system_time_fnc( (LARGE_INTEGER *) p );
231  #else // Windows user space
232  {
233  gstaft_fnc( (FILETIME *) p );
234  }
235  #endif
236 
237  #else
238 
239  *p = 0; // dummy
240 
241  #endif
242 
243 } // mbg_get_sys_time
244 
245 
246 
247 static __mbg_inline
248 void mbg_get_sys_uptime( MBG_SYS_UPTIME *p )
249 {
250  #if defined( MBG_TGT_WIN32 )
251 
252  #if defined( MBG_TGT_KERNEL ) // kernel space
253 
254  ULONGLONG time_increment = KeQueryTimeIncrement();
255  LARGE_INTEGER tick_count;
256 
257  KeQueryTickCount( &tick_count );
258 
259  // multiplication by time_increment yields HNS units,
260  // but we need seconds
261  *p = ( tick_count.QuadPart * time_increment ) / HNS_PER_SEC;
262 
263  #else // user space
264 
265  DWORD tickCount;
266  DWORD timeAdjustment;
267  DWORD timeIncrement;
268  BOOL timeAdjustmentDisabled;
269 
270  if ( !GetSystemTimeAdjustment( &timeAdjustment, &timeIncrement, &timeAdjustmentDisabled ) )
271  *p = -1; // failed
272 
273  // ATTENTION: This is compatible with older Windows versions, but
274  // the returned tick count wraps around to zero after 49.7 days.
275  // A new GetTickCount64() call is available under Windows Vista and newer,
276  // but the function call had to be imported dynamically since otherwise
277  // programs refused to start under pre-Vista versions due to undefined DLL symbol.
278  tickCount = GetTickCount();
279 
280  *p = ( ( (MBG_SYS_UPTIME) tickCount ) * timeIncrement ) / HNS_PER_SEC;
281 
282  #endif
283 
284  #elif defined( MBG_TGT_LINUX )
285 
286  #if defined( MBG_TGT_KERNEL )
287  // getrawmonotonic() can possibly be used for this in newer kernels
288  {
289  // Using a simple 64 bit division may result in a linker error
290  // in kernel mode due to a missing symbol __udivdi3, so we use
291  // a specific inline function do_div().
292  // Also, the jiffies counter is not set to 0 at startup but to
293  // a defined initialization value we need to account for.
294  uint64_t tmp = get_jiffies_64() - INITIAL_JIFFIES;
295  do_div( tmp, HZ );
296  *p = tmp;
297  }
298  #else
299  {
300  struct sysinfo si;
301  int rc = sysinfo( &si );
302  *p = ( rc == 0 ) ? si.uptime : -1;
303  }
304  #endif
305 
306  #elif defined( MBG_TGT_BSD )
307 
308  #if defined( MBG_TGT_KERNEL )
309  {
310  struct timespec ts;
311  #if 0 //##+++++++
312  {
313  struct bintime bt;
314 
315  binuptime( &bt );
316  #if defined( DEBUG )
317  printf( "binuptime: %lli.%09lli\n",
318  (long long) bt.sec,
319  (long long) bt.frac );
320  #endif
321  }
322  #endif
323 
324  nanouptime( &ts );
325  #if defined( DEBUG )
326  printf( "nanouptime: %lli.%09lli\n",
327  (long long) ts.tv_sec,
328  (long long) ts.tv_nsec );
329  #endif
330  *p = ts.tv_sec;
331  }
332  #elif defined( MBG_TGT_FREEBSD )
333  {
334  struct timespec ts;
335  // CLOCK_UPTIME_FAST is specific to FreeBSD
336  int rc = clock_gettime( CLOCK_UPTIME_FAST, &ts );
337  *p = ( rc == 0 ) ? ts.tv_sec : -1;
338  }
339  #else // MBG_TGT_NETBSD, ...
340 
341  *p = -1; //##++ needs to be implemented
342 
343  #endif
344 
345  #else
346 
347  *p = -1; // not supported
348 
349  #endif
350 
351 } // mbg_get_sys_uptime
352 
353 
354 
363 static __mbg_inline
364 long mbg_delta_sys_time_ms( const MBG_SYS_TIME *t2, const MBG_SYS_TIME *t1 )
365 {
366  #if defined( MBG_TGT_POSIX )
367  long dt = ( t2->secs - t1->secs ) * 1000;
368  #if defined ( MBG_TGT_LINUX ) && defined( MBG_TGT_KERNEL )
369  uint64_t tmp64 = t2->nano_secs - t1->nano_secs;
370  do_div( tmp64, 1000000 );
371  dt += tmp64;
372  #else
373  dt += ( t2->nano_secs - t1->nano_secs ) / 1000000;
374  #endif
375  return dt;
376  #elif defined( MBG_TGT_WIN32 )
377  return (long) ( ( *t2 - *t1 ) / HNS_PER_MS );
378  #else
379  return 0;
380  #endif
381 
382 } // mbg_delta_sys_time_ms
383 
384 
385 
386 static __mbg_inline
387 void mbg_sleep_sec( long sec )
388 {
389  #if defined( MBG_TGT_POSIX )
390 
391  #if defined( MBG_TGT_KERNEL ) // kernel space functions even differ for POSIX systems
392 
393  #if defined( MBG_TGT_LINUX ) // Linux kernel space
394 
395  // msleep is not defined in older kernels, so we use this
396  // only if it is surely supported.
397  #if LINUX_KERNEL_HAS_MSLEEP
398  msleep( sec * 1000 );
399  #else
400  {
401  DECLARE_WAIT_QUEUE_HEAD( tmp_wait );
402  wait_event_interruptible_timeout( tmp_wait, 0, sec * HZ + 1 );
403  }
404  #endif
405 
406  #elif defined( MBG_TGT_FREEBSD )
407 
408  struct timeval tv = { 0 };
409  int ticks;
410  tv.tv_sec = sec;
411  ticks = tvtohz( &tv );
412 
413  #if defined( DEBUG )
414  printf( "pause: %lli.%06lli (%i ticks)\n",
415  (long long) tv.tv_sec,
416  (long long) tv.tv_usec,
417  ticks );
418  #endif
419 
420  pause( "pause", ticks );
421 
422  #elif defined( MBG_TGT_NETBSD )
423 
424  int timeo = mstohz( sec * 1000 );
425 
426  #if defined( DEBUG )
427  printf( "kpause: %i s (%i ticks)\n", sec, timeo );
428  #endif
429 
430  kpause( "pause", 1, timeo, NULL );
431 
432  #endif
433 
434  #else // POSIX user space
435 
436  sleep( sec );
437 
438  #endif
439 
440  #elif defined( MBG_TGT_WIN32 )
441 
442  #if defined( MBG_TGT_KERNEL ) // kernel space
443 
444  LARGE_INTEGER delay;
445 
446  // we need to pass a negative value to KeDelayExecutionThread()
447  // since the given time is a relative time interval, not absolute
448  // time. See the API docs for KeDelayExecutionThread().
449  delay.QuadPart = - ((LONGLONG) sec * HNS_PER_SEC);
450 
451  KeDelayExecutionThread( KernelMode, FALSE, &delay );
452 
453  #else // user space
454 
455  // Sleep() expects milliseconds
456  Sleep( sec * 1000 );
457 
458  #endif
459 
460  #elif defined( MBG_TGT_DOS )
461 
462  delay( (unsigned) ( sec * 1000 ) );
463 
464  #else
465 
466  // This needs to be implemented for the target OS
467  // and thus will probably yield a linker error.
468  do_sleep_sec( sec );
469 
470  #endif
471 
472 } // mbg_sleep_sec
473 
474 
475 
476 /* ----- function prototypes begin ----- */
477 
478 /* This section was generated automatically */
479 /* by MAKEHDR, do not remove the comments. */
480 
481 /* (no header definitions found) */
482 
483 /* ----- function prototypes end ----- */
484 
485 #ifdef __cplusplus
486 }
487 #endif
488 
489 /* End of header body */
490 
491 #undef _ext
492 #undef _DO_INIT
493 
494 #endif /* _MBGSYSTM_H */
#define HNS_PER_MS
Definition: mbgtime.h:272
A timestamp with nanosecond resolution, but 64 bit size.
Definition: words.h:621
static __mbg_inline void mbg_get_sys_uptime(MBG_SYS_UPTIME *p)
Definition: mbgsystm.h:248
static __mbg_inline void mbg_get_sys_time(MBG_SYS_TIME *p)
Definition: mbgsystm.h:171
static __mbg_inline long mbg_delta_sys_time_ms(const MBG_SYS_TIME *t2, const MBG_SYS_TIME *t1)
Compute delta between two MBG_SYS_TIME times, in milliseconds.
Definition: mbgsystm.h:364
__int64 int64_t
Definition: words.h:249
#define FILETIME
Definition: mbgdevio.h:456
uint32_t DWORD
Definition: mbgerror.h:222
static __mbg_inline void mbg_sleep_sec(long sec)
Definition: mbgsystm.h:387
NANO_TIME_64 MBG_SYS_TIME
Definition: mbgsystm.h:137
#define HNS_PER_SEC
Definition: mbgtime.h:268
int64_t MBG_SYS_UPTIME
Definition: mbgsystm.h:138
int64_t nano_secs
[nanoseconds]
Definition: words.h:628
int64_t secs
[seconds], usually since 1970-01-01 00:00:00
Definition: words.h:627
unsigned __int64 uint64_t
Definition: words.h:250