htop/plpa-1.1/src/plpa_dispatch.c

202 lines
5.9 KiB
C

/* -*- c -*-
*
* Copyright (c) 2004-2006 The Trustees of Indiana University.
* All rights reserved.
* Copyright (c) 2004-2005 The Regents of the University of California.
* All rights reserved.
* Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "plpa_config.h"
#include "plpa.h"
#include "plpa_internal.h"
#include <errno.h>
#include <sys/syscall.h>
#include <unistd.h>
/**
* Call the kernel's setaffinity, massaging the user's input
* parameters as necessary
*/
int PLPA_NAME(sched_setaffinity)(pid_t pid, size_t cpusetsize,
const PLPA_NAME(cpu_set_t) *cpuset)
{
int ret;
size_t i;
PLPA_NAME(cpu_set_t) tmp;
PLPA_NAME(api_type_t) api;
/* Check to see that we're initialized */
if (!PLPA_NAME(initialized)) {
if (0 != (ret = PLPA_NAME(init)())) {
return ret;
}
}
/* Check for bozo arguments */
if (NULL == cpuset) {
return EINVAL;
}
/* Probe the API type */
if (0 != (ret = PLPA_NAME(api_probe)(&api))) {
return ret;
}
switch (api) {
case PLPA_NAME_CAPS(PROBE_OK):
/* This shouldn't happen, but check anyway */
if (cpusetsize > sizeof(*cpuset)) {
return EINVAL;
}
/* If the user-supplied bitmask is smaller than what the
kernel wants, zero out a temporary buffer of the size that
the kernel wants and copy the user-supplied bitmask to the
lower part of the temporary buffer. This could be done
more efficiently, but we're looking for clarity/simplicity
of code here -- this is not intended to be
performance-critical. */
if (cpusetsize < PLPA_NAME(len)) {
memset(&tmp, 0, sizeof(tmp));
for (i = 0; i < cpusetsize * 8; ++i) {
if (PLPA_CPU_ISSET(i, cpuset)) {
PLPA_CPU_SET(i, &tmp);
}
}
}
/* If the user-supplied bitmask is larger than what the kernel
will accept, scan it and see if there are any set bits in
the part larger than what the kernel will accept. If so,
return EINVAL. Otherwise, copy the part that the kernel
will accept into a temporary and use that. Again,
efficinency is not the issue of this code -- clarity is. */
else if (cpusetsize > PLPA_NAME(len)) {
for (i = PLPA_NAME(len) * 8; i < cpusetsize * 8; ++i) {
if (PLPA_CPU_ISSET(i, cpuset)) {
return EINVAL;
}
}
/* No upper-level bits are set, so now copy over the bits
that the kernel will look at */
memset(&tmp, 0, sizeof(tmp));
for (i = 0; i < PLPA_NAME(len) * 8; ++i) {
if (PLPA_CPU_ISSET(i, cpuset)) {
PLPA_CPU_SET(i, &tmp);
}
}
}
/* Otherwise, the user supplied a buffer that is exactly the
right size. Just for clarity of code, copy the user's
buffer into the temporary and use that. */
else {
memcpy(&tmp, cpuset, cpusetsize);
}
/* Now do the syscall */
ret = syscall(__NR_sched_setaffinity, pid, PLPA_NAME(len), &tmp);
/* Return 0 upon success. According to
http://www.open-mpi.org/community/lists/plpa-users/2006/02/0016.php,
all the kernel implementations return >= 0 upon success. */
if (ret >= 0) {
return 0;
} else {
return ret;
}
break;
case PLPA_NAME_CAPS(PROBE_NOT_SUPPORTED):
/* Process affinity not supported here */
return ENOSYS;
break;
default:
/* Something went wrong */
/* JMS: would be good to have something other than EINVAL here
-- suggestions? */
return EINVAL;
break;
}
}
/**
* Call the kernel's getaffinity, massaging the user's input
* parameters as necessary
*/
int PLPA_NAME(sched_getaffinity)(pid_t pid, size_t cpusetsize,
PLPA_NAME(cpu_set_t) *cpuset)
{
int ret;
PLPA_NAME(api_type_t) api;
/* Check to see that we're initialized */
if (!PLPA_NAME(initialized)) {
if (0 != (ret = PLPA_NAME(init)())) {
return ret;
}
}
/* Check for bozo arguments */
if (NULL == cpuset) {
return EINVAL;
}
/* Probe the API type */
if (0 != (ret = PLPA_NAME(api_probe)(&api))) {
return ret;
}
switch (api) {
case PLPA_NAME_CAPS(PROBE_OK):
/* This shouldn't happen, but check anyway */
if (PLPA_NAME(len) > sizeof(*cpuset)) {
return EINVAL;
}
/* If the user supplied a buffer that is too small, then don't
even bother */
if (cpusetsize < PLPA_NAME(len)) {
return EINVAL;
}
/* Now we know that the user's buffer is >= the size required
by the kernel. If it's >, then zero it out so that the
bits at the top are cleared (since they won't be set by the
kernel) */
if (cpusetsize > PLPA_NAME(len)) {
memset(cpuset, 0, cpusetsize);
}
/* Now do the syscall */
ret = syscall(__NR_sched_getaffinity, pid, PLPA_NAME(len), cpuset);
/* Return 0 upon success. According to
http://www.open-mpi.org/community/lists/plpa-users/2006/02/0016.php,
all the kernel implementations return >= 0 upon success. */
if (ret >= 0) {
return 0;
} else {
return ret;
}
break;
case PLPA_NAME_CAPS(PROBE_NOT_SUPPORTED):
/* Process affinity not supported here */
return ENOSYS;
break;
default:
/* Something went wrong */
return EINVAL;
break;
}
}