Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 98bce344a707a42fa567b6df0fc749e90a281eec (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*******************************************************************************
 * Copyright (c) 2010 Ericsson 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:
 *     Ericsson - initial API and implementation
 *******************************************************************************/
package org.eclipse.cdt.dsf.gdb.service;

import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateDataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.ImmediateRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.Immutable;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.datamodel.IDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExitedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IStartedDMEvent;
import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
import org.eclipse.cdt.dsf.debug.service.command.BufferedCommandControl;
import org.eclipse.cdt.dsf.debug.service.command.CommandCache;
import org.eclipse.cdt.dsf.debug.service.command.ICommandControlService.ICommandControlDMContext;
import org.eclipse.cdt.dsf.gdb.internal.GdbPlugin;
import org.eclipse.cdt.dsf.gdb.service.command.IGDBControl;
import org.eclipse.cdt.dsf.mi.service.IMICommandControl;
import org.eclipse.cdt.dsf.mi.service.IMIProcessDMContext;
import org.eclipse.cdt.dsf.mi.service.command.CommandFactory;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIListThreadGroupsInfo.IThreadGroupInfo;
import org.eclipse.cdt.dsf.mi.service.command.output.MIThread;
import org.eclipse.cdt.dsf.mi.service.command.output.MIThreadInfoInfo;
import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;

/**
 * This class implements the IProcesses interface for GDB 7.1
 * which provides new information about cores for threads and processes.
 * 
 * @since 4.0
 */
public class GDBProcesses_7_1 extends GDBProcesses_7_0 {

	@Immutable
	protected static class MIThreadDMData_7_1 extends MIThreadDMData implements IGdbThreadDMData {
		final String[] fCores;

		public MIThreadDMData_7_1(String name, String id, String[] cores) {
			super(name, id);
			fCores = cores;
		}

		@Override
		public String[] getCores() { return fCores; }

		@Override
		public String getOwner() { return null; }
	}

    private CommandFactory fCommandFactory;
    // This cache is used when we send command to get the cores.
    // The value of the cores can change at any time, but we provide
    // an updated value whenever there is a suspended event.
    private CommandCache fCommandForCoresCache;
    private IGDBControl fCommandControl;

	public GDBProcesses_7_1(DsfSession session) {
		super(session);
	}

	@Override
	public void initialize(final RequestMonitor requestMonitor) {
		super.initialize(new ImmediateRequestMonitor(requestMonitor) {
			@Override
			protected void handleSuccess() {
				doInitialize(requestMonitor);
			}
		});
	}

	/**
	 * This method initializes this service after our superclass's initialize()
	 * method succeeds.
	 * 
	 * @param requestMonitor
	 *            The call-back object to notify when this service's
	 *            initialization is done.
	 */
	private void doInitialize(RequestMonitor requestMonitor) {
		fCommandControl = getServicesTracker().getService(IGDBControl.class);

		// This caches stores the result of a command when received; also, this cache
		// is manipulated when receiving events.  Currently, events are received after
		// three scheduling of the executor, while command results after only one.  This
		// can cause problems because command results might be processed before an event
		// that actually arrived before the command result.
		// To solve this, we use a bufferedCommandControl that will delay the command
		// result by two scheduling of the executor.
		// See bug 280461
        fCommandForCoresCache = new CommandCache(getSession(), 
        		new BufferedCommandControl(fCommandControl, getExecutor(), 2));
        fCommandForCoresCache.setContextAvailable(fCommandControl.getContext(), true);

        fCommandFactory = getServicesTracker().getService(IMICommandControl.class).getCommandFactory();
        getSession().addServiceEventListener(this, null);

        requestMonitor.done();
	}

	@Override
	public void shutdown(RequestMonitor requestMonitor) {
        getSession().removeServiceEventListener(this);

		super.shutdown(requestMonitor);
	}

	@Override
	public void getExecutionData(final IThreadDMContext dmc, final DataRequestMonitor<IThreadDMData> rm) {
		if (dmc instanceof IMIProcessDMContext) {
			// Starting with GDB 7.1, we can obtain the list of cores a process is currently
			// running on (each core that has a thread of that process).
			// We have to use -list-thread-groups to obtain that information
			// Note that -list-thread-groups does not show the 'user' field
			super.getExecutionData(dmc, new ImmediateDataRequestMonitor<IThreadDMData>(rm) {
				@Override
				protected void handleSuccess() {
					final IThreadDMData firstLevelData = getData();
					
					ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
					final String groupId = getGroupFromPid(((IMIProcessDMContext)dmc).getProcId());

					fCommandForCoresCache.execute(
							fCommandFactory.createMIListThreadGroups(controlDmc),
							new ImmediateDataRequestMonitor<MIListThreadGroupsInfo>(rm) {
								@Override
								protected void handleCompleted() {
									String[] cores = null;
									if (isSuccess()) {
										IThreadGroupInfo[] groups = getData().getGroupList();
										if (groups != null) {
											for (IThreadGroupInfo group : groups) {
												if (group.getGroupId().equals(groupId)) {
													cores = group.getCores();
													break;
												}
											}
										}
									}
									rm.setData(new MIThreadDMData_7_1(firstLevelData.getName(),
				                                                      firstLevelData.getId(),
				                                                      cores));
									rm.done();	
								}
							});
				} 
			});
		} else if (dmc instanceof MIThreadDMC) {
			// Starting with GDB 7.1, we can obtain the core on which a thread
			// is currently located.  The info is a new field in -thread-info
			final MIThreadDMC threadDmc = (MIThreadDMC)dmc;

			ICommandControlDMContext controlDmc = DMContexts.getAncestorOfType(dmc, ICommandControlDMContext.class);
			fCommandForCoresCache.execute(fCommandFactory.createMIThreadInfo(controlDmc, threadDmc.getId()),
					new ImmediateDataRequestMonitor<MIThreadInfoInfo>(rm) {
				        @Override
			          	protected void handleSuccess() {
				        	IThreadDMData threadData = null;
				        	if (getData().getThreadList().length != 0) {
				        		MIThread thread = getData().getThreadList()[0];
				        		if (thread.getThreadId().equals(threadDmc.getId())) {
        	        				String id = thread.getOsId();
        	        				// append thread details (if any) to the thread ID
        	        				// as for GDB 6.x with CLIInfoThreadsInfo#getOsId()
        	        				final String details = thread.getDetails();
        	        				if (details != null && details.length() > 0) {
        	        					id += " (" + details + ")"; //$NON-NLS-1$ //$NON-NLS-2$
        	        				}
				        			
				        			String core = thread.getCore();
				        			threadData = new MIThreadDMData_7_1("", id, //$NON-NLS-1$
				        					                            core == null ? null : new String[] { core });
				        		}
				        	}

				        	if (threadData != null) {
				        		rm.setData(threadData);        	        			
				        	} else {
				        		rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Could not get thread info", null)); //$NON-NLS-1$        	        			
				        	}
				        	rm.done();
				        }
			});
		} else {
			rm.setStatus(new Status(IStatus.ERROR, GdbPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid DMC type", null)); //$NON-NLS-1$
			rm.done();
		}
	}
	
	@DsfServiceEventHandler
	public void eventDispatched_7_1(IResumedDMEvent e) {
		if (e instanceof IContainerResumedDMEvent) {
			// This will happen in all-stop mode
			fCommandForCoresCache.setContextAvailable(e.getDMContext(), false);
		} else {
			// This will happen in non-stop mode
			// Keep target available for Container commands
		}
	}

	// Something has suspended, core allocation could have changed
	// during the time it was running.
    @DsfServiceEventHandler
    public void eventDispatched_7_1(ISuspendedDMEvent e) {
       	if (e instanceof IContainerSuspendedDMEvent) {
    		// This will happen in all-stop mode
       		fCommandForCoresCache.setContextAvailable(fCommandControl.getContext(), true);
       	} else {
       		// This will happen in non-stop mode
       	}
       	
       	fCommandForCoresCache.reset();
    }
    
    // Event handler when a thread or threadGroup starts, core allocation 
    // could have changed
    @DsfServiceEventHandler
    public void eventDispatched_7_1(IStartedDMEvent e) {
       	fCommandForCoresCache.reset();
	}
    
    // Event handler when a thread or a threadGroup exits, core allocation
    // could have changed
    @DsfServiceEventHandler
    public void eventDispatched_7_1(IExitedDMEvent e) {
       	fCommandForCoresCache.reset();
    }
    
	@Override
	public void flushCache(IDMContext context) {
		fCommandForCoresCache.reset(context);
		super.flushCache(context);
	}
}

Back to the top