FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
sleep.c
1
20#include <winpr/config.h>
21
22#include <winpr/platform.h>
23#include <winpr/windows.h>
24
25#include <winpr/synch.h>
26
27#include "../log.h"
28#include "../thread/apc.h"
29#include "../thread/thread.h"
30#include "../synch/pollset.h"
31
32#define TAG WINPR_TAG("synch.sleep")
33
34#ifndef _WIN32
35
36#include <time.h>
37
38WINPR_PRAGMA_DIAG_PUSH
39WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
40WINPR_PRAGMA_DIAG_IGNORED_UNUSED_MACRO
41
42#ifdef WINPR_HAVE_UNISTD_H
43#ifndef _XOPEN_SOURCE
44#define _XOPEN_SOURCE 500 // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
45#endif
46#include <unistd.h>
47#endif
48
49WINPR_PRAGMA_DIAG_POP
50
51VOID Sleep(DWORD dwMilliseconds)
52{
53 usleep(dwMilliseconds * 1000);
54}
55
56DWORD SleepEx(DWORD dwMilliseconds, BOOL bAlertable)
57{
58 WINPR_THREAD* thread = winpr_GetCurrentThread();
59 WINPR_POLL_SET pollset;
60 int status = 0;
61 DWORD ret = WAIT_FAILED;
62 BOOL autoSignalled = 0;
63
64 if (thread)
65 {
66 /* treat re-entrancy if a completion is calling us */
67 if (thread->apc.treatingCompletions)
68 bAlertable = FALSE;
69 }
70 else
71 {
72 /* called from a non WinPR thread */
73 bAlertable = FALSE;
74 }
75
76 if (!bAlertable || !thread->apc.length)
77 {
78 usleep(dwMilliseconds * 1000);
79 return 0;
80 }
81
82 if (!pollset_init(&pollset, thread->apc.length))
83 {
84 WLog_ERR(TAG, "unable to initialize pollset");
85 return WAIT_FAILED;
86 }
87
88 if (!apc_collectFds(thread, &pollset, &autoSignalled))
89 {
90 WLog_ERR(TAG, "unable to APC file descriptors");
91 goto out;
92 }
93
94 if (!autoSignalled)
95 {
96 /* we poll and wait only if no APC member is ready */
97 status = pollset_poll(&pollset, dwMilliseconds);
98 if (status < 0)
99 {
100 WLog_ERR(TAG, "polling of apc fds failed");
101 goto out;
102 }
103 }
104
105 if (apc_executeCompletions(thread, &pollset, 0))
106 {
107 ret = WAIT_IO_COMPLETION;
108 }
109 else
110 {
111 /* according to the spec return value is 0 see
112 * https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepex*/
113 ret = 0;
114 }
115out:
116 pollset_uninit(&pollset);
117 return ret;
118}
119
120#endif
121
122VOID USleep(DWORD dwMicroseconds)
123{
124#ifndef _WIN32
125 usleep(dwMicroseconds);
126#else
127 static LARGE_INTEGER freq = { 0 };
128 LARGE_INTEGER t1 = { 0 };
129 LARGE_INTEGER t2 = { 0 };
130
131 QueryPerformanceCounter(&t1);
132
133 if (freq.QuadPart == 0)
134 {
135 QueryPerformanceFrequency(&freq);
136 }
137
138 // in order to save cpu cycles we use Sleep() for the large share ...
139 if (dwMicroseconds >= 1000)
140 {
141 Sleep(dwMicroseconds / 1000);
142 }
143 // ... and busy loop until all the requested micro seconds have passed
144 do
145 {
146 QueryPerformanceCounter(&t2);
147 } while (((t2.QuadPart - t1.QuadPart) * 1000000) / freq.QuadPart < dwMicroseconds);
148#endif
149}