1/**
2 * \file
3 * \brief Distributed (percore) memory server: stealing related code
4 */
5
6/*
7 * Copyright (c) 2007-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 <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <getopt.h>
19
20#include <inttypes.h>
21#include <barrelfish/barrelfish.h>
22#include <trace/trace.h>
23#include <trace_definitions/trace_defs.h>
24#include <mm/mm.h>
25#include <if/mem_defs.h>
26#include <if/monitor_blocking_defs.h>
27
28#include <thc/thc.h>
29#include <thc/thcsync.h>
30
31#include <if/mem_defs.h>
32#include <if/mem_defs.h>
33#include <if/mem_thc.h>
34
35// #include "barrier.h"
36
37#include "mem_serv.h"
38#include "steal.h"
39
40/// Keep track of our peer mem_servs
41struct peer_core {
42    coreid_t id;
43    bool is_bound;
44    struct mem_thc_client_binding_t cl;
45    thc_lock_t lock;
46};
47
48coreid_t mycore;
49static struct peer_core *peer_cores;
50static int num_peers;
51
52// FIXME: possible race if handling two concurrent alloc request that both
53// try to connect to the same peer
54static errval_t connect_peer(struct peer_core *peer)
55{
56    assert(peer != NULL);
57
58    errval_t err;
59    struct mem_binding *b;
60
61    // debug_printf("connecting to %u\n", peer->id);
62
63    char service_name[NAME_LEN];
64    snprintf(service_name, NAME_LEN, "%s.%d", MEMSERV_DIST, peer->id);
65
66    err = mem_thc_connect_by_name(service_name,
67                                  get_default_waitset(),
68                                  IDC_BIND_FLAGS_DEFAULT,
69                                  &b);
70    if (err_is_fail(err)) {
71        DEBUG_ERR(err, "could not bind (thc)");
72        return err;
73    }
74
75    err = mem_thc_init_client(&peer->cl, b, b);
76    if (err_is_fail(err)) {
77        DEBUG_ERR(err, "could not init client (thc)");
78        return err;
79    }
80
81    thc_lock_init(&peer->lock);
82
83    return SYS_ERR_OK;
84}
85
86static errval_t steal_from_serv(struct peer_core *peer,
87                                struct capref *ret_cap,
88                                uint8_t bits,
89                                genpaddr_t minbase,
90                                genpaddr_t maxlimit)
91{
92    assert(peer != NULL);
93
94    errval_t err;
95
96    if (!peer->is_bound) {
97      printf("Connecting to new peer\n");
98        err = connect_peer(peer);
99        if (err_is_fail(err)) {
100            DEBUG_ERR(err, "failed to connect to peer");
101            return err;
102        }
103        peer->is_bound = true;
104    }
105
106    // due to the single-waiter rule of thc we need to make sure we only
107    // ever have one of these rpcs outstanding at a time.
108    thc_lock_acquire(&peer->lock);
109    peer->cl.call_seq.steal(&peer->cl, bits, minbase, maxlimit,
110                                &err, ret_cap);
111    thc_lock_release(&peer->lock);
112
113    return err;
114}
115
116// Round-robin steal. Try to get memory from each peer in turn.
117static errval_t rr_steal(struct capref *ret_cap, uint8_t bits,
118                                genpaddr_t minbase, genpaddr_t maxlimit)
119{
120    errval_t err = MM_ERR_NOT_FOUND;
121    static int next_serv = 0;
122
123    int serv = next_serv;
124    struct peer_core *peer = &peer_cores[serv];
125
126    int i;
127    for (i = 0; i < num_peers; i++) {
128        if (serv >= num_peers) {
129            serv = 0;
130        }
131        peer = &peer_cores[serv++];
132        if (peer->id == mycore) {
133            continue;
134        }
135	    printf("%d: Trying to steal from %d/%d\n", disp_get_core_id(), i, num_peers);
136        err = steal_from_serv(peer, ret_cap, bits, minbase, maxlimit);
137        if (err_is_ok(err)) {
138            break;
139        }
140    }
141    next_serv = serv;
142
143    /*
144    if (i >= num_peers) {
145        debug_printf("rr_steal: could not steal from any peers\n");
146    }
147    */
148
149    return err;
150}
151
152
153static errval_t steal_and_alloc(struct capref *ret_cap, uint8_t steal_bits,
154                                uint8_t alloc_bits,
155                                genpaddr_t minbase, genpaddr_t maxlimit)
156{
157    errval_t err;
158
159    struct capref ramcap;
160    struct capability info;
161
162    /*
163    debug_printf("steal_and_alloc(steal_bits: %d, alloc_bits: %d, "
164                 "minbase: 0x%"PRIxGENPADDR", maxlimit: 0x%"PRIxGENPADDR")\n",
165                 steal_bits, alloc_bits, minbase, maxlimit);
166    */
167
168    err = rr_steal(&ramcap, steal_bits, minbase, maxlimit);
169    if (err_is_fail(err)) {
170        return err;
171    }
172
173    // XXX: Mark as local to this core, until we have x-core cap management
174    err = monitor_cap_set_remote(ramcap, false);
175    if(err_is_fail(err)) {
176        DEBUG_ERR(err, "Warning: failed to set cap non-remote. "
177                  "This memory will leak.");
178    }
179
180    err = debug_cap_identify(ramcap, &info);
181    if (err_is_fail(err)) {
182        return err_push(err, MON_ERR_CAP_IDENTIFY);
183    }
184#if 0
185    debug_printf("STOLEN cap is type %d Ram base 0x%"PRIxGENPADDR
186                 " (%"PRIuGENPADDR") Bits %d\n",
187                 info.type, info.u.ram.base, info.u.ram.base,
188                 info.u.ram.bits);
189#endif
190    if(steal_bits != log2ceil(info.u.ram.bytes)) {
191      printf("asked for %d bits, but got %d bits of type %d\n",
192	     steal_bits, log2ceil(info.u.ram.bytes), info.type);
193    }
194    assert(steal_bits == log2ceil(info.u.ram.bytes));
195
196    memsize_t mem_to_add = (memsize_t)info.u.ram.bytes;
197
198    err = mm_free(&mm_percore, ramcap, info.u.ram.base, log2ceil(info.u.ram.bytes));
199    if (err_is_fail(err)) {
200        if (err_no(err) == MM_ERR_NOT_FOUND) {
201            // memory wasn't there initially, add it
202            err = mm_add(&mm_percore, ramcap, log2ceil(info.u.ram.bytes), info.u.ram.base);
203            if (err_is_fail(err)) {
204                return err_push(err, MM_ERR_MM_ADD);
205            }
206            mem_total += mem_to_add;
207        } else {
208            return err_push(err, MM_ERR_MM_FREE);
209        }
210    }
211
212    mem_avail += mem_to_add;
213
214    err = percore_alloc(ret_cap, alloc_bits, minbase, maxlimit);
215
216    return err;
217}
218
219
220void try_steal(errval_t *ret, struct capref *cap, uint8_t bits,
221               genpaddr_t minbase, genpaddr_t maxlimit)
222{
223    printf("[%d][%"PRIuDOMAINID"]: failed percore alloc request: bits: %d going to STEAL\n",
224            disp_get_core_id(), disp_get_domain_id(), bits);
225	printf("%p %p %p %p %p %p\n",	__builtin_return_address(0),
226								 	__builtin_return_address(1),
227									__builtin_return_address(2),
228									__builtin_return_address(3),
229									__builtin_return_address(4),
230									__builtin_return_address(5));
231    //DEBUG_ERR(*ret, "allocation of %d bits in 0x%" PRIxGENPADDR
232    //           "-0x%" PRIxGENPADDR " failed", bits, minbase, maxlimit);
233    *ret = steal_and_alloc(cap, bits+1, bits, minbase, maxlimit);
234    if (err_is_fail(*ret)) {
235        DEBUG_ERR(*ret, "stealing of %d bits in 0x%" PRIxGENPADDR "-0x%"
236                 PRIxGENPADDR " failed", bits, minbase, maxlimit);
237        *cap = NULL_CAP;
238    }
239//	*ret = MM_ERR_NOT_FOUND;
240//	*cap = NULL_CAP;
241}
242
243errval_t init_peers(coreid_t core, int len_cores, coreid_t *cores)
244{
245    // initialise info about our peers
246    mycore = core;
247    num_peers = len_cores;
248    peer_cores = malloc(num_peers * sizeof(struct peer_core));
249    if (peer_cores == NULL) {
250        return LIB_ERR_MALLOC_FAIL;
251    }
252
253    for (int i = 0; i < num_peers; i++) {
254        peer_cores[i].id = cores[i];
255        peer_cores[i].is_bound = false;
256    }
257
258    return SYS_ERR_OK;
259}
260
261errval_t percore_steal_handler_common(uint8_t bits,
262                                      genpaddr_t minbase,
263                                      genpaddr_t maxlimit,
264                                      struct capref *retcap)
265{
266    struct capref cap;
267    errval_t err, ret;
268
269    trace_event(TRACE_SUBSYS_MEMSERV, TRACE_EVENT_MEMSERV_PERCORE_ALLOC, bits);
270    /* debug_printf("%d: percore steal request: bits: %d\n", disp_get_core_id(), bits); */
271
272    // refill slot allocator if needed
273    err = slot_prealloc_refill(mm_percore.slot_alloc_inst);
274    if (err_is_fail(err)) {
275        DEBUG_ERR(err, "Warning: failure in slot_prealloc_refill\n");
276        cap = NULL_CAP;
277        return err;
278    }
279
280    // refill slab allocator if needed
281    err = slab_refill(&mm_percore.slabs);
282    if (err_is_fail(err)) {
283        DEBUG_ERR(err, "Warning: failure when refilling mm_percore slab\n");
284    }
285
286    // get actual ram cap
287    ret = percore_alloc(&cap, bits, minbase, maxlimit);
288    if (err_is_fail(ret)){
289        // debug_printf("percore steal request failed\n");
290        //DEBUG_ERR(ret, "allocation of stolen %d bits in 0x%" PRIxGENPADDR
291        //          "-0x%" PRIxGENPADDR " failed", bits, minbase, maxlimit);
292        cap = NULL_CAP;
293    }
294
295    trace_event(TRACE_SUBSYS_MEMSERV, TRACE_EVENT_MEMSERV_PERCORE_ALLOC_COMPLETE, bits);
296
297    *retcap = cap;
298    return ret;
299}
300
301
302int main(int argc, char ** argv)
303{
304    return common_main(argc, argv);
305}
306