1/**
2 * \file
3 * \brief Distributed (percore) memory server: code specific to THC version
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, Universitaetstrasse 6, 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 <barrelfish/dispatch.h>
23#include <trace/trace.h>
24#include <trace_definitions/trace_defs.h>
25#include <barrelfish/monitor_client.h>
26#include <dist/barrier.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#include <if/monitor_defs.h>
35
36// #include "barrier.h"
37
38#include "mem_serv.h"
39#include "steal.h"
40
41// The various request handler functions
42
43static void percore_free_handler(struct mem_thc_service_binding_t *sv,
44                                 struct capref ramcap, genpaddr_t base,
45                                 uint8_t bits)
46{
47    errval_t ret;
48    ret = percore_free_handler_common(ramcap, base, bits);
49    sv->send.free_monitor(sv, ret);
50}
51
52static void mem_available_handler(struct mem_thc_service_binding_t *sv)
53{
54    memsize_t mem_available;
55    mem_available = mem_available_handler_common();
56    sv->send.available(sv, mem_available);
57}
58
59
60static void percore_steal_handler(struct mem_thc_service_binding_t *sv,
61                                     uint8_t bits,
62                                     genpaddr_t minbase, genpaddr_t maxlimit)
63{
64    errval_t ret;
65    struct capref cap;
66    ret = percore_steal_handler_common(bits, minbase, maxlimit, &cap);
67    sv->send.steal(sv, ret, cap);
68
69    trace_event(TRACE_SUBSYS_MEMSERV, TRACE_EVENT_MEMSERV_PERCORE_ALLOC_COMPLETE, 0);
70
71}
72
73static void percore_allocate_handler(struct mem_thc_service_binding_t *sv,
74                                     uint8_t bits,
75                                     genpaddr_t minbase, genpaddr_t maxlimit)
76{
77    errval_t ret;
78    struct capref cap;
79    ret = percore_allocate_handler_common(bits, minbase, maxlimit, &cap);
80    sv->send.allocate(sv, ret, cap);
81    if(!capref_is_null(cap)) {
82        ret = cap_delete(cap);
83        if(err_is_fail(ret)) {
84            DEBUG_ERR(err, "cap_delete after send. This memory will leak.");
85        }
86    }
87
88    trace_event(TRACE_SUBSYS_MEMSERV, TRACE_EVENT_MEMSERV_PERCORE_ALLOC_COMPLETE, 0);
89}
90
91// Various startup procedures
92
93static void run_server(struct mem_thc_service_binding_t *sv)
94{
95    mem_service_msg_t msg;
96    bool loop = true;
97
98    // this is the bitmap of messages we are interested in receiving
99    struct mem_service_selector selector = {
100        .allocate = 1,
101        .available = 1,
102        .free = 1,
103        .steal = 1,
104    };
105
106    while (loop) {
107        // receive any message
108        sv->recv_any(sv, &msg, selector);
109
110        // dispatch it
111        switch(msg.msg) {
112        case mem_allocate:
113            percore_allocate_handler(sv, msg.args.allocate.in.bits,
114                                     msg.args.allocate.in.minbase,
115                                     msg.args.allocate.in.maxlimit);
116            break;
117        case mem_steal:
118            percore_steal_handler(sv, msg.args.allocate.in.bits,
119                                     msg.args.allocate.in.minbase,
120                                     msg.args.allocate.in.maxlimit);
121            break;
122        case mem_available:
123            mem_available_handler(sv);
124            break;
125        case mem_free_monitor:
126            percore_free_handler(sv, msg.args.free.in.mem_cap);
127            break;
128        default:
129            debug_printf("unexpected message: %d\n", msg.msg);
130            loop = false;
131            break;
132        }
133    }
134}
135
136errval_t percore_mem_serv(coreid_t core, coreid_t *cores,
137                                 int len_cores, memsize_t ram)
138{
139    errval_t err;
140
141    struct waitset *ws = get_default_waitset();
142
143    // Init the memory allocator
144    err = initialize_percore_mem_serv(core, cores, len_cores, ram);
145    if (err_is_fail(err)) {
146        DEBUG_ERR(err, "initializing percore mem_serv");
147        return err;
148    }
149
150    struct mem_thc_export_info e_info;
151    struct mem_thc_service_binding_t *sv;
152    struct mem_binding *b;
153    iref_t iref;
154
155    char service_name[NAME_LEN];
156    snprintf(service_name, NAME_LEN, "%s.%d", MEMSERV_DIST, core);
157
158    //    err = mem_thc_export(&e_info, service_name, ws,
159    err = mem_thc_export(&e_info, NULL, ws,
160                         IDC_EXPORT_FLAGS_DEFAULT,
161                         &iref);
162    if (err_is_fail(err)) {
163        DEBUG_ERR(err, "exporting percore mem interface");
164        return err;
165    }
166
167    struct monitor_binding *mb = get_monitor_binding();
168    err = mb->tx_vtbl. set_mem_iref_request(mb, NOP_CONT, iref);
169    if (err_is_fail(err)) {
170        DEBUG_ERR(err, "setting monitor's percore mem_serv iref");
171        return err;
172    }
173
174    // explicitly tell spawnd to use us
175    err = set_local_spawnd_memserv(core);
176    if (err_is_fail(err)) {
177        DEBUG_ERR(err, "setting spawnd.%d's local memserv", core);
178        return err;
179    }
180
181    // register only after spawnd's local memserv has been set
182    err = nameservice_register(service_name, iref);
183    if (err_is_fail(err)) {
184        DEBUG_ERR(err, "nameservice_register failed");
185        return err;
186    }
187    // let the master know we are ready
188    err = nsb_register_n(core, MEMSERV_DIST);
189    if (err_is_fail(err)) {
190        USER_PANIC_ERR(err, "nsb_register_n failed");
191    }
192
193
194    do {
195    while (true) {
196
197        mem_thc_accept(&e_info, &b);
198        if (err_is_fail(err)) {
199            DEBUG_ERR(err, "thc accept failed");
200            continue;
201        }
202
203        sv = malloc(sizeof(struct mem_thc_service_binding_t));
204        if (sv == NULL) {
205            DEBUG_ERR(LIB_ERR_MALLOC_FAIL, "allocating thc service binding");
206            continue;
207        }
208
209        err = mem_thc_init_service(sv, b, b);
210        if (err_is_fail(err)) {
211            DEBUG_ERR(err, "thc init failed");
212            continue;
213        }
214
215        async run_server(sv);
216
217    }
218    } finish;
219
220    // should never reach here
221    return SYS_ERR_OK;
222}
223