1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  *
23  */
24 
25 #ifndef SHARE_UTILITIES_FILTERQUEUE_INLINE_HPP
26 #define SHARE_UTILITIES_FILTERQUEUE_INLINE_HPP
27 
28 #include "utilities/filterQueue.hpp"
29 #include "utilities/spinYield.hpp"
30 
31 template <class E>
push(E data)32 void FilterQueue<E>::push(E data) {
33   Node* head;
34   Node* insnode = new Node(data);
35   SpinYield yield(SpinYield::default_spin_limit * 10); // Very unlikely with multiple failed CAS.
36   while (true){
37     head = load_first();
38     insnode->_next = head;
39     if (Atomic::cmpxchg(&_first, head, insnode) == head) {
40       break;
41     }
42     yield.wait();
43   }
44 }
45 
46 // MT-Unsafe, external serialization needed.
47 template <class E>
48 template <typename MATCH_FUNC>
contains(MATCH_FUNC & match_func)49 bool FilterQueue<E>::contains(MATCH_FUNC& match_func) {
50   Node* cur = load_first();
51   if (cur == NULL) {
52     return false;
53   }
54   do {
55     if (match_func(cur->_data)) {
56       return true;
57     }
58     cur = cur->_next;
59   } while (cur != NULL);
60   return false;
61 }
62 
63 // MT-Unsafe, external serialization needed.
64 template <class E>
65 template <typename MATCH_FUNC>
pop(MATCH_FUNC & match_func)66 E FilterQueue<E>::pop(MATCH_FUNC& match_func) {
67   Node*  first       = load_first();
68   Node*  cur         = first;
69   Node*  prev        = NULL;
70   Node*  match       = NULL;
71   Node*  match_prev  = NULL;
72 
73   if (cur == NULL) {
74     return (E)NULL;
75   }
76   SpinYield yield(SpinYield::default_spin_limit * 10); // Very unlikely with multiple failed CAS.
77   do {
78     do {
79       if (match_func(cur->_data)) {
80         match = cur;
81         match_prev = prev;
82       }
83       prev = cur;
84       cur = cur->_next;
85     } while (cur != NULL);
86 
87     if (match == NULL) {
88       return (E)NULL;
89     }
90 
91     if (match_prev == NULL) {
92       // Working on first
93       if (Atomic::cmpxchg(&_first, match, match->_next) == match) {
94         E ret = match->_data;
95         delete match;
96         return ret;
97       }
98       yield.wait();
99       // Failed, we need to restart to know the Node prior to the match.
100       first       = load_first();
101       cur         = first;
102       prev        = NULL;
103       match       = NULL;
104       match_prev  = NULL;
105     } else {
106       match_prev->_next = match->_next;
107       E ret = match->_data;
108       delete match;
109       return ret;
110     }
111   } while (true);
112 }
113 
114 #endif // SHARE_UTILITIES_FILTERQUEUE_INLINE_HPP
115