Cygwin: Implement sched_[gs]etaffinity()
This patch set implements the Linux syscalls sched_getaffinity, sched_setaffinity, pthread_getaffinity_np, and pthread_setaffinity_np. Linux has a straightforward view of the cpu sets used in affinity masks. They are simply long (1024-bit) bit masks. This code emulates that view while internally dealing with Windows' distribution of available CPUs among processor groups.
This commit is contained in:
		
							parent
							
								
									d54edfdf81
								
							
						
					
					
						commit
						641ecb0753
					
				|  | @ -92,6 +92,29 @@ int sched_yield( void ); | ||||||
| 
 | 
 | ||||||
| #if __GNU_VISIBLE | #if __GNU_VISIBLE | ||||||
| int sched_getcpu(void); | int sched_getcpu(void); | ||||||
|  | 
 | ||||||
|  | /* Affinity-related definitions, here until numerous enough to separate out */ | ||||||
|  | #ifdef __x86_64__ | ||||||
|  | typedef uint64_t __cpu_mask; | ||||||
|  | #else | ||||||
|  | typedef uint32_t __cpu_mask; | ||||||
|  | #endif | ||||||
|  | #define __CPU_SETSIZE 1024  // maximum number of logical processors tracked
 | ||||||
|  | #define __NCPUBITS (8 * sizeof (__cpu_mask))  // max size of processor group
 | ||||||
|  | #define __CPU_GROUPMAX (__CPU_SETSIZE / __NCPUBITS)  // maximum group number
 | ||||||
|  | 
 | ||||||
|  | #define __CPUELT(cpu)	((cpu) / __NCPUBITS) | ||||||
|  | #define __CPUMASK(cpu)	((__cpu_mask) 1 << ((cpu) % __NCPUBITS)) | ||||||
|  | 
 | ||||||
|  | typedef struct | ||||||
|  | { | ||||||
|  |   __cpu_mask __bits[__CPU_GROUPMAX]; | ||||||
|  | } cpu_set_t; | ||||||
|  | 
 | ||||||
|  | int sched_getaffinity (pid_t, size_t, cpu_set_t *); | ||||||
|  | int sched_get_thread_affinity (void *, size_t, cpu_set_t *); | ||||||
|  | int sched_setaffinity (pid_t, size_t, const cpu_set_t *); | ||||||
|  | int sched_set_thread_affinity (void *, size_t, const cpu_set_t *); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
|  |  | ||||||
|  | @ -1084,6 +1084,7 @@ pthread_create SIGFE | ||||||
| pthread_detach SIGFE | pthread_detach SIGFE | ||||||
| pthread_equal SIGFE | pthread_equal SIGFE | ||||||
| pthread_exit SIGFE | pthread_exit SIGFE | ||||||
|  | pthread_getaffinity_np SIGFE | ||||||
| pthread_getattr_np SIGFE | pthread_getattr_np SIGFE | ||||||
| pthread_getconcurrency SIGFE | pthread_getconcurrency SIGFE | ||||||
| pthread_getcpuclockid SIGFE | pthread_getcpuclockid SIGFE | ||||||
|  | @ -1128,6 +1129,7 @@ pthread_rwlockattr_getpshared SIGFE | ||||||
| pthread_rwlockattr_init SIGFE | pthread_rwlockattr_init SIGFE | ||||||
| pthread_rwlockattr_setpshared SIGFE | pthread_rwlockattr_setpshared SIGFE | ||||||
| pthread_self SIGFE | pthread_self SIGFE | ||||||
|  | pthread_setaffinity_np SIGFE | ||||||
| pthread_setcancelstate SIGFE | pthread_setcancelstate SIGFE | ||||||
| pthread_setcanceltype SIGFE | pthread_setcanceltype SIGFE | ||||||
| pthread_setconcurrency SIGFE | pthread_setconcurrency SIGFE | ||||||
|  | @ -1248,10 +1250,12 @@ 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_getaffinity SIGFE | ||||||
| sched_getcpu 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 | ||||||
|  | sched_setaffinity SIGFE | ||||||
| sched_setparam SIGFE | sched_setparam SIGFE | ||||||
| sched_setscheduler SIGFE | sched_setscheduler SIGFE | ||||||
| sched_yield SIGFE | sched_yield SIGFE | ||||||
|  |  | ||||||
|  | @ -509,12 +509,14 @@ details. */ | ||||||
|   336: New Cygwin PID algorithm (yeah, not really an API change) |   336: New Cygwin PID algorithm (yeah, not really an API change) | ||||||
|   337: MOUNT_BINARY -> MOUNT_TEXT |   337: MOUNT_BINARY -> MOUNT_TEXT | ||||||
|   338: Export secure_getenv. |   338: Export secure_getenv. | ||||||
|  |   339: Export sched_getaffinity, sched_setaffinity, pthread_getaffinity_np, | ||||||
|  |        pthread_setaffinity_np. | ||||||
| 
 | 
 | ||||||
|   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 338 | #define CYGWIN_VERSION_API_MINOR 339 | ||||||
| 
 | 
 | ||||||
| /* 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 | ||||||
|  |  | ||||||
|  | @ -226,8 +226,10 @@ void pthread_testcancel (void); | ||||||
| /* Non posix calls */ | /* Non posix calls */ | ||||||
| 
 | 
 | ||||||
| #if __GNU_VISIBLE | #if __GNU_VISIBLE | ||||||
|  | int pthread_getaffinity_np (pthread_t, size_t, cpu_set_t *); | ||||||
| int pthread_getattr_np (pthread_t, pthread_attr_t *); | int pthread_getattr_np (pthread_t, pthread_attr_t *); | ||||||
| int pthread_getname_np (pthread_t, char *, size_t) __attribute__((__nonnull__(2))); | int pthread_getname_np (pthread_t, char *, size_t) __attribute__((__nonnull__(2))); | ||||||
|  | int pthread_setaffinity_np (pthread_t, size_t, const cpu_set_t *); | ||||||
| int pthread_setname_np (pthread_t, const char *) __attribute__((__nonnull__(2))); | int pthread_setname_np (pthread_t, const char *) __attribute__((__nonnull__(2))); | ||||||
| int pthread_sigqueue (pthread_t *, int, const union sigval); | int pthread_sigqueue (pthread_t *, int, const union sigval); | ||||||
| int pthread_timedjoin_np (pthread_t, void **, const struct timespec *); | int pthread_timedjoin_np (pthread_t, void **, const struct timespec *); | ||||||
|  |  | ||||||
|  | @ -963,17 +963,19 @@ SetThreadName(DWORD dwThreadID, const char* threadName) | ||||||
| 
 | 
 | ||||||
| #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s)))) | #define add_size(p,s) ((p) = ((__typeof__(p))((PBYTE)(p)+(s)))) | ||||||
| 
 | 
 | ||||||
|  | static WORD num_cpu_per_group = 0; | ||||||
|  | static WORD group_count = 0; | ||||||
|  | 
 | ||||||
| WORD | WORD | ||||||
| __get_cpus_per_group (void) | __get_cpus_per_group (void) | ||||||
| { | { | ||||||
|   static WORD num_cpu_per_group = 0; |  | ||||||
| 
 |  | ||||||
|   tmp_pathbuf tp; |   tmp_pathbuf tp; | ||||||
| 
 | 
 | ||||||
|   if (num_cpu_per_group) |   if (num_cpu_per_group) | ||||||
|     return num_cpu_per_group; |     return num_cpu_per_group; | ||||||
| 
 | 
 | ||||||
|   num_cpu_per_group = 64; |   num_cpu_per_group = 64; | ||||||
|  |   group_count = 1; | ||||||
| 
 | 
 | ||||||
|   PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi = |   PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX lpi = | ||||||
|             (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get (); |             (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX) tp.c_get (); | ||||||
|  | @ -1005,10 +1007,20 @@ __get_cpus_per_group (void) | ||||||
| 	   actually available CPUs.  The ActiveProcessorCount is correct | 	   actually available CPUs.  The ActiveProcessorCount is correct | ||||||
| 	   though.  So we just use ActiveProcessorCount for now, hoping for | 	   though.  So we just use ActiveProcessorCount for now, hoping for | ||||||
| 	   the best. */ | 	   the best. */ | ||||||
|         num_cpu_per_group |         num_cpu_per_group = plpi->Group.GroupInfo[0].ActiveProcessorCount; | ||||||
|                 = plpi->Group.GroupInfo[0].ActiveProcessorCount; | 
 | ||||||
|  | 	/* Follow that lead to get the group count. */ | ||||||
|  | 	group_count = plpi->Group.ActiveGroupCount; | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|   return num_cpu_per_group; |   return num_cpu_per_group; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | WORD | ||||||
|  | __get_group_count (void) | ||||||
|  | { | ||||||
|  |   if (group_count == 0) | ||||||
|  |     (void) __get_cpus_per_group (); // caller should have called this first
 | ||||||
|  |   return group_count; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -120,5 +120,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); | WORD __get_cpus_per_group (void); | ||||||
|  | WORD __get_group_count (void); | ||||||
| 
 | 
 | ||||||
| #endif /*_MISCFUNCS_H*/ | #endif /*_MISCFUNCS_H*/ | ||||||
|  |  | ||||||
|  | @ -5,6 +5,9 @@ What's new: | ||||||
|   1703 or later.  Add fake 24 bit color support for legacy console, |   1703 or later.  Add fake 24 bit color support for legacy console, | ||||||
|   which uses the nearest color from 16 system colors. |   which uses the nearest color from 16 system colors. | ||||||
| 
 | 
 | ||||||
|  | - New APIs: sched_getaffinity, sched_setaffinity, pthread_getaffinity_np, | ||||||
|  |   pthread_setaffinity_np. | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| What changed: | What changed: | ||||||
| ------------- | ------------- | ||||||
|  |  | ||||||
|  | @ -424,4 +424,312 @@ sched_getcpu () | ||||||
|   return pnum.Group * __get_cpus_per_group () + pnum.Number; |   return pnum.Group * __get_cpus_per_group () + pnum.Number; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /* construct an affinity mask with just the 'count' lower-order bits set */ | ||||||
|  | static __cpu_mask | ||||||
|  | groupmask (int count) | ||||||
|  | { | ||||||
|  |   if (count >= (int) (NBBY * sizeof (__cpu_mask))) | ||||||
|  |     return ~(__cpu_mask) 0; | ||||||
|  |   else | ||||||
|  |     return ((__cpu_mask) 1 << count) - 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* return the affinity mask of the indicated group from the given cpu set */ | ||||||
|  | static __cpu_mask | ||||||
|  | getgroup (size_t sizeof_set, const cpu_set_t *set, int groupnum) | ||||||
|  | { | ||||||
|  |   int groupsize = __get_cpus_per_group (); | ||||||
|  |   int bitindex = groupnum * groupsize; | ||||||
|  | 
 | ||||||
|  |   int setsize = NBBY * sizeof_set; // bit size of whole cpu set
 | ||||||
|  |   if (bitindex + groupsize > setsize) | ||||||
|  |     return (__cpu_mask) 0; | ||||||
|  | 
 | ||||||
|  |   int wordsize = NBBY * sizeof (cpu_set_t); | ||||||
|  |   int wordindex = bitindex / wordsize; | ||||||
|  | 
 | ||||||
|  |   __cpu_mask result = set->__bits[wordindex]; | ||||||
|  |   int offset = bitindex % wordsize; | ||||||
|  |   if (offset) | ||||||
|  |     { | ||||||
|  |       result >>= offset; | ||||||
|  |       offset = wordsize - offset; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     offset = wordsize; | ||||||
|  | 
 | ||||||
|  |   if (offset < groupsize) | ||||||
|  |     result |= (set->__bits[wordindex + 1] << offset); | ||||||
|  |   if (groupsize < wordsize) | ||||||
|  |     result &= groupmask (groupsize); | ||||||
|  | 
 | ||||||
|  |   return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* set the given affinity mask for indicated group within the given cpu set */ | ||||||
|  | static __cpu_mask | ||||||
|  | setgroup (size_t sizeof_set, cpu_set_t *set, int groupnum, __cpu_mask aff) | ||||||
|  | { | ||||||
|  |   int groupsize = __get_cpus_per_group (); | ||||||
|  |   int bitindex = groupnum * groupsize; | ||||||
|  | 
 | ||||||
|  |   int setsize = NBBY * sizeof_set; // bit size of whole cpu set
 | ||||||
|  |   if (bitindex + groupsize > setsize) | ||||||
|  |     return (__cpu_mask) 0; | ||||||
|  | 
 | ||||||
|  |   int wordsize = NBBY * sizeof (cpu_set_t); | ||||||
|  |   int wordindex = bitindex / wordsize; | ||||||
|  |   int offset = bitindex % wordsize; | ||||||
|  |   __cpu_mask mask = groupmask (groupsize); | ||||||
|  |   aff &= mask; | ||||||
|  | 
 | ||||||
|  |   set->__bits[wordindex] &= ~(mask << offset); | ||||||
|  |   set->__bits[wordindex] |= aff << offset; | ||||||
|  | 
 | ||||||
|  |   if ((bitindex + groupsize - 1) / wordsize != wordindex) | ||||||
|  |     { | ||||||
|  |       offset = wordsize - offset; | ||||||
|  |       set->__bits[wordindex + 1] &= ~(mask >> offset); | ||||||
|  |       set->__bits[wordindex + 1] |= aff >> offset; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |   return aff; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* figure out which processor group the set bits indicate; can only be one */ | ||||||
|  | static int | ||||||
|  | whichgroup (size_t sizeof_set, const cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   int res = -1; | ||||||
|  |   int maxgroup = min (__get_group_count (), | ||||||
|  |                       (NBBY * sizeof_set) / __get_cpus_per_group ()); | ||||||
|  | 
 | ||||||
|  |   for (int i = 0; i < maxgroup; ++i) | ||||||
|  |     if (getgroup (sizeof_set, set, i)) | ||||||
|  |       { | ||||||
|  | 	if (res >= 0) | ||||||
|  | 	  return -1; // error return if more than one group indicated
 | ||||||
|  | 	else | ||||||
|  | 	  res = i; // remember first group found
 | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |   return res; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | sched_get_thread_affinity (HANDLE thread, size_t sizeof_set, cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   int status = 0; | ||||||
|  | 
 | ||||||
|  |   if (thread) | ||||||
|  |     { | ||||||
|  |       memset (set, 0, sizeof_set); | ||||||
|  |       if (wincap.has_processor_groups () && __get_group_count () > 1) | ||||||
|  | 	{ | ||||||
|  | 	  GROUP_AFFINITY ga; | ||||||
|  | 
 | ||||||
|  | 	  if (!GetThreadGroupAffinity (thread, &ga)) | ||||||
|  | 	    { | ||||||
|  | 	      status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	  setgroup (sizeof_set, set, ga.Group, ga.Mask); | ||||||
|  | 	} | ||||||
|  |       else | ||||||
|  | 	{ | ||||||
|  | 	  THREAD_BASIC_INFORMATION tbi; | ||||||
|  | 
 | ||||||
|  | 	  status = NtQueryInformationThread (thread, ThreadBasicInformation, | ||||||
|  | 					     &tbi, sizeof (tbi), NULL); | ||||||
|  | 	  if (NT_SUCCESS (status)) | ||||||
|  | 	    setgroup (sizeof_set, set, 0, tbi.AffinityMask); | ||||||
|  | 	  else | ||||||
|  | 	    status = geterrno_from_nt_status (status); | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     status = ESRCH; | ||||||
|  | 
 | ||||||
|  | done: | ||||||
|  |   return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | sched_getaffinity (pid_t pid, size_t sizeof_set, cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   HANDLE process = 0; | ||||||
|  |   int status = 0; | ||||||
|  | 
 | ||||||
|  |   pinfo p (pid ? pid : getpid ()); | ||||||
|  |   if (p) | ||||||
|  |     { | ||||||
|  |       process = pid && pid != myself->pid ? | ||||||
|  |                 OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE, | ||||||
|  |                              p->dwProcessId) : GetCurrentProcess (); | ||||||
|  |       KAFFINITY procmask; | ||||||
|  |       KAFFINITY sysmask; | ||||||
|  | 
 | ||||||
|  |       if (!GetProcessAffinityMask (process, &procmask, &sysmask)) | ||||||
|  |         { | ||||||
|  |           status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  |           goto done; | ||||||
|  |         } | ||||||
|  |       memset (set, 0, sizeof_set); | ||||||
|  |       if (wincap.has_processor_groups () && __get_group_count () > 1) | ||||||
|  |         { | ||||||
|  |           USHORT groupcount = __CPU_GROUPMAX; | ||||||
|  |           USHORT grouparray[__CPU_GROUPMAX]; | ||||||
|  | 
 | ||||||
|  |           if (!GetProcessGroupAffinity (process, &groupcount, grouparray)) | ||||||
|  |             { | ||||||
|  | 	      status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 
 | ||||||
|  | 	  KAFFINITY miscmask = groupmask (__get_cpus_per_group ()); | ||||||
|  | 	  for (int i = 0; i < groupcount; i++) | ||||||
|  | 	    setgroup (sizeof_set, set, grouparray[i], miscmask); | ||||||
|  |         } | ||||||
|  |       else | ||||||
|  |         setgroup (sizeof_set, set, 0, procmask); | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     status = ESRCH; | ||||||
|  | 
 | ||||||
|  | done: | ||||||
|  |   if (process && process != GetCurrentProcess ()) | ||||||
|  |     CloseHandle (process); | ||||||
|  | 
 | ||||||
|  |   if (status) | ||||||
|  |     { | ||||||
|  |       set_errno (status); | ||||||
|  |       status = -1; | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     { | ||||||
|  |       /* Emulate documented Linux kernel behavior on successful return */ | ||||||
|  |       status = wincap.cpu_count (); | ||||||
|  |     } | ||||||
|  |   return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | sched_set_thread_affinity (HANDLE thread, size_t sizeof_set, const cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   int group = whichgroup (sizeof_set, set); | ||||||
|  |   int status = 0; | ||||||
|  | 
 | ||||||
|  |   if (thread) | ||||||
|  |     { | ||||||
|  |       if (wincap.has_processor_groups () && __get_group_count () > 1) | ||||||
|  | 	{ | ||||||
|  | 	  GROUP_AFFINITY ga; | ||||||
|  | 
 | ||||||
|  | 	  if (group < 0) | ||||||
|  | 	    { | ||||||
|  | 	      status = EINVAL; | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	  memset (&ga, 0, sizeof (ga)); | ||||||
|  | 	  ga.Mask = getgroup (sizeof_set, set, group); | ||||||
|  | 	  ga.Group = group; | ||||||
|  | 	  if (!SetThreadGroupAffinity (thread, &ga, NULL)) | ||||||
|  | 	    { | ||||||
|  | 	      status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |       else | ||||||
|  | 	{ | ||||||
|  | 	  if (group != 0) | ||||||
|  | 	    { | ||||||
|  | 	      status = EINVAL; | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	  if (!SetThreadAffinityMask (thread, getgroup (sizeof_set, set, 0))) | ||||||
|  | 	    { | ||||||
|  | 	      status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     status = ESRCH; | ||||||
|  | 
 | ||||||
|  | done: | ||||||
|  |   return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int | ||||||
|  | sched_setaffinity (pid_t pid, size_t sizeof_set, const cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   int group = whichgroup (sizeof_set, set); | ||||||
|  |   HANDLE process = 0; | ||||||
|  |   int status = 0; | ||||||
|  | 
 | ||||||
|  |   pinfo p (pid ? pid : getpid ()); | ||||||
|  |   if (p) | ||||||
|  |     { | ||||||
|  |       process = pid && pid != myself->pid ? | ||||||
|  | 		OpenProcess (PROCESS_SET_INFORMATION, FALSE, | ||||||
|  | 			     p->dwProcessId) : GetCurrentProcess (); | ||||||
|  |       if (wincap.has_processor_groups () && __get_group_count () > 1) | ||||||
|  | 	{ | ||||||
|  | 	  USHORT groupcount = __CPU_GROUPMAX; | ||||||
|  | 	  USHORT grouparray[__CPU_GROUPMAX]; | ||||||
|  | 
 | ||||||
|  | 	  if (!GetProcessGroupAffinity (process, &groupcount, grouparray)) | ||||||
|  | 	    { | ||||||
|  | 	      status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	  if (group < 0) | ||||||
|  | 	    { | ||||||
|  | 	      status = EINVAL; | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	  if (groupcount == 1 && grouparray[0] == group) | ||||||
|  | 	    { | ||||||
|  | 	      if (!SetProcessAffinityMask (process, getgroup (sizeof_set, set, group))) | ||||||
|  | 		status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 
 | ||||||
|  | 	  /* If we get here, the user is trying to add the process to another
 | ||||||
|  |              group or move it from current group to another group.  These ops | ||||||
|  |              are not allowed by Windows.  One has to move one or more of the | ||||||
|  |              process' threads to the new group(s) one by one.  Here, we bail. | ||||||
|  |           */ | ||||||
|  | 	  status = EINVAL; | ||||||
|  | 	  goto done; | ||||||
|  | 	} | ||||||
|  |       else | ||||||
|  | 	{ | ||||||
|  | 	  if (group != 0) | ||||||
|  | 	    { | ||||||
|  | 	      status = EINVAL; | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	  if (!SetProcessAffinityMask (process, getgroup (sizeof_set, set, 0))) | ||||||
|  | 	    { | ||||||
|  | 	      status = geterrno_from_win_error (GetLastError (), EPERM); | ||||||
|  | 	      goto done; | ||||||
|  | 	    } | ||||||
|  | 	} | ||||||
|  |     } | ||||||
|  |   else | ||||||
|  |     status = ESRCH; | ||||||
|  | 
 | ||||||
|  | done: | ||||||
|  |   if (process && process != GetCurrentProcess ()) | ||||||
|  |     CloseHandle (process); | ||||||
|  | 
 | ||||||
|  |   if (status) | ||||||
|  |     { | ||||||
|  |       set_errno (status); | ||||||
|  |       status = -1; | ||||||
|  |     } | ||||||
|  |   return status; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } /* extern C */ | } /* extern C */ | ||||||
|  |  | ||||||
|  | @ -23,6 +23,7 @@ details. */ | ||||||
| #include "winsup.h" | #include "winsup.h" | ||||||
| #include "miscfuncs.h" | #include "miscfuncs.h" | ||||||
| #include "path.h" | #include "path.h" | ||||||
|  | #include <sched.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include "sigproc.h" | #include "sigproc.h" | ||||||
| #include "fhandler.h" | #include "fhandler.h" | ||||||
|  | @ -2606,6 +2607,24 @@ pthread_timedjoin_np (pthread_t thread, void **return_val, | ||||||
|   return pthread::join (&thread, (void **) return_val, &timeout); |   return pthread::join (&thread, (void **) return_val, &timeout); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | extern "C" int | ||||||
|  | pthread_getaffinity_np (pthread_t thread, size_t sizeof_set, cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   if (!pthread::is_good_object (&thread)) | ||||||
|  |     return ESRCH; | ||||||
|  | 
 | ||||||
|  |   return sched_get_thread_affinity (thread->win32_obj_id, sizeof_set, set); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern "C" int | ||||||
|  | pthread_setaffinity_np (pthread_t thread, size_t sizeof_set, const cpu_set_t *set) | ||||||
|  | { | ||||||
|  |   if (!pthread::is_good_object (&thread)) | ||||||
|  |     return ESRCH; | ||||||
|  | 
 | ||||||
|  |   return sched_set_thread_affinity (thread->win32_obj_id, sizeof_set, set); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| extern "C" int | extern "C" int | ||||||
| pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) | pthread_getattr_np (pthread_t thread, pthread_attr_t *attr) | ||||||
| { | { | ||||||
|  |  | ||||||
|  | @ -29,6 +29,12 @@ If a SA_SIGINFO signal handler changes the ucontext_t pointed to by the | ||||||
| third parameter, follow it after returning from the handler. | third parameter, follow it after returning from the handler. | ||||||
| </para></listitem> | </para></listitem> | ||||||
| 
 | 
 | ||||||
|  | <listitem><para> | ||||||
|  | Support for getting and setting process and thread affinities.  New APIs: | ||||||
|  | sched_getaffinity, sched_setaffinity, pthread_getaffinity_np, | ||||||
|  | pthread_setaffinity_np. | ||||||
|  | </para></listitem> | ||||||
|  | 
 | ||||||
| </itemizedlist> | </itemizedlist> | ||||||
| 
 | 
 | ||||||
| </sect2> | </sect2> | ||||||
|  |  | ||||||
|  | @ -1359,8 +1359,10 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para> | ||||||
|     pow10f |     pow10f | ||||||
|     pow10l |     pow10l | ||||||
|     ppoll |     ppoll | ||||||
|  |     pthread_getaffinity_np | ||||||
|     pthread_getattr_np |     pthread_getattr_np | ||||||
|     pthread_getname_np |     pthread_getname_np | ||||||
|  |     pthread_setaffinity_np | ||||||
|     pthread_setname_np |     pthread_setname_np | ||||||
|     pthread_sigqueue |     pthread_sigqueue | ||||||
|     pthread_timedjoin_np |     pthread_timedjoin_np | ||||||
|  | @ -1374,7 +1376,9 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para> | ||||||
|     rawmemchr |     rawmemchr | ||||||
|     removexattr |     removexattr | ||||||
|     scandirat |     scandirat | ||||||
|  |     sched_getaffinity | ||||||
|     sched_getcpu |     sched_getcpu | ||||||
|  |     sched_setaffinity | ||||||
|     secure_getenv |     secure_getenv | ||||||
|     setxattr |     setxattr | ||||||
|     signalfd |     signalfd | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue