1/**
2 * \file
3 * \brief Barrelfish trace server, Version 2
4 */
5
6/*
7 * Copyright (c) 2007-2013, 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 <stdio.h>
16#include <stdlib.h>
17#include <errno.h>
18
19#include <barrelfish/barrelfish.h>
20#include <barrelfish/dispatch.h>
21#include <barrelfish/dispatcher_arch.h>
22#include <barrelfish/lmp_endpoints.h>
23#include <barrelfish/event_queue.h>
24#include <barrelfish/nameservice_client.h>
25#include <trace/trace.h>
26
27#include <flounder/flounder.h>
28#include <if/monitor_defs.h>
29
30#include <if/empty_defs.h>
31
32/* LWIP Network stack includes */
33#include <lwip/init.h>
34#include <lwip/netif.h>
35#include <lwip/dhcp.h>
36#include <lwip/tcp.h>
37#include <netif/bfeth.h>
38#include <netif/etharp.h>
39
40#define BFSCOPE_TCP_PORT 6666
41
42#define BFSCOPE_BUFLEN (2<<20)
43
44extern struct waitset *lwip_waitset;
45
46static char *trace_buf = NULL;
47static size_t trace_length = 0;
48static size_t trace_sent = 0;
49static bool dump_in_progress = false;
50
51/// Timestamp when the sending of a trace dump over the network started
52static uint64_t timestamp_start = 0;
53
54/// The client that connected to this bfscope instance.
55static struct tcp_pcb *bfscope_client = NULL;
56
57/// If we are in autoflush is enabled, bfscope can itself determine to flush. In
58/// that case, we don't want to notify anyone after doing a locally initiated flush.
59static bool local_flush = false;
60
61
62#define DEBUG if (0) printf
63
64static void bfscope_send_flush_ack_to_monitor(void);
65
66/*
67 * \brief Close the specified TCP connection
68 */
69static void bfscope_connection_close(struct tcp_pcb *tpcb)
70{
71    DEBUG("bfscope: close\n");
72    printf("%s:%s:%d:\n", __FILE__, __FUNCTION__, __LINE__);
73    trace_length = 0;
74    //tcp_arg(tpcb, NULL);
75    //tcp_close(tpcb);
76    //bfscope_client = NULL;
77}
78
79/*
80 * \brief Error callback from lwip
81 */
82static void error_cb(void *arg, err_t err)
83{
84    struct tcp_pcb *tpcb = (struct tcp_pcb *)arg;
85
86    printf("bfscope: TCP(%p) error %d\n", arg, err);
87
88    if (tpcb) {
89        bfscope_connection_close(tpcb);
90    }
91}
92
93/*
94 * Call this method when you finished dumping the current trace buffer.
95 */
96static void bfscope_trace_dump_finished(void)
97{
98    trace_length = 0;
99    trace_sent = 0;
100    dump_in_progress = false;
101
102    if (!local_flush) {
103        bfscope_send_flush_ack_to_monitor();
104    } else {
105        // Locally initiated flush is finished.
106        local_flush = false;
107    }
108}
109
110/*
111 * \brief Send the next chunk of trace data down given TCP connection
112 */
113static void bfscope_trace_send(struct tcp_pcb *tpcb)
114{
115    char *bufptr;
116    int len;
117
118    //DEBUG("tcp_sndbuf=%d\n", tcp_sndbuf(tpcb));
119
120    bufptr = trace_buf + trace_sent;
121    len = trace_length - trace_sent;
122
123    int more = 0;
124    if (len > tcp_sndbuf(tpcb)) {
125        len = tcp_sndbuf(tpcb);
126        more = 1;
127    }
128
129    /* Give the data to LWIP until it runs out of buffer space */
130    err_t lwip_err = tcp_write(tpcb, bufptr, len,
131                      TCP_WRITE_FLAG_COPY | (more ? TCP_WRITE_FLAG_MORE : 0));
132
133    //DEBUG("%d %ld+%d\n", r, trace_sent, len);
134
135    if (lwip_err == ERR_MEM) {
136        printf("bfscope: lwip: out of memory\n");
137        return;
138    }
139
140    trace_sent += len;
141
142    if (trace_sent >= trace_length) {
143        /* No more events */
144        uint64_t timestamp_stop = rdtsc();
145        DEBUG("bfscope: done (%zx bytes) in %"PRIuCYCLES" cycles\n",
146               trace_sent, timestamp_stop - timestamp_start);
147
148        bfscope_trace_dump_finished();
149    }
150}
151
152/*
153 * \brief Callback from LWIP when each chunk of data has been sent
154 */
155static err_t send_cb(void *arg, struct tcp_pcb *tpcb, u16_t length)
156{
157    //printf("send_cb %d\n", length);
158
159    /* If we haven't finished sending the trace, then send more data */
160    if (trace_length) {
161        bfscope_trace_send(tpcb);
162    }
163
164    return ERR_OK;
165}
166
167/*
168 * \brief This method should be called when a trace should be dumped on the network.
169 */
170static void bfscope_trace_dump_network(void)
171{
172    assert(bfscope_client != NULL);
173    assert(trace_length > 0);
174
175    printf("bfscope: sending %zu bytes to network...\n", trace_length);
176
177    /* Send length field */
178    char tmpbuf[10];
179    int len;
180    len = snprintf(tmpbuf, 9, "%zu", trace_length);
181    tcp_write(bfscope_client, tmpbuf, 8, TCP_WRITE_FLAG_COPY);
182
183    /* Start to send the trace */
184    timestamp_start = rdtsc();
185    trace_sent = 0;
186
187    bfscope_trace_send(bfscope_client);
188
189    tcp_output(bfscope_client);
190}
191
192/*
193 * \brief This method should be called when a trace should be dumped on the console.
194 */
195static void bfscope_trace_dump_console(void)
196{
197     printf("%s\n", trace_buf);
198
199     bfscope_trace_dump_finished();
200}
201
202/*
203 * \brief This method should be called when a trace should be dumped.
204 *
205 * (Based upon a different application calling trace_flush() or so.)
206 */
207static void bfscope_trace_dump(void)
208{
209    if(dump_in_progress) {
210        // Currently there is already a dump in progress, do nothing.
211        return;
212    }
213
214    int number_of_events = 0;
215    // Acquire the trace buffer
216    trace_length = trace_dump(trace_buf, BFSCOPE_BUFLEN, &number_of_events);
217
218    DEBUG("bfscope: trace length %zu, nr. of events %d\n", trace_length, number_of_events);
219
220    if (trace_length <= 0 || number_of_events <= 0) {
221        DEBUG("bfscope: trace length too small, not dumping.\n");
222        return;
223    }
224
225    dump_in_progress = true;
226
227    printf("%s:%s:%d: bfscope_client=%p\n",
228            __FILE__, __FUNCTION__, __LINE__, bfscope_client);
229    if (bfscope_client != NULL) {
230        // We have a connected client, dump to network
231        bfscope_trace_dump_network();
232    } else {
233        // There is no client, just dump to console
234        bfscope_trace_dump_console();
235    }
236}
237
238/*
239 * \brief Callback from LWIP when we receive TCP data
240 */
241static err_t recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p,
242                     err_t err)
243{
244    if (p == NULL) {
245        // close the connection
246        bfscope_connection_close(tpcb);
247        return ERR_OK;
248    }
249
250    /* don't send an immediate ack here, do it later with the data */
251    tpcb->flags |= TF_ACK_DELAY;
252
253    assert(p->next == 0);
254
255
256    if ((p->tot_len > 2) && (p->tot_len < 200)) {
257        if (strncmp(p->payload, "trace", strlen("trace")) == 0) {
258
259            DEBUG("bfscope: trace request\n");
260
261            // NOOP
262
263        } else {
264            DEBUG("bfscope: could not understand request\n");
265        }
266    }
267
268
269    /* Done with the incoming data */
270    tcp_recved(tpcb, p->len);
271    pbuf_free(p);
272
273    return ERR_OK;
274}
275
276/*
277 * \brief Callback from LWIP when a client connects to our TCP listen sock
278 */
279static err_t accept_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
280{
281    printf("bfscope: connected\n");
282
283    assert(err == ERR_OK);
284
285    tcp_recv(tpcb, recv_cb);
286    tcp_sent(tpcb, send_cb);
287    tcp_err(tpcb, error_cb);
288    tcp_arg(tpcb, (void*)tpcb);
289
290    tcp_accepted(tpcb);
291
292
293    bfscope_client = tpcb;
294    printf("%s:%s:%d: bfscope_client=%p\n",
295           __FILE__, __FUNCTION__, __LINE__, bfscope_client);
296    return ERR_OK;
297}
298
299/*
300 * \brief Start listening on the bfscope server port
301 */
302static err_t bfscope_server_init(void)
303{
304    err_t err;
305
306    uint16_t bind_port = BFSCOPE_TCP_PORT;
307
308    struct tcp_pcb *pcb = tcp_new();
309    if (pcb == NULL) {
310        return ERR_MEM;
311    }
312
313    err = tcp_bind(pcb, IP_ADDR_ANY, bind_port);
314    if(err != ERR_OK) {
315        return(err);
316    }
317
318    struct tcp_pcb *pcb2 = tcp_listen(pcb);
319    assert(pcb2 != NULL);
320    tcp_accept(pcb2, accept_cb);
321
322    printf("bfscope: listening on port %"PRIu16"\n", BFSCOPE_TCP_PORT);
323
324    return ERR_OK;
325}
326
327//------------------------------------------------------------------------------
328// Monitor Messaging Interface
329//------------------------------------------------------------------------------
330
331/*
332 * This function is called when we receive a flush message from our monitor.
333 */
334static void bfscope_handle_flush_msg(struct monitor_binding *mb, iref_t iref)
335{
336    printf("bfscope flush request message received!\n");
337
338    bfscope_trace_dump();
339}
340
341struct bfscope_ack_send_state {
342    struct event_queue_node qnode;
343    struct monitor_binding *monitor_binding;
344};
345
346static void bfscope_send_flush_ack_cont(void* arg)
347{
348    errval_t err;
349
350    struct bfscope_ack_send_state *state = (struct bfscope_ack_send_state*) arg;
351    struct monitor_binding *monitor_binding = state->monitor_binding;
352
353    err = monitor_binding->tx_vtbl.bfscope_flush_ack(monitor_binding, MKCONT(free, state));
354
355    if (err_is_ok(err)) {
356        event_mutex_unlock(&monitor_binding->mutex);
357    } else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
358        err = monitor_binding->register_send(monitor_binding, monitor_binding->waitset, MKCONT(&bfscope_send_flush_ack_cont, state));
359        assert(err_is_ok(err));
360    } else {
361        event_mutex_unlock(&monitor_binding->mutex);
362        //TODO: Error handling
363        USER_PANIC_ERR(err, "Could not send flush ack message to monitor of bfscope");
364    }
365}
366
367/*
368 * Call this method when bfscope is done with flushing and wants to notify
369 * the initiator of the flush request.
370 */
371static void bfscope_send_flush_ack_to_monitor(void) {
372
373
374    struct bfscope_ack_send_state *state = malloc(sizeof(struct bfscope_ack_send_state));
375    //memset(state, 0, sizeof(struct trace_broadcast_start_state));
376
377    state->monitor_binding = get_monitor_binding();
378
379    event_mutex_enqueue_lock(&state->monitor_binding->mutex, &state->qnode, MKCLOSURE(&bfscope_send_flush_ack_cont, state));
380}
381
382//------------------------------------------------------------------------------
383// Interface Exporting
384//------------------------------------------------------------------------------
385
386static void export_cb(void *st, errval_t err, iref_t iref)
387{
388    if (err_is_fail(err)) {
389        USER_PANIC_ERR(err, "export failed");
390    }
391
392    printf("bfscope: exported at iref %"PRIuIREF"\n", iref);
393
394    // register this iref with the name service
395    err = nameservice_register("bfscope", iref);
396    if (err_is_fail(err)) {
397        USER_PANIC_ERR(err, "nameservice_register failed");
398    }
399}
400
401static errval_t connect_cb(void *st, struct empty_binding *b)
402{
403    USER_PANIC("bfscope: connect_cb got called");
404}
405
406//------------------------------------------------------------------------------
407// Main
408//------------------------------------------------------------------------------
409
410int main(int argc, char**argv)
411{
412
413#ifndef CONFIG_TRACE
414    // bail - no tracing support
415    printf("%.*s: Error, no tracing support, cannot start bfscope\n",
416           DISP_NAME_LEN, disp_name());
417    printf("%.*s: recompile with trace = TRUE in build/hake/Config.hs\n",
418           DISP_NAME_LEN, disp_name());
419    return -1;
420#endif
421
422    // Allocate the outgoing buffer
423    if (trace_buf == NULL) {
424        trace_buf = malloc(BFSCOPE_BUFLEN);
425    }
426    assert(trace_buf);
427
428    /* Disable tracing for bfscope */
429    dispatcher_handle_t handle = curdispatcher();
430    struct dispatcher_generic *disp = get_dispatcher_generic(handle);
431    disp->trace_buf = NULL;
432
433    printf("%.*s running on core %d\n", DISP_NAME_LEN, disp_name(),
434           disp_get_core_id());
435
436    /* Connect to e1000 driver */
437    printf("%.*s: trying to connect to the e1000 driver...\n",
438           DISP_NAME_LEN, disp_name());
439
440    lwip_init_auto();
441
442    err_t lwip_err = bfscope_server_init();
443
444    assert(lwip_err == ERR_OK);
445
446
447    // Export our empty interface
448    errval_t err;
449    err = empty_export(NULL /* state pointer for connect/export callbacks */,
450            export_cb, connect_cb, get_default_waitset(),
451            IDC_EXPORT_FLAGS_DEFAULT);
452    if (err_is_fail(err)) {
453        USER_PANIC_ERR(err, "export failed");
454    }
455
456    // Register our message handlers with the monitor
457    struct monitor_binding *monitor_binding;
458    monitor_binding = get_monitor_binding();
459    monitor_binding->rx_vtbl.bfscope_flush_send = &bfscope_handle_flush_msg;
460
461
462    while (1) {
463        //err = event_dispatch(lwip_waitset);
464        err = event_dispatch_non_block(lwip_waitset);
465
466        if (err == LIB_ERR_NO_EVENT) {
467            // It is ok that no event is dispatched.
468            err = ERR_OK;
469        }
470
471        DEBUG("bfscope: dispatched event, autoflush: %d\n",((struct trace_buffer*) trace_buffer_master)->autoflush);
472
473        // Check if we are in autoflush mode
474        if(((struct trace_buffer*) trace_buffer_master)->autoflush) {
475            local_flush = true;
476            bfscope_trace_dump();
477        }
478
479        thread_yield_dispatcher(NULL_CAP);
480
481
482        if (err_is_fail(err)) {
483            DEBUG_ERR(err, "in event_dispatch");
484            break;
485        }
486    }
487
488    return 0;
489}
490
491