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
10 #include "miscfuncs.h"
17 /* not yet prototyped in w32api */
18 extern "C" HRESULT
SetThreadDescription (HANDLE hThread
, PCWSTR lpThreadDescription
);
20 /* Get handle count of an object. */
22 get_obj_handle_count (HANDLE h
)
24 OBJECT_BASIC_INFORMATION obi
;
28 status
= NtQueryObject (h
, ObjectBasicInformation
, &obi
, sizeof obi
, NULL
);
29 if (!NT_SUCCESS (status
))
30 debug_printf ("NtQueryObject: %y", status
);
32 hdl_cnt
= obi
.HandleCount
;
36 static char __attribute__ ((noinline
))
37 dummytest (volatile char *p
)
43 check_iovec (const struct iovec
*iov
, int iovcnt
, bool forwrite
)
45 if (iovcnt
< 0 || iovcnt
> IOV_MAX
)
58 if (iov
->iov_len
> SSIZE_MAX
|| (tot
+= iov
->iov_len
) > SSIZE_MAX
)
64 volatile char *p
= ((char *) iov
->iov_base
) + iov
->iov_len
- 1;
86 /* Try hard to schedule another thread.
87 Remember not to call this in a lock condition or you'll potentially
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. */
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
)
114 case REALTIME_PRIORITY_CLASS
:
116 case HIGH_PRIORITY_CLASS
:
118 case ABOVE_NORMAL_PRIORITY_CLASS
:
120 case NORMAL_PRIORITY_CLASS
:
122 case BELOW_NORMAL_PRIORITY_CLASS
:
124 case IDLE_PRIORITY_CLASS
:
130 /* Get a Win32 priority matching the incoming nice factor. The incoming
131 nice is limited to the interval [-NZERO,NZERO-1]. */
133 nice_to_winprio (int &nice
)
135 static const DWORD priority
[] =
137 REALTIME_PRIORITY_CLASS
, /* 0 */
138 HIGH_PRIORITY_CLASS
, /* 1 */
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 */
176 IDLE_PRIORITY_CLASS
/* 39 */
180 else if (nice
> NZERO
- 1)
182 DWORD prio
= priority
[nice
+ NZERO
];
186 /* Set Win32 priority or return false on failure. Also return
187 false and revert to the original priority if a different (lower)
188 priority is set instead. */
190 set_and_check_winprio (HANDLE proc
, DWORD prio
)
192 DWORD prev_prio
= GetPriorityClass (proc
);
195 if (prev_prio
== prio
)
198 if (!SetPriorityClass (proc
, prio
))
201 /* Windows silently sets a lower priority (HIGH_PRIORITY_CLASS) if
202 the new priority (REALTIME_PRIORITY_CLASS) requires administrator
204 DWORD curr_prio
= GetPriorityClass (proc
);
205 if (curr_prio
!= prio
)
207 debug_printf ("Failed to set priority 0x%x, revert from 0x%x to 0x%x",
208 prio
, curr_prio
, prev_prio
);
209 SetPriorityClass (proc
, prev_prio
);
213 debug_printf ("Changed priority from 0x%x to 0x%x", prev_prio
, curr_prio
);
217 /* Minimal overlapped pipe I/O implementation for signal and commune stuff. */
220 CreatePipeOverlapped (PHANDLE hr
, PHANDLE hw
, LPSECURITY_ATTRIBUTES sa
)
222 int ret
= fhandler_pipe::create (sa
, hr
, hw
, 0, NULL
,
223 FILE_FLAG_OVERLAPPED
);
230 ReadPipeOverlapped (HANDLE h
, PVOID buf
, DWORD len
, LPDWORD ret_len
,
236 memset (&ov
, 0, sizeof ov
);
237 ov
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
238 ret
= ReadFile (h
, buf
, len
, NULL
, &ov
);
239 if (ret
|| GetLastError () == ERROR_IO_PENDING
)
241 if (!ret
&& WaitForSingleObject (ov
.hEvent
, timeout
) != WAIT_OBJECT_0
)
243 ret
= GetOverlappedResult (h
, &ov
, ret_len
, FALSE
);
245 CloseHandle (ov
.hEvent
);
250 WritePipeOverlapped (HANDLE h
, LPCVOID buf
, DWORD len
, LPDWORD ret_len
,
256 memset (&ov
, 0, sizeof ov
);
257 ov
.hEvent
= CreateEvent (NULL
, TRUE
, FALSE
, NULL
);
258 ret
= WriteFile (h
, buf
, len
, NULL
, &ov
);
259 if (ret
|| GetLastError () == ERROR_IO_PENDING
)
261 if (!ret
&& WaitForSingleObject (ov
.hEvent
, timeout
) != WAIT_OBJECT_0
)
263 ret
= GetOverlappedResult (h
, &ov
, ret_len
, FALSE
);
265 CloseHandle (ov
.hEvent
);
270 NT_readline::init (POBJECT_ATTRIBUTES attr
, PCHAR in_buf
, ULONG in_buflen
)
275 status
= NtOpenFile (&fh
, SYNCHRONIZE
| FILE_READ_DATA
, attr
, &io
,
276 FILE_SHARE_VALID_FLAGS
,
277 FILE_SYNCHRONOUS_IO_NONALERT
278 | FILE_OPEN_FOR_BACKUP_INTENT
);
279 if (!NT_SUCCESS (status
))
281 paranoid_printf ("NtOpenFile(%S) failed, status %y",
282 attr
->ObjectName
, status
);
300 /* len == 0 indicates we have to read from the file. */
303 if (!NT_SUCCESS (NtReadFile (fh
, NULL
, NULL
, NULL
, &io
, got
,
304 (buflen
- 2) - (got
- buf
), NULL
, NULL
)))
306 len
= io
.Information
;
307 /* Set end marker. */
308 got
[len
] = got
[len
+ 1] = '\0';
309 /* Set len to the absolute len of bytes in buf. */
311 /* Reset got to start reading at the start of the buffer again. */
319 /* Still some valid full line? */
322 if ((end
= strchr (got
, '\n')))
324 end
[end
[-1] == '\r' ? -1 : 0] = '\0';
327 /* Last line missing a \n at EOF? */
328 if (len
< buflen
- 2)
334 /* We have to read once more. Move remaining bytes to the start of
335 the buffer and reposition got so that it points to the end of
336 the remaining bytes. */
337 len
= buf
+ len
- got
;
338 memmove (buf
, got
, len
);
340 buf
[len
] = buf
[len
+ 1] = '\0';
345 /* Signal the thread name to any attached debugger
347 (See "How to: Set a Thread Name in Native Code"
348 https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx) */
350 #define MS_VC_EXCEPTION 0x406D1388
353 SetThreadNameExc (DWORD dwThreadID
, const char* threadName
)
355 if (!IsDebuggerPresent ())
360 0x1000, /* type, must be 0x1000 */
361 (ULONG_PTR
) threadName
, /* pointer to threadname */
362 dwThreadID
, /* thread ID (+ flags on x86_64) */
367 RaiseException (MS_VC_EXCEPTION
, 0, sizeof (info
) / sizeof (ULONG_PTR
),
375 SetThreadName (DWORD dwThreadID
, const char* threadName
)
377 HANDLE hThread
= OpenThread (THREAD_SET_LIMITED_INFORMATION
, FALSE
, dwThreadID
);
380 /* SetThreadDescription only exists in a wide-char version, so we must
381 convert threadname to wide-char. The encoding of threadName is
382 unclear, so use UTF8 until we know better. */
383 int bufsize
= MultiByteToWideChar (CP_UTF8
, 0, threadName
, -1, NULL
, 0);
385 bufsize
= MultiByteToWideChar (CP_UTF8
, 0, threadName
, -1, buf
, bufsize
);
386 HRESULT hr
= SetThreadDescription (hThread
, buf
);
389 debug_printf ("SetThreadDescription() failed. %08x %08x\n",
390 GetLastError (), hr
);
392 CloseHandle (hThread
);
395 /* also use the older, exception-based method of setting threadname for the
396 benefit of things which don't known about GetThreadDescription. */
397 SetThreadNameExc (dwThreadID
, threadName
);
400 #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
402 static WORD num_cpu_per_group
= 0;
403 static WORD group_count
= 0;
406 __get_cpus_per_group (void)
410 if (num_cpu_per_group
)
411 return num_cpu_per_group
;
413 num_cpu_per_group
= 64;
416 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi
=
417 (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX
) tp
.c_get ();
418 DWORD lpi_size
= NT_MAX_PATH
;
420 /* Fake a SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX group info block if
421 GetLogicalProcessorInformationEx fails for some reason. */
422 if (!GetLogicalProcessorInformationEx (RelationGroup
, lpi
, &lpi_size
))
424 lpi_size
= sizeof *lpi
;
425 lpi
->Relationship
= RelationGroup
;
426 lpi
->Size
= lpi_size
;
427 lpi
->Group
.MaximumGroupCount
= 1;
428 lpi
->Group
.ActiveGroupCount
= 1;
429 lpi
->Group
.GroupInfo
[0].MaximumProcessorCount
= wincap
.cpu_count ();
430 lpi
->Group
.GroupInfo
[0].ActiveProcessorCount
431 = __builtin_popcountl (wincap
.cpu_mask ());
432 lpi
->Group
.GroupInfo
[0].ActiveProcessorMask
= wincap
.cpu_mask ();
435 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX plpi
= lpi
;
436 for (DWORD size
= lpi_size
; size
> 0;
437 size
-= plpi
->Size
, add_size (plpi
, plpi
->Size
))
438 if (plpi
->Relationship
== RelationGroup
)
440 /* There are systems with a MaximumProcessorCount not reflecting the
441 actually available CPUs. The ActiveProcessorCount is correct
442 though. So we just use ActiveProcessorCount for now, hoping for
444 num_cpu_per_group
= plpi
->Group
.GroupInfo
[0].ActiveProcessorCount
;
446 /* Follow that lead to get the group count. */
447 group_count
= plpi
->Group
.ActiveGroupCount
;
451 return num_cpu_per_group
;
455 __get_group_count (void)
457 if (group_count
== 0)
458 (void) __get_cpus_per_group (); // caller should have called this first