Cygwin: signal: Increase chance of handling signal in main thread
[newlib-cygwin.git] / winsup / cygwin / miscfuncs.cc
blobebe401b93f63d40c36b1f1396a9676a9ca2cc585
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 /* 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. */
189 bool
190 set_and_check_winprio (HANDLE proc, DWORD prio)
192 DWORD prev_prio = GetPriorityClass (proc);
193 if (!prev_prio)
194 return false;
195 if (prev_prio == prio)
196 return true;
198 if (!SetPriorityClass (proc, prio))
199 return false;
201 /* Windows silently sets a lower priority (HIGH_PRIORITY_CLASS) if
202 the new priority (REALTIME_PRIORITY_CLASS) requires administrator
203 privileges. */
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);
210 return false;
213 debug_printf ("Changed priority from 0x%x to 0x%x", prev_prio, curr_prio);
214 return true;
217 /* Minimal overlapped pipe I/O implementation for signal and commune stuff. */
219 BOOL
220 CreatePipeOverlapped (PHANDLE hr, PHANDLE hw, LPSECURITY_ATTRIBUTES sa)
222 int ret = fhandler_pipe::create (sa, hr, hw, 0, NULL,
223 FILE_FLAG_OVERLAPPED);
224 if (ret)
225 SetLastError (ret);
226 return ret == 0;
229 BOOL
230 ReadPipeOverlapped (HANDLE h, PVOID buf, DWORD len, LPDWORD ret_len,
231 DWORD timeout)
233 OVERLAPPED ov;
234 BOOL ret;
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)
242 CancelIo (h);
243 ret = GetOverlappedResult (h, &ov, ret_len, FALSE);
245 CloseHandle (ov.hEvent);
246 return ret;
249 BOOL
250 WritePipeOverlapped (HANDLE h, LPCVOID buf, DWORD len, LPDWORD ret_len,
251 DWORD timeout)
253 OVERLAPPED ov;
254 BOOL ret;
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)
262 CancelIo (h);
263 ret = GetOverlappedResult (h, &ov, ret_len, FALSE);
265 CloseHandle (ov.hEvent);
266 return ret;
269 bool
270 NT_readline::init (POBJECT_ATTRIBUTES attr, PCHAR in_buf, ULONG in_buflen)
272 NTSTATUS status;
273 IO_STATUS_BLOCK io;
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);
283 return false;
285 buf = in_buf;
286 buflen = in_buflen;
287 got = end = buf;
288 len = 0;
289 line = 1;
290 return true;
293 PCHAR
294 NT_readline::gets ()
296 IO_STATUS_BLOCK io;
298 while (true)
300 /* len == 0 indicates we have to read from the file. */
301 if (!len)
303 if (!NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, got,
304 (buflen - 2) - (got - buf), NULL, NULL)))
305 return 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. */
310 len += got - buf;
311 /* Reset got to start reading at the start of the buffer again. */
312 got = end = buf;
314 else
316 got = end + 1;
317 ++line;
319 /* Still some valid full line? */
320 if (got < buf + len)
322 if ((end = strchr (got, '\n')))
324 end[end[-1] == '\r' ? -1 : 0] = '\0';
325 return got;
327 /* Last line missing a \n at EOF? */
328 if (len < buflen - 2)
330 len = 0;
331 return got;
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);
339 got = buf + len;
340 buf[len] = buf[len + 1] = '\0';
341 len = 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
352 static void
353 SetThreadNameExc (DWORD dwThreadID, const char* threadName)
355 if (!IsDebuggerPresent ())
356 return;
358 ULONG_PTR info[] =
360 0x1000, /* type, must be 0x1000 */
361 (ULONG_PTR) threadName, /* pointer to threadname */
362 dwThreadID, /* thread ID (+ flags on x86_64) */
365 __try
367 RaiseException (MS_VC_EXCEPTION, 0, sizeof (info) / sizeof (ULONG_PTR),
368 info);
370 __except (NO_ERROR)
371 __endtry
374 void
375 SetThreadName (DWORD dwThreadID, const char* threadName)
377 HANDLE hThread = OpenThread (THREAD_SET_LIMITED_INFORMATION, FALSE, dwThreadID);
378 if (hThread)
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);
384 WCHAR buf[bufsize];
385 bufsize = MultiByteToWideChar (CP_UTF8, 0, threadName, -1, buf, bufsize);
386 HRESULT hr = SetThreadDescription (hThread, buf);
387 if (IS_ERROR (hr))
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;
405 WORD
406 __get_cpus_per_group (void)
408 tmp_pathbuf tp;
410 if (num_cpu_per_group)
411 return num_cpu_per_group;
413 num_cpu_per_group = 64;
414 group_count = 1;
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
443 the best. */
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;
448 break;
451 return num_cpu_per_group;
454 WORD
455 __get_group_count (void)
457 if (group_count == 0)
458 (void) __get_cpus_per_group (); // caller should have called this first
459 return group_count;