431 static void print(); |
431 static void print(); |
432 }; |
432 }; |
433 |
433 |
434 #endif // !JVMTI_KERNEL |
434 #endif // !JVMTI_KERNEL |
435 |
435 |
|
436 /** |
|
437 * When a thread (such as the compiler thread or VM thread) cannot post a |
|
438 * JVMTI event itself because the event needs to be posted from a Java |
|
439 * thread, then it can defer the event to the Service thread for posting. |
|
440 * The information needed to post the event is encapsulated into this class |
|
441 * and then enqueued onto the JvmtiDeferredEventQueue, where the Service |
|
442 * thread will pick it up and post it. |
|
443 * |
|
444 * This is currently only used for posting compiled-method-load and unload |
|
445 * events, which we don't want posted from the compiler thread. |
|
446 */ |
|
447 class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC { |
|
448 friend class JvmtiDeferredEventQueue; |
|
449 private: |
|
450 typedef enum { |
|
451 TYPE_NONE, |
|
452 TYPE_COMPILED_METHOD_LOAD, |
|
453 TYPE_COMPILED_METHOD_UNLOAD, |
|
454 TYPE_FLUSH // pseudo-event used to implement flush_queue() |
|
455 } Type; |
|
456 |
|
457 Type _type; |
|
458 union { |
|
459 nmethod* compiled_method_load; |
|
460 struct { |
|
461 jmethodID method_id; |
|
462 const void* code_begin; |
|
463 } compiled_method_unload; |
|
464 int* flush_state_addr; |
|
465 } _event_data; |
|
466 |
|
467 JvmtiDeferredEvent(Type t) : _type(t) {} |
|
468 |
|
469 void set_compiled_method_load(nmethod* nm) { |
|
470 assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be"); |
|
471 _event_data.compiled_method_load = nm; |
|
472 } |
|
473 |
|
474 nmethod* compiled_method_load() const { |
|
475 assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be"); |
|
476 return _event_data.compiled_method_load; |
|
477 } |
|
478 |
|
479 void set_compiled_method_unload(jmethodID id, const void* code) { |
|
480 assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be"); |
|
481 _event_data.compiled_method_unload.method_id = id; |
|
482 _event_data.compiled_method_unload.code_begin = code; |
|
483 } |
|
484 |
|
485 jmethodID compiled_method_unload_method_id() const { |
|
486 assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be"); |
|
487 return _event_data.compiled_method_unload.method_id; |
|
488 } |
|
489 |
|
490 const void* compiled_method_unload_code_begin() const { |
|
491 assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be"); |
|
492 return _event_data.compiled_method_unload.code_begin; |
|
493 } |
|
494 |
|
495 bool is_flush_event() const { return _type == TYPE_FLUSH; } |
|
496 |
|
497 int* flush_state_addr() const { |
|
498 assert(is_flush_event(), "must be"); |
|
499 return _event_data.flush_state_addr; |
|
500 } |
|
501 |
|
502 void set_flush_state_addr(int* flag) { |
|
503 assert(is_flush_event(), "must be"); |
|
504 _event_data.flush_state_addr = flag; |
|
505 } |
|
506 |
|
507 public: |
|
508 |
|
509 JvmtiDeferredEvent() : _type(TYPE_NONE) {} |
|
510 |
|
511 // Factory methods |
|
512 static JvmtiDeferredEvent compiled_method_load_event(nmethod* nm) |
|
513 KERNEL_RETURN_(JvmtiDeferredEvent()); |
|
514 static JvmtiDeferredEvent compiled_method_unload_event( |
|
515 jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent()); |
|
516 |
|
517 // Actually posts the event. |
|
518 void post() KERNEL_RETURN; |
|
519 }; |
|
520 |
|
521 /** |
|
522 * Events enqueued on this queue wake up the Service thread which dequeues |
|
523 * and posts the events. The Service_lock is required to be held |
|
524 * when operating on the queue (except for the "pending" events). |
|
525 */ |
|
526 class JvmtiDeferredEventQueue : AllStatic { |
|
527 friend class JvmtiDeferredEvent; |
|
528 private: |
|
529 class QueueNode : public CHeapObj { |
|
530 private: |
|
531 JvmtiDeferredEvent _event; |
|
532 QueueNode* _next; |
|
533 |
|
534 public: |
|
535 QueueNode(const JvmtiDeferredEvent& event) |
|
536 : _event(event), _next(NULL) {} |
|
537 |
|
538 const JvmtiDeferredEvent& event() const { return _event; } |
|
539 QueueNode* next() const { return _next; } |
|
540 |
|
541 void set_next(QueueNode* next) { _next = next; } |
|
542 }; |
|
543 |
|
544 static QueueNode* _queue_head; // Hold Service_lock to access |
|
545 static QueueNode* _queue_tail; // Hold Service_lock to access |
|
546 static volatile QueueNode* _pending_list; // Uses CAS for read/update |
|
547 |
|
548 // Transfers events from the _pending_list to the _queue. |
|
549 static void process_pending_events() KERNEL_RETURN; |
|
550 |
|
551 static void flush_complete(int* flush_state) KERNEL_RETURN; |
|
552 |
|
553 public: |
|
554 // Must be holding Service_lock when calling these |
|
555 static bool has_events() KERNEL_RETURN_(false); |
|
556 static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN; |
|
557 static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent()); |
|
558 |
|
559 // This call blocks until all events enqueued prior to this call |
|
560 // have been posted. The Service_lock is acquired and waited upon. |
|
561 // |
|
562 // Implemented by creating a "flush" event and placing it in the queue. |
|
563 // When the flush event is "posted" it will call flush_complete(), which |
|
564 // will release the caller. |
|
565 // |
|
566 // Can be called by any thread (maybe even the service thread itself). |
|
567 // Not necessary for the caller to be a JavaThread. |
|
568 static void flush_queue(Thread* current) KERNEL_RETURN; |
|
569 |
|
570 // Used to enqueue events without using a lock, for times (such as during |
|
571 // safepoint) when we can't or don't want to lock the Service_lock. |
|
572 // |
|
573 // Events will be held off to the side until there's a call to |
|
574 // dequeue(), enqueue(), or process_pending_events() (all of which require |
|
575 // the holding of the Service_lock), and will be enqueued at that time. |
|
576 static void add_pending_event(const JvmtiDeferredEvent&) KERNEL_RETURN; |
|
577 }; |
|
578 |
436 // Utility macro that checks for NULL pointers: |
579 // Utility macro that checks for NULL pointers: |
437 #define NULL_CHECK(X, Y) if ((X) == NULL) { return (Y); } |
580 #define NULL_CHECK(X, Y) if ((X) == NULL) { return (Y); } |
438 |
581 |
439 #endif // SHARE_VM_PRIMS_JVMTIIMPL_HPP |
582 #endif // SHARE_VM_PRIMS_JVMTIIMPL_HPP |