| 395 | } |
| 396 | |
| 397 | Event Connection::WaitForEvent(EventKind kind, const rdcarray<EventFilter> &eventFilters, |
| 398 | EventFilterFunction filterCallback) |
| 399 | { |
| 400 | int32_t eventRequestID = 0; |
| 401 | |
| 402 | { |
| 403 | Command cmd(CommandSet::EventRequest, 1); |
| 404 | CommandData data = cmd.GetData(); |
| 405 | |
| 406 | // always suspend all threads |
| 407 | data.Write((byte)kind).Write((byte)SuspendPolicy::All); |
| 408 | |
| 409 | WriteVector<EventFilter>(data, eventFilters, [](CommandData &d, const EventFilter &f) { |
| 410 | d.Write((byte)f.modKind); |
| 411 | if(f.modKind == ModifierKind::ClassOnly) |
| 412 | d.Write(f.ClassOnly); |
| 413 | else |
| 414 | RDCERR("Unsupported event filter %d", f.modKind); |
| 415 | }); |
| 416 | |
| 417 | if(!SendReceive(cmd)) |
| 418 | return {}; |
| 419 | |
| 420 | cmd.GetData().Read(eventRequestID).Done(); |
| 421 | } |
| 422 | |
| 423 | if(eventRequestID == 0) |
| 424 | { |
| 425 | RDCERR("Failed to set event"); |
| 426 | error = true; |
| 427 | return {}; |
| 428 | } |
| 429 | |
| 430 | // unfortunately because JDWP is shit, from the point the event request is sent we might get |
| 431 | // events at any time. This means we could get event replies before we even get confirmation of |
| 432 | // the resume. That means we have to resume manually without calling Resume() which expects a |
| 433 | // synchronous reply. |
| 434 | |
| 435 | RDCASSERTEQUAL(suspendRefCount, 1); |
| 436 | |
| 437 | uint32_t resumeID = ~0U; |
| 438 | { |
| 439 | Command cmd(CommandSet::VirtualMachine, 9); |
| 440 | resumeID = cmd.Send(writer); |
| 441 | suspendRefCount = 0; |
| 442 | } |
| 443 | |
| 444 | // wait for method entry on the method we care about |
| 445 | while(!reader.IsErrored()) |
| 446 | { |
| 447 | SuspendPolicy suspendPolicy; |
| 448 | rdcarray<Event> events; |
| 449 | |
| 450 | Command msg; |
| 451 | msg.Recv(reader); |
| 452 | |
| 453 | if(resumeID == msg.GetID()) |
| 454 | { |