1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3     queue.c
4     Copyright (C) 2005 S�bastien Granjoux
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19 */
20 
21 /*
22  * Keep all debugger commands in a queue and send them one by one to the
23  * debugger (implementing IAnjutaDebugger).
24  *---------------------------------------------------------------------------*/
25 
26 #include <config.h>
27 
28 #include "queue.h"
29 
30 /*#define DEBUG*/
31 #include <libanjuta/anjuta-debug.h>
32 #include <libanjuta/interfaces/ianjuta-message-manager.h>
33 #include <libanjuta/interfaces/ianjuta-debugger-register.h>
34 #include <libanjuta/interfaces/ianjuta-debugger-memory.h>
35 #include <libanjuta/interfaces/ianjuta-debugger-instruction.h>
36 #include <libanjuta/interfaces/ianjuta-debugger-breakpoint.h>
37 #include <libanjuta/interfaces/ianjuta-debugger-variable.h>
38 
39 
40 /* Contants defintion
41  *---------------------------------------------------------------------------*/
42 
43 #define ICON_FILE "anjuta-debug-manager.plugin.png"
44 
45 /* Private type
46  *---------------------------------------------------------------------------*/
47 
48 struct _DmaDebuggerQueue {
49 	GObject parent;
50 
51 	AnjutaPlugin* plugin;
52 	IAnjutaDebugger* debugger;
53 	guint support;
54 
55 	/* Command queue */
56 	GQueue *queue;
57 	DmaQueueCommand *last;
58 	GList *insert_command;		/* Insert command at the head of the list */
59 
60 	IAnjutaDebuggerState debugger_state;
61 	IAnjutaDebuggerState queue_state;
62 	gboolean stop_on_sharedlib;
63 
64 	/* View for debugger messages */
65 	IAnjutaMessageView* log;
66 
67 	gboolean busy;
68 };
69 
70 struct _DmaDebuggerQueueClass {
71 	GObjectClass parent;
72  };
73 
74 /* Call backs
75  *---------------------------------------------------------------------------*/
76 
77 /* Queue function
78  *---------------------------------------------------------------------------*/
79 
80 
81 /* Cancel all commands those cannot handle this unexpected state
82  * Return TRUE if the state of the queue need to be changed too
83  */
84 
85 static gboolean
dma_queue_cancel_unexpected(DmaDebuggerQueue * self,IAnjutaDebuggerState state)86 dma_queue_cancel_unexpected (DmaDebuggerQueue *self, IAnjutaDebuggerState state)
87 {
88 	GList* node = g_queue_peek_head_link(self->queue);
89 
90 	/* IANJUTA_DEBUGGER_BUSY is used as a do nothing marker*/
91 	if (state == IANJUTA_DEBUGGER_BUSY) return FALSE;
92 
93 	/* Cancel all commands in queue with the flag */
94 	while (node != NULL)
95 	{
96 		GList* next = g_list_next (node);
97 		DmaQueueCommand* cmd = (DmaQueueCommand *)node->data;
98 
99 		if (!dma_command_is_valid_in_state(cmd, state))
100 		{
101 			/* Command is not allowed in this state, cancel it */
102 			dma_command_cancel (cmd);
103 			g_queue_delete_link (self->queue, node);
104 		}
105 		else if (dma_command_is_going_to_state (cmd) != IANJUTA_DEBUGGER_BUSY)
106 		{
107 			/* A command setting the state is kept,
108 		   	debugger state is known again afterward, queue state is kept too */
109 
110 			return FALSE;
111 		}
112 		node = next;
113 	}
114 	/* End in this unexpected state */
115 	self->queue_state = state;
116 
117 	return TRUE;
118 }
119 
120 static void
dma_debugger_queue_clear(DmaDebuggerQueue * self)121 dma_debugger_queue_clear (DmaDebuggerQueue *self)
122 {
123 	g_queue_foreach (self->queue, (GFunc)dma_command_free, NULL);
124 	/* Do not use g_queue_clear yet as it is defined only in GLib 2.14 */
125 	while (g_queue_pop_head(self->queue) != NULL);
126 	if (self->last != NULL)
127 	{
128 		DEBUG_PRINT("clear command %x", dma_command_get_type (self->last));
129 		dma_command_free (self->last);
130 		self->last = NULL;
131 	}
132 
133 	/* Queue is empty so has the same state than debugger */
134 	self->queue_state = self->debugger_state;
135 
136 	g_list_free (self->insert_command);
137 	self->insert_command = NULL;
138 }
139 
140 static void
dma_queue_emit_debugger_state_change(DmaDebuggerQueue * self,IAnjutaDebuggerState state,GError * err)141 dma_queue_emit_debugger_state_change (DmaDebuggerQueue *self, IAnjutaDebuggerState state, GError* err)
142 {
143 	enum
144 	{
145 		NO_SIGNAL,
146 		DEBUGGER_STOPPED_SIGNAL,
147 		DEBUGGER_STARTED_SIGNAL,
148 		PROGRAM_LOADED_SIGNAL,
149 		PROGRAM_UNLOADED_SIGNAL,
150 		PROGRAM_STARTED_SIGNAL,
151 		PROGRAM_EXITED_SIGNAL,
152 		PROGRAM_RUNNING_SIGNAL,
153 		PROGRAM_STOPPED_SIGNAL
154 	} signal = NO_SIGNAL;
155 
156 	DEBUG_PRINT("change debugger state new %d old %d", state, self->debugger_state);
157 
158 	switch (state)
159 	{
160 	case IANJUTA_DEBUGGER_BUSY:
161 		/* Debugger is busy, nothing to do */
162 		g_return_if_reached();
163 		return;
164 	case IANJUTA_DEBUGGER_STOPPED:
165 		self->stop_on_sharedlib = FALSE;
166 		signal = DEBUGGER_STOPPED_SIGNAL;
167 		self->debugger_state = state;
168 		break;
169 	case IANJUTA_DEBUGGER_STARTED:
170 		self->stop_on_sharedlib = FALSE;
171 		signal = self->debugger_state < IANJUTA_DEBUGGER_STARTED ? DEBUGGER_STARTED_SIGNAL : PROGRAM_UNLOADED_SIGNAL;
172 		self->debugger_state = state;
173 		break;
174 	case IANJUTA_DEBUGGER_PROGRAM_LOADED:
175 		self->stop_on_sharedlib = FALSE;
176 		signal = self->debugger_state < IANJUTA_DEBUGGER_PROGRAM_LOADED ? PROGRAM_LOADED_SIGNAL : PROGRAM_EXITED_SIGNAL;
177 		self->debugger_state = state;
178 		break;
179 	case IANJUTA_DEBUGGER_PROGRAM_STOPPED:
180 		if (self->debugger_state < IANJUTA_DEBUGGER_PROGRAM_STOPPED)
181 		{
182 			signal = PROGRAM_STARTED_SIGNAL;
183 			/* Emit a debugger stopped after program started */
184 			self->debugger_state = IANJUTA_DEBUGGER_PROGRAM_RUNNING;
185 			break;
186 		}
187 		if (!self->stop_on_sharedlib)
188 		{
189 			signal = PROGRAM_STOPPED_SIGNAL;
190 		}
191 		self->debugger_state = state;
192 		break;
193 	case IANJUTA_DEBUGGER_PROGRAM_RUNNING:
194 		self->stop_on_sharedlib = FALSE;
195 		if (self->debugger_state < IANJUTA_DEBUGGER_PROGRAM_STOPPED)
196 		{
197 			signal = PROGRAM_STARTED_SIGNAL;
198 			/* Emit a debugger stopped after program started */
199 			self->debugger_state = IANJUTA_DEBUGGER_PROGRAM_STOPPED;
200 			break;
201 		}
202 		signal = PROGRAM_RUNNING_SIGNAL;
203 		self->debugger_state = state;
204 		break;
205 	}
206 
207 	self->insert_command = g_list_prepend (self->insert_command, g_queue_peek_head_link (self->queue));
208 	/* Emit signal */
209 	switch (signal)
210 	{
211 	case NO_SIGNAL:
212 		/* Do nothing */
213 		break;
214 	case DEBUGGER_STOPPED_SIGNAL:
215 		DEBUG_PRINT("%s", "** emit debugger-stopped **");
216 		g_signal_emit_by_name (self->plugin, "debugger-stopped", err);
217 		break;
218 	case DEBUGGER_STARTED_SIGNAL:
219 		DEBUG_PRINT("%s", "** emit debugger-started **");
220 		g_signal_emit_by_name (self->plugin, "debugger-started");
221 		break;
222 	case PROGRAM_LOADED_SIGNAL:
223 		DEBUG_PRINT("%s", "** emit program-loaded **");
224 		g_signal_emit_by_name (self->plugin, "program-loaded");
225 		break;
226 	case PROGRAM_UNLOADED_SIGNAL:
227 		DEBUG_PRINT("%s", "** emit program-unloaded **");
228 		g_signal_emit_by_name (self->plugin, "program-unloaded");
229 		break;
230 	case PROGRAM_STARTED_SIGNAL:
231 		DEBUG_PRINT("%s", "** emit program-started **");
232 		g_signal_emit_by_name (self->plugin, "program-started");
233 		break;
234 	case PROGRAM_EXITED_SIGNAL:
235 		DEBUG_PRINT("%s", "** emit program-exited **");
236 		g_signal_emit_by_name (self->plugin, "program-exited");
237 		break;
238 	case PROGRAM_STOPPED_SIGNAL:
239 		DEBUG_PRINT("%s", "** emit program-stopped **");
240 		g_signal_emit_by_name (self->plugin, "program-stopped");
241 		break;
242 	case PROGRAM_RUNNING_SIGNAL:
243 		DEBUG_PRINT("%s", "** emit program-running **");
244 		g_signal_emit_by_name (self->plugin, "program-running");
245 		break;
246 	}
247 	self->insert_command = g_list_delete_link (self->insert_command, self->insert_command);
248 }
249 
250 static void
dma_queue_emit_debugger_state(DmaDebuggerQueue * self,IAnjutaDebuggerState state,GError * err)251 dma_queue_emit_debugger_state (DmaDebuggerQueue *self, IAnjutaDebuggerState state, GError* err)
252 {
253 	DEBUG_PRINT("update debugger state new %d old %d", state, self->debugger_state);
254 
255 	/* Add missing states if useful */
256 	for(;self->debugger_state != state;)
257 	{
258 		IAnjutaDebuggerState next_state = state;
259 
260 		switch (state)
261 		{
262 		case IANJUTA_DEBUGGER_STOPPED:
263 			if ((self->debugger_state == IANJUTA_DEBUGGER_PROGRAM_RUNNING) ||
264 				(self->debugger_state == IANJUTA_DEBUGGER_PROGRAM_STOPPED))
265 			{
266 				next_state = IANJUTA_DEBUGGER_PROGRAM_LOADED;
267 			}
268 			else if	(self->debugger_state == IANJUTA_DEBUGGER_PROGRAM_LOADED)
269 			{
270 				next_state = IANJUTA_DEBUGGER_STARTED;
271 			}
272 			break;
273 		case IANJUTA_DEBUGGER_STARTED:
274 			if ((self->debugger_state == IANJUTA_DEBUGGER_PROGRAM_RUNNING) ||
275 				(self->debugger_state == IANJUTA_DEBUGGER_PROGRAM_STOPPED))
276 			{
277 				next_state = IANJUTA_DEBUGGER_PROGRAM_LOADED;
278 			}
279 			break;
280 		case IANJUTA_DEBUGGER_PROGRAM_LOADED:
281 			if (self->debugger_state == IANJUTA_DEBUGGER_STOPPED)
282 			{
283 				next_state = IANJUTA_DEBUGGER_STARTED;
284 			}
285 			break;
286 		case IANJUTA_DEBUGGER_PROGRAM_STOPPED:
287 			if (self->debugger_state == IANJUTA_DEBUGGER_STOPPED)
288 			{
289 				next_state = IANJUTA_DEBUGGER_STARTED;
290 			}
291 			else if (self->debugger_state == IANJUTA_DEBUGGER_STARTED)
292 			{
293 				next_state = IANJUTA_DEBUGGER_PROGRAM_LOADED;
294 			}
295 			break;
296 		case IANJUTA_DEBUGGER_PROGRAM_RUNNING:
297 			if (self->debugger_state == IANJUTA_DEBUGGER_STOPPED)
298 			{
299 				next_state = IANJUTA_DEBUGGER_STARTED;
300 			}
301 			else if (self->debugger_state == IANJUTA_DEBUGGER_STARTED)
302 			{
303 				next_state = IANJUTA_DEBUGGER_PROGRAM_LOADED;
304 			}
305 			break;
306 		case IANJUTA_DEBUGGER_BUSY:
307 			return;
308 		}
309 		dma_queue_emit_debugger_state_change (self, next_state, NULL);
310 	}
311 }
312 
313 static void
dma_queue_emit_debugger_ready(DmaDebuggerQueue * self)314 dma_queue_emit_debugger_ready (DmaDebuggerQueue *self)
315 {
316 	gboolean busy;
317 
318 	if (g_queue_is_empty(self->queue) && (self->last == NULL))
319 	{
320 		busy = FALSE;
321 	}
322 	else
323 	{
324 		busy = TRUE;
325 	}
326 
327 	if (busy != self->busy)
328 	{
329 		/* FIXME: set AnjutaStatus to busy? */
330 		self->busy = busy;
331 	}
332 }
333 
334 static void dma_debugger_queue_execute (DmaDebuggerQueue *self);
335 
336 /* Call when debugger has completed the current command */
337 
338 static void
dma_debugger_queue_complete(DmaDebuggerQueue * self,IAnjutaDebuggerState state)339 dma_debugger_queue_complete (DmaDebuggerQueue *self, IAnjutaDebuggerState state)
340 {
341 	DEBUG_PRINT("debugger_queue_complete %d", state);
342 
343 	if (state != IANJUTA_DEBUGGER_BUSY)
344 	{
345 		if (self->last != NULL)
346 		{
347 			if (dma_command_is_going_to_state (self->last) != state)
348 			{
349 				/* Command end in an unexpected state,
350 			 	* Remove invalid following command */
351 				dma_queue_cancel_unexpected (self, state);
352 			}
353 
354 			/* Remove current command */
355 			DEBUG_PRINT("end command %x", dma_command_get_type (self->last));
356 			dma_command_free (self->last);
357 			self->last = NULL;
358 		}
359 
360 
361 		/* Emit new state if necessary */
362 		dma_queue_emit_debugger_state (self, state, NULL);
363 
364 		/* Send next command */
365 		dma_debugger_queue_execute (self);
366 	}
367 }
368 
369 /* Call to send next command */
370 
371 static void
dma_debugger_queue_execute(DmaDebuggerQueue * self)372 dma_debugger_queue_execute (DmaDebuggerQueue *self)
373 {
374 	DEBUG_PRINT("%s", "debugger_queue_execute");
375 
376 	/* Check if debugger is connected to a debugger backend */
377 	g_return_if_fail (self->debugger != NULL);
378 
379 	/* Check if there debugger is busy */
380 	if (self->last != NULL)
381 	{
382 		IAnjutaDebuggerState state;
383 		/* Recheck state in case of desynchronization */
384 		state = ianjuta_debugger_get_state (self->debugger, NULL);
385 		dma_debugger_queue_complete (self, state);
386 	}
387 
388 	/* Check if there is something to execute */
389 	while (!g_queue_is_empty(self->queue) && (self->last == NULL))
390 	{
391 		DmaQueueCommand *cmd;
392 		GError *err = NULL;
393 		gboolean ok;
394 
395 		cmd = (DmaQueueCommand *)g_queue_pop_head(self->queue);
396 
397 		/* Start command */
398 		self->last = cmd;
399 		DEBUG_PRINT("run command %x", dma_command_get_type (cmd));
400 		ok = dma_command_run (cmd, self->debugger, self, &err);
401 
402 		if (!ok || (err != NULL))
403 		{
404 			/* Something fail */
405 			if (dma_command_is_going_to_state (self->last) != IANJUTA_DEBUGGER_BUSY)
406 			{
407 				/* Command has been canceled in an unexpected state,
408 				 * Remove invalid following command */
409 				dma_queue_cancel_unexpected (self, self->debugger_state);
410 			}
411 
412 			/* Remove current command */
413 			DEBUG_PRINT("cancel command %x", dma_command_get_type (self->last));
414 			dma_command_free (self->last);
415 			self->last = NULL;
416 
417 			/* Display error message to user */
418 			if (err != NULL)
419 			{
420 				if (err->message != NULL)
421 				{
422 					anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (self->plugin)->shell), err->message);
423 				}
424 
425 				g_error_free (err);
426 			}
427 		}
428 	}
429 
430 	dma_queue_emit_debugger_ready (self);
431 }
432 
433 static gboolean
dma_queue_check_state(DmaDebuggerQueue * self,DmaQueueCommand * cmd)434 dma_queue_check_state (DmaDebuggerQueue *self, DmaQueueCommand* cmd)
435 {
436 	gboolean recheck;
437 
438 	for (recheck = FALSE; recheck != TRUE; recheck = TRUE)
439 	{
440 		IAnjutaDebuggerState state;
441 
442 		if ((self->insert_command != NULL) || dma_command_has_flag (cmd, HIGH_PRIORITY))
443 		{
444 			/* Prepend command and high priority command use debugger state or current command state */
445 			if (self->last != NULL)
446 			{
447 				state = dma_command_is_going_to_state (self->last);
448 				if (state == IANJUTA_DEBUGGER_BUSY)
449 				{
450 					state = self->debugger_state;
451 				}
452 			}
453 			else
454 			{
455 				state = self->debugger_state;
456 			}
457 		}
458 		else
459 		{
460 			/* Append command use queue state */
461 			state = self->queue_state;
462 		}
463 
464 		/* Only the debugger can be busy */
465 		g_return_val_if_fail (state != IANJUTA_DEBUGGER_BUSY, FALSE);
466 
467 		if (dma_command_is_valid_in_state (cmd, state))
468     	{
469 			/* State is right */
470 			return TRUE;
471 		}
472 
473 		g_warning ("Cancel command %x, debugger in state %d", dma_command_get_type (cmd), state);
474 
475 		/* Check if synchronization is still ok */
476 		state = ianjuta_debugger_get_state (self->debugger, NULL);
477 		dma_debugger_queue_complete (self, state);
478 
479 		/* Check again */
480 	}
481 
482 	return FALSE;
483 }
484 
485 static gboolean
dma_debugger_activate_plugin(DmaDebuggerQueue * self,const gchar * mime_type)486 dma_debugger_activate_plugin (DmaDebuggerQueue* self, const gchar *mime_type)
487 {
488 	AnjutaPluginManager *plugin_manager;
489 	AnjutaPluginHandle *plugin;
490 	GList *plugins = NULL;
491 	gchar *value;
492 
493 	/* Get list of debugger plugins */
494 	plugin_manager = anjuta_shell_get_plugin_manager (ANJUTA_PLUGIN(self->plugin)->shell, NULL);
495 	if (mime_type == NULL)
496 	{
497 		/* User has to select the right debugger */
498 		plugins = anjuta_plugin_manager_query (plugin_manager,
499 		                                       "Anjuta Plugin","Interfaces", "IAnjutaDebugger", NULL);
500 	}
501 	else
502 	{
503 		/* Propose only debugger supporting correct mime type */
504 		plugins = anjuta_plugin_manager_query (plugin_manager,
505 		                                       "Anjuta Plugin","Interfaces", "IAnjutaDebugger",
506 		                                       "File Loader", "SupportedMimeTypes", mime_type,
507 		                                       NULL);
508 	}
509 
510 	if (plugins == NULL)
511 	{
512 		/* No plugin found */
513 		anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (self->plugin)->shell),
514 				_("Unable to find a debugger plugin supporting a target with %s MIME type"), mime_type);
515 
516 		return FALSE;
517 	}
518 	else if (g_list_length (plugins) == 1)
519 	{
520 		/* Only one plugin found, use it */
521 		plugin = (AnjutaPluginHandle *)plugins->data;
522 	}
523 	else
524 	{
525 		/* Ask the user to select one plugin */
526 		plugin = anjuta_plugin_manager_select (plugin_manager,
527 		                                       _("Select a plugin"),
528 		                                       _("Please select a plugin to activate"),
529 		                                       plugins);
530 	}
531 
532 	if (plugin != NULL)
533 	{
534 		/* Get debugger interface */
535 		self->debugger = (IAnjutaDebugger *)anjuta_plugin_manager_get_plugin_by_handle (plugin_manager, plugin);
536 
537 		self->support = 0;
538 		/* Check if register interface is available */
539 		self->support |= IANJUTA_IS_DEBUGGER_REGISTER(self->debugger) ? HAS_REGISTER : 0;
540 		/* Check if memory interface is available */
541 		self->support |= IANJUTA_IS_DEBUGGER_MEMORY(self->debugger) ? HAS_MEMORY : 0;
542 		/* Check if instruction interface is available */
543 		self->support |= IANJUTA_IS_DEBUGGER_INSTRUCTION(self->debugger) ? HAS_INSTRUCTION : 0;
544 		/* Check if breakpoint interface is available */
545 		self->support |= IANJUTA_IS_DEBUGGER_BREAKPOINT(self->debugger) ? HAS_BREAKPOINT : 0;
546 		if (IANJUTA_IS_DEBUGGER_BREAKPOINT (self->debugger))
547 		{
548 			self->support |= ianjuta_debugger_breakpoint_implement_breakpoint (IANJUTA_DEBUGGER_BREAKPOINT (self->debugger), NULL) * HAS_BREAKPOINT * 2;
549 		}
550 		/* Check if variable interface is available */
551 		self->support |= IANJUTA_IS_DEBUGGER_VARIABLE(self->debugger) ? HAS_VARIABLE : 0;
552 
553 		return TRUE;
554 	}
555 	else
556 	{
557 		/* No plugin selected */
558 
559 		return FALSE;
560 	}
561 }
562 
563 /* IAnjutaDebugger callback
564  *---------------------------------------------------------------------------*/
565 
566 static void
on_dma_debugger_ready(DmaDebuggerQueue * self,IAnjutaDebuggerState state)567 on_dma_debugger_ready (DmaDebuggerQueue *self, IAnjutaDebuggerState state)
568 {
569 	DEBUG_PRINT ("From debugger: receive debugger ready %d", state);
570 
571 	dma_debugger_queue_complete (self, state);
572 }
573 
574 static void
on_dma_debugger_started(DmaDebuggerQueue * self)575 on_dma_debugger_started (DmaDebuggerQueue *self)
576 {
577 	DEBUG_PRINT ("%s", "From debugger: receive debugger started");
578 	dma_queue_emit_debugger_state (self, IANJUTA_DEBUGGER_STARTED, NULL);
579 }
580 
581 static void
on_dma_debugger_stopped(DmaDebuggerQueue * self,GError * err)582 on_dma_debugger_stopped (DmaDebuggerQueue *self, GError *err)
583 {
584 	IAnjutaDebuggerState state;
585 
586 	DEBUG_PRINT ("From debugger: receive debugger stopped with error %p", err);
587 	dma_queue_emit_debugger_state (self, IANJUTA_DEBUGGER_STOPPED, err);
588 
589 	/* Reread debugger state, could have changed while emitting signal */
590 	state = ianjuta_debugger_get_state (self->debugger, NULL);
591 	dma_debugger_queue_complete (self, state);
592 }
593 
594 static void
on_dma_program_loaded(DmaDebuggerQueue * self)595 on_dma_program_loaded (DmaDebuggerQueue *self)
596 {
597 	DEBUG_PRINT ("%s", "From debugger: receive program loaded");
598 	dma_queue_emit_debugger_state (self, IANJUTA_DEBUGGER_PROGRAM_LOADED, NULL);
599 }
600 
601 static void
on_dma_program_running(DmaDebuggerQueue * self)602 on_dma_program_running (DmaDebuggerQueue *self)
603 {
604 	DEBUG_PRINT ("%s", "From debugger: debugger_program_running");
605 	dma_queue_emit_debugger_state (self, IANJUTA_DEBUGGER_PROGRAM_RUNNING, NULL);
606 }
607 
608 static void
on_dma_program_stopped(DmaDebuggerQueue * self)609 on_dma_program_stopped (DmaDebuggerQueue *self)
610 {
611 	DEBUG_PRINT ("%s", "From debugger: receive program stopped");
612 	dma_queue_emit_debugger_state (self, IANJUTA_DEBUGGER_PROGRAM_STOPPED, NULL);
613 }
614 
615 static void
on_dma_program_exited(DmaDebuggerQueue * self)616 on_dma_program_exited (DmaDebuggerQueue *self)
617 {
618 	DEBUG_PRINT ("%s", "From debugger: receive program exited");
619 	dma_queue_emit_debugger_state (self, IANJUTA_DEBUGGER_PROGRAM_LOADED, NULL);
620 }
621 
622 static void
on_dma_program_moved(DmaDebuggerQueue * self,guint pid,gint tid,gulong address,const gchar * src_path,guint line)623 on_dma_program_moved (DmaDebuggerQueue *self, guint pid, gint tid, gulong address, const gchar* src_path, guint line)
624 {
625 	DEBUG_PRINT ("%s", "From debugger: program moved");
626 	self->insert_command = g_list_prepend (self->insert_command, g_queue_peek_head_link (self->queue));
627 	g_signal_emit_by_name (self->plugin, "program-moved", pid, tid, address, src_path, line);
628 	self->insert_command = g_list_delete_link (self->insert_command, self->insert_command);
629 }
630 
631 static void
on_dma_frame_changed(DmaDebuggerQueue * self,guint frame,gint thread)632 on_dma_frame_changed (DmaDebuggerQueue *self, guint frame, gint thread)
633 {
634 	DEBUG_PRINT ("%s", "From debugger: frame changed");
635 	self->insert_command = g_list_prepend (self->insert_command, g_queue_peek_head_link (self->queue));
636 	g_signal_emit_by_name (self->plugin, "frame-changed", frame, thread);
637 	self->insert_command = g_list_delete_link (self->insert_command, self->insert_command);
638 }
639 
640 static void
on_dma_signal_received(DmaDebuggerQueue * self,const gchar * name,const gchar * description)641 on_dma_signal_received (DmaDebuggerQueue *self, const gchar* name, const gchar* description)
642 {
643 	DEBUG_PRINT ("%s", "From debugger: signal received");
644 	self->insert_command = g_list_prepend (self->insert_command, g_queue_peek_head_link (self->queue));
645 	g_signal_emit_by_name (self->plugin, "signal-received", name, description);
646 	self->insert_command = g_list_delete_link (self->insert_command, self->insert_command);
647 }
648 
649 static void
on_dma_sharedlib_event(DmaDebuggerQueue * self)650 on_dma_sharedlib_event (DmaDebuggerQueue *self)
651 {
652 	DEBUG_PRINT ("%s", "From debugger: shared lib event");
653 	self->stop_on_sharedlib = TRUE;
654 	dma_debugger_queue_complete (self, IANJUTA_DEBUGGER_PROGRAM_STOPPED);
655 	self->insert_command = g_list_prepend (self->insert_command, g_queue_peek_head_link (self->queue));
656 	g_signal_emit_by_name (self->plugin, "sharedlib-event");
657 	self->insert_command = g_list_delete_link (self->insert_command, self->insert_command);
658 	dma_queue_run (self);
659 }
660 
661 /* Public function
662  *---------------------------------------------------------------------------*/
663 
664 /* Command callback will add their commands at the beginning of the queue */
665 void
dma_debugger_queue_command_callback(const gpointer data,gpointer user_data,GError * err)666 dma_debugger_queue_command_callback (const gpointer data, gpointer user_data, GError* err)
667 {
668 	DmaDebuggerQueue *self = (DmaDebuggerQueue *)user_data;
669 
670 	g_return_if_fail (self->last != NULL);
671 
672 	self->insert_command = g_list_prepend (self->insert_command, g_queue_peek_head_link (self->queue));
673 	if (self->queue_state != IANJUTA_DEBUGGER_STOPPED)
674 	{
675 		dma_command_callback (self->last, data, err);
676 	}
677 	self->insert_command = g_list_delete_link (self->insert_command, self->insert_command);
678 }
679 
680 gboolean
dma_debugger_queue_append(DmaDebuggerQueue * self,DmaQueueCommand * cmd)681 dma_debugger_queue_append (DmaDebuggerQueue *self, DmaQueueCommand *cmd)
682 {
683 	DEBUG_PRINT("append cmd %x prepend %p", dma_command_get_type (cmd), self->insert_command);
684 	DEBUG_PRINT("current %x", self->last == NULL ? 0 : dma_command_get_type (self->last));
685 	DEBUG_PRINT("queue %x", self->queue->head == NULL ? 0 : dma_command_get_type (self->queue->head->data));
686 
687 	if ((self->debugger != NULL) && dma_queue_check_state(self, cmd))
688 	{
689 		/* If command is asynchronous stop current command */
690 		if (dma_command_has_flag (cmd, ASYNCHRONOUS))
691 		{
692 			IAnjutaDebuggerState state;
693 
694 			state = dma_command_is_going_to_state (cmd);
695 			if (state != IANJUTA_DEBUGGER_BUSY)
696 			{
697 				/* Command is changing debugger state */
698 				dma_queue_cancel_unexpected (self, state);
699 			}
700 
701 			/* Append command at the beginning */
702 			g_queue_push_head (self->queue, cmd);
703 
704 			/* We must not interrupt command having callback, as the command
705 			 * will be removed, the callback when emitted will be redirected to
706 			 * the handler of the next command */
707 			if ((state == IANJUTA_DEBUGGER_STOPPED) || (self->debugger_state == IANJUTA_DEBUGGER_PROGRAM_RUNNING))
708 			{
709 				dma_debugger_queue_complete (self, self->debugger_state);
710 			}
711 		}
712 		else if (dma_command_has_flag (cmd, HIGH_PRIORITY))
713 		{
714 			IAnjutaDebuggerState state;
715 
716 			state = dma_command_is_going_to_state (cmd);
717 			if (state != IANJUTA_DEBUGGER_BUSY)
718 			{
719 				/* Command is changing debugger state */
720 				dma_queue_cancel_unexpected (self, state);
721 			}
722 
723 			/* Prepend command at the beginning */
724 			g_queue_push_head (self->queue, cmd);
725 		}
726 		else if ((self->insert_command != NULL) && (self->insert_command->data != NULL))
727 		{
728 			IAnjutaDebuggerState state;
729 
730 			state = dma_command_is_going_to_state (cmd);
731 			if (state != IANJUTA_DEBUGGER_BUSY)
732 			{
733 				/* Command is changing debugger state */
734 				dma_queue_cancel_unexpected (self, state);
735 			}
736 
737 			/* Insert command in the beginning */
738 			g_queue_insert_before (self->queue, (GList *)self->insert_command->data, cmd);
739 		}
740 		else
741 		{
742 			/* Append command at the end (in the queue) */
743 			IAnjutaDebuggerState state;
744 
745 			g_queue_push_tail (self->queue, cmd);
746 
747 			state = dma_command_is_going_to_state (cmd);
748 			if (state != IANJUTA_DEBUGGER_BUSY)
749 			{
750 				self->queue_state = state;
751 			}
752 		}
753 
754 		dma_debugger_queue_execute(self);
755 
756 		return TRUE;
757 	}
758 	else
759 	{
760 		dma_command_free (cmd);
761 
762 		return FALSE;
763 	}
764 }
765 
766 void
dma_debugger_queue_stop(DmaDebuggerQueue * self)767 dma_debugger_queue_stop (DmaDebuggerQueue *self)
768 {
769 	/* Disconnect signal */
770 	if (self->debugger)
771 	{
772 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_debugger_ready), self);
773 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_debugger_started), self);
774 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_debugger_stopped), self);
775 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_program_loaded), self);
776 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_program_running), self);
777 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_program_stopped), self);
778 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_program_exited), self);
779 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_program_moved), self);
780 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_signal_received), self);
781 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_frame_changed), self);
782 		g_signal_handlers_disconnect_by_func (self->debugger, G_CALLBACK (on_dma_sharedlib_event), self);
783 		self->debugger = NULL;
784 		self->support = 0;
785 	}
786 }
787 
788 gboolean
dma_debugger_queue_start(DmaDebuggerQueue * self,const gchar * mime_type)789 dma_debugger_queue_start (DmaDebuggerQueue *self, const gchar *mime_type)
790 {
791 	dma_debugger_queue_stop (self);
792 
793 	/* Look for a debugger supporting mime_type */
794 	if (!dma_debugger_activate_plugin (self, mime_type))
795 	{
796 		return FALSE;
797 	}
798 
799 	if (self->debugger)
800 	{
801 		/* Connect signal */
802 		g_signal_connect_swapped (self->debugger, "debugger-ready", G_CALLBACK (on_dma_debugger_ready), self);
803 		g_signal_connect_swapped (self->debugger, "debugger-started", G_CALLBACK (on_dma_debugger_started), self);
804 		g_signal_connect_swapped (self->debugger, "debugger-stopped", G_CALLBACK (on_dma_debugger_stopped), self);
805 		g_signal_connect_swapped (self->debugger, "program-loaded", G_CALLBACK (on_dma_program_loaded), self);
806 		g_signal_connect_swapped (self->debugger, "program-running", G_CALLBACK (on_dma_program_running), self);
807 		g_signal_connect_swapped (self->debugger, "program-stopped", G_CALLBACK (on_dma_program_stopped), self);
808 		g_signal_connect_swapped (self->debugger, "program-exited", G_CALLBACK (on_dma_program_exited), self);
809 		g_signal_connect_swapped (self->debugger, "program-moved", G_CALLBACK (on_dma_program_moved), self);
810 		g_signal_connect_swapped (self->debugger, "signal-received", G_CALLBACK (on_dma_signal_received), self);
811 		g_signal_connect_swapped (self->debugger, "frame-changed", G_CALLBACK (on_dma_frame_changed), self);
812 		g_signal_connect_swapped (self->debugger, "sharedlib-event", G_CALLBACK (on_dma_sharedlib_event), self);
813 
814 		if (self->log == NULL)
815 		{
816 			dma_queue_disable_log (self);
817 		}
818 		else
819 		{
820 			dma_queue_enable_log (self, self->log);
821 		}
822 	}
823 
824 	return self->debugger != NULL;
825 }
826 
827 void
dma_queue_enable_log(DmaDebuggerQueue * self,IAnjutaMessageView * log)828 dma_queue_enable_log (DmaDebuggerQueue *self, IAnjutaMessageView *log)
829 {
830 	self->log = log;
831 	if (self->debugger != NULL)
832 	{
833 		ianjuta_debugger_enable_log (self->debugger, self->log, NULL);
834 	}
835 }
836 
837 void
dma_queue_disable_log(DmaDebuggerQueue * self)838 dma_queue_disable_log (DmaDebuggerQueue *self)
839 {
840 	self->log = NULL;
841 	if (self->debugger != NULL)
842 	{
843 		ianjuta_debugger_disable_log (self->debugger, NULL);
844 	}
845 }
846 
847 IAnjutaDebuggerState
dma_debugger_queue_get_state(DmaDebuggerQueue * self)848 dma_debugger_queue_get_state (DmaDebuggerQueue *self)
849 {
850 	return self->queue_state;
851 }
852 
853 gboolean
dma_debugger_queue_is_supported(DmaDebuggerQueue * self,DmaDebuggerCapability capability)854 dma_debugger_queue_is_supported (DmaDebuggerQueue *self, DmaDebuggerCapability capability)
855 {
856 	return self->support & capability ? TRUE : FALSE;
857 }
858 
859 /* GObject functions
860  *---------------------------------------------------------------------------*/
861 
862 /* Used in dispose and finalize */
863 static gpointer parent_class;
864 
865 /* dispose is the first destruction step. It is used to unref object created
866  * with instance_init in order to break reference counting cycles. This
867  * function could be called several times. All function should still work
868  * after this call. It has to called its parents.*/
869 
870 static void
dma_debugger_queue_dispose(GObject * obj)871 dma_debugger_queue_dispose (GObject *obj)
872 {
873 	DmaDebuggerQueue *self = DMA_DEBUGGER_QUEUE (obj);
874 
875 	dma_debugger_queue_clear (self);
876 
877 	G_OBJECT_CLASS (parent_class)->dispose (obj);
878 }
879 
880 /* finalize is the last destruction step. It must free all memory allocated
881  * with instance_init. It is called only one time just before releasing all
882  * memory */
883 
884 static void
dma_debugger_queue_finalize(GObject * obj)885 dma_debugger_queue_finalize (GObject *obj)
886 {
887 	DmaDebuggerQueue *self = DMA_DEBUGGER_QUEUE (obj);
888 
889 	g_queue_free (self->queue);
890 
891 	G_OBJECT_CLASS (parent_class)->finalize (obj);
892 }
893 
894 /* instance_init is the constructor. All functions should work after this
895  * call. */
896 
897 static void
dma_debugger_queue_instance_init(DmaDebuggerQueue * self)898 dma_debugger_queue_instance_init (DmaDebuggerQueue *self)
899 {
900 	self->plugin = NULL;
901 	self->debugger = NULL;
902 	self->support = 0;
903 	self->queue = g_queue_new ();
904 	self->last = NULL;
905 	self->busy = FALSE;
906 	self->insert_command = NULL;
907 	self->debugger_state = IANJUTA_DEBUGGER_STOPPED;
908 	self->queue_state = IANJUTA_DEBUGGER_STOPPED;
909 	self->log = NULL;
910 }
911 
912 /* class_init intialize the class itself not the instance */
913 
914 static void
dma_debugger_queue_class_init(DmaDebuggerQueueClass * klass)915 dma_debugger_queue_class_init (DmaDebuggerQueueClass * klass)
916 {
917 	GObjectClass *object_class;
918 
919 	g_return_if_fail (klass != NULL);
920 	object_class = G_OBJECT_CLASS (klass);
921 
922 	parent_class = g_type_class_peek_parent (klass);
923 
924 	object_class->dispose = dma_debugger_queue_dispose;
925 	object_class->finalize = dma_debugger_queue_finalize;
926 }
927 
928 GType
dma_debugger_queue_get_type(void)929 dma_debugger_queue_get_type (void)
930 {
931 	static GType type = 0;
932 
933 	if (!type)
934 	{
935 		static const GTypeInfo type_info =
936 		{
937 			sizeof (DmaDebuggerQueueClass),
938 			(GBaseInitFunc) NULL,
939 			(GBaseFinalizeFunc) NULL,
940 			(GClassInitFunc) dma_debugger_queue_class_init,
941 			(GClassFinalizeFunc) NULL,
942 			NULL,           /* class_data */
943 			sizeof (DmaDebuggerQueue),
944 			0,              /* n_preallocs */
945 			(GInstanceInitFunc) dma_debugger_queue_instance_init,
946 			NULL            /* value_table */
947 		};
948 
949 		type = g_type_register_static (G_TYPE_OBJECT,
950 		                            "DmaDebuggerQueue", &type_info, 0);
951 	}
952 
953 	return type;
954 }
955 
956 /* Creation and Destruction
957  *---------------------------------------------------------------------------*/
958 
959 DmaDebuggerQueue*
dma_debugger_queue_new(AnjutaPlugin * plugin)960 dma_debugger_queue_new (AnjutaPlugin *plugin)
961 {
962 	DmaDebuggerQueue *self;
963 
964 	self = g_object_new (DMA_DEBUGGER_QUEUE_TYPE, NULL);
965 	self->plugin = plugin;
966 
967 	return self;
968 }
969 
970 void
dma_debugger_queue_free(DmaDebuggerQueue * self)971 dma_debugger_queue_free (DmaDebuggerQueue *self)
972 {
973 	dma_debugger_queue_stop (self);
974 	g_object_unref (self);
975 }
976