353 lines
10 KiB
C
353 lines
10 KiB
C
/*
|
|
* sched_setaffinity.c
|
|
*
|
|
* Description:
|
|
* POSIX scheduling functions that deal with CPU affinity.
|
|
*
|
|
* --------------------------------------------------------------------------
|
|
*
|
|
* Pthreads-win32 - POSIX Threads Library for Win32
|
|
* Copyright(C) 1998 John E. Bossom
|
|
* Copyright(C) 1999,2012 Pthreads-win32 contributors
|
|
*
|
|
* Homepage1: http://sourceware.org/pthreads-win32/
|
|
* Homepage2: http://sourceforge.net/projects/pthreads4w/
|
|
*
|
|
* The current list of contributors is contained
|
|
* in the file CONTRIBUTORS included with the source
|
|
* code distribution. The list can also be seen at the
|
|
* following World Wide Web location:
|
|
* http://sources.redhat.com/pthreads-win32/contributors.html
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library in the file COPYING.LIB;
|
|
* if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include <config.h>
|
|
#endif
|
|
|
|
#include "pthread.h"
|
|
#include "implement.h"
|
|
#include "sched.h"
|
|
|
|
int
|
|
sched_setaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *set)
|
|
/*
|
|
* ------------------------------------------------------
|
|
* DOCPUBLIC
|
|
* Sets the CPU affinity mask of the process whose ID is pid
|
|
* to the value specified by mask. If pid is zero, then the
|
|
* calling process is used. The argument cpusetsize is the
|
|
* length (in bytes) of the data pointed to by mask. Normally
|
|
* this argument would be specified as sizeof(cpu_set_t).
|
|
*
|
|
* If the process specified by pid is not currently running on
|
|
* one of the CPUs specified in mask, then that process is
|
|
* migrated to one of the CPUs specified in mask.
|
|
*
|
|
* PARAMETERS
|
|
* pid
|
|
* Process ID
|
|
*
|
|
* cpusetsize
|
|
* Currently ignored in pthreads4w.
|
|
* Usually set to sizeof(cpu_set_t)
|
|
*
|
|
* mask
|
|
* Pointer to the CPU mask to set (cpu_set_t).
|
|
*
|
|
* DESCRIPTION
|
|
* Sets the CPU affinity mask of the process whose ID is pid
|
|
* to the value specified by mask. If pid is zero, then the
|
|
* calling process is used. The argument cpusetsize is the
|
|
* length (in bytes) of the data pointed to by mask. Normally
|
|
* this argument would be specified as sizeof(cpu_set_t).
|
|
*
|
|
* If the process specified by pid is not currently running on
|
|
* one of the CPUs specified in mask, then that process is
|
|
* migrated to one of the CPUs specified in mask.
|
|
*
|
|
* RESULTS
|
|
* 0 successfully created semaphore,
|
|
* EFAULT 'mask' is a NULL pointer.
|
|
* EINVAL '*mask' contains no CPUs in the set
|
|
* of available CPUs.
|
|
* EAGAIN The system available CPUs could not
|
|
* be obtained.
|
|
* EPERM The process referred to by 'pid' is
|
|
* not modifiable by us.
|
|
* ESRCH The process referred to by 'pid' was
|
|
* not found.
|
|
* ENOSYS Function not supported.
|
|
*
|
|
* ------------------------------------------------------
|
|
*/
|
|
{
|
|
#if ! defined(NEED_PROCESS_AFFINITY_MASK)
|
|
|
|
DWORD_PTR vProcessMask;
|
|
DWORD_PTR vSystemMask;
|
|
HANDLE h;
|
|
int targetPid = (int)(size_t) pid;
|
|
int result = 0;
|
|
|
|
if (NULL == set)
|
|
{
|
|
result = EFAULT;
|
|
}
|
|
else
|
|
{
|
|
if (0 == targetPid)
|
|
{
|
|
targetPid = (int) GetCurrentProcessId ();
|
|
}
|
|
|
|
h = OpenProcess (PROCESS_QUERY_INFORMATION|PROCESS_SET_INFORMATION, PTW32_FALSE, (DWORD) targetPid);
|
|
|
|
if (NULL == h)
|
|
{
|
|
result = (((0xFF & ERROR_ACCESS_DENIED) == GetLastError()) ? EPERM : ESRCH);
|
|
}
|
|
else
|
|
{
|
|
if (GetProcessAffinityMask (h, &vProcessMask, &vSystemMask))
|
|
{
|
|
/*
|
|
* Result is the intersection of available CPUs and the mask.
|
|
*/
|
|
DWORD_PTR newMask = vSystemMask & ((_sched_cpu_set_vector_*)set)->_cpuset;
|
|
|
|
if (newMask)
|
|
{
|
|
if (SetProcessAffinityMask(h, newMask) == 0)
|
|
{
|
|
switch (GetLastError())
|
|
{
|
|
case (0xFF & ERROR_ACCESS_DENIED):
|
|
result = EPERM;
|
|
break;
|
|
case (0xFF & ERROR_INVALID_PARAMETER):
|
|
result = EINVAL;
|
|
break;
|
|
default:
|
|
result = EAGAIN;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Mask does not contain any CPUs currently available on the system.
|
|
*/
|
|
result = EINVAL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = EAGAIN;
|
|
}
|
|
}
|
|
CloseHandle(h);
|
|
}
|
|
|
|
if (result != 0)
|
|
{
|
|
PTW32_SET_ERRNO(result);
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
PTW32_SET_ERRNO(ENOSYS);
|
|
return -1;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
int
|
|
sched_getaffinity (pid_t pid, size_t cpusetsize, cpu_set_t *set)
|
|
/*
|
|
* ------------------------------------------------------
|
|
* DOCPUBLIC
|
|
* Gets the CPU affinity mask of the process whose ID is pid
|
|
* to the value specified by mask. If pid is zero, then the
|
|
* calling process is used. The argument cpusetsize is the
|
|
* length (in bytes) of the data pointed to by mask. Normally
|
|
* this argument would be specified as sizeof(cpu_set_t).
|
|
*
|
|
* PARAMETERS
|
|
* pid
|
|
* Process ID
|
|
*
|
|
* cpusetsize
|
|
* Currently ignored in pthreads4w.
|
|
* Usually set to sizeof(cpu_set_t)
|
|
*
|
|
* mask
|
|
* Pointer to the CPU mask to set (cpu_set_t).
|
|
*
|
|
* DESCRIPTION
|
|
* Sets the CPU affinity mask of the process whose ID is pid
|
|
* to the value specified by mask. If pid is zero, then the
|
|
* calling process is used. The argument cpusetsize is the
|
|
* length (in bytes) of the data pointed to by mask. Normally
|
|
* this argument would be specified as sizeof(cpu_set_t).
|
|
*
|
|
* RESULTS
|
|
* 0 successfully created semaphore,
|
|
* EFAULT 'mask' is a NULL pointer.
|
|
* EAGAIN The system available CPUs could not
|
|
* be obtained.
|
|
* EPERM The process referred to by 'pid' is
|
|
* not modifiable by us.
|
|
* ESRCH The process referred to by 'pid' was
|
|
* not found.
|
|
*
|
|
* ------------------------------------------------------
|
|
*/
|
|
{
|
|
DWORD_PTR vProcessMask;
|
|
DWORD_PTR vSystemMask;
|
|
HANDLE h;
|
|
int targetPid = (int)(size_t) pid;
|
|
int result = 0;
|
|
|
|
if (NULL == set)
|
|
{
|
|
result = EFAULT;
|
|
}
|
|
else
|
|
{
|
|
|
|
#if ! defined(NEED_PROCESS_AFFINITY_MASK)
|
|
|
|
if (0 == targetPid)
|
|
{
|
|
targetPid = (int) GetCurrentProcessId ();
|
|
}
|
|
|
|
h = OpenProcess (PROCESS_QUERY_INFORMATION, PTW32_FALSE, (DWORD) targetPid);
|
|
|
|
if (NULL == h)
|
|
{
|
|
result = (((0xFF & ERROR_ACCESS_DENIED) == GetLastError()) ? EPERM : ESRCH);
|
|
}
|
|
else
|
|
{
|
|
if (GetProcessAffinityMask (h, &vProcessMask, &vSystemMask))
|
|
{
|
|
((_sched_cpu_set_vector_*)set)->_cpuset = vProcessMask;
|
|
}
|
|
else
|
|
{
|
|
result = EAGAIN;
|
|
}
|
|
}
|
|
CloseHandle(h);
|
|
|
|
#else
|
|
((_sched_cpu_set_vector_*)set)->_cpuset = (size_t)0x1;
|
|
#endif
|
|
|
|
}
|
|
|
|
if (result != 0)
|
|
{
|
|
PTW32_SET_ERRNO(result);
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Support routines for cpu_set_t
|
|
*/
|
|
int _sched_affinitycpucount (const cpu_set_t *set)
|
|
{
|
|
size_t tset;
|
|
int count;
|
|
|
|
/*
|
|
* Relies on tset being unsigned, otherwise the right-shift will
|
|
* be arithmetic rather than logical and the 'for' will loop forever.
|
|
*/
|
|
for (count = 0, tset = ((_sched_cpu_set_vector_*)set)->_cpuset; tset; tset >>= 1)
|
|
{
|
|
if (tset & (size_t)1)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
void _sched_affinitycpuzero (cpu_set_t *pset)
|
|
{
|
|
((_sched_cpu_set_vector_*)pset)->_cpuset = (size_t)0;
|
|
}
|
|
|
|
void _sched_affinitycpuset (int cpu, cpu_set_t *pset)
|
|
{
|
|
((_sched_cpu_set_vector_*)pset)->_cpuset |= ((size_t)1 << cpu);
|
|
}
|
|
|
|
void _sched_affinitycpuclr (int cpu, cpu_set_t *pset)
|
|
{
|
|
((_sched_cpu_set_vector_*)pset)->_cpuset &= ~((size_t)1 << cpu);
|
|
}
|
|
|
|
int _sched_affinitycpuisset (int cpu, const cpu_set_t *pset)
|
|
{
|
|
return ((((_sched_cpu_set_vector_*)pset)->_cpuset &
|
|
((size_t)1 << cpu)) != (size_t)0);
|
|
}
|
|
|
|
void _sched_affinitycpuand(cpu_set_t *pdestset, const cpu_set_t *psrcset1, const cpu_set_t *psrcset2)
|
|
{
|
|
((_sched_cpu_set_vector_*)pdestset)->_cpuset =
|
|
(((_sched_cpu_set_vector_*)psrcset1)->_cpuset &
|
|
((_sched_cpu_set_vector_*)psrcset2)->_cpuset);
|
|
}
|
|
|
|
void _sched_affinitycpuor(cpu_set_t *pdestset, const cpu_set_t *psrcset1, const cpu_set_t *psrcset2)
|
|
{
|
|
((_sched_cpu_set_vector_*)pdestset)->_cpuset =
|
|
(((_sched_cpu_set_vector_*)psrcset1)->_cpuset |
|
|
((_sched_cpu_set_vector_*)psrcset2)->_cpuset);
|
|
}
|
|
|
|
void _sched_affinitycpuxor(cpu_set_t *pdestset, const cpu_set_t *psrcset1, const cpu_set_t *psrcset2)
|
|
{
|
|
((_sched_cpu_set_vector_*)pdestset)->_cpuset =
|
|
(((_sched_cpu_set_vector_*)psrcset1)->_cpuset ^
|
|
((_sched_cpu_set_vector_*)psrcset2)->_cpuset);
|
|
}
|
|
|
|
int _sched_affinitycpuequal (const cpu_set_t *pset1, const cpu_set_t *pset2)
|
|
{
|
|
return (((_sched_cpu_set_vector_*)pset1)->_cpuset ==
|
|
((_sched_cpu_set_vector_*)pset2)->_cpuset);
|
|
}
|