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 /* Minimal overlapped pipe I/O implementation for signal and commune stuff. */
189 CreatePipeOverlapped (PHANDLE hr
, PHANDLE hw
, LPSECURITY_ATTRIBUTES sa
)
191 int ret
= fhandler_pipe::create (sa
, hr
, hw
, 0, NULL
,
192 FILE_FLAG_OVERLAPPED
);
199 ReadPipeOverlapped (HANDLE h
, PVOID buf
, DWORD len
, LPDWORD ret_len
,
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
)
212 ret
= GetOverlappedResult (h
, &ov
, ret_len
, FALSE
);
214 CloseHandle (ov
.hEvent
);
219 WritePipeOverlapped (HANDLE h
, LPCVOID buf
, DWORD len
, LPDWORD ret_len
,
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
)
232 ret
= GetOverlappedResult (h
, &ov
, ret_len
, FALSE
);
234 CloseHandle (ov
.hEvent
);
239 NT_readline::init (POBJECT_ATTRIBUTES attr
, PCHAR in_buf
, ULONG in_buflen
)
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
);
269 /* len == 0 indicates we have to read from the file. */
272 if (!NT_SUCCESS (NtReadFile (fh
, NULL
, NULL
, NULL
, &io
, got
,
273 (buflen
- 2) - (got
- buf
), NULL
, 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. */
280 /* Reset got to start reading at the start of the buffer again. */
288 /* Still some valid full line? */
291 if ((end
= strchr (got
, '\n')))
293 end
[end
[-1] == '\r' ? -1 : 0] = '\0';
296 /* Last line missing a \n at EOF? */
297 if (len
< buflen
- 2)
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
);
309 buf
[len
] = buf
[len
+ 1] = '\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
322 SetThreadNameExc (DWORD dwThreadID
, const char* threadName
)
324 if (!IsDebuggerPresent ())
329 0x1000, /* type, must be 0x1000 */
330 (ULONG_PTR
) threadName
, /* pointer to threadname */
331 dwThreadID
, /* thread ID (+ flags on x86_64) */
336 RaiseException (MS_VC_EXCEPTION
, 0, sizeof (info
) / sizeof (ULONG_PTR
),
344 SetThreadName (DWORD dwThreadID
, const char* threadName
)
346 HANDLE hThread
= OpenThread (THREAD_SET_LIMITED_INFORMATION
, FALSE
, dwThreadID
);
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);
354 bufsize
= MultiByteToWideChar (CP_UTF8
, 0, threadName
, -1, buf
, bufsize
);
355 HRESULT hr
= SetThreadDescription (hThread
, buf
);
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;
375 __get_cpus_per_group (void)
379 if (num_cpu_per_group
)
380 return num_cpu_per_group
;
382 num_cpu_per_group
= 64;
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
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
;
420 return num_cpu_per_group
;
424 __get_group_count (void)
426 if (group_count
== 0)
427 (void) __get_cpus_per_group (); // caller should have called this first