features.h: support POSIX.1-2024
[newlib-cygwin.git] / winsup / cygwin / miscfuncs.cc
blob767384faa9aefcd09798eb8f37a15b942ab97b47
1 /* miscfuncs.cc: misc funcs that don't belong anywhere else
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include "miscfuncs.h"
11 #include <sys/uio.h>
12 #include "ntdll.h"
13 #include "path.h"
14 #include "fhandler.h"
15 #include "tls_pbuf.h"
17 /* not yet prototyped in w32api */
18 extern "C" HRESULT SetThreadDescription (HANDLE hThread, PCWSTR lpThreadDescription);
20 /* Get handle count of an object. */
21 ULONG
22 get_obj_handle_count (HANDLE h)
24 OBJECT_BASIC_INFORMATION obi;
25 NTSTATUS status;
26 ULONG hdl_cnt = 0;
28 status = NtQueryObject (h, ObjectBasicInformation, &obi, sizeof obi, NULL);
29 if (!NT_SUCCESS (status))
30 debug_printf ("NtQueryObject: %y", status);
31 else
32 hdl_cnt = obi.HandleCount;
33 return hdl_cnt;
36 static char __attribute__ ((noinline))
37 dummytest (volatile char *p)
39 return *p;
42 ssize_t
43 check_iovec (const struct iovec *iov, int iovcnt, bool forwrite)
45 if (iovcnt < 0 || iovcnt > IOV_MAX)
47 set_errno (EINVAL);
48 return -1;
51 __try
54 size_t tot = 0;
56 while (iovcnt > 0)
58 if (iov->iov_len > SSIZE_MAX || (tot += iov->iov_len) > SSIZE_MAX)
60 set_errno (EINVAL);
61 __leave;
64 volatile char *p = ((char *) iov->iov_base) + iov->iov_len - 1;
65 if (!iov->iov_len)
66 /* nothing to do */;
67 else if (!forwrite)
68 *p = dummytest (p);
69 else
70 dummytest (p);
72 iov++;
73 iovcnt--;
76 if (tot <= SSIZE_MAX)
77 return (ssize_t) tot;
79 set_errno (EINVAL);
81 __except (EFAULT)
82 __endtry
83 return -1;
86 /* Try hard to schedule another thread.
87 Remember not to call this in a lock condition or you'll potentially
88 suffer starvation. */
89 void
90 yield ()
92 /* MSDN implies that Sleep will force scheduling of other threads.
93 Unlike SwitchToThread() the documentation does not mention other
94 cpus so, presumably (hah!), this + using a lower priority will
95 stall this thread temporarily and cause another to run.
96 (stackoverflow and others seem to confirm that setting this thread
97 to a lower priority and calling Sleep with a 0 paramenter will
98 have this desired effect)
100 CV 2017-03-08: Drop lowering the priority. It leads to potential
101 starvation and it should not be necessary anymore
102 since Server 2003. See the MSDN Sleep man page. */
103 Sleep (0L);
106 /* Get a default value for the nice factor. When changing these values,
107 have a look into the below function nice_to_winprio. The values must
108 match the layout of the static "priority" array. */
110 winprio_to_nice (DWORD prio)
112 switch (prio)
114 case REALTIME_PRIORITY_CLASS:
115 return -20;
116 case HIGH_PRIORITY_CLASS:
117 return -16;
118 case ABOVE_NORMAL_PRIORITY_CLASS:
119 return -8;
120 case NORMAL_PRIORITY_CLASS:
121 return 0;
122 case BELOW_NORMAL_PRIORITY_CLASS:
123 return 8;
124 case IDLE_PRIORITY_CLASS:
125 return 16;
127 return 0;
130 /* Get a Win32 priority matching the incoming nice factor. The incoming
131 nice is limited to the interval [-NZERO,NZERO-1]. */
132 DWORD
133 nice_to_winprio (int &nice)
135 static const DWORD priority[] =
137 REALTIME_PRIORITY_CLASS, /* 0 */
138 HIGH_PRIORITY_CLASS, /* 1 */
139 HIGH_PRIORITY_CLASS,
140 HIGH_PRIORITY_CLASS,
141 HIGH_PRIORITY_CLASS,
142 HIGH_PRIORITY_CLASS,
143 HIGH_PRIORITY_CLASS,
144 HIGH_PRIORITY_CLASS, /* 7 */
145 ABOVE_NORMAL_PRIORITY_CLASS, /* 8 */
146 ABOVE_NORMAL_PRIORITY_CLASS,
147 ABOVE_NORMAL_PRIORITY_CLASS,
148 ABOVE_NORMAL_PRIORITY_CLASS,
149 ABOVE_NORMAL_PRIORITY_CLASS,
150 ABOVE_NORMAL_PRIORITY_CLASS,
151 ABOVE_NORMAL_PRIORITY_CLASS,
152 ABOVE_NORMAL_PRIORITY_CLASS, /* 15 */
153 NORMAL_PRIORITY_CLASS, /* 16 */
154 NORMAL_PRIORITY_CLASS,
155 NORMAL_PRIORITY_CLASS,
156 NORMAL_PRIORITY_CLASS,
157 NORMAL_PRIORITY_CLASS,
158 NORMAL_PRIORITY_CLASS,
159 NORMAL_PRIORITY_CLASS,
160 NORMAL_PRIORITY_CLASS, /* 23 */
161 BELOW_NORMAL_PRIORITY_CLASS, /* 24 */
162 BELOW_NORMAL_PRIORITY_CLASS,
163 BELOW_NORMAL_PRIORITY_CLASS,
164 BELOW_NORMAL_PRIORITY_CLASS,
165 BELOW_NORMAL_PRIORITY_CLASS,
166 BELOW_NORMAL_PRIORITY_CLASS,
167 BELOW_NORMAL_PRIORITY_CLASS,
168 BELOW_NORMAL_PRIORITY_CLASS, /* 31 */
169 IDLE_PRIORITY_CLASS, /* 32 */
170 IDLE_PRIORITY_CLASS,
171 IDLE_PRIORITY_CLASS,
172 IDLE_PRIORITY_CLASS,
173 IDLE_PRIORITY_CLASS,
174 IDLE_PRIORITY_CLASS,
175 IDLE_PRIORITY_CLASS,
176 IDLE_PRIORITY_CLASS /* 39 */
178 if (nice < -NZERO)
179 nice = -NZERO;
180 else if (nice > NZERO - 1)
181 nice = NZERO - 1;
182 DWORD prio = priority[nice + NZERO];
183 return prio;
186 /* Minimal overlapped pipe I/O implementation for signal and commune stuff. */
188 BOOL
189 CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa)
191 int ret = fhandler_pipe::create (sa, hr, hw, 0, NULL,
192 FILE_FLAG_OVERLAPPED);
193 if (ret)
194 SetLastError (ret);
195 return ret == 0;
198 BOOL
199 ReadPipeOverlapped (HANDLE h, PVOID buf, DWORD len, LPDWORD ret_len,
200 DWORD timeout)
202 OVERLAPPED ov;
203 BOOL ret;
205 memset (&ov, 0, sizeof ov);
206 ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
207 ret = ReadFile (h, buf, len, NULL, &ov);
208 if (ret || GetLastError () == ERROR_IO_PENDING)
210 if (!ret && WaitForSingleObject (ov.hEvent, timeout) != WAIT_OBJECT_0)
211 CancelIo (h);
212 ret = GetOverlappedResult (h, &ov, ret_len, FALSE);
214 CloseHandle (ov.hEvent);
215 return ret;
218 BOOL
219 WritePipeOverlapped (HANDLE h, LPCVOID buf, DWORD len, LPDWORD ret_len,
220 DWORD timeout)
222 OVERLAPPED ov;
223 BOOL ret;
225 memset (&ov, 0, sizeof ov);
226 ov.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
227 ret = WriteFile (h, buf, len, NULL, &ov);
228 if (ret || GetLastError () == ERROR_IO_PENDING)
230 if (!ret && WaitForSingleObject (ov.hEvent, timeout) != WAIT_OBJECT_0)
231 CancelIo (h);
232 ret = GetOverlappedResult (h, &ov, ret_len, FALSE);
234 CloseHandle (ov.hEvent);
235 return ret;
238 bool
239 NT_readline::init (POBJECT_ATTRIBUTES attr, PCHAR in_buf, ULONG in_buflen)
241 NTSTATUS status;
242 IO_STATUS_BLOCK io;
244 status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, attr, &io,
245 FILE_SHARE_VALID_FLAGS,
246 FILE_SYNCHRONOUS_IO_NONALERT
247 | FILE_OPEN_FOR_BACKUP_INTENT);
248 if (!NT_SUCCESS (status))
250 paranoid_printf ("NtOpenFile(%S) failed, status %y",
251 attr->ObjectName, status);
252 return false;
254 buf = in_buf;
255 buflen = in_buflen;
256 got = end = buf;
257 len = 0;
258 line = 1;
259 return true;
262 PCHAR
263 NT_readline::gets ()
265 IO_STATUS_BLOCK io;
267 while (true)
269 /* len == 0 indicates we have to read from the file. */
270 if (!len)
272 if (!NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, got,
273 (buflen - 2) - (got - buf), NULL, NULL)))
274 return NULL;
275 len = io.Information;
276 /* Set end marker. */
277 got[len] = got[len + 1] = '\0';
278 /* Set len to the absolute len of bytes in buf. */
279 len += got - buf;
280 /* Reset got to start reading at the start of the buffer again. */
281 got = end = buf;
283 else
285 got = end + 1;
286 ++line;
288 /* Still some valid full line? */
289 if (got < buf + len)
291 if ((end = strchr (got, '\n')))
293 end[end[-1] == '\r' ? -1 : 0] = '\0';
294 return got;
296 /* Last line missing a \n at EOF? */
297 if (len < buflen - 2)
299 len = 0;
300 return got;
303 /* We have to read once more. Move remaining bytes to the start of
304 the buffer and reposition got so that it points to the end of
305 the remaining bytes. */
306 len = buf + len - got;
307 memmove (buf, got, len);
308 got = buf + len;
309 buf[len] = buf[len + 1] = '\0';
310 len = 0;
314 /* Signal the thread name to any attached debugger
316 (See "How to: Set a Thread Name in Native Code"
317 https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx) */
319 #define MS_VC_EXCEPTION 0x406D1388
321 static void
322 SetThreadNameExc (DWORD dwThreadID, const char* threadName)
324 if (!IsDebuggerPresent ())
325 return;
327 ULONG_PTR info[] =
329 0x1000, /* type, must be 0x1000 */
330 (ULONG_PTR) threadName, /* pointer to threadname */
331 dwThreadID, /* thread ID (+ flags on x86_64) */
334 __try
336 RaiseException (MS_VC_EXCEPTION, 0, sizeof (info) / sizeof (ULONG_PTR),
337 info);
339 __except (NO_ERROR)
340 __endtry
343 void
344 SetThreadName (DWORD dwThreadID, const char* threadName)
346 HANDLE hThread = OpenThread (THREAD_SET_LIMITED_INFORMATION, FALSE, dwThreadID);
347 if (hThread)
349 /* SetThreadDescription only exists in a wide-char version, so we must
350 convert threadname to wide-char. The encoding of threadName is
351 unclear, so use UTF8 until we know better. */
352 int bufsize = MultiByteToWideChar (CP_UTF8, 0, threadName, -1, NULL, 0);
353 WCHAR buf[bufsize];
354 bufsize = MultiByteToWideChar (CP_UTF8, 0, threadName, -1, buf, bufsize);
355 HRESULT hr = SetThreadDescription (hThread, buf);
356 if (hr != S_OK)
358 debug_printf ("SetThreadDescription() failed. %08x %08x\n",
359 GetLastError (), hr);
361 CloseHandle (hThread);
364 /* also use the older, exception-based method of setting threadname for the
365 benefit of things which don't known about GetThreadDescription. */
366 SetThreadNameExc (dwThreadID, threadName);
369 #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
371 static WORD num_cpu_per_group = 0;
372 static WORD group_count = 0;
374 WORD
375 __get_cpus_per_group (void)
377 tmp_pathbuf tp;
379 if (num_cpu_per_group)
380 return num_cpu_per_group;
382 num_cpu_per_group = 64;
383 group_count = 1;
385 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi =
386 (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get ();
387 DWORD lpi_size = NT_MAX_PATH;
389 /* Fake a SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX group info block if
390 GetLogicalProcessorInformationEx fails for some reason. */
391 if (!GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size))
393 lpi_size = sizeof *lpi;
394 lpi->Relationship = RelationGroup;
395 lpi->Size = lpi_size;
396 lpi->Group.MaximumGroupCount = 1;
397 lpi->Group.ActiveGroupCount = 1;
398 lpi->Group.GroupInfo[0].MaximumProcessorCount = wincap.cpu_count ();
399 lpi->Group.GroupInfo[0].ActiveProcessorCount
400 = __builtin_popcountl (wincap.cpu_mask ());
401 lpi->Group.GroupInfo[0].ActiveProcessorMask = wincap.cpu_mask ();
404 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX plpi = lpi;
405 for (DWORD size = lpi_size; size > 0;
406 size -= plpi->Size, add_size (plpi, plpi->Size))
407 if (plpi->Relationship == RelationGroup)
409 /* There are systems with a MaximumProcessorCount not reflecting the
410 actually available CPUs. The ActiveProcessorCount is correct
411 though. So we just use ActiveProcessorCount for now, hoping for
412 the best. */
413 num_cpu_per_group = plpi->Group.GroupInfo[0].ActiveProcessorCount;
415 /* Follow that lead to get the group count. */
416 group_count = plpi->Group.ActiveGroupCount;
417 break;
420 return num_cpu_per_group;
423 WORD
424 __get_group_count (void)
426 if (group_count == 0)
427 (void) __get_cpus_per_group (); // caller should have called this first
428 return group_count;