aboutsummaryrefslogtreecommitdiffstats
path: root/plpa-1.3.2/src/libplpa/plpa_dispatch.c
blob: 13dc820807590cc8a8b6912ecb09bbfe718d9b1b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/* -*- 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. */
        return (ret >= 0) ? 0 : 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. */
        return (ret >= 0) ? 0 : ret;
        break;

    case PLPA_NAME_CAPS(PROBE_NOT_SUPPORTED):
        /* Process affinity not supported here */
        return ENOSYS;
        break;

    default:
        /* Something went wrong */
        return EINVAL;
        break;
    }
}

© 2014-2024 Faster IT GmbH | imprint | privacy policy