1/*
2 *  Copyright (C) 2011 Apple Inc. All rights reserved.
3 *
4 *  This library is free software; you can redistribute it and/or
5 *  modify it under the terms of the GNU Lesser General Public
6 *  License as published by the Free Software Foundation; either
7 *  version 2 of the License, or (at your option) any later version.
8 *
9 *  This library is distributed in the hope that it will be useful,
10 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 *  Lesser General Public License for more details.
13 *
14 *  You should have received a copy of the GNU Lesser General Public
15 *  License along with this library; if not, write to the Free Software
16 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 *
18 */
19
20#ifndef ListableHandler_h
21#define ListableHandler_h
22
23#include <stdint.h>
24#include <wtf/Locker.h>
25#include <wtf/Noncopyable.h>
26#include <wtf/ThreadingPrimitives.h>
27#include <wtf/TCSpinLock.h>
28
29namespace JSC {
30
31class MarkStack;
32class MarkStackThreadSharedData;
33class SlotVisitor;
34
35template<typename T>
36class ListableHandler {
37    WTF_MAKE_NONCOPYABLE(ListableHandler);
38
39protected:
40    ListableHandler()
41        : m_nextAndFlag(0)
42    {
43    }
44
45    virtual ~ListableHandler() { }
46
47    T* next() const
48    {
49        return reinterpret_cast<T*>(m_nextAndFlag & ~1);
50    }
51
52private:
53    // Allow these classes to use ListableHandler::List.
54    friend class MarkStack;
55    friend class GCThreadSharedData;
56    friend class SlotVisitor;
57
58    class List {
59        WTF_MAKE_NONCOPYABLE(List);
60    public:
61        List()
62            : m_first(0)
63        {
64            m_lock.Init();
65        }
66
67        void addThreadSafe(T* handler)
68        {
69            SpinLockHolder locker(&m_lock);
70            addNotThreadSafe(handler);
71        }
72
73        bool hasNext()
74        {
75            return !!m_first;
76        }
77
78        T* head()
79        {
80            return m_first;
81        }
82
83        T* removeNext()
84        {
85            T* current = m_first;
86            T* next = current->next();
87            current->m_nextAndFlag = 0;
88            m_first = next;
89            return current;
90        }
91
92        void removeAll()
93        {
94            while (hasNext())
95                removeNext();
96        }
97
98    private:
99        void addNotThreadSafe(T* handler)
100        {
101            if (handler->m_nextAndFlag & 1)
102                return;
103            handler->m_nextAndFlag = reinterpret_cast<uintptr_t>(m_first) | 1;
104            m_first = handler;
105        }
106
107        SpinLock m_lock;
108        T* m_first;
109    };
110
111    uintptr_t m_nextAndFlag;
112};
113
114} // namespace JSC
115
116#endif // ListableHandler_h
117