1/**
2 * \file
3 * \brief Argument processing
4 */
5
6/*
7 * Copyright (c) 2007-2010, ETH Zurich.
8 * All rights reserved.
9 *
10 * This file is distributed under the terms in the attached LICENSE file.
11 * If you do not find this file, copies can be found by writing to:
12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16#include <string.h>
17
18#include <getopt.h>
19
20#include <barrelfish/barrelfish.h>
21
22#include "skb.h"
23
24#include "args.h"
25
26static bool is_excluded(coreid_t core, coreid_t *exclude, int exclude_len)
27{
28    // assume exclude list isn't sorted
29    for (int i = 0; i < exclude_len; i++) {
30        if (core == exclude[i]) {
31            return true;
32        }
33    }
34    return false;
35}
36
37// mallocs res_cores
38static void make_core_list(coreid_t *cores, int cores_len,
39                           coreid_t *exclude, int exclude_len,
40                           int num_cores,
41                           coreid_t **res_cores, int *res_len)
42{
43    assert(cores != NULL);
44    assert(res_cores != NULL);
45    assert(res_len != NULL);
46
47    if ((exclude == NULL) || (exclude_len <= 0)) {
48        // nothing to exclude, simply copy cores to res_cores
49        *res_len = cores_len;
50        *res_cores = malloc(*res_len * sizeof(coreid_t));
51        if (*res_cores != NULL) {
52            if (memcpy(*res_cores, cores, cores_len*sizeof(coreid_t)) == NULL) {
53                *res_cores = NULL;
54            }
55        } else {
56            DEBUG_ERR(LIB_ERR_MALLOC_FAIL,"when processing core list argument");
57        }
58        return;
59    }
60
61    // otherwise deal with exclusions
62
63    *res_len = cores_len - exclude_len;
64    *res_cores = malloc(*res_len * sizeof(coreid_t));
65    if (*res_cores == NULL) {
66        DEBUG_ERR(LIB_ERR_MALLOC_FAIL,"when processing core list argument");
67        return;
68    }
69
70    int r_i = 0;
71    for (int i = 0; i < cores_len; i++) {
72        if (!is_excluded(cores[i], exclude, exclude_len)) {
73            (*res_cores)[r_i] = cores[i];
74            r_i++;
75        }
76        if ((num_cores > 0) && (r_i >= num_cores)) {
77            break;
78        }
79    }
80
81    *res_len = r_i;
82}
83
84// mallocs *list
85static void parse_list(char *optargs, coreid_t **list, int *len)
86{
87    assert(optargs != NULL);
88    assert(list != NULL);
89    assert(len != NULL);
90
91    *list = NULL;
92
93    // a list looks like this: 0,1,2,3,4,5
94
95    // make extra copy bcause strtok clobbers it
96    char *p = malloc(strlen(optargs) + 1);
97    if (p == NULL) {
98        DEBUG_ERR(LIB_ERR_MALLOC_FAIL, "when parsing core list");
99        return;
100    }
101    strcpy(p, optargs);
102
103    // first get the number of elements
104    int i;
105    char *tok = p;
106    for (i = 0; tok != NULL; i++, p = NULL) {
107        tok = strtok(p, ",");
108    }
109    free(p);
110    *len = --i;
111    *list = malloc(sizeof(coreid_t)*i);
112    if (*list == NULL) {
113        DEBUG_ERR(LIB_ERR_MALLOC_FAIL, "when parsing core list");
114        return;
115    }
116
117    // now get the actual elements
118    p = optargs;
119    tok = p;
120    for (i = 0; tok != NULL; i++, p = NULL) {
121        tok = strtok(p, ",");
122        if (tok != NULL) {
123            (*list)[i] = strtol(tok, NULL, 10);
124        } else {
125            break;
126        }
127    }
128}
129
130
131#if 0
132static void print_list(char *s, coreid_t *list, int len)
133{
134    debug_printf("%s", s);
135    if ((s == NULL) || (len <= 0)) {
136        debug_printf("\tList is empty\n");
137    } else {
138        for (int i = 0; i < len; i++) {
139            debug_printf("\t%d: %d\n", i, list[i]);
140        }
141    }
142}
143#endif
144
145
146// mallocs return string
147char *list_to_string(coreid_t *list, size_t l_len)
148{
149    /* Guess we need up to 4 bytes per entry. */
150    int n, size = 4 * l_len;
151    char *s, *ns;
152
153    if ((s = malloc(size)) == NULL) {
154        DEBUG_ERR(LIB_ERR_MALLOC_FAIL, "when converting core list to string");
155        return NULL;
156    }
157
158    int out_len = 0;
159    for (int i = 0; i < l_len;  i++) {
160        n = snprintf(&s[out_len], size - out_len, "%d,", list[i]);
161        if (out_len + n < size) {
162            out_len += n;
163        } else {
164            // ran out of space;
165            size *= 2;
166            ns = realloc(s, size);
167            if (ns == NULL) {
168                free(s);
169                DEBUG_ERR(LIB_ERR_MALLOC_FAIL,
170                          "when converting core list to string");
171                return NULL;
172            } else {
173                s = ns;
174                i--; // try again
175                continue;
176            }
177        }
178    }
179    return s;
180}
181
182
183// mallocs list elements of struct. but not path
184struct args process_args(int argc, char *argv[])
185{
186    errval_t err;
187
188    struct args res = (struct args) {
189        .path = argv[0],
190        .cores = NULL,
191        .cores_len = 0,
192        .exclude = NULL,
193        .exclude_len = 0,
194        .num_cores = -1,
195        .all_cores = false,
196        .master = false,
197        .ram = 0,
198    };
199
200    int opt;
201
202    while ((opt = getopt(argc, argv, "wmax:c:n:r:")) != -1) {
203
204        switch (opt) {
205        case 'w':
206            // be a worker
207            res.master = false;
208            break;
209        case 'm':
210            // be a master
211            res.master = true;
212            break;
213        case 'a':
214            // use all available cores
215            res.all_cores = true;
216            break;
217        case 'c':
218            // use the cores given in the list argument
219            parse_list(optarg, &res.cores, &res.cores_len);
220            if (res.cores == NULL) {
221                goto fail;
222            }
223            break;
224        case 'x':
225            // exclude the cores given in the list argument
226            parse_list(optarg, &res.exclude, &res.exclude_len);
227            if (res.exclude == NULL) {
228                goto fail;
229            }
230            break;
231        case 'n':
232            // total number of cores to use
233            res.num_cores = strtol(optarg, NULL, 10);
234            break;
235        case 'r':
236            // memory to use per core
237            res.ram = (genpaddr_t) strtoll(optarg, NULL, 10);
238            break;
239        default:
240            goto fail;
241        }
242    }
243
244    if (res.all_cores) {
245        err = get_cores_skb(&res.cores, &res.cores_len);
246        if (err_is_fail(err)) {
247            DEBUG_ERR(err, "in get_cores_skb");
248            goto fail;
249        }
250        /*
251        print_list("res.cores with all cores: \n", res.cores, res.cores_len);
252        */
253    }
254
255    // by this point we must have a list of cores, either because one was
256    // provided explicitly or because all_cores were requested.
257    if ((res.cores == NULL) || (res.cores_len <= 0)) {
258        goto fail;
259    }
260
261    if (res.cores != NULL) {
262        coreid_t *cores;
263        int cores_len;
264
265        make_core_list(res.cores, res.cores_len, res.exclude, res.exclude_len,
266                       res.num_cores, &cores, &cores_len);
267
268        free(res.cores);
269
270        if (cores == NULL) {
271            goto fail;
272        }
273
274        res.cores = cores;
275        res.cores_len = cores_len;
276    }
277
278    return res;
279
280 fail:
281    printf("Usage: %s [-mw] [-a] [-c list] [-x list] [-n num_cores]\n",
282           argv[0]);
283    exit(EXIT_FAILURE);
284    return res;
285}
286
287