1414 ********************************************************************/
1515
1616#include "osal.h"
17+ #include "osal_log.h"
1718
18- #define URESOLUTION 10
19+ #ifdef __GNUC__
20+ #define CC_THREAD_LOCAL __thread
21+ #elif defined(_MSC_VER )
22+ #define CC_THREAD_LOCAL __declspec (thread)
23+ #elif __STDC_VERSION__ >= 201112L
24+ #define CC_THREAD_LOCAL _Thread_local
25+ #else
26+ #error Cannot define CC_THREAD
27+ #endif
28+
29+ #define SCALE_100NS_PER_S 10000000ULL
30+ #define SCALE_100NS_PER_US 10ULL
31+
32+ typedef struct os_thread_state
33+ {
34+ HANDLE timer ;
35+ void (* entry ) (void * arg );
36+ void * arg ;
37+ } os_thread_state_t ;
38+
39+ static CC_THREAD_LOCAL os_thread_state_t * os_thread_state ;
1940
2041void * os_malloc (size_t size )
2142{
@@ -50,9 +71,73 @@ void os_mutex_destroy (os_mutex_t * mutex)
5071 CloseHandle (mutex );
5172}
5273
74+ static os_thread_state_t * os_thread_state_init (void (* entry ) (void * ), void * arg )
75+ {
76+ os_thread_state_t * state =
77+ (os_thread_state_t * )calloc (1 , sizeof (os_thread_state_t ));
78+ CC_ASSERT (state != NULL );
79+
80+ state -> entry = entry ;
81+ state -> arg = arg ;
82+ state -> timer = CreateWaitableTimerExA (
83+ NULL ,
84+ NULL ,
85+ CREATE_WAITABLE_TIMER_HIGH_RESOLUTION ,
86+ TIMER_ALL_ACCESS );
87+ CC_ASSERT (state -> timer != INVALID_HANDLE_VALUE );
88+
89+ return state ;
90+ }
91+
92+ static os_thread_state_t * os_thread_state_get (void )
93+ {
94+ if (os_thread_state == NULL )
95+ {
96+ os_thread_state = os_thread_state_init (NULL , NULL );
97+ }
98+ return os_thread_state ;
99+ }
100+
101+ static void os_thread_state_free (os_thread_state_t * state )
102+ {
103+ CloseHandle (state -> timer );
104+ free (state );
105+ }
106+
107+ static void os_internal_sleep (uint64_t delay_100_ns )
108+ {
109+ LARGE_INTEGER ft ;
110+ BOOL res ;
111+ DWORD event ;
112+ os_thread_state_t * state ;
113+
114+ state = os_thread_state_get ();
115+
116+ CC_ASSERT (delay_100_ns < INT64_MAX );
117+
118+ ft .QuadPart = - (int64_t )delay_100_ns ;
119+
120+ res = SetWaitableTimer (state -> timer , & ft , 0 , NULL , NULL , FALSE);
121+ CC_ASSERT (res );
122+
123+ event = WaitForSingleObject (state -> timer , INFINITE );
124+ CC_ASSERT (event == WAIT_OBJECT_0 );
125+ }
126+
53127void os_usleep (uint32_t usec )
54128{
55- Sleep (usec / 1000 );
129+ os_internal_sleep (SCALE_100NS_PER_US * usec );
130+ }
131+
132+ static void os_thread_entry (void * arg )
133+ {
134+ os_thread_state_t * state = arg ;
135+
136+ os_thread_state = state ;
137+ os_thread_state -> entry (os_thread_state -> arg );
138+ os_thread_state = NULL ;
139+
140+ os_thread_state_free (state );
56141}
57142
58143os_thread_t * os_thread_create (
@@ -63,8 +148,16 @@ os_thread_t * os_thread_create (
63148 void * arg )
64149{
65150 HANDLE handle ;
66- handle =
67- CreateThread (NULL , 0 , (LPTHREAD_START_ROUTINE )entry , (LPVOID )arg , 0 , NULL );
151+ os_thread_state_t * state ;
152+
153+ state = os_thread_state_init (entry , arg );
154+ handle = CreateThread (
155+ NULL ,
156+ 0 ,
157+ (LPTHREAD_START_ROUTINE )os_thread_entry ,
158+ (LPVOID )state ,
159+ 0 ,
160+ NULL );
68161 CC_ASSERT (handle != INVALID_HANDLE_VALUE );
69162
70163 if (priority < 5 )
@@ -84,7 +177,6 @@ static uint64_t os_get_frequency_tick (void)
84177 if (frequency == 0 )
85178 {
86179 LARGE_INTEGER performanceFrequency ;
87- timeBeginPeriod (URESOLUTION );
88180 QueryPerformanceFrequency (& performanceFrequency );
89181 frequency = performanceFrequency .QuadPart ;
90182 }
@@ -114,7 +206,11 @@ os_tick_t os_tick_from_us (uint32_t us)
114206
115207void os_tick_sleep (os_tick_t tick )
116208{
117- Sleep ((DWORD )(1000u * tick / os_get_frequency_tick ()));
209+ uint64_t delay ;
210+ delay = SCALE_100NS_PER_S ;
211+ delay *= tick ;
212+ delay /= os_get_frequency_tick ();
213+ os_internal_sleep (delay );
118214}
119215
120216os_sem_t * os_sem_create (size_t count )
@@ -304,15 +400,30 @@ void os_mbox_destroy (os_mbox_t * mbox)
304400 free (mbox );
305401}
306402
307- static VOID CALLBACK
308- timer_callback (UINT uTimerID , UINT uMsg , DWORD_PTR dwUser , DWORD_PTR dw1 , DWORD_PTR dw2 )
403+ static VOID CALLBACK timer_thread (void * arg )
309404{
310- os_timer_t * timer = (os_timer_t * )dwUser ;
405+ os_timer_t * timer = (os_timer_t * )arg ;
406+ BOOL res ;
311407
312- if (timer -> fn )
408+ while (timer -> run )
313409 {
314- timer -> fn (timer , timer -> arg );
410+ res = WaitForSingleObject (timer -> timer , INFINITE );
411+ CC_ASSERT (res == WAIT_OBJECT_0 );
412+
413+ if (!timer -> oneshot )
414+ {
415+ res = SetWaitableTimer (timer -> timer , & timer -> time , 0 , NULL , NULL , 0 );
416+ CC_ASSERT (res == TRUE);
417+ }
418+
419+ if (timer -> fn )
420+ {
421+ timer -> fn (timer , timer -> arg );
422+ }
315423 }
424+
425+ CloseHandle (timer -> timer );
426+ free (timer );
316427}
317428
318429os_timer_t * os_timer_create (
@@ -323,47 +434,61 @@ os_timer_t * os_timer_create (
323434{
324435 os_timer_t * timer ;
325436
326- timer = (os_timer_t * )malloc ( sizeof (* timer ));
437+ timer = (os_timer_t * )calloc ( 1 , sizeof (os_timer_t ));
327438
328439 timer -> fn = fn ;
329440 timer -> arg = arg ;
330- timer -> us = us ;
331441 timer -> oneshot = oneshot ;
442+ timer -> run = true;
443+
444+ os_timer_set (timer , us );
445+
446+ timer -> timer = CreateWaitableTimerExA (
447+ NULL ,
448+ NULL ,
449+ CREATE_WAITABLE_TIMER_HIGH_RESOLUTION ,
450+ TIMER_ALL_ACCESS );
451+ CC_ASSERT (timer -> timer != INVALID_HANDLE_VALUE );
452+
453+ HANDLE thread = CreateThread (
454+ NULL ,
455+ 0 ,
456+ (LPTHREAD_START_ROUTINE )timer_thread ,
457+ (LPVOID )timer ,
458+ 0 ,
459+ NULL );
460+ CC_ASSERT (thread != INVALID_HANDLE_VALUE );
461+
462+ SetThreadPriority (thread , THREAD_PRIORITY_TIME_CRITICAL );
463+
464+ /* Thread will clean itself up,
465+ we don't need this handle */
466+ CloseHandle (thread );
332467
333468 return timer ;
334469}
335470
336471void os_timer_set (os_timer_t * timer , uint32_t us )
337472{
338- timer -> us = us ;
473+ uint64_t delay = SCALE_100NS_PER_US * (uint64_t )us ;
474+ CC_ASSERT (delay < INT64_MAX );
475+ timer -> time .QuadPart = - (int64_t )(delay );
339476}
340477
341478void os_timer_start (os_timer_t * timer )
342479{
343- timeBeginPeriod (URESOLUTION );
344-
345- /****************************************************************
346- * N.B. The function timeSetEvent is obsolete. *
347- * The reason for still using it here is that it gives *
348- * much better resolution (15 ms -> 1 ms) than when *
349- * using the recommended function CreateTimerQueueTimer. *
350- ****************************************************************/
351- timer -> timerID = timeSetEvent (
352- timer -> us / 1000 ,
353- URESOLUTION ,
354- timer_callback ,
355- (DWORD_PTR )timer ,
356- (timer -> oneshot ) ? TIME_ONESHOT : TIME_PERIODIC );
480+ BOOL res ;
481+ res = SetWaitableTimer (timer -> timer , & timer -> time , 0 , NULL , NULL , FALSE);
482+ CC_ASSERT (res == TRUE);
357483}
358484
359485void os_timer_stop (os_timer_t * timer )
360486{
361- timeKillEvent (timer -> timerID );
362-
363- timeEndPeriod (URESOLUTION );
487+ CancelWaitableTimer (timer -> timer );
364488}
365489
366490void os_timer_destroy (os_timer_t * timer )
367491{
368- free (timer );
492+ CancelWaitableTimer (timer -> timer );
493+ timer -> run = false;
369494}
0 commit comments