Cygwin: implement sched_getcpu
* create new function __get_cpus_per_group to evaluate # of CPU groups * Call from format_proc_cpuinfo and sched_getcpu * Bump API minor version Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
This commit is contained in:
		| @@ -580,6 +580,7 @@ LoadDLLfunc (if_indextoname, 8, iphlpapi) | |||||||
| LoadDLLfunc (if_nametoindex, 4, iphlpapi) | LoadDLLfunc (if_nametoindex, 4, iphlpapi) | ||||||
|  |  | ||||||
| LoadDLLfuncEx2 (DiscardVirtualMemory, 8, kernel32, 1, 127) | LoadDLLfuncEx2 (DiscardVirtualMemory, 8, kernel32, 1, 127) | ||||||
|  | LoadDLLfunc (GetCurrentProcessorNumberEx, 4, kernel32) | ||||||
| LoadDLLfuncEx (GetLogicalProcessorInformationEx, 12, kernel32, 1) | LoadDLLfuncEx (GetLogicalProcessorInformationEx, 12, kernel32, 1) | ||||||
| LoadDLLfunc (GetSystemTimePreciseAsFileTime, 4, kernel32) | LoadDLLfunc (GetSystemTimePreciseAsFileTime, 4, kernel32) | ||||||
| LoadDLLfuncEx (PrefetchVirtualMemory, 16, kernel32, 1) | LoadDLLfuncEx (PrefetchVirtualMemory, 16, kernel32, 1) | ||||||
|   | |||||||
| @@ -1249,6 +1249,7 @@ scandirat SIGFE | |||||||
| scanf SIGFE | scanf SIGFE | ||||||
| sched_get_priority_max SIGFE | sched_get_priority_max SIGFE | ||||||
| sched_get_priority_min SIGFE | sched_get_priority_min SIGFE | ||||||
|  | sched_getcpu SIGFE | ||||||
| sched_getparam SIGFE | sched_getparam SIGFE | ||||||
| sched_getscheduler NOSIGFE | sched_getscheduler NOSIGFE | ||||||
| sched_rr_get_interval SIGFE | sched_rr_get_interval SIGFE | ||||||
|   | |||||||
| @@ -600,7 +600,6 @@ format_proc_stat (void *, char *&destbuf) | |||||||
|   return eobuf - buf; |   return eobuf - buf; | ||||||
| } | } | ||||||
|  |  | ||||||
| #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s)))) |  | ||||||
| #define print(x) { bufptr = stpcpy (bufptr, (x)); } | #define print(x) { bufptr = stpcpy (bufptr, (x)); } | ||||||
|  |  | ||||||
| static inline uint32_t | static inline uint32_t | ||||||
| @@ -640,46 +639,7 @@ format_proc_cpuinfo (void *, char *&destbuf) | |||||||
|   char *bufptr = buf; |   char *bufptr = buf; | ||||||
|  |  | ||||||
|   //WORD num_cpu_groups = 1;	/* Pre Windows 7, only one group... */ |   //WORD num_cpu_groups = 1;	/* Pre Windows 7, only one group... */ | ||||||
|   WORD num_cpu_per_group = 64;	/* ...and a max of 64 CPUs. */ |   WORD num_cpu_per_group = __get_cpus_per_group (); | ||||||
|  |  | ||||||
|   PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi = |  | ||||||
| 	    (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get (); |  | ||||||
|   DWORD lpi_size = NT_MAX_PATH; |  | ||||||
|  |  | ||||||
|   /* Fake a SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX group info block on Vista |  | ||||||
|      systems.  This may be over the top but if the below code just using |  | ||||||
|      ActiveProcessorCount turns out to be insufficient, we can build on that. */ |  | ||||||
|   if (!wincap.has_processor_groups () |  | ||||||
|       || !GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size)) |  | ||||||
|     { |  | ||||||
|       lpi_size = sizeof *lpi; |  | ||||||
|       lpi->Relationship = RelationGroup; |  | ||||||
|       lpi->Size = lpi_size; |  | ||||||
|       lpi->Group.MaximumGroupCount = 1; |  | ||||||
|       lpi->Group.ActiveGroupCount = 1; |  | ||||||
|       lpi->Group.GroupInfo[0].MaximumProcessorCount = wincap.cpu_count (); |  | ||||||
|       lpi->Group.GroupInfo[0].ActiveProcessorCount |  | ||||||
| 	= __builtin_popcountl (wincap.cpu_mask ()); |  | ||||||
|       lpi->Group.GroupInfo[0].ActiveProcessorMask = wincap.cpu_mask (); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   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; |  | ||||||
| 	/* Turns out, there are systems with a MaximumProcessorCount not |  | ||||||
| 	   reflecting the actually available CPUs.  The ActiveProcessorCount |  | ||||||
| 	   is correct though.  So we just use ActiveProcessorCount for now, |  | ||||||
| 	   hoping the best.  If it turns out that we have to handle more |  | ||||||
| 	   complex CPU layouts with weird ActiveProcessorMasks, we can |  | ||||||
| 	   do that by restructuring the subsequent CPU loop. */ |  | ||||||
| 	num_cpu_per_group |  | ||||||
| 		= plpi->Group.GroupInfo[0].ActiveProcessorCount; |  | ||||||
| 	break; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   cpu_num_p = wcpcpy (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION" |   cpu_num_p = wcpcpy (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION" | ||||||
| 				"\\System\\CentralProcessor\\"); | 				"\\System\\CentralProcessor\\"); | ||||||
|   | |||||||
| @@ -498,12 +498,13 @@ details. */ | |||||||
|   327: Export pthread_tryjoin_np, pthread_timedjoin_np. |   327: Export pthread_tryjoin_np, pthread_timedjoin_np. | ||||||
|   328: Export aio_cancel, aio_error, aio_fsync, aio_read, aio_return, |   328: Export aio_cancel, aio_error, aio_fsync, aio_read, aio_return, | ||||||
|        aio_suspend, aio_write, lio_listio. |        aio_suspend, aio_write, lio_listio. | ||||||
|  |   329: Export sched_getcpu.. | ||||||
|  |  | ||||||
|   Note that we forgot to bump the api for ualarm, strtoll, strtoull, |   Note that we forgot to bump the api for ualarm, strtoll, strtoull, | ||||||
|   sigaltstack, sethostname. */ |   sigaltstack, sethostname. */ | ||||||
|  |  | ||||||
| #define CYGWIN_VERSION_API_MAJOR 0 | #define CYGWIN_VERSION_API_MAJOR 0 | ||||||
| #define CYGWIN_VERSION_API_MINOR 328 | #define CYGWIN_VERSION_API_MINOR 329 | ||||||
|  |  | ||||||
| /* There is also a compatibity version number associated with the shared memory | /* There is also a compatibity version number associated with the shared memory | ||||||
|    regions.  It is incremented when incompatible changes are made to the shared |    regions.  It is incremented when incompatible changes are made to the shared | ||||||
|   | |||||||
| @@ -15,6 +15,7 @@ details. */ | |||||||
| #include "path.h" | #include "path.h" | ||||||
| #include "fhandler.h" | #include "fhandler.h" | ||||||
| #include "exception.h" | #include "exception.h" | ||||||
|  | #include "tls_pbuf.h" | ||||||
|  |  | ||||||
| int __reg2 | int __reg2 | ||||||
| check_invalid_virtual_addr (const void *s, unsigned sz) | check_invalid_virtual_addr (const void *s, unsigned sz) | ||||||
| @@ -959,3 +960,55 @@ SetThreadName(DWORD dwThreadID, const char* threadName) | |||||||
|   __except (NO_ERROR) |   __except (NO_ERROR) | ||||||
|   __endtry |   __endtry | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s)))) | ||||||
|  |  | ||||||
|  | WORD | ||||||
|  | __get_cpus_per_group (void) | ||||||
|  | { | ||||||
|  |   static WORD num_cpu_per_group = 0; | ||||||
|  |  | ||||||
|  |   tmp_pathbuf tp; | ||||||
|  |  | ||||||
|  |   if (num_cpu_per_group) | ||||||
|  |     return num_cpu_per_group; | ||||||
|  |  | ||||||
|  |   num_cpu_per_group = 64; | ||||||
|  |  | ||||||
|  |   PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi = | ||||||
|  |             (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get (); | ||||||
|  |   DWORD lpi_size = NT_MAX_PATH; | ||||||
|  |  | ||||||
|  |   /* Fake a SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX group info block on Vista | ||||||
|  |      systems.  This may be over the top but if the below code just using | ||||||
|  |      ActiveProcessorCount turns out to be insufficient, we can build on that. */ | ||||||
|  |   if (!wincap.has_processor_groups () | ||||||
|  |       || !GetLogicalProcessorInformationEx (RelationGroup, lpi, &lpi_size)) | ||||||
|  |     { | ||||||
|  |       lpi_size = sizeof *lpi; | ||||||
|  |       lpi->Relationship = RelationGroup; | ||||||
|  |       lpi->Size = lpi_size; | ||||||
|  |       lpi->Group.MaximumGroupCount = 1; | ||||||
|  |       lpi->Group.ActiveGroupCount = 1; | ||||||
|  |       lpi->Group.GroupInfo[0].MaximumProcessorCount = wincap.cpu_count (); | ||||||
|  |       lpi->Group.GroupInfo[0].ActiveProcessorCount | ||||||
|  |         = __builtin_popcountl (wincap.cpu_mask ()); | ||||||
|  |       lpi->Group.GroupInfo[0].ActiveProcessorMask = wincap.cpu_mask (); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   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) | ||||||
|  |       { | ||||||
|  |         /* There are systems with a MaximumProcessorCount not reflecting the | ||||||
|  | 	   actually available CPUs.  The ActiveProcessorCount is correct | ||||||
|  | 	   though.  So we just use ActiveProcessorCount for now, hoping for | ||||||
|  | 	   the best. */ | ||||||
|  |         num_cpu_per_group | ||||||
|  |                 = plpi->Group.GroupInfo[0].ActiveProcessorCount; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |   return num_cpu_per_group; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -119,4 +119,6 @@ extern "C" HANDLE WINAPI CygwinCreateThread (LPTHREAD_START_ROUTINE thread_func, | |||||||
|  |  | ||||||
| void SetThreadName (DWORD dwThreadID, const char* threadName); | void SetThreadName (DWORD dwThreadID, const char* threadName); | ||||||
|  |  | ||||||
|  | WORD __get_cpus_per_group (void); | ||||||
|  |  | ||||||
| #endif /*_MISCFUNCS_H*/ | #endif /*_MISCFUNCS_H*/ | ||||||
|   | |||||||
| @@ -1,7 +1,8 @@ | |||||||
| What's new: | What's new: | ||||||
| ----------- | ----------- | ||||||
|  |  | ||||||
| - New API: clearenv, pthread_tryjoin_np, pthread_timedjoin_np. | - New APIs: clearenv, pthread_tryjoin_np, pthread_timedjoin_np, | ||||||
|  |   sched_getcpu. | ||||||
|  |  | ||||||
| - New APIs: aio_cancel, aio_error, aio_fsync, aio_read, aio_return, | - New APIs: aio_cancel, aio_error, aio_fsync, aio_read, aio_return, | ||||||
|   aio_suspend, aio_write, lio_listio. |   aio_suspend, aio_write, lio_listio. | ||||||
|   | |||||||
| @@ -411,4 +411,17 @@ sched_yield () | |||||||
|   SwitchToThread (); |   SwitchToThread (); | ||||||
|   return 0; |   return 0; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | int | ||||||
|  | sched_getcpu () | ||||||
|  | { | ||||||
|  |   if (!wincap.has_processor_groups ()) | ||||||
|  |     return (int) GetCurrentProcessorNumber (); | ||||||
|  |  | ||||||
|  |   PROCESSOR_NUMBER pnum; | ||||||
|  |  | ||||||
|  |   GetCurrentProcessorNumberEx (&pnum); | ||||||
|  |   return pnum.Group * __get_cpus_per_group () + pnum.Number; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | } /* extern C */ | ||||||
|   | |||||||
| @@ -17,7 +17,7 @@ SO_RCVTIMEO and SO_SNDTIMEO socket options are now honored. | |||||||
| </para></listitem> | </para></listitem> | ||||||
|  |  | ||||||
| <listitem><para> | <listitem><para> | ||||||
| New API: clearenv, pthread_tryjoin_np, pthread_timedjoin_np. | New APIs: clearenv, pthread_tryjoin_np, pthread_timedjoin_np, sched_getcpu. | ||||||
| </para></listitem> | </para></listitem> | ||||||
|  |  | ||||||
| <listitem><para> | <listitem><para> | ||||||
|   | |||||||
| @@ -1375,6 +1375,7 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para> | |||||||
|     rawmemchr |     rawmemchr | ||||||
|     removexattr |     removexattr | ||||||
|     scandirat |     scandirat | ||||||
|  |     sched_getcpu | ||||||
|     setxattr |     setxattr | ||||||
|     sincos |     sincos | ||||||
|     sincosf |     sincosf | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user