1/**
2 * \file
3 * \brief Bfscope (trace server) support for the monitor.
4 */
5
6/*
7 * Copyright (c) 2012 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 <barrelfish/barrelfish.h>
16#include <barrelfish/nameservice_client.h>
17#include <barrelfish/event_queue.h>
18#include <trace/trace.h>
19#include <sys/time.h>
20#include "monitor.h"
21
22struct bfscope_flush_state
23{
24	struct intermon_binding *ib;
25	iref_t iref;
26};
27
28struct bfscope_ack_state
29{
30	struct intermon_binding* to_initiator_binding;
31};
32
33struct notify_bfscope_state
34{
35	struct monitor_binding *monitor_binding;
36	struct event_queue_node qnode;
37};
38
39// --------- Global variables
40
41// Monitor binding to the process that initiated the trace_start
42static struct monitor_binding *requester_monitor_binding = NULL;
43
44// Intermonitor binding between monitor on the core that initiated the flush request
45// and monitor on the core that runs bfscope
46static struct intermon_binding *requester_intermon_binding = NULL;
47
48// ----------
49
50//-----------
51// Receiving a flush ack message from bfscope
52//-----------
53
54static void bfscope_intermon_flush_ack_continue(void *arg);
55static void bfscope_intermon_flush_forward_handler(struct intermon_binding *imb, iref_t iref);
56static void bfscope_intermon_flush_ack(struct intermon_binding *ib);
57
58/*
59 * We received a message from bfscope, telling us that the flushing has been
60 * completed.
61 *
62 * So let's forward this information to the initiator.
63 */
64static void bfscope_monitor_flush_ack_handler(struct monitor_binding *mb)
65{
66	if(requester_intermon_binding == NULL) {
67		// The initiator and bfscope run on the same core, do no intermon communication
68
69		bfscope_intermon_flush_ack(NULL);
70		return;
71	}
72
73	struct bfscope_ack_state *state = malloc(sizeof (struct bfscope_ack_state));
74	state->to_initiator_binding = requester_intermon_binding;
75
76	requester_intermon_binding = NULL;
77
78	bfscope_intermon_flush_ack_continue(state);
79}
80
81// -------
82
83static void bfscope_monitor_flush_send_continue(void* arg)
84{
85
86	struct bfscope_flush_state *state = (struct bfscope_flush_state*) arg;
87
88	assert(state->ib != NULL);
89
90	// Send the intermonitor message
91	errval_t err;
92	err = state->ib->tx_vtbl.bfscope_flush_send_forward(state->ib, MKCONT(free, state), state->iref);
93
94	if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
95		// Sending failed, must be repeated for this core
96		err = state->ib->register_send(state->ib, state->ib->waitset, MKCONT(&bfscope_monitor_flush_send_continue, state));
97		assert(err_is_ok(err));
98	} else if(err_is_fail(err)) {
99		//TODO: Error handling
100		USER_PANIC_ERR(err, "Could not broadcast trace_monitor_broadcast_start_continue");
101	} else {
102		// Everything was ok, do nothing.
103	}
104
105}
106
107/*
108 * This function is called on the monitor that initiated the "trace_flush" command.
109 *
110 * Let's forward the message to the core on which bfscope is running.
111 */
112static void bfscope_monitor_flush_send_handler(struct monitor_binding *mb, iref_t iref)
113{
114	//printf("bfscope_monitor_flush_send_handler\n");
115
116	requester_monitor_binding = mb;
117
118	struct bfscope_flush_state *state = malloc(sizeof(struct bfscope_flush_state));
119	state->iref = iref;
120
121	// Get the coreid on which bfscope is running
122	coreid_t coreid;
123	errval_t err = iref_get_core_id(iref, &coreid);
124	if (err_is_fail(err)) {
125		USER_PANIC_ERR(err, "iref_get_core_id for bfscope failed");
126	}
127
128	//printf("bfscope runs on core: %d\n", coreid);
129
130	if(coreid == my_core_id) {
131		//printf("bfscope runs on the same core as the initiator of the flush request\n");
132
133                // we don't need the state in this case
134                free(state);
135		// Send message to bfscope directly
136		bfscope_intermon_flush_forward_handler(NULL, iref);
137		return;
138	}
139
140	err = intermon_binding_get(coreid, &state->ib);
141
142	if(err_is_fail(err)) {
143		USER_PANIC_ERR(err, "intermon_binding_get failed");
144	}
145
146	bfscope_monitor_flush_send_continue(state);
147}
148
149
150/*
151 * This function is called on the monitor on which the initiator of the flush
152 * message is running, once the flush has been performed and the ack has been
153 * received.
154 */
155static void bfscope_monitor_flush_finished_successfully(void *arg)
156{
157	// Reset the global state
158
159	requester_monitor_binding = NULL;
160}
161
162static void bfscope_intermon_flush_ack_continue(void* arg)
163{
164	struct bfscope_ack_state *state = (struct bfscope_ack_state*) arg;
165	struct intermon_binding *intermon_binding = state->to_initiator_binding;
166
167	errval_t err;
168
169	err = intermon_binding->tx_vtbl.bfscope_flush_ack_forward(intermon_binding, MKCONT(free, state));
170
171	if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
172		err = intermon_binding->register_send(intermon_binding, intermon_binding->waitset, MKCONT(&bfscope_intermon_flush_ack_continue, state));
173		assert(err_is_ok(err));
174	} else if(err_is_fail(err)) {
175		//TODO: Error handling
176		USER_PANIC_ERR(err, "Could not forward ack in bfscope_intermon_flush_ack_continue");
177	} else {
178		// Everything was ok, do nothing.
179	}
180}
181
182static void bfscope_send_flush_msg_to_bfscope(void* arg)
183{
184	errval_t err;
185
186	struct notify_bfscope_state *state = (struct notify_bfscope_state*) arg;
187	struct monitor_binding *monitor_binding = state->monitor_binding;
188
189	err = monitor_binding->tx_vtbl.bfscope_flush_send(monitor_binding, MKCONT(free, state), 0);
190
191	if (err_is_ok(err)) {
192		event_mutex_unlock(&monitor_binding->mutex);
193	} else if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
194		err = monitor_binding->register_send(monitor_binding, monitor_binding->waitset, MKCONT(&bfscope_send_flush_msg_to_bfscope, state));
195		assert(err_is_ok(err));
196	} else {
197		event_mutex_unlock(&monitor_binding->mutex);
198		//TODO: Error handling
199		USER_PANIC_ERR(err, "Could not send flush message to bfscope");
200	}
201}
202
203/*
204 * The flush message has received on the monitor where bfscope is running.
205 *
206 * Let's Notify bfscope about the flush request.
207 */
208static void bfscope_intermon_flush_forward_handler(struct intermon_binding *imb, iref_t iref)
209{
210	//printf("bfscope_intermon_flush_forward_handler on core %d.\n", my_core_id);
211
212	// Store the intermonitor binding so that we can later reply
213	requester_intermon_binding = imb;
214
215	// Notify bfscope
216
217	struct notify_bfscope_state *state = malloc(sizeof(struct notify_bfscope_state));
218	//memset(state, 0, sizeof(struct trace_broadcast_start_state));
219
220	// Get the monitor binding to bfscope
221	errval_t err = iref_get_binding(iref, &state->monitor_binding);
222	if(err_is_fail(err)) {
223		USER_PANIC_ERR(err, "iref_get_binding for bfscope failed");
224	}
225	// Send the message to bfscope
226	event_mutex_enqueue_lock(&state->monitor_binding->mutex, &state->qnode, MKCLOSURE(&bfscope_send_flush_msg_to_bfscope, state));
227
228}
229
230static void bfscope_monitor_flush_forward_ack_to_requester(void *arg)
231{
232
233	assert(requester_monitor_binding != NULL);
234
235	errval_t err;
236
237	err = requester_monitor_binding->tx_vtbl.bfscope_flush_ack(requester_monitor_binding, MKCONT(bfscope_monitor_flush_finished_successfully, NULL));
238
239	if(err_no(err) == FLOUNDER_ERR_TX_BUSY) {
240		err = requester_monitor_binding->register_send(requester_monitor_binding,
241				requester_monitor_binding->waitset, MKCONT(&bfscope_monitor_flush_forward_ack_to_requester, NULL));
242		assert(err_is_ok(err));
243	} else if(err_is_fail(err)) {
244		//TODO: Error handling
245		USER_PANIC_ERR(err, "Could not reply to flush bfscope_monitor_flush_forward_ack_to_requester");
246	} else {
247		// Everything was ok, do nothing.
248	}
249}
250
251// This function is automatically called when the initiating monitor receives an ack from another monitor
252static void bfscope_intermon_flush_ack(struct intermon_binding *ib)
253{
254	//printf("bfscope_intermon_flush_ack\n");
255
256	bfscope_monitor_flush_forward_ack_to_requester(NULL);
257}
258
259//------------------------------------------------------------------------------
260// Message Table Initialization
261//------------------------------------------------------------------------------
262
263
264// set up receive vtable in the intermonitor interface
265errval_t bfscope_intermon_init(struct intermon_binding *ib)
266{
267	ib->rx_vtbl.bfscope_flush_send_forward = &bfscope_intermon_flush_forward_handler;
268	ib->rx_vtbl.bfscope_flush_ack_forward = &bfscope_intermon_flush_ack;
269
270	return SYS_ERR_OK;
271}
272
273// set up receive vtable in the monitor interface
274errval_t bfscope_monitor_init(struct monitor_binding *mb)
275{
276    mb->rx_vtbl.bfscope_flush_send = &bfscope_monitor_flush_send_handler;
277    mb->rx_vtbl.bfscope_flush_ack = &bfscope_monitor_flush_ack_handler;
278
279    return SYS_ERR_OK;
280}
281