31
31
#include " runtime/atomic.hpp"
32
32
#include " runtime/os.inline.hpp"
33
33
34
- JvmtiAgent* JvmtiAgentList::_list = nullptr ;
34
+ JvmtiAgent* JvmtiAgentList::_head = nullptr ;
35
35
36
36
// Selection as a function of the filter.
37
37
JvmtiAgent* JvmtiAgentList::Iterator::select (JvmtiAgent* agent) const {
@@ -61,68 +61,59 @@ JvmtiAgent* JvmtiAgentList::Iterator::select(JvmtiAgent* agent) const {
61
61
return nullptr ;
62
62
}
63
63
64
- static inline JvmtiAgent* head (JvmtiAgent** list) {
65
- assert (list != nullptr , " invariant" );
66
- return Atomic::load_acquire (list);
67
- }
68
-
69
- // The storage list is a single cas-linked-list, to allow for concurrent iterations.
70
- // Especially during initial loading of agents, there exist an order requirement to iterate oldest -> newest.
71
- // Our concurrent storage linked-list is newest -> oldest.
72
- // The correct order is preserved by the iterator, by storing a filtered set of entries in a stack.
73
- JvmtiAgentList::Iterator::Iterator (JvmtiAgent** list, Filter filter) :
74
- _stack(new GrowableArrayCHeap<JvmtiAgent*, mtServiceability>(16 )), _filter(filter) {
75
- JvmtiAgent* next = head (list);
76
- while (next != nullptr ) {
77
- next = select (next);
78
- if (next != nullptr ) {
79
- _stack->push (next);
80
- next = next->next ();
81
- }
82
- }
64
+ JvmtiAgentList::Iterator::Iterator (JvmtiAgent* head, Filter filter) : _filter(filter), _next(select(head)) {
83
65
}
84
66
85
67
bool JvmtiAgentList::Iterator::has_next () const {
86
- assert (_stack != nullptr , " invariant" );
87
- return _stack->is_nonempty ();
88
- }
89
-
90
- const JvmtiAgent* JvmtiAgentList::Iterator::next () const {
91
- assert (has_next (), " invariant" );
92
- return _stack->pop ();
68
+ return _next != nullptr ;
93
69
}
94
70
95
71
JvmtiAgent* JvmtiAgentList::Iterator::next () {
96
- return const_cast <JvmtiAgent*>(const_cast <const Iterator*>(this )->next ());
72
+ assert (_next != nullptr , " must be" );
73
+ JvmtiAgent* result = _next;
74
+ _next = select (_next->next ());
75
+ return result;
76
+
97
77
}
98
78
99
79
JvmtiAgentList::Iterator JvmtiAgentList::agents () {
100
- return Iterator (&_list , Iterator::NOT_XRUN);
80
+ return Iterator (head () , Iterator::NOT_XRUN);
101
81
}
102
82
103
83
JvmtiAgentList::Iterator JvmtiAgentList::java_agents () {
104
- return Iterator (&_list , Iterator::JAVA);
84
+ return Iterator (head () , Iterator::JAVA);
105
85
}
106
86
107
87
JvmtiAgentList::Iterator JvmtiAgentList::native_agents () {
108
- return Iterator (&_list , Iterator::NATIVE);
88
+ return Iterator (head () , Iterator::NATIVE);
109
89
}
110
90
111
91
JvmtiAgentList::Iterator JvmtiAgentList::xrun_agents () {
112
- return Iterator (&_list , Iterator::XRUN);
92
+ return Iterator (head () , Iterator::XRUN);
113
93
}
114
94
115
95
JvmtiAgentList::Iterator JvmtiAgentList::all () {
116
- return Iterator (&_list , Iterator::ALL);
96
+ return Iterator (head () , Iterator::ALL);
117
97
}
118
98
119
99
void JvmtiAgentList::add (JvmtiAgent* agent) {
120
100
assert (agent != nullptr , " invariant" );
121
- JvmtiAgent* next;
122
- do {
123
- next = head (&_list);
124
- agent->set_next (next);
125
- } while (Atomic::cmpxchg (&_list, next, agent) != next);
101
+
102
+ // address of the pointer to add new agent (&_head when the list is empty or &agent->_next of the last agent in the list)
103
+ JvmtiAgent** tail_ptr = &_head;
104
+ while (true ) {
105
+ JvmtiAgent* next = Atomic::load (tail_ptr);
106
+ if (next == nullptr ) {
107
+ // *tail_ptr == nullptr here
108
+ if (Atomic::cmpxchg (tail_ptr, (JvmtiAgent*)nullptr , agent) != nullptr ) {
109
+ // another thread added an agent, reload next from tail_ptr
110
+ continue ;
111
+ }
112
+ // successfully set, exit
113
+ break ;
114
+ }
115
+ tail_ptr = &next->_next ;
116
+ }
126
117
}
127
118
128
119
void JvmtiAgentList::add (const char * name, const char * options, bool absolute_path) {
@@ -143,6 +134,10 @@ static void assert_initialized(JvmtiAgentList::Iterator& it) {
143
134
}
144
135
#endif
145
136
137
+ JvmtiAgent* JvmtiAgentList::head () {
138
+ return Atomic::load_acquire (&_head);
139
+ }
140
+
146
141
// In case an agent did not enable the VMInit callback, or if it is an -Xrun agent,
147
142
// it gets an initializiation timestamp here.
148
143
void JvmtiAgentList::initialize () {
@@ -283,6 +278,6 @@ void JvmtiAgentList::disable_agent_list() {
283
278
assert (CDSConfig::is_dumping_final_static_archive (), " use this only for -XX:AOTMode=create!" );
284
279
assert (!Universe::is_bootstrapping () && !Universe::is_fully_initialized (), " must do this very early" );
285
280
log_info (aot)(" Disabled all JVMTI agents during -XX:AOTMode=create" );
286
- _list = nullptr ; // Pretend that no agents have been added.
281
+ _head = nullptr ; // Pretend that no agents have been added.
287
282
#endif
288
283
}
0 commit comments