[newlib-cygwin] Fix /proc/cpuinfo topology and cache size info
Corinna Vinschen
corinna@sourceware.org
Thu Aug 13 15:59:00 GMT 2015
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=e0d48debedfa27a7a31dd1caf8e23cf71708cf4c
commit e0d48debedfa27a7a31dd1caf8e23cf71708cf4c
Author: Corinna Vinschen <corinna@vinschen.de>
Date: Thu Aug 13 17:59:47 2015 +0200
Fix /proc/cpuinfo topology and cache size info
* autoload.cc (GetLogicalProcessorInformationEx): Import.
(SetThreadGroupAffinity): Import.
* fhandler_proc.cc (add_size): New macro.
(get_msb): New inline function.
(mask_bits): Ditto.
(format_proc_cpuinfo): Drop handling of old CPUs. Check if we're
running on a OS version supporting porcessor groups. If so, use
SetThreadGroupAffinity to set thread affinity. Improve cache info
to include 3rd level cache on Intel CPUs. Improve multi core info.
* wincap.h (wincaps::has_processor_groups): New element.
* wincap.cc: Implement above element throughout.
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diff:
---
winsup/cygwin/ChangeLog | 14 +
winsup/cygwin/autoload.cc | 2 +
winsup/cygwin/fhandler_proc.cc | 1074 ++++++++++++++++++++++------------------
winsup/cygwin/release/2.2.1 | 10 +-
winsup/cygwin/wincap.cc | 6 +
winsup/cygwin/wincap.h | 2 +
6 files changed, 618 insertions(+), 490 deletions(-)
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 79134b2..cf0495e 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,17 @@
+2015-08-13 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc (GetLogicalProcessorInformationEx): Import.
+ (SetThreadGroupAffinity): Import.
+ * fhandler_proc.cc (add_size): New macro.
+ (get_msb): New inline function.
+ (mask_bits): Ditto.
+ (format_proc_cpuinfo): Drop handling of old CPUs. Check if we're
+ running on a OS version supporting porcessor groups. If so, use
+ SetThreadGroupAffinity to set thread affinity. Improve cache info
+ to include 3rd level cache on Intel CPUs. Improve multi core info.
+ * wincap.h (wincaps::has_processor_groups): New element.
+ * wincap.cc: Implement above element throughout.
+
2015-08-10 Corinna Vinschen <corinna@vinschen.de>
* miscfuncs.cc: Fix comment preceeding x86_64 memset and friends.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 6423a67..4299e3a 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -576,11 +576,13 @@ LoadDLLfunc (GetUdpTable, 12, iphlpapi)
LoadDLLfuncEx (CancelSynchronousIo, 4, kernel32, 1)
LoadDLLfunc (CreateSymbolicLinkW, 12, kernel32)
+LoadDLLfuncEx (GetLogicalProcessorInformationEx, 12, kernel32, 1)
LoadDLLfuncEx (GetNamedPipeClientProcessId, 8, kernel32, 1)
LoadDLLfunc (GetSystemTimePreciseAsFileTime, 4, kernel32)
LoadDLLfuncEx (IdnToAscii, 20, kernel32, 1)
LoadDLLfuncEx (IdnToUnicode, 20, kernel32, 1)
LoadDLLfunc (LocaleNameToLCID, 8, kernel32)
+LoadDLLfunc (SetThreadGroupAffinity, 12, kernel32)
LoadDLLfunc (SetThreadStackGuarantee, 4, kernel32)
/* ldap functions are cdecl! */
diff --git a/winsup/cygwin/fhandler_proc.cc b/winsup/cygwin/fhandler_proc.cc
index 974da93..13311b8 100644
--- a/winsup/cygwin/fhandler_proc.cc
+++ b/winsup/cygwin/fhandler_proc.cc
@@ -593,12 +593,30 @@ format_proc_stat (void *, char *&destbuf)
return eobuf - buf;
}
+#define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s))))
#define print(x) { bufptr = stpcpy (bufptr, (x)); }
+static inline uint32_t
+get_msb (uint32_t in)
+{
+ return 32 - __builtin_clz (in);
+}
+
+static inline uint32_t
+mask_bits (uint32_t in)
+{
+ uint32_t bits = get_msb (in) - 1;
+ if (in & (in - 1))
+ ++bits;
+ return bits;
+}
+
static off_t
format_proc_cpuinfo (void *, char *&destbuf)
{
- DWORD orig_affinity_mask;
+ WCHAR cpu_key[128], *cpu_num_p;
+ DWORD orig_affinity_mask = 0;
+ GROUP_AFFINITY orig_group_affinity;
int cpu_number;
const int BUFSIZE = 256;
union
@@ -614,556 +632,640 @@ format_proc_cpuinfo (void *, char *&destbuf)
char *buf = tp.c_get ();
char *bufptr = buf;
+ DWORD lpi_size = NT_MAX_PATH;
+ //WORD num_cpu_groups = 1; /* Pre Windows 7, only one group... */
+ WORD num_cpu_per_group = 64; /* ...and a max of 64 CPUs. */
+
+ if (wincap.has_processor_groups ())
+ {
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi =
+ (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get ();
+ lpi_size = NT_MAX_PATH;
+ if (!GetLogicalProcessorInformationEx (RelationAll, lpi, &lpi_size))
+ lpi = NULL;
+ else
+ {
+ PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX plpi = lpi;
+ for (DWORD size = lpi_size; size > 0;
+ size -= plpi->Size, add_size (plpi, plpi->Size))
+ if (plpi->Relationship == RelationGroup)
+ {
+ //num_cpu_groups = plpi->Group.MaximumGroupCount;
+ num_cpu_per_group
+ = plpi->Group.GroupInfo[0].MaximumProcessorCount;
+ break;
+ }
+ }
+ }
+
+ cpu_num_p = wcpcpy (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
+ "\\System\\CentralProcessor\\");
for (cpu_number = 0; ; cpu_number++)
{
- WCHAR cpu_key[128];
- __small_swprintf (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
- "\\System\\CentralProcessor\\%d", cpu_number);
+ __small_swprintf (cpu_num_p, L"%d", cpu_number);
if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key)))
break;
if (cpu_number)
print ("\n");
- orig_affinity_mask = SetThreadAffinityMask (GetCurrentThread (),
- 1 << cpu_number);
- if (orig_affinity_mask == 0)
- debug_printf ("SetThreadAffinityMask failed %E");
+ WORD cpu_group = cpu_number / num_cpu_per_group;
+ KAFFINITY cpu_mask = 1L << (cpu_number % num_cpu_per_group);
+
+ if (wincap.has_processor_groups ())
+ {
+ GROUP_AFFINITY affinity = {
+ .Mask = cpu_mask,
+ .Group = cpu_group,
+ };
+
+ if (!SetThreadGroupAffinity (GetCurrentThread (), &affinity,
+ &orig_group_affinity))
+ system_printf ("SetThreadGroupAffinity(%x,%d (%x/%d)) failed %E", cpu_mask, cpu_group, cpu_number, cpu_number);
+ orig_affinity_mask = 1; /* Just mark success. */
+ }
+ else
+ {
+ orig_affinity_mask = SetThreadAffinityMask (GetCurrentThread (),
+ 1 << cpu_number);
+ if (orig_affinity_mask == 0)
+ debug_printf ("SetThreadAffinityMask failed %E");
+ }
/* I'm not sure whether the thread changes processor immediately
and I'm not sure whether this function will cause the thread
to be rescheduled */
yield ();
- bool has_cpuid = false;
-
- if (!can_set_flag (0x00040000))
- debug_printf ("386 processor - no cpuid");
+ DWORD cpu_mhz = 0;
+ RTL_QUERY_REGISTRY_TABLE tab[2] = {
+ { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
+ L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
+ { NULL, 0, NULL, NULL, 0, NULL, 0 }
+ };
+
+ RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
+ NULL, NULL);
+ bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number);
+ uint32_t maxf, vendor_id[4], unused;
+
+ cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0x00000000);
+ maxf &= 0xffff;
+ vendor_id[3] = 0;
+
+ /* Vendor identification. */
+ bool is_amd = false, is_intel = false;
+ if (!strcmp ((char*)vendor_id, "AuthenticAMD"))
+ is_amd = true;
+ else if (!strcmp ((char*)vendor_id, "GenuineIntel"))
+ is_intel = true;
+
+ bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n",
+ (char *)vendor_id);
+
+ uint32_t features1, features2, extra_info, cpuid_sig;
+ cpuid (&cpuid_sig, &extra_info, &features2, &features1, 0x00000001);
+ uint32_t family = (cpuid_sig & 0x00000f00) >> 8,
+ model = (cpuid_sig & 0x000000f0) >> 4,
+ stepping = cpuid_sig & 0x0000000f,
+ apic_id = (extra_info & 0xff000000) >> 24;
+ if (family == 15)
+ family += (cpuid_sig >> 20) & 0xff;
+ if (family >= 6)
+ model += ((cpuid_sig >> 16) & 0x0f) << 4;
+
+ uint32_t maxe = 0;
+ cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
+ if (maxe >= 0x80000004)
+ {
+ cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2],
+ &in_buf.m[3], 0x80000002);
+ cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6],
+ &in_buf.m[7], 0x80000003);
+ cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10],
+ &in_buf.m[11], 0x80000004);
+ in_buf.m[12] = 0;
+ }
else
{
- debug_printf ("486 processor");
- if (can_set_flag (0x00200000))
+ /* Could implement a lookup table here if someone needs it. */
+ strcpy (in_buf.s, "unknown");
+ }
+ int cache_size = -1,
+ clflush = 64,
+ cache_alignment = 64;
+ if (features1 & (1 << 19)) /* CLFSH */
+ clflush = ((extra_info >> 8) & 0xff) << 3;
+ if (is_intel && family == 15)
+ cache_alignment = clflush * 2;
+ if (is_intel)
+ {
+ uint32_t cache_level = 0;
+ uint32_t info, layout, sets;
+
+ for (int idx = 0; ; ++idx)
{
- debug_printf ("processor supports CPUID instruction");
- has_cpuid = true;
+ cpuid (&info, &layout, &sets, &unused, 0x00000004, idx);
+ uint32_t cache_type = (info & 0x1f);
+ if (cache_type == 0)
+ break;
+ uint32_t cur_level = ((info >> 5) & 0x7);
+ uint32_t ways = ((layout >> 22) & 0x3ff) + 1;
+ uint32_t part = ((layout >> 12) & 0x3ff) + 1;
+ uint32_t line = (layout & 0xfff) + 1;
+ sets++;
+ if (cur_level == cache_level)
+ cache_size += ways * part * line * sets;
+ else if (cur_level > cache_level)
+ {
+ cache_size = ways * part * line * sets;
+ cache_level = cur_level;
+ }
}
- else
- debug_printf ("processor does not support CPUID instruction");
+ if (cache_size != -1)
+ cache_size >>= 10;
}
+ /* L2 Cache and L2 TLB Identifiers. */
+ if (cache_size == -1 && maxe >= 0x80000006)
+ {
+ uint32_t l2;
+ cpuid (&unused, &unused, &l2, &unused, 0x80000006);
- if (!has_cpuid)
+ cache_size = l2 >> 16;
+ }
+ /* L1 Cache and TLB Identifiers. */
+ if (cache_size == -1 && maxe >= 0x80000005)
{
- WCHAR vendor[64], id[64];
- UNICODE_STRING uvendor, uid;
- RtlInitEmptyUnicodeString (&uvendor, vendor, sizeof (vendor));
- RtlInitEmptyUnicodeString (&uid, id, sizeof (id));
- DWORD cpu_mhz = 0;
- RTL_QUERY_REGISTRY_TABLE tab[4] = {
- { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT,
- L"VendorIdentifier", &uvendor, REG_NONE, NULL, 0 },
- { NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT,
- L"Identifier", &uid, REG_NONE, NULL, 0 },
- { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
- L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
- { NULL, 0, NULL, NULL, 0, NULL, 0 }
- };
+ uint32_t data_cache, inst_cache;
+ cpuid (&unused, &unused, &data_cache, &inst_cache,
+ 0x80000005);
- RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
- NULL, NULL);
- bufptr += __small_sprintf (bufptr,
- "processor : %d\n"
- "vendor_id : %S\n"
- "identifier : %S\n"
- "cpu MHz : %u\n",
- cpu_number, &uvendor, &uid, cpu_mhz);
- print ("flags :");
- if (IsProcessorFeaturePresent (PF_3DNOW_INSTRUCTIONS_AVAILABLE))
- print (" 3dnow");
- if (IsProcessorFeaturePresent (PF_COMPARE_EXCHANGE_DOUBLE))
- print (" cx8");
- if (!IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED))
- print (" fpu");
- if (IsProcessorFeaturePresent (PF_MMX_INSTRUCTIONS_AVAILABLE))
- print (" mmx");
- if (IsProcessorFeaturePresent (PF_PAE_ENABLED))
- print (" pae");
- if (IsProcessorFeaturePresent (PF_RDTSC_INSTRUCTION_AVAILABLE))
- print (" tsc");
- if (IsProcessorFeaturePresent (PF_XMMI_INSTRUCTIONS_AVAILABLE))
- print (" sse");
- if (IsProcessorFeaturePresent (PF_XMMI64_INSTRUCTIONS_AVAILABLE))
- print (" sse2");
+ cache_size = (inst_cache >> 24) + (data_cache >> 24);
}
- else
+ bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
+ "model\t\t: %d\n"
+ "model name\t: %s\n"
+ "stepping\t: %d\n"
+ "cpu MHz\t\t: %d.000\n",
+ family,
+ model,
+ in_buf.s + strspn (in_buf.s, " "),
+ stepping,
+ cpu_mhz);
+
+ if (cache_size >= 0)
+ bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n",
+ cache_size);
+
+ /* Recognize multi-core CPUs. */
+ if (features1 & (1 << 28)) /* HTT */
{
- DWORD cpu_mhz = 0;
- RTL_QUERY_REGISTRY_TABLE tab[2] = {
- { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
- L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
- { NULL, 0, NULL, NULL, 0, NULL, 0 }
- };
+ uint32_t siblings = 0;
+ uint32_t cpu_cores = 0;
+ uint32_t phys_id = 0;
+ uint32_t core_id = 0;
+ uint32_t initial_apic_id = apic_id;
+
+ uint32_t logical_bits = 0; /* # of logical core bits in apicid. */
+ uint32_t ht_bits = 0; /* # of thread bits in apic_id. */
- RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
- NULL, NULL);
- bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number);
- uint32_t maxf, vendor_id[4], unused;
- cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0);
- maxf &= 0xffff;
- vendor_id[3] = 0;
-
- /* Vendor identification. */
- bool is_amd = false, is_intel = false;
- if (!strcmp ((char*)vendor_id, "AuthenticAMD"))
- is_amd = true;
- else if (!strcmp ((char*)vendor_id, "GenuineIntel"))
- is_intel = true;
-
- bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n",
- (char *)vendor_id);
- if (maxf >= 1)
+ if (is_intel)
{
- uint32_t features2, features1, extra_info, cpuid_sig;
- cpuid (&cpuid_sig, &extra_info, &features2, &features1, 1);
- /* uint32_t extended_family = (cpuid_sig & 0x0ff00000) >> 20,
- extended_model = (cpuid_sig & 0x000f0000) >> 16,
- type = (cpuid_sig & 0x00003000) >> 12; */
- uint32_t family = (cpuid_sig & 0x00000f00) >> 8,
- model = (cpuid_sig & 0x000000f0) >> 4,
- stepping = cpuid_sig & 0x0000000f;
- /* Not printed on Linux */
- //uint32_t brand_id = extra_info & 0x0000000f;
- //uint32_t cpu_count = (extra_info & 0x00ff0000) >> 16;
- uint32_t apic_id = (extra_info & 0xff000000) >> 24;
- if (family == 15)
- family += (cpuid_sig >> 20) & 0xff;
- if (family >= 6)
- model += ((cpuid_sig >> 16) & 0x0f) << 4;
- uint32_t maxe = 0;
- cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
- if (maxe >= 0x80000004)
+ bool valid = false;
+ if (maxf >= 0x0000000b) /* topoext supported? */
{
- cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2],
- &in_buf.m[3], 0x80000002);
- cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6],
- &in_buf.m[7], 0x80000003);
- cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10],
- &in_buf.m[11], 0x80000004);
- in_buf.m[12] = 0;
- }
- else
- {
- /* Could implement a lookup table here if someone needs it. */
- strcpy (in_buf.s, "unknown");
+ uint32_t bits, logical, level, unused;
+
+ /* Threads */
+ cpuid (&bits, &logical, &level, &unused,
+ 0x0000000b, 0x00);
+ /* Even if topoext is supposedly supported, it can return
+ "invalid". */
+ if (bits != 0 && ((level >> 8) & 0xff) == 1)
+ {
+ valid = true;
+ ht_bits = (bits & 0x1f);
+ siblings = (logical & 0xffff);
+ cpu_cores = siblings;
+ for (uint32_t idx = 1; ; ++idx)
+ {
+ cpuid (&bits, &logical, &level, &initial_apic_id,
+ 0x0000000b, idx);
+
+ uint32_t level_type = ((level >> 8) & 0xff);
+ if (level_type == 0) /* Invalid */
+ break;
+ if (level_type == 2) /* Core */
+ {
+ logical_bits = (bits & 0x1f);
+ siblings = (logical & 0xffff);
+ cpu_cores = siblings >> ht_bits;
+ break;
+ }
+ }
+ }
}
- int cache_size = -1,
- tlb_size = -1,
- clflush = 64,
- cache_alignment = 64;
- if (features1 & (1 << 19)) /* CLFSH */
- clflush = ((extra_info >> 8) & 0xff) << 3;
- if (is_intel && family == 15)
- cache_alignment = clflush * 2;
- if (maxe >= 0x80000005) /* L1 Cache and TLB Identifiers. */
+ if (!valid && maxf >= 0x00000004)
{
- uint32_t data_cache, inst_cache;
- cpuid (&unused, &unused, &data_cache, &inst_cache,
- 0x80000005);
+ uint32_t apic_reserved;
- cache_size = (inst_cache >> 24) + (data_cache >> 24);
- tlb_size = 0;
+ cpuid (&apic_reserved, &unused, &unused, &unused,
+ 0x00000004, 0x00);
+ if (apic_reserved & 0x1f)
+ {
+ valid = true;
+ cpu_cores = ((apic_reserved >> 26) & 0x3f) + 1;
+ siblings = (extra_info >> 16) & 0xff;
+ if (siblings <= 1) /* HT could be fused out */
+ {
+ logical_bits = mask_bits (cpu_cores);
+ ht_bits = 0;
+ }
+ else
+ {
+ logical_bits = mask_bits (siblings);
+ ht_bits = mask_bits (siblings / cpu_cores);
+ }
+ }
}
- if (maxe >= 0x80000006) /* L2 Cache and L2 TLB Identifiers. */
+ if (!valid) /* single core, multi thread */
{
- uint32_t tlb, l2;
- cpuid (&unused, &tlb, &l2, &unused, 0x80000006);
-
- cache_size = l2 >> 16;
- tlb_size = ((tlb >> 16) & 0xfff) + (tlb & 0xfff);
+ cpu_cores = 1;
+ siblings = (extra_info >> 16) & 0xff;
+ logical_bits = mask_bits (siblings);
+ ht_bits = logical_bits;
}
- bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
- "model\t\t: %d\n"
- "model name\t: %s\n"
- "stepping\t: %d\n"
- "cpu MHz\t\t: %d.000\n",
- family,
- model,
- in_buf.s + strspn (in_buf.s, " "),
- stepping,
- cpu_mhz);
- if (cache_size >= 0)
- bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n",
- cache_size);
-
- /* Recognize multi-core CPUs. */
+ }
+ else if (is_amd)
+ {
if (maxe >= 0x80000008)
{
uint32_t core_info;
- cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
- int max_cores = 1 + (core_info & 0xff);
- if (max_cores > 1)
- {
- int shift = (core_info >> 12) & 0x0f;
- if (!shift)
- while ((1 << shift) < max_cores)
- ++shift;
- int core_id = apic_id & ((1 << shift) - 1);
- apic_id >>= shift;
-
- bufptr += __small_sprintf (bufptr, "physical id\t: %d\n"
- "core id\t\t: %d\n"
- "cpu cores\t: %d\n",
- apic_id, core_id, max_cores);
- }
+ cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
+ cpu_cores = (core_info & 0xff) + 1;
+ siblings = cpu_cores;
}
- /* Recognize Intel Hyper-Transport CPUs. */
- else if (is_intel && (features1 & (1 << 28)) && maxf >= 4)
+ else
{
- /* TODO */
+ cpu_cores = (extra_info >> 16) & 0xff;
+ siblings = cpu_cores;
}
+ logical_bits = mask_bits (cpu_cores);
+ ht_bits = 0;
+ }
+ phys_id = initial_apic_id >> logical_bits;
+ core_id = (initial_apic_id & ((1 << logical_bits) - 1)) >> ht_bits;
+
+ bufptr += __small_sprintf (bufptr, "physical id\t: %d\n", phys_id);
+ if (siblings > 0)
+ bufptr += __small_sprintf (bufptr, "siblings\t: %u\n", siblings);
+ bufptr += __small_sprintf (bufptr, "core id\t\t: %d\n"
+ "cpu cores\t: %d\n",
+ core_id, cpu_cores);
+ if (features1 & (1 << 9)) /* apic */
+ bufptr += __small_sprintf (bufptr, "apicid\t\t: %d\n"
+ "initial apicid\t: %d\n",
+ apic_id, initial_apic_id);
+
+ }
+
+ bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n"
+ "fpu_exception\t: %s\n"
+ "cpuid level\t: %d\n"
+ "wp\t\t: yes\n",
+ (features1 & (1 << 0)) ? "yes" : "no",
+ (features1 & (1 << 0)) ? "yes" : "no",
+ maxf);
+ print ("flags\t\t:");
+ if (features1 & (1 << 0))
+ print (" fpu");
+ if (features1 & (1 << 1))
+ print (" vme");
+ if (features1 & (1 << 2))
+ print (" de");
+ if (features1 & (1 << 3))
+ print (" pse");
+ if (features1 & (1 << 4))
+ print (" tsc");
+ if (features1 & (1 << 5))
+ print (" msr");
+ if (features1 & (1 << 6))
+ print (" pae");
+ if (features1 & (1 << 7))
+ print (" mce");
+ if (features1 & (1 << 8))
+ print (" cx8");
+ if (features1 & (1 << 9))
+ print (" apic");
+ if (features1 & (1 << 11))
+ print (" sep");
+ if (features1 & (1 << 12))
+ print (" mtrr");
+ if (features1 & (1 << 13))
+ print (" pge");
+ if (features1 & (1 << 14))
+ print (" mca");
+ if (features1 & (1 << 15))
+ print (" cmov");
+ if (features1 & (1 << 16))
+ print (" pat");
+ if (features1 & (1 << 17))
+ print (" pse36");
+ if (features1 & (1 << 18))
+ print (" pn");
+ if (features1 & (1 << 19))
+ print (" clflush");
+ if (is_intel && features1 & (1 << 21))
+ print (" dts");
+ if (is_intel && features1 & (1 << 22))
+ print (" acpi");
+ if (features1 & (1 << 23))
+ print (" mmx");
+ if (features1 & (1 << 24))
+ print (" fxsr");
+ if (features1 & (1 << 25))
+ print (" sse");
+ if (features1 & (1 << 26))
+ print (" sse2");
+ if (is_intel && (features1 & (1 << 27)))
+ print (" ss");
+ if (features1 & (1 << 28))
+ print (" ht");
+ if (is_intel)
+ {
+ if (features1 & (1 << 29))
+ print (" tm");
+ if (features1 & (1 << 30))
+ print (" ia64");
+ if (features1 & (1 << 31))
+ print (" pbe");
+ }
+
+ if (is_amd && maxe >= 0x80000001)
+ {
+ cpuid (&unused, &unused, &unused, &features1, 0x80000001);
+
+ if (features1 & (1 << 11))
+ print (" syscall");
+ if (features1 & (1 << 19)) /* Huh? Not in AMD64 specs. */
+ print (" mp");
+ if (features1 & (1 << 20))
+ print (" nx");
+ if (features1 & (1 << 22))
+ print (" mmxext");
+ if (features1 & (1 << 25))
+ print (" fxsr_opt");
+ if (features1 & (1 << 26))
+ print (" pdpe1gb");
+ if (features1 & (1 << 27))
+ print (" rdtscp");
+ if (features1 & (1 << 29))
+ print (" lm");
+ if (features1 & (1 << 30)) /* 31th bit is on. */
+ print (" 3dnowext");
+ if (features1 & (1 << 31)) /* 32th bit (highest) is on. */
+ print (" 3dnow");
+ }
- bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n"
- "fpu_exception\t: %s\n"
- "cpuid level\t: %d\n"
- "wp\t\t: yes\n",
- (features1 & (1 << 0)) ? "yes" : "no",
- (features1 & (1 << 0)) ? "yes" : "no",
- maxf);
- print ("flags\t\t:");
- if (features1 & (1 << 0))
- print (" fpu");
- if (features1 & (1 << 1))
- print (" vme");
+ if (features2 & (1 << 0))
+ print (" pni");
+ if (is_intel)
+ {
+ if (features2 & (1 << 2))
+ print (" dtes64");
+ if (features2 & (1 << 3))
+ print (" monitor");
+ if (features2 & (1 << 4))
+ print (" ds_cpl");
+ if (features2 & (1 << 5))
+ print (" vmx");
+ if (features2 & (1 << 6))
+ print (" smx");
+ if (features2 & (1 << 7))
+ print (" est");
+ if (features2 & (1 << 8))
+ print (" tm2");
+ if (features2 & (1 << 9))
+ print (" ssse3");
+ if (features2 & (1 << 10))
+ print (" cid");
+ if (features2 & (1 << 12))
+ print (" fma");
+ }
+ if (features2 & (1 << 13))
+ print (" cx16");
+ if (is_intel)
+ {
+ if (features2 & (1 << 14))
+ print (" xtpr");
+ if (features2 & (1 << 15))
+ print (" pdcm");
+ if (features2 & (1 << 18))
+ print (" dca");
+ if (features2 & (1 << 19))
+ print (" sse4_1");
+ if (features2 & (1 << 20))
+ print (" sse4_2");
+ if (features2 & (1 << 21))
+ print (" x2apic");
+ if (features2 & (1 << 22))
+ print (" movbe");
+ if (features2 & (1 << 23))
+ print (" popcnt");
+ if (features2 & (1 << 25))
+ print (" aes");
+ if (features2 & (1 << 26))
+ print (" xsave");
+ if (features2 & (1 << 27))
+ print (" osxsave");
+ if (features2 & (1 << 28))
+ print (" avx");
+ if (features2 & (1 << 29))
+ print (" f16c");
+ if (features2 & (1 << 30))
+ print (" rdrand");
+ if (features2 & (1 << 31))
+ print (" hypervisor");
+ }
+
+ if (maxe >= 0x80000001)
+ {
+ cpuid (&unused, &unused, &features1, &unused, 0x80000001);
+
+ if (features1 & (1 << 0))
+ print (" lahf_lm");
+ if (features1 & (1 << 1))
+ print (" cmp_legacy");
+ if (is_amd)
+ {
if (features1 & (1 << 2))
- print (" de");
+ print (" svm");
if (features1 & (1 << 3))
- print (" pse");
+ print (" extapic");
if (features1 & (1 << 4))
- print (" tsc");
+ print (" cr8_legacy");
if (features1 & (1 << 5))
- print (" msr");
+ print (" abm");
if (features1 & (1 << 6))
- print (" pae");
+ print (" sse4a");
if (features1 & (1 << 7))
- print (" mce");
+ print (" misalignsse");
if (features1 & (1 << 8))
- print (" cx8");
+ print (" 3dnowprefetch");
if (features1 & (1 << 9))
- print (" apic");
+ print (" osvw");
+ }
+ if (features1 & (1 << 10))
+ print (" ibs");
+ if (is_amd)
+ {
if (features1 & (1 << 11))
- print (" sep");
+ print (" sse5");
if (features1 & (1 << 12))
- print (" mtrr");
+ print (" skinit");
if (features1 & (1 << 13))
- print (" pge");
- if (features1 & (1 << 14))
- print (" mca");
+ print (" wdt");
if (features1 & (1 << 15))
- print (" cmov");
+ print (" lwp");
if (features1 & (1 << 16))
- print (" pat");
+ print (" fma4");
if (features1 & (1 << 17))
- print (" pse36");
- if (features1 & (1 << 18))
- print (" pn");
+ print (" tce");
if (features1 & (1 << 19))
- print (" clflush");
- if (is_intel && features1 & (1 << 21))
- print (" dts");
- if (is_intel && features1 & (1 << 22))
- print (" acpi");
+ print (" nodeid_msr");
+ if (features1 & (1 << 21))
+ print (" tbm");
+ if (features1 & (1 << 22))
+ print (" topoext");
if (features1 & (1 << 23))
- print (" mmx");
+ print (" perfctr_core");
if (features1 & (1 << 24))
- print (" fxsr");
- if (features1 & (1 << 25))
- print (" sse");
- if (features1 & (1 << 26))
- print (" sse2");
- if (is_intel && (features1 & (1 << 27)))
- print (" ss");
+ print (" perfctr_nb");
if (features1 & (1 << 28))
- print (" ht");
- if (is_intel)
- {
- if (features1 & (1 << 29))
- print (" tm");
- if (features1 & (1 << 30))
- print (" ia64");
- if (features1 & (1 << 31))
- print (" pbe");
- }
-
- if (is_amd && maxe >= 0x80000001)
- {
- cpuid (&unused, &unused, &unused, &features1, 0x80000001);
-
- if (features1 & (1 << 11))
- print (" syscall");
- if (features1 & (1 << 19)) /* Huh? Not in AMD64 specs. */
- print (" mp");
- if (features1 & (1 << 20))
- print (" nx");
- if (features1 & (1 << 22))
- print (" mmxext");
- if (features1 & (1 << 25))
- print (" fxsr_opt");
- if (features1 & (1 << 26))
- print (" pdpe1gb");
- if (features1 & (1 << 27))
- print (" rdtscp");
- if (features1 & (1 << 29))
- print (" lm");
- if (features1 & (1 << 30)) /* 31th bit is on. */
- print (" 3dnowext");
- if (features1 & (1 << 31)) /* 32th bit (highest) is on. */
- print (" 3dnow");
- }
-
- if (features2 & (1 << 0))
- print (" pni");
- if (is_intel)
- {
- if (features2 & (1 << 2))
- print (" dtes64");
- if (features2 & (1 << 3))
- print (" monitor");
- if (features2 & (1 << 4))
- print (" ds_cpl");
- if (features2 & (1 << 5))
- print (" vmx");
- if (features2 & (1 << 6))
- print (" smx");
- if (features2 & (1 << 7))
- print (" est");
- if (features2 & (1 << 8))
- print (" tm2");
- if (features2 & (1 << 9))
- print (" ssse3");
- if (features2 & (1 << 10))
- print (" cid");
- if (features2 & (1 << 12))
- print (" fma");
- }
- if (features2 & (1 << 13))
- print (" cx16");
- if (is_intel)
- {
- if (features2 & (1 << 14))
- print (" xtpr");
- if (features2 & (1 << 15))
- print (" pdcm");
- if (features2 & (1 << 18))
- print (" dca");
- if (features2 & (1 << 19))
- print (" sse4_1");
- if (features2 & (1 << 20))
- print (" sse4_2");
- if (features2 & (1 << 21))
- print (" x2apic");
- if (features2 & (1 << 22))
- print (" movbe");
- if (features2 & (1 << 23))
- print (" popcnt");
- if (features2 & (1 << 25))
- print (" aes");
- if (features2 & (1 << 26))
- print (" xsave");
- if (features2 & (1 << 27))
- print (" osxsave");
- if (features2 & (1 << 28))
- print (" avx");
- if (features2 & (1 << 29))
- print (" f16c");
- if (features2 & (1 << 30))
- print (" rdrand");
- if (features2 & (1 << 31))
- print (" hypervisor");
- }
-
- if (maxe >= 0x80000001)
- {
- cpuid (&unused, &unused, &features1, &unused, 0x80000001);
+ print (" perfctr_l2");
+ }
+ }
+ if (is_intel) /* features scattered in various CPUID levels. */
+ {
+ cpuid (&features1, &unused, &features2, &unused, 0x06);
+
+ if (features1 & (1 << 1))
+ print (" ida");
+ if (features1 & (1 << 2))
+ print (" arat");
+ if (features2 & (1 << 3))
+ print (" epb");
+
+ cpuid (&features2, &unused, &unused, &unused, 0x0d, 1);
+ if (features2 & (1 << 0))
+ print (" xsaveopt");
+
+ if (features1 & (1 << 4))
+ print (" pln");
+ if (features1 & (1 << 6))
+ print (" pts");
+ if (features1 & (1 << 0))
+ print (" dtherm");
+ }
+ if (is_intel) /* Extended feature flags */
+ {
+ cpuid (&unused, &features1, &unused, &unused, 0x07, 0);
+
+ if (features1 & (1 << 0))
+ print (" fsgsbase");
+ if (features1 & (1 << 1))
+ print (" tsc_adjust");
+ if (features1 & (1 << 3))
+ print (" bmi1");
+ if (features1 & (1 << 4))
+ print (" hle");
+ if (features1 & (1 << 5))
+ print (" avx2");
+ if (features1 & (1 << 7))
+ print (" smep");
+ if (features1 & (1 << 8))
+ print (" bmi2");
+ if (features1 & (1 << 9))
+ print (" erms");
+ if (features1 & (1 << 10))
+ print (" invpcid");
+ if (features1 & (1 << 11))
+ print (" rtm");
+ if (features1 & (1 << 14))
+ print (" mpx");
+ if (features1 & (1 << 16))
+ print (" avx512f");
+ if (features1 & (1 << 18))
+ print (" rdseed");
+ if (features1 & (1 << 19))
+ print (" adx");
+ if (features1 & (1 << 20))
+ print (" smap");
+ if (features1 & (1 << 23))
+ print (" clflushopt");
+ if (features1 & (1 << 26))
+ print (" avx512pf");
+ if (features1 & (1 << 27))
+ print (" avx512er");
+ if (features1 & (1 << 28))
+ print (" avx512cd");
+ }
- if (features1 & (1 << 0))
- print (" lahf_lm");
- if (features1 & (1 << 1))
- print (" cmp_legacy");
- if (is_amd)
- {
- if (features1 & (1 << 2))
- print (" svm");
- if (features1 & (1 << 3))
- print (" extapic");
- if (features1 & (1 << 4))
- print (" cr8_legacy");
- if (features1 & (1 << 5))
- print (" abm");
- if (features1 & (1 << 6))
- print (" sse4a");
- if (features1 & (1 << 7))
- print (" misalignsse");
- if (features1 & (1 << 8))
- print (" 3dnowprefetch");
- if (features1 & (1 << 9))
- print (" osvw");
- }
- if (features1 & (1 << 10))
- print (" ibs");
- if (is_amd)
- {
- if (features1 & (1 << 11))
- print (" sse5");
- if (features1 & (1 << 12))
- print (" skinit");
- if (features1 & (1 << 13))
- print (" wdt");
- if (features1 & (1 << 15))
- print (" lwp");
- if (features1 & (1 << 16))
- print (" fma4");
- if (features1 & (1 << 17))
- print (" tce");
- if (features1 & (1 << 19))
- print (" nodeid_msr");
- if (features1 & (1 << 21))
- print (" tbm");
- if (features1 & (1 << 22))
- print (" topoext");
- if (features1 & (1 << 23))
- print (" perfctr_core");
- if (features1 & (1 << 24))
- print (" perfctr_nb");
- if (features1 & (1 << 28))
- print (" perfctr_l2");
- }
- }
- if (is_intel) /* features scattered in various CPUID levels. */
- {
- cpuid (&features1, &unused, &features2, &unused, 0x06);
-
- if (features1 & (1 << 1))
- print (" ida");
- if (features1 & (1 << 2))
- print (" arat");
- if (features2 & (1 << 3))
- print (" epb");
-
- cpuid (&features2, &unused, &unused, &unused, 0x0d, 1);
- if (features2 & (1 << 0))
- print (" xsaveopt");
-
- if (features1 & (1 << 4))
- print (" pln");
- if (features1 & (1 << 6))
- print (" pts");
- if (features1 & (1 << 0))
- print (" dtherm");
- }
- if (is_intel) /* Extended feature flags */
- {
- cpuid (&unused, &features1, &unused, &unused, 0x07, 0);
-
- if (features1 & (1 << 0))
- print (" fsgsbase");
- if (features1 & (1 << 1))
- print (" tsc_adjust");
- if (features1 & (1 << 3))
- print (" bmi1");
- if (features1 & (1 << 4))
- print (" hle");
- if (features1 & (1 << 5))
- print (" avx2");
- if (features1 & (1 << 7))
- print (" smep");
- if (features1 & (1 << 8))
- print (" bmi2");
- if (features1 & (1 << 9))
- print (" erms");
- if (features1 & (1 << 10))
- print (" invpcid");
- if (features1 & (1 << 11))
- print (" rtm");
- if (features1 & (1 << 14))
- print (" mpx");
- if (features1 & (1 << 16))
- print (" avx512f");
- if (features1 & (1 << 18))
- print (" rdseed");
- if (features1 & (1 << 19))
- print (" adx");
- if (features1 & (1 << 20))
- print (" smap");
- if (features1 & (1 << 23))
- print (" clflushopt");
- if (features1 & (1 << 26))
- print (" avx512pf");
- if (features1 & (1 << 27))
- print (" avx512er");
- if (features1 & (1 << 28))
- print (" avx512cd");
- }
+ print ("\n");
- print ("\n");
+ /* TODO: bogomips */
- /* TODO: bogomips */
+ bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
+ "cache_alignment\t: %d\n",
+ clflush,
+ cache_alignment);
- if (tlb_size >= 0)
- bufptr += __small_sprintf (bufptr,
- "TLB size\t: %d 4K pages\n",
- tlb_size);
- bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
- "cache_alignment\t: %d\n",
- clflush,
- cache_alignment);
+ if (maxe >= 0x80000008) /* Address size. */
+ {
+ uint32_t addr_size, phys, virt;
+ cpuid (&addr_size, &unused, &unused, &unused, 0x80000008);
+
+ phys = addr_size & 0xff;
+ virt = (addr_size >> 8) & 0xff;
+ /* Fix an errata on Intel CPUs */
+ if (is_intel && family == 15 && model == 3 && stepping == 4)
+ phys = 36;
+ bufptr += __small_sprintf (bufptr, "address sizes\t: "
+ "%u bits physical, "
+ "%u bits virtual\n",
+ phys, virt);
+ }
- if (maxe >= 0x80000008) /* Address size. */
- {
- uint32_t addr_size, phys, virt;
- cpuid (&addr_size, &unused, &unused, &unused, 0x80000008);
-
- phys = addr_size & 0xff;
- virt = (addr_size >> 8) & 0xff;
- /* Fix an errata on Intel CPUs */
- if (is_intel && family == 15 && model == 3 && stepping == 4)
- phys = 36;
- bufptr += __small_sprintf (bufptr, "address sizes\t: "
- "%u bits physical, "
- "%u bits virtual\n",
- phys, virt);
- }
+ if (maxe >= 0x80000007) /* Advanced power management. */
+ {
+ cpuid (&unused, &unused, &unused, &features1, 0x80000007);
+
+ print ("power management:");
+ if (features1 & (1 << 0))
+ print (" ts");
+ if (features1 & (1 << 1))
+ print (" fid");
+ if (features1 & (1 << 2))
+ print (" vid");
+ if (features1 & (1 << 3))
+ print (" ttp");
+ if (features1 & (1 << 4))
+ print (" tm");
+ if (features1 & (1 << 5))
+ print (" stc");
+ if (features1 & (1 << 6))
+ print (" 100mhzsteps");
+ if (features1 & (1 << 7))
+ print (" hwpstate");
+ }
- if (maxe >= 0x80000007) /* Advanced power management. */
- {
- cpuid (&unused, &unused, &unused, &features1, 0x80000007);
-
- print ("power management:");
- if (features1 & (1 << 0))
- print (" ts");
- if (features1 & (1 << 1))
- print (" fid");
- if (features1 & (1 << 2))
- print (" vid");
- if (features1 & (1 << 3))
- print (" ttp");
- if (features1 & (1 << 4))
- print (" tm");
- if (features1 & (1 << 5))
- print (" stc");
- if (features1 & (1 << 6))
- print (" 100mhzsteps");
- if (features1 & (1 << 7))
- print (" hwpstate");
- }
- }
+ if (orig_affinity_mask != 0)
+ {
+ if (wincap.has_processor_groups ())
+ SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity,
+ NULL);
else
- {
- bufptr += __small_sprintf (bufptr, "cpu MHz : %d\n"
- "fpu : %s\n",
- cpu_mhz,
- IsProcessorFeaturePresent (PF_FLOATING_POINT_EMULATED) ? "no" : "yes");
- }
+ SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask);
}
- if (orig_affinity_mask != 0)
- SetThreadAffinityMask (GetCurrentThread (), orig_affinity_mask);
print ("\n");
}
diff --git a/winsup/cygwin/release/2.2.1 b/winsup/cygwin/release/2.2.1
index 3a6da3a..d8453d3 100644
--- a/winsup/cygwin/release/2.2.1
+++ b/winsup/cygwin/release/2.2.1
@@ -5,11 +5,13 @@ What's new:
What changed:
-------------
-- Revert the following patch from 2.2.0:
- When started from a non-Cygwin process, check if $HOME starts with a
- slash (absolute POSIX path). Otherwise ignore it.
-
Bug Fixes
---------
+- Revert the following patch from 2.2.0:
+ When started from a non-Cygwin process, check if $HOME starts with a
+ slash (absolute POSIX path). Otherwise ignore it.
+
+- Fix output of /proc/cpuinfo in terms of cpu topology and cache size for
+ modern CPUs and modern Windows OSes supporting more than 64 logical CPUs.
diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc
index 78baa68..92d47d3 100644
--- a/winsup/cygwin/wincap.cc
+++ b/winsup/cygwin/wincap.cc
@@ -49,6 +49,7 @@ wincaps wincap_xpsp2 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_microsoft_accounts:false,
has_set_thread_stack_guarantee:false,
has_broken_rtl_query_process_debug_information:false,
+ has_processor_groups:false,
};
wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -80,6 +81,7 @@ wincaps wincap_2003 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_microsoft_accounts:false,
has_set_thread_stack_guarantee:true,
has_broken_rtl_query_process_debug_information:true,
+ has_processor_groups:false,
};
wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -111,6 +113,7 @@ wincaps wincap_vista __attribute__((section (".cygwin_dll_common"), shared)) = {
has_microsoft_accounts:false,
has_set_thread_stack_guarantee:true,
has_broken_rtl_query_process_debug_information:false,
+ has_processor_groups:false,
};
wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -142,6 +145,7 @@ wincaps wincap_7 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_microsoft_accounts:false,
has_set_thread_stack_guarantee:true,
has_broken_rtl_query_process_debug_information:false,
+ has_processor_groups:true,
};
wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -173,6 +177,7 @@ wincaps wincap_8 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_microsoft_accounts:true,
has_set_thread_stack_guarantee:true,
has_broken_rtl_query_process_debug_information:false,
+ has_processor_groups:true,
};
wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
@@ -204,6 +209,7 @@ wincaps wincap_10 __attribute__((section (".cygwin_dll_common"), shared)) = {
has_microsoft_accounts:true,
has_set_thread_stack_guarantee:true,
has_broken_rtl_query_process_debug_information:false,
+ has_processor_groups:true,
};
wincapc wincap __attribute__((section (".cygwin_dll_common"), shared));
diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h
index 4058557..e4f67bc 100644
--- a/winsup/cygwin/wincap.h
+++ b/winsup/cygwin/wincap.h
@@ -42,6 +42,7 @@ struct wincaps
unsigned has_microsoft_accounts : 1;
unsigned has_set_thread_stack_guarantee : 1;
unsigned has_broken_rtl_query_process_debug_information : 1;
+ unsigned has_processor_groups : 1;
};
class wincapc
@@ -98,6 +99,7 @@ public:
bool IMPLEMENT (has_microsoft_accounts)
bool IMPLEMENT (has_set_thread_stack_guarantee)
bool IMPLEMENT (has_broken_rtl_query_process_debug_information)
+ bool IMPLEMENT (has_processor_groups)
#undef IMPLEMENT
};
More information about the Cygwin-cvs
mailing list