annotate src/share/back/debugLoop.c @ 0:37a05a11f281

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