/**********************************************************************
 * Copyright (c) 2007, 2010 QNX Software Systems and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors: 
 *     QNX Software Systems - Initial API and implementation
 **********************************************************************/

package org.eclipse.cdt.debug.mi.core;

import java.io.IOException;

import org.eclipse.cdt.utils.spawner.Spawner;
import org.eclipse.core.runtime.IProgressMonitor;

/**
 * @author Doug Schaefer
 */
public class CygwinMIProcessAdapter extends MIProcessAdapter {

	/**
	 * @param args
	 * @param launchTimeout
	 * @param monitor
	 * @throws IOException
	 */
	public CygwinMIProcessAdapter(String[] args, int launchTimeout,
			IProgressMonitor monitor) throws IOException {
		super(args, launchTimeout, monitor);
	}

	@Override
	public void interrupt(MIInferior inferior) {
		if (fGDBProcess instanceof Spawner) {
			if (inferior.isRunning()) {
				boolean interruptedInferior = false;
				Spawner gdbSpawner = (Spawner) fGDBProcess;
				
				// Cygwin gdb 6.8 is capricious when it comes to interrupting
				// the target. MinGW and later versions of Cygwin aren't. A
				// simple CTRL-C to gdb seems to do the trick in every case.
				// Once we drop support for gdb 6.8, we should be able to ditch
				// this method and rely on the base implementation
				// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=304096#c56
				if (inferior.isRemoteInferior()) {
					// Interrupt gdb with a 'kill -SIGINT'. The reason we
					// need to send a simulated Cygwin/POSIX SIGINT to
					// Cygwin gdb is that it has special handling in the case
					// of remote debugging, as explained in the bugzilla 
					// comment above. That special handling will forward the
					// interrupt request through gdbserver to the remote
					// inferior, but the interrupt to gdb *must* be a
					// simulated Cygwin/POSIX SIGINT; a CTRL-C won't do.
					gdbSpawner.interrupt();		
				}
				else if (inferior.isAttachedInferior()) {
					// Cygwin gdb 6.8 has no support for forwarding an
					// interrupt request to the local process it has
					// attached to. That support has since been added and
					// will be available in 7.x. So, the only way to suspend the
					// attached-to inferior is to interrupt it directly.
					// The following call will take a special path in the
					// JNI code. See
					// Java_org_eclipse_cdt_utils_spawner_Spawner_raise()
					// We don't use the Cygwin 'kill' command since (a) we don't
					// know if the process associated with PID (the inferior) is
					// a cygwin one (kill only works on cygwin programs), and
					// (b) a CTRL-C will work just fine whether it's a cygwin
					// program or not
					interruptInferior(inferior);
					interruptedInferior = true;
				}
				else {
					// The typical case--gdb launches the inferior.
					// Interrupt gdb but with a CTRL-C. gdb (6.8) itself
					// doesn't have a handler for CTRL-C, but all processes
					// in the console
					// process group will receive the CTRL-C, and gdb
					// registers itself to catch any such events that
					// happen in the inferior. Thus it is able to determine
					// and report that the inferior has been interrupted.
					// But it's important we don't interrupt Cygwin gdb with
					// a 'kill' since that will only reach gdb, and gdb
					// won't forward the request on to the inferior. See
					// bugzilla comment referenced above for details.
					gdbSpawner.interruptCTRLC(); 
				}
				
				waitForInterrupt(inferior);

				// If we are still running try to interrupt the inferior (unless we
				// already tried that above)
				if (inferior.isRunning() && inferior.getInferiorPID() > 0 && !interruptedInferior) {
					// lets try something else.
					interruptInferior(inferior);
				}
			}
		}
			
	}
	
}
