source: trunk/openjdk/jdk/src/share/back/debugLoop.c

Last change on this file was 278, checked in by dmik, 14 years ago

trunk: Merged in openjdk6 b22 from branches/vendor/oracle.

File size: 8.6 KB
Line 
1/*
2 * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include "util.h"
27#include "transport.h"
28#include "debugLoop.h"
29#include "debugDispatch.h"
30#include "standardHandlers.h"
31#include "inStream.h"
32#include "outStream.h"
33#include "threadControl.h"
34
35
36static void JNICALL reader(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg);
37static void enqueue(jdwpPacket *p);
38static jboolean dequeue(jdwpPacket *p);
39static void notifyTransportError(void);
40
41struct PacketList {
42 jdwpPacket packet;
43 struct PacketList *next;
44};
45
46static volatile struct PacketList *cmdQueue;
47static jrawMonitorID cmdQueueLock;
48static jrawMonitorID resumeLock;
49static jboolean transportError;
50
51static jboolean
52lastCommand(jdwpCmdPacket *cmd)
53{
54 if ((cmd->cmdSet == JDWP_COMMAND_SET(VirtualMachine)) &&
55 ((cmd->cmd == JDWP_COMMAND(VirtualMachine, Dispose)) ||
56 (cmd->cmd == JDWP_COMMAND(VirtualMachine, Exit)))) {
57 return JNI_TRUE;
58 } else {
59 return JNI_FALSE;
60 }
61}
62
63static jboolean
64resumeCommand(jdwpCmdPacket *cmd)
65{
66 if ( (cmd->cmdSet == JDWP_COMMAND_SET(VirtualMachine)) &&
67 (cmd->cmd == JDWP_COMMAND(VirtualMachine, Resume)) ) {
68 return JNI_TRUE;
69 } else {
70 return JNI_FALSE;
71 }
72}
73
74void
75debugLoop_initialize(void)
76{
77 resumeLock = debugMonitorCreate("JDWP Resume Lock");
78}
79
80void
81debugLoop_sync(void)
82{
83 debugMonitorEnter(resumeLock);
84 debugMonitorExit(resumeLock);
85}
86
87/*
88 * This is where all the work gets done.
89 */
90
91void
92debugLoop_run(void)
93{
94 jboolean shouldListen;
95 jdwpPacket p;
96 jvmtiStartFunction func;
97
98 /* Initialize all statics */
99 /* We may be starting a new connection after an error */
100 cmdQueue = NULL;
101 cmdQueueLock = debugMonitorCreate("JDWP Command Queue Lock");
102 transportError = JNI_FALSE;
103
104 shouldListen = JNI_TRUE;
105
106 func = &reader;
107 (void)spawnNewThread(func, NULL, "JDWP Command Reader");
108
109 standardHandlers_onConnect();
110 threadControl_onConnect();
111
112 /* Okay, start reading cmds! */
113 while (shouldListen) {
114 if (!dequeue(&p)) {
115 break;
116 }
117
118 if (p.type.cmd.flags & JDWPTRANSPORT_FLAGS_REPLY) {
119 /*
120 * Its a reply packet.
121 */
122 continue;
123 } else {
124 /*
125 * Its a cmd packet.
126 */
127 jdwpCmdPacket *cmd = &p.type.cmd;
128 PacketInputStream in;
129 PacketOutputStream out;
130 CommandHandler func;
131
132 /* Should reply be sent to sender.
133 * For error handling, assume yes, since
134 * only VM/exit does not reply
135 */
136 jboolean replyToSender = JNI_TRUE;
137
138 /*
139 * For VirtualMachine.Resume commands we hold the resumeLock
140 * while executing and replying to the command. This ensures
141 * that a Resume after VM_DEATH will be allowed to complete
142 * before the thread posting the VM_DEATH continues VM
143 * termination.
144 */
145 if (resumeCommand(cmd)) {
146 debugMonitorEnter(resumeLock);
147 }
148
149 /* Initialize the input and output streams */
150 inStream_init(&in, p);
151 outStream_initReply(&out, inStream_id(&in));
152
153 LOG_MISC(("Command set %d, command %d", cmd->cmdSet, cmd->cmd));
154
155 func = debugDispatch_getHandler(cmd->cmdSet,cmd->cmd);
156 if (func == NULL) {
157 /* we've never heard of this, so I guess we
158 * haven't implemented it.
159 * Handle gracefully for future expansion
160 * and platform / vendor expansion.
161 */
162 outStream_setError(&out, JDWP_ERROR(NOT_IMPLEMENTED));
163 } else if (gdata->vmDead &&
164 ((cmd->cmdSet) != JDWP_COMMAND_SET(VirtualMachine))) {
165 /* Protect the VM from calls while dead.
166 * VirtualMachine cmdSet quietly ignores some cmds
167 * after VM death, so, it sends it's own errors.
168 */
169 outStream_setError(&out, JDWP_ERROR(VM_DEAD));
170 } else {
171 /* Call the command handler */
172 replyToSender = func(&in, &out);
173 }
174
175 /* Reply to the sender */
176 if (replyToSender) {
177 if (inStream_error(&in)) {
178 outStream_setError(&out, inStream_error(&in));
179 }
180 outStream_sendReply(&out);
181 }
182
183 /*
184 * Release the resumeLock as the reply has been posted.
185 */
186 if (resumeCommand(cmd)) {
187 debugMonitorExit(resumeLock);
188 }
189
190 inStream_destroy(&in);
191 outStream_destroy(&out);
192
193 shouldListen = !lastCommand(cmd);
194 }
195 }
196 threadControl_onDisconnect();
197 standardHandlers_onDisconnect();
198
199 /*
200 * Cut off the transport immediately. This has the effect of
201 * cutting off any events that the eventHelper thread might
202 * be trying to send.
203 */
204 transport_close();
205 debugMonitorDestroy(cmdQueueLock);
206
207 /* Reset for a new connection to this VM if it's still alive */
208 if ( ! gdata->vmDead ) {
209 debugInit_reset(getEnv());
210 }
211}
212
213/* Command reader */
214static void JNICALL
215reader(jvmtiEnv* jvmti_env, JNIEnv* jni_env, void* arg)
216{
217 jdwpPacket packet;
218 jdwpCmdPacket *cmd;
219 jboolean shouldListen = JNI_TRUE;
220
221 LOG_MISC(("Begin reader thread"));
222
223 while (shouldListen) {
224 jint rc;
225
226 rc = transport_receivePacket(&packet);
227
228 /* I/O error or EOF */
229 if (rc != 0 || (rc == 0 && packet.type.cmd.len == 0)) {
230 shouldListen = JNI_FALSE;
231 notifyTransportError();
232 } else {
233 cmd = &packet.type.cmd;
234
235 LOG_MISC(("Command set %d, command %d", cmd->cmdSet, cmd->cmd));
236
237 /*
238 * FIXME! We need to deal with high priority
239 * packets and queue flushes!
240 */
241 enqueue(&packet);
242
243 shouldListen = !lastCommand(cmd);
244 }
245 }
246 LOG_MISC(("End reader thread"));
247}
248
249/*
250 * The current system for queueing packets is highly
251 * inefficient, and should be rewritten! It'd be nice
252 * to avoid any additional memory allocations.
253 */
254
255static void
256enqueue(jdwpPacket *packet)
257{
258 struct PacketList *pL;
259 struct PacketList *walker;
260
261 pL = jvmtiAllocate((jint)sizeof(struct PacketList));
262 if (pL == NULL) {
263 EXIT_ERROR(AGENT_ERROR_OUT_OF_MEMORY,"packet list");
264 }
265
266 pL->packet = *packet;
267 pL->next = NULL;
268
269 debugMonitorEnter(cmdQueueLock);
270
271 if (cmdQueue == NULL) {
272 cmdQueue = pL;
273 debugMonitorNotify(cmdQueueLock);
274 } else {
275 walker = (struct PacketList *)cmdQueue;
276 while (walker->next != NULL)
277 walker = walker->next;
278
279 walker->next = pL;
280 }
281
282 debugMonitorExit(cmdQueueLock);
283}
284
285static jboolean
286dequeue(jdwpPacket *packet) {
287 struct PacketList *node = NULL;
288
289 debugMonitorEnter(cmdQueueLock);
290
291 while (!transportError && (cmdQueue == NULL)) {
292 debugMonitorWait(cmdQueueLock);
293 }
294
295 if (cmdQueue != NULL) {
296 node = (struct PacketList *)cmdQueue;
297 cmdQueue = node->next;
298 }
299 debugMonitorExit(cmdQueueLock);
300
301 if (node != NULL) {
302 *packet = node->packet;
303 jvmtiDeallocate(node);
304 }
305 return (node != NULL);
306}
307
308static void
309notifyTransportError(void) {
310 debugMonitorEnter(cmdQueueLock);
311 transportError = JNI_TRUE;
312 debugMonitorNotify(cmdQueueLock);
313 debugMonitorExit(cmdQueueLock);
314}
Note: See TracBrowser for help on using the repository browser.