FreeRDP
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 
38 WINPR_PRAGMA_DIAG_PUSH
39 WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
40 WINPR_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 
49 WINPR_PRAGMA_DIAG_POP
50 
51 VOID Sleep(DWORD dwMilliseconds)
52 {
53  usleep(dwMilliseconds * 1000);
54 }
55 
56 DWORD 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  }
115 out:
116  pollset_uninit(&pollset);
117  return ret;
118 }
119 
120 #endif
121 
122 VOID 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 cyles 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 }