1/**
2 * \file
3 * \brief Argument processing for distributed services
4 */
5
6/*
7 * Copyright (c) 2010-2011, 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 <dist/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 that 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 dist_args process_dist_args(int *argc, char **argv[])
185{
186    errval_t err;
187
188    debug_printf("process_dist_args: start\n");
189
190    struct dist_args res = (struct dist_args) {
191        .path = (*argv)[0],
192        .cores = NULL,
193        .cores_len = 0,
194        //        .exclude = NULL,
195        //        .exclude_len = 0,
196        .num_cores = -1,
197        //        .all_cores = false,
198        .master = false,
199    };
200
201    coreid_t *exclude = NULL;
202    int exclude_len = 0;
203    bool all_cores = false;
204
205    int opt;
206
207    while ((opt = getopt(*argc, *argv, ":wmax:c:n:")) != -1) {
208
209        switch (opt) {
210        case 'w':
211            // be a worker
212            res.master = false;
213            break;
214        case 'm':
215            // be a master
216            res.master = true;
217            break;
218        case 'a':
219            // use all available cores
220            all_cores = true;
221            break;
222        case 'c':
223            // use the cores given in the list argument
224            parse_list(optarg, &res.cores, &res.cores_len);
225            if (res.cores == NULL) {
226                goto fail;
227            }
228            break;
229        case 'x':
230            // exclude the cores given in the list argument
231            parse_list(optarg, &exclude, &exclude_len);
232            if (exclude == NULL) {
233                goto fail;
234            }
235            break;
236        case 'n':
237            // total number of cores to use
238            res.num_cores = strtol(optarg, NULL, 10);
239            break;
240        default:
241            // ignore
242            break;
243        }
244    }
245
246
247    debug_printf("pda: after getopt loop\n");
248
249    if (all_cores) {
250        err = get_cores_skb(&res.cores, &res.cores_len);
251        if (err_is_fail(err)) {
252            DEBUG_ERR(err, "in get_cores_skb");
253            goto fail;
254        }
255        /*
256        print_list("res.cores with all cores: \n", res.cores, res.cores_len);
257        */
258    }
259
260    debug_printf("pda: after all cores\n");
261
262    // by this point we must have a list of cores, either because one was
263    // provided explicitly or because all_cores were requested.
264    if ((res.cores == NULL) || (res.cores_len <= 0)) {
265        goto fail;
266    }
267
268    if (res.cores != NULL) {
269        coreid_t *cores;
270        int cores_len;
271
272        make_core_list(res.cores, res.cores_len, exclude, exclude_len,
273                       res.num_cores, &cores, &cores_len);
274
275        debug_printf("pda: after make_core_list\n");
276
277        free(res.cores);
278        if (exclude != NULL) {
279            free(exclude);
280        }
281
282        if (cores == NULL) {
283            goto fail;
284        }
285
286        res.cores = cores;
287        res.cores_len = cores_len;
288    }
289
290    *argc = *argc - optind;
291    *argv = &((*argv)[optind]);
292
293    debug_printf("pda: after modifying argv\n");
294
295    return res;
296
297 fail:
298    if (exclude != NULL) {
299        free(exclude);
300    }
301    printf("Usage: %s [-mw] [-a] [-c list] [-x list] [-n num_cores]\n",
302           (*argv)[0]);
303    exit(EXIT_FAILURE);
304    return res;
305}
306
307