1 /** 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 #ifndef PANDA_RUNTIME_RUNTIME_NOTIFICATION_H_ 16 #define PANDA_RUNTIME_RUNTIME_NOTIFICATION_H_ 17 18 #include <cstdint> 19 #include <optional> 20 #include <string_view> 21 22 #include "libpandabase/os/mutex.h" 23 #include "runtime/include/console_call_type.h" 24 #include "runtime/include/coretypes/tagged_value.h" 25 #include "runtime/include/locks.h" 26 #include "runtime/include/mem/panda_containers.h" 27 #include "runtime/include/mem/panda_string.h" 28 #include "runtime/include/runtime.h" 29 #include "runtime/handle_scope-inl.h" 30 31 namespace ark { 32 33 class Method; 34 class Class; 35 class Rendezvous; 36 37 class RuntimeListener { 38 public: 39 RuntimeListener() = default; 40 virtual ~RuntimeListener() = default; 41 DEFAULT_COPY_SEMANTIC(RuntimeListener); 42 DEFAULT_MOVE_SEMANTIC(RuntimeListener); 43 LoadModule(std::string_view name)44 virtual void LoadModule([[maybe_unused]] std::string_view name) {} 45 ThreadStart(ManagedThread * managedThread)46 virtual void ThreadStart([[maybe_unused]] ManagedThread *managedThread) {} ThreadEnd(ManagedThread * managedThread)47 virtual void ThreadEnd([[maybe_unused]] ManagedThread *managedThread) {} 48 BytecodePcChanged(ManagedThread * thread,Method * method,uint32_t bcOffset)49 virtual void BytecodePcChanged([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method, 50 [[maybe_unused]] uint32_t bcOffset) 51 { 52 } 53 GarbageCollectorStart()54 virtual void GarbageCollectorStart() {} GarbageCollectorFinish()55 virtual void GarbageCollectorFinish() {} 56 ExceptionThrow(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)57 virtual void ExceptionThrow([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method, 58 [[maybe_unused]] ObjectHeader *exceptionObject, [[maybe_unused]] uint32_t bcOffset) 59 { 60 } 61 ExceptionCatch(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)62 virtual void ExceptionCatch([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method, 63 [[maybe_unused]] ObjectHeader *exceptionObject, [[maybe_unused]] uint32_t bcOffset) 64 { 65 } 66 ConsoleCall(ManagedThread * thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)67 virtual void ConsoleCall([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] ConsoleCallType type, 68 [[maybe_unused]] uint64_t timestamp, 69 [[maybe_unused]] const PandaVector<TypedValue> &arguments) 70 { 71 } 72 VmStart()73 virtual void VmStart() {} VmInitialization(ManagedThread * managedThread)74 virtual void VmInitialization([[maybe_unused]] ManagedThread *managedThread) {} VmDeath()75 virtual void VmDeath() {} 76 MethodEntry(ManagedThread * thread,Method * method)77 virtual void MethodEntry([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method) {} MethodExit(ManagedThread * thread,Method * method)78 virtual void MethodExit([[maybe_unused]] ManagedThread *thread, [[maybe_unused]] Method *method) {} 79 ClassLoad(Class * klass)80 virtual void ClassLoad([[maybe_unused]] Class *klass) {} ClassPrepare(Class * klass)81 virtual void ClassPrepare([[maybe_unused]] Class *klass) {} 82 MonitorWait(ObjectHeader * object,int64_t timeout)83 virtual void MonitorWait([[maybe_unused]] ObjectHeader *object, [[maybe_unused]] int64_t timeout) {} MonitorWaited(ObjectHeader * object,bool timedOut)84 virtual void MonitorWaited([[maybe_unused]] ObjectHeader *object, [[maybe_unused]] bool timedOut) {} MonitorContendedEnter(ObjectHeader * object)85 virtual void MonitorContendedEnter([[maybe_unused]] ObjectHeader *object) {} MonitorContendedEntered(ObjectHeader * object)86 virtual void MonitorContendedEntered([[maybe_unused]] ObjectHeader *object) {} 87 ObjectAlloc(BaseClass * klass,ObjectHeader * object,ManagedThread * thread,size_t size)88 virtual void ObjectAlloc([[maybe_unused]] BaseClass *klass, [[maybe_unused]] ObjectHeader *object, 89 [[maybe_unused]] ManagedThread *thread, [[maybe_unused]] size_t size) 90 { 91 } 92 93 // Deprecated events ThreadStart(ManagedThread::ThreadId threadId)94 virtual void ThreadStart([[maybe_unused]] ManagedThread::ThreadId threadId) {} ThreadEnd(ManagedThread::ThreadId threadId)95 virtual void ThreadEnd([[maybe_unused]] ManagedThread::ThreadId threadId) {} VmInitialization(ManagedThread::ThreadId threadId)96 virtual void VmInitialization([[maybe_unused]] ManagedThread::ThreadId threadId) {} ExceptionCatch(const ManagedThread * thread,const Method * method,uint32_t bcOffset)97 virtual void ExceptionCatch([[maybe_unused]] const ManagedThread *thread, [[maybe_unused]] const Method *method, 98 [[maybe_unused]] uint32_t bcOffset) 99 { 100 } 101 }; 102 103 class DebuggerListener { 104 public: 105 DebuggerListener() = default; 106 virtual ~DebuggerListener() = default; 107 DEFAULT_COPY_SEMANTIC(DebuggerListener); 108 DEFAULT_MOVE_SEMANTIC(DebuggerListener); 109 110 virtual void StartDebugger() = 0; 111 virtual void StopDebugger() = 0; 112 virtual bool IsDebuggerConfigured() = 0; 113 }; 114 115 class RuntimeNotificationManager { 116 public: 117 enum Event : uint32_t { 118 BYTECODE_PC_CHANGED = 0x01, 119 LOAD_MODULE = 0x02, 120 THREAD_EVENTS = 0x04, 121 GARBAGE_COLLECTOR_EVENTS = 0x08, 122 EXCEPTION_EVENTS = 0x10, 123 VM_EVENTS = 0x20, 124 METHOD_EVENTS = 0x40, 125 CLASS_EVENTS = 0x80, 126 MONITOR_EVENTS = 0x100, 127 ALLOCATION_EVENTS = 0x200, 128 CONSOLE_EVENTS = 0x400, 129 ALL = 0xFFFFFFFF 130 }; 131 RuntimeNotificationManager(mem::AllocatorPtr<mem::AllocatorPurpose::ALLOCATOR_PURPOSE_INTERNAL> allocator)132 explicit RuntimeNotificationManager(mem::AllocatorPtr<mem::AllocatorPurpose::ALLOCATOR_PURPOSE_INTERNAL> allocator) 133 : bytecodePcListeners_(allocator->Adapter()), 134 loadModuleListeners_(allocator->Adapter()), 135 threadEventsListeners_(allocator->Adapter()), 136 garbageCollectorListeners_(allocator->Adapter()), 137 exceptionListeners_(allocator->Adapter()), 138 vmEventsListeners_(allocator->Adapter()), 139 methodListeners_(allocator->Adapter()), 140 classListeners_(allocator->Adapter()), 141 monitorListeners_(allocator->Adapter()) 142 { 143 } 144 AddListener(RuntimeListener * listener,uint32_t eventMask)145 void AddListener(RuntimeListener *listener, uint32_t eventMask) 146 { 147 ScopedSuspendAllThreads ssat(rendezvous_); 148 AddListenerIfMatches(listener, eventMask, &bytecodePcListeners_, Event::BYTECODE_PC_CHANGED, 149 &hasBytecodePcListeners_); 150 151 AddListenerIfMatches(listener, eventMask, &loadModuleListeners_, Event::LOAD_MODULE, &hasLoadModuleListeners_); 152 153 AddListenerIfMatches(listener, eventMask, &threadEventsListeners_, Event::THREAD_EVENTS, 154 &hasThreadEventsListeners_); 155 156 AddListenerIfMatches(listener, eventMask, &exceptionListeners_, Event::EXCEPTION_EVENTS, 157 &hasExceptionListeners_); 158 159 AddListenerIfMatches(listener, eventMask, &vmEventsListeners_, Event::VM_EVENTS, &hasVmEventsListeners_); 160 161 AddListenerIfMatches(listener, eventMask, &methodListeners_, Event::METHOD_EVENTS, &hasMethodListeners_); 162 163 AddListenerIfMatches(listener, eventMask, &classListeners_, Event::CLASS_EVENTS, &hasClassListeners_); 164 165 AddListenerIfMatches(listener, eventMask, &monitorListeners_, Event::MONITOR_EVENTS, &hasMonitorListeners_); 166 167 AddListenerIfMatches(listener, eventMask, &allocationListeners_, Event::ALLOCATION_EVENTS, 168 &hasAllocationListeners_); 169 170 AddListenerIfMatches(listener, eventMask, &consoleListeners_, Event::CONSOLE_EVENTS, &hasConsoleListeners_); 171 172 { 173 // We cannot stop GC thread, so holding lock to avoid data race 174 os::memory::WriteLockHolder rwlock(gcEventLock_); 175 AddListenerIfMatches(listener, eventMask, &garbageCollectorListeners_, Event::GARBAGE_COLLECTOR_EVENTS, 176 &hasGarbageCollectorListeners_); 177 } 178 } 179 RemoveListener(RuntimeListener * listener,uint32_t eventMask)180 void RemoveListener(RuntimeListener *listener, uint32_t eventMask) 181 { 182 ScopedSuspendAllThreads ssat(rendezvous_); 183 RemoveListenerIfMatches(listener, eventMask, &bytecodePcListeners_, Event::BYTECODE_PC_CHANGED, 184 &hasBytecodePcListeners_); 185 186 RemoveListenerIfMatches(listener, eventMask, &loadModuleListeners_, Event::LOAD_MODULE, 187 &hasLoadModuleListeners_); 188 189 RemoveListenerIfMatches(listener, eventMask, &threadEventsListeners_, Event::THREAD_EVENTS, 190 &hasThreadEventsListeners_); 191 192 RemoveListenerIfMatches(listener, eventMask, &exceptionListeners_, Event::EXCEPTION_EVENTS, 193 &hasExceptionListeners_); 194 195 RemoveListenerIfMatches(listener, eventMask, &vmEventsListeners_, Event::VM_EVENTS, &hasVmEventsListeners_); 196 197 RemoveListenerIfMatches(listener, eventMask, &methodListeners_, Event::METHOD_EVENTS, &hasMethodListeners_); 198 199 RemoveListenerIfMatches(listener, eventMask, &classListeners_, Event::CLASS_EVENTS, &hasClassListeners_); 200 201 RemoveListenerIfMatches(listener, eventMask, &monitorListeners_, Event::MONITOR_EVENTS, &hasMonitorListeners_); 202 203 RemoveListenerIfMatches(listener, eventMask, &allocationListeners_, Event::ALLOCATION_EVENTS, 204 &hasAllocationListeners_); 205 206 RemoveListenerIfMatches(listener, eventMask, &consoleListeners_, Event::CONSOLE_EVENTS, &hasConsoleListeners_); 207 208 { 209 // We cannot stop GC thread, so holding lock to avoid data race 210 os::memory::WriteLockHolder rwlock(gcEventLock_); 211 RemoveListenerIfMatches(listener, eventMask, &garbageCollectorListeners_, Event::GARBAGE_COLLECTOR_EVENTS, 212 &hasGarbageCollectorListeners_); 213 } 214 } 215 LoadModuleEvent(std::string_view name)216 void LoadModuleEvent(std::string_view name) 217 { 218 if (UNLIKELY(hasLoadModuleListeners_)) { 219 for (auto *listener : loadModuleListeners_) { 220 if (listener != nullptr) { 221 listener->LoadModule(name); 222 } 223 } 224 } 225 } 226 ThreadStartEvent(ManagedThread * managedThread)227 void ThreadStartEvent(ManagedThread *managedThread) 228 { 229 if (UNLIKELY(hasThreadEventsListeners_)) { 230 for (auto *listener : threadEventsListeners_) { 231 if (listener != nullptr) { 232 listener->ThreadStart(managedThread); 233 } 234 } 235 } 236 } 237 ThreadEndEvent(ManagedThread * managedThread)238 void ThreadEndEvent(ManagedThread *managedThread) 239 { 240 if (UNLIKELY(hasThreadEventsListeners_)) { 241 for (auto *listener : threadEventsListeners_) { 242 if (listener != nullptr) { 243 listener->ThreadEnd(managedThread); 244 } 245 } 246 } 247 } 248 BytecodePcChangedEvent(ManagedThread * thread,Method * method,uint32_t bcOffset)249 void BytecodePcChangedEvent(ManagedThread *thread, Method *method, uint32_t bcOffset) 250 { 251 if (UNLIKELY(hasBytecodePcListeners_)) { 252 for (auto *listener : bytecodePcListeners_) { 253 if (listener != nullptr) { 254 listener->BytecodePcChanged(thread, method, bcOffset); 255 } 256 } 257 } 258 } 259 GarbageCollectorStartEvent()260 void GarbageCollectorStartEvent() 261 { 262 if (UNLIKELY(hasGarbageCollectorListeners_)) { 263 os::memory::ReadLockHolder rwlock(gcEventLock_); 264 for (auto *listener : garbageCollectorListeners_) { 265 if (listener != nullptr) { 266 listener->GarbageCollectorStart(); 267 } 268 } 269 } 270 } 271 GarbageCollectorFinishEvent()272 void GarbageCollectorFinishEvent() 273 { 274 if (UNLIKELY(hasGarbageCollectorListeners_)) { 275 os::memory::ReadLockHolder rwlock(gcEventLock_); 276 for (auto *listener : garbageCollectorListeners_) { 277 if (listener != nullptr) { 278 listener->GarbageCollectorFinish(); 279 } 280 } 281 } 282 } 283 ExceptionThrowEvent(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)284 void ExceptionThrowEvent(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject, uint32_t bcOffset) 285 { 286 if (UNLIKELY(hasExceptionListeners_)) { 287 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread); 288 VMHandle<ObjectHeader> objHandle(thread, exceptionObject); 289 for (auto *listener : exceptionListeners_) { 290 if (listener != nullptr) { 291 listener->ExceptionThrow(thread, method, objHandle.GetPtr(), bcOffset); 292 } 293 } 294 } 295 } 296 ExceptionCatchEvent(ManagedThread * thread,Method * method,ObjectHeader * exceptionObject,uint32_t bcOffset)297 void ExceptionCatchEvent(ManagedThread *thread, Method *method, ObjectHeader *exceptionObject, uint32_t bcOffset) 298 { 299 if (UNLIKELY(hasExceptionListeners_)) { 300 [[maybe_unused]] HandleScope<ObjectHeader *> scope(thread); 301 VMHandle<ObjectHeader> objHandle(thread, exceptionObject); 302 for (auto *listener : exceptionListeners_) { 303 if (listener != nullptr) { 304 listener->ExceptionCatch(thread, method, objHandle.GetPtr(), bcOffset); 305 } 306 } 307 } 308 } 309 VmStartEvent()310 void VmStartEvent() 311 { 312 if (UNLIKELY(hasVmEventsListeners_)) { 313 for (auto *listener : vmEventsListeners_) { 314 if (listener != nullptr) { 315 listener->VmStart(); 316 } 317 } 318 } 319 } 320 VmInitializationEvent(ManagedThread * managedThread)321 void VmInitializationEvent(ManagedThread *managedThread) 322 { 323 if (UNLIKELY(hasVmEventsListeners_)) { 324 for (auto *listener : vmEventsListeners_) { 325 if (listener != nullptr) { 326 listener->VmInitialization(managedThread); 327 } 328 } 329 } 330 } 331 332 // Deprecated API VmInitializationEvent(ManagedThread::ThreadId threadId)333 void VmInitializationEvent(ManagedThread::ThreadId threadId) 334 { 335 if (UNLIKELY(hasVmEventsListeners_)) { 336 for (auto *listener : vmEventsListeners_) { 337 if (listener != nullptr) { 338 listener->VmInitialization(threadId); 339 } 340 } 341 } 342 } 343 VmDeathEvent()344 void VmDeathEvent() 345 { 346 if (UNLIKELY(hasVmEventsListeners_)) { 347 for (auto *listener : vmEventsListeners_) { 348 if (listener != nullptr) { 349 listener->VmDeath(); 350 } 351 } 352 } 353 } 354 MethodEntryEvent(ManagedThread * thread,Method * method)355 void MethodEntryEvent(ManagedThread *thread, Method *method) 356 { 357 if (UNLIKELY(hasMethodListeners_)) { 358 for (auto *listener : methodListeners_) { 359 if (listener != nullptr) { 360 listener->MethodEntry(thread, method); 361 } 362 } 363 } 364 } 365 MethodExitEvent(ManagedThread * thread,Method * method)366 void MethodExitEvent(ManagedThread *thread, Method *method) 367 { 368 if (UNLIKELY(hasMethodListeners_)) { 369 for (auto *listener : methodListeners_) { 370 if (listener != nullptr) { 371 listener->MethodExit(thread, method); 372 } 373 } 374 } 375 } 376 ClassLoadEvent(Class * klass)377 void ClassLoadEvent(Class *klass) 378 { 379 if (UNLIKELY(hasClassListeners_)) { 380 for (auto *listener : classListeners_) { 381 if (listener != nullptr) { 382 listener->ClassLoad(klass); 383 } 384 } 385 } 386 } 387 ClassPrepareEvent(Class * klass)388 void ClassPrepareEvent(Class *klass) 389 { 390 if (UNLIKELY(hasClassListeners_)) { 391 for (auto *listener : classListeners_) { 392 if (listener != nullptr) { 393 listener->ClassPrepare(klass); 394 } 395 } 396 } 397 } 398 MonitorWaitEvent(ObjectHeader * object,int64_t timeout)399 void MonitorWaitEvent(ObjectHeader *object, int64_t timeout) 400 { 401 if (UNLIKELY(hasMonitorListeners_)) { 402 // If we need to support multiple monitor listeners, 403 // the object must be wrapped to ObjectHandle to protect from GC move 404 ASSERT(monitorListeners_.size() == 1); 405 auto *listener = monitorListeners_.front(); 406 if (listener != nullptr) { 407 listener->MonitorWait(object, timeout); 408 } 409 } 410 } 411 MonitorWaitedEvent(ObjectHeader * object,bool timedOut)412 void MonitorWaitedEvent(ObjectHeader *object, bool timedOut) 413 { 414 if (UNLIKELY(hasMonitorListeners_)) { 415 // If we need to support multiple monitor listeners, 416 // the object must be wrapped to ObjectHandle to protect from GC move 417 ASSERT(monitorListeners_.size() == 1); 418 auto *listener = monitorListeners_.front(); 419 if (listener != nullptr) { 420 monitorListeners_.front()->MonitorWaited(object, timedOut); 421 } 422 } 423 } 424 MonitorContendedEnterEvent(ObjectHeader * object)425 void MonitorContendedEnterEvent(ObjectHeader *object) 426 { 427 if (UNLIKELY(hasMonitorListeners_)) { 428 // If we need to support multiple monitor listeners, 429 // the object must be wrapped to ObjectHandle to protect from GC move 430 ASSERT(monitorListeners_.size() == 1); 431 auto *listener = monitorListeners_.front(); 432 if (listener != nullptr) { 433 monitorListeners_.front()->MonitorContendedEnter(object); 434 } 435 } 436 } 437 MonitorContendedEnteredEvent(ObjectHeader * object)438 void MonitorContendedEnteredEvent(ObjectHeader *object) 439 { 440 if (UNLIKELY(hasMonitorListeners_)) { 441 // If we need to support multiple monitor listeners, 442 // the object must be wrapped to ObjectHandle to protect from GC move 443 ASSERT(monitorListeners_.size() == 1); 444 auto *listener = monitorListeners_.front(); 445 if (listener != nullptr) { 446 monitorListeners_.front()->MonitorContendedEntered(object); 447 } 448 } 449 } 450 HasAllocationListeners()451 bool HasAllocationListeners() const 452 { 453 return hasAllocationListeners_; 454 } 455 ObjectAllocEvent(BaseClass * klass,ObjectHeader * object,ManagedThread * thread,size_t size)456 void ObjectAllocEvent(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) const 457 { 458 if (UNLIKELY(hasAllocationListeners_)) { 459 // If we need to support multiple allocation listeners, 460 // the object must be wrapped to ObjectHandle to protect from GC move 461 ASSERT(allocationListeners_.size() == 1); 462 auto *listener = allocationListeners_.front(); 463 if (listener != nullptr) { 464 allocationListeners_.front()->ObjectAlloc(klass, object, thread, size); 465 } 466 } 467 } 468 ConsoleCallEvent(ManagedThread * thread,ConsoleCallType type,uint64_t timestamp,const PandaVector<TypedValue> & arguments)469 void ConsoleCallEvent(ManagedThread *thread, ConsoleCallType type, uint64_t timestamp, 470 const PandaVector<TypedValue> &arguments) const 471 { 472 if (UNLIKELY(hasConsoleListeners_)) { 473 for (auto listener : consoleListeners_) { 474 if (listener != nullptr) { 475 listener->ConsoleCall(thread, type, timestamp, arguments); 476 } 477 } 478 } 479 } 480 StartDebugger()481 void StartDebugger() 482 { 483 os::memory::ReadLockHolder holder(debuggerLock_); 484 for (auto *listener : debuggerListeners_) { 485 listener->StartDebugger(); 486 } 487 } 488 StopDebugger()489 void StopDebugger() 490 { 491 os::memory::ReadLockHolder holder(debuggerLock_); 492 for (auto *listener : debuggerListeners_) { 493 listener->StopDebugger(); 494 } 495 } 496 IsDebuggerConfigured()497 bool IsDebuggerConfigured() 498 { 499 os::memory::ReadLockHolder holder(debuggerLock_); 500 for (auto *listener : debuggerListeners_) { 501 if (!listener->IsDebuggerConfigured()) { 502 return false; 503 } 504 } 505 return true; 506 } 507 SetRendezvous(Rendezvous * rendezvous)508 void SetRendezvous(Rendezvous *rendezvous) 509 { 510 rendezvous_ = rendezvous; 511 } 512 AddDebuggerListener(DebuggerListener * listener)513 void AddDebuggerListener(DebuggerListener *listener) 514 { 515 os::memory::WriteLockHolder holder(debuggerLock_); 516 debuggerListeners_.push_back(listener); 517 } 518 RemoveDebuggerListener(DebuggerListener * listener)519 void RemoveDebuggerListener(DebuggerListener *listener) 520 { 521 os::memory::WriteLockHolder holder(debuggerLock_); 522 RemoveListener(debuggerListeners_, listener); 523 } 524 525 private: 526 template <typename FlagType> AddListenerIfMatches(RuntimeListener * listener,uint32_t eventMask,PandaList<RuntimeListener * > * listenerGroup,Event eventModifier,FlagType * eventFlag)527 static void AddListenerIfMatches(RuntimeListener *listener, uint32_t eventMask, 528 PandaList<RuntimeListener *> *listenerGroup, Event eventModifier, 529 FlagType *eventFlag) 530 { 531 if ((eventMask & eventModifier) != 0) { 532 // If a free group item presents, use it, otherwise push back a new item 533 auto it = std::find(listenerGroup->begin(), listenerGroup->end(), nullptr); 534 if (it != listenerGroup->end()) { 535 *it = listener; 536 } else { 537 listenerGroup->push_back(listener); 538 } 539 *eventFlag = true; 540 } 541 } 542 543 template <typename Container, typename T> RemoveListener(Container & c,T & listener)544 ALWAYS_INLINE void RemoveListener(Container &c, T &listener) 545 { 546 c.erase(std::remove_if(c.begin(), c.end(), [&listener](const T &elem) { return listener == elem; })); 547 } 548 549 template <typename FlagType> RemoveListenerIfMatches(RuntimeListener * listener,uint32_t eventMask,PandaList<RuntimeListener * > * listenerGroup,Event eventModifier,FlagType * eventFlag)550 static void RemoveListenerIfMatches(RuntimeListener *listener, uint32_t eventMask, 551 PandaList<RuntimeListener *> *listenerGroup, Event eventModifier, 552 FlagType *eventFlag) 553 { 554 if ((eventMask & eventModifier) != 0) { 555 auto it = std::find(listenerGroup->begin(), listenerGroup->end(), listener); 556 if (it == listenerGroup->end()) { 557 return; 558 } 559 // Removing a listener is not safe, because the iteration can not be completed in another thread. 560 // We just null the item in the group 561 *it = nullptr; 562 563 // Check if any listener presents and update the flag if not 564 if (std::find_if(listenerGroup->begin(), listenerGroup->end(), 565 [](RuntimeListener *item) { return item != nullptr; }) == listenerGroup->end()) { 566 *eventFlag = false; 567 } 568 } 569 } 570 571 PandaList<RuntimeListener *> bytecodePcListeners_; 572 PandaList<RuntimeListener *> loadModuleListeners_; 573 PandaList<RuntimeListener *> threadEventsListeners_; 574 PandaList<RuntimeListener *> garbageCollectorListeners_; 575 PandaList<RuntimeListener *> exceptionListeners_; 576 PandaList<RuntimeListener *> vmEventsListeners_; 577 PandaList<RuntimeListener *> methodListeners_; 578 PandaList<RuntimeListener *> classListeners_; 579 PandaList<RuntimeListener *> monitorListeners_; 580 PandaList<RuntimeListener *> allocationListeners_; 581 PandaList<RuntimeListener *> consoleListeners_; 582 583 bool hasBytecodePcListeners_ = false; 584 bool hasLoadModuleListeners_ = false; 585 bool hasThreadEventsListeners_ = false; 586 std::atomic<bool> hasGarbageCollectorListeners_ = false; 587 bool hasExceptionListeners_ = false; 588 bool hasVmEventsListeners_ = false; 589 bool hasMethodListeners_ = false; 590 bool hasClassListeners_ = false; 591 bool hasMonitorListeners_ = false; 592 bool hasAllocationListeners_ = false; 593 bool hasConsoleListeners_ = false; 594 Rendezvous *rendezvous_ {nullptr}; 595 596 os::memory::RWLock debuggerLock_; 597 os::memory::RWLock gcEventLock_; 598 PandaList<DebuggerListener *> debuggerListeners_; 599 }; 600 601 } // namespace ark 602 603 #endif // PANDA_RUNTIME_RUNTIME_NOTIFICATION_H_ 604