Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #ifndef mozilla_dom_workers_queue_h__
8 : #define mozilla_dom_workers_queue_h__
9 :
10 : #include "Workers.h"
11 :
12 : #include "mozilla/Mutex.h"
13 : #include "nsTArray.h"
14 :
15 : BEGIN_WORKERS_NAMESPACE
16 :
17 : template <typename T, int TCount>
18 : struct StorageWithTArray
19 : {
20 : typedef AutoTArray<T, TCount> StorageType;
21 :
22 66 : static void Reverse(StorageType& aStorage)
23 : {
24 66 : uint32_t length = aStorage.Length();
25 66 : for (uint32_t index = 0; index < length / 2; index++) {
26 0 : uint32_t reverseIndex = length - 1 - index;
27 :
28 0 : T t1 = aStorage.ElementAt(index);
29 0 : T t2 = aStorage.ElementAt(reverseIndex);
30 :
31 0 : aStorage.ReplaceElementsAt(index, 1, t2);
32 0 : aStorage.ReplaceElementsAt(reverseIndex, 1, t1);
33 : }
34 66 : }
35 :
36 252 : static bool IsEmpty(const StorageType& aStorage)
37 : {
38 252 : return !!aStorage.IsEmpty();
39 : }
40 :
41 0 : static bool Push(StorageType& aStorage, const T& aEntry)
42 : {
43 0 : return !!aStorage.AppendElement(aEntry);
44 : }
45 :
46 66 : static bool Pop(StorageType& aStorage, T& aEntry)
47 : {
48 66 : if (IsEmpty(aStorage)) {
49 66 : return false;
50 : }
51 :
52 0 : uint32_t index = aStorage.Length() - 1;
53 0 : aEntry = aStorage.ElementAt(index);
54 0 : aStorage.RemoveElementAt(index);
55 0 : return true;
56 : }
57 :
58 : static void Clear(StorageType& aStorage)
59 : {
60 : aStorage.Clear();
61 : }
62 :
63 66 : static void Compact(StorageType& aStorage)
64 : {
65 66 : aStorage.Compact();
66 66 : }
67 : };
68 :
69 : class LockingWithMutex
70 : {
71 : mozilla::Mutex mMutex;
72 :
73 : protected:
74 : LockingWithMutex()
75 : : mMutex("LockingWithMutex::mMutex")
76 : { }
77 :
78 : void Lock()
79 : {
80 : mMutex.Lock();
81 : }
82 :
83 : void Unlock()
84 : {
85 : mMutex.Unlock();
86 : }
87 :
88 : class AutoLock
89 : {
90 : LockingWithMutex& mHost;
91 :
92 : public:
93 : explicit AutoLock(LockingWithMutex& aHost)
94 : : mHost(aHost)
95 : {
96 : mHost.Lock();
97 : }
98 :
99 : ~AutoLock()
100 : {
101 : mHost.Unlock();
102 : }
103 : };
104 :
105 : friend class AutoLock;
106 : };
107 :
108 2 : class NoLocking
109 : {
110 : protected:
111 : void Lock()
112 : { }
113 :
114 : void Unlock()
115 : { }
116 :
117 : class AutoLock
118 : {
119 : public:
120 126 : explicit AutoLock(NoLocking& aHost)
121 126 : { }
122 :
123 126 : ~AutoLock()
124 126 : { }
125 : };
126 : };
127 :
128 : template <typename T,
129 : int TCount = 256,
130 : class LockingPolicy = NoLocking,
131 : class StoragePolicy = StorageWithTArray<T, TCount % 2 ?
132 : TCount / 2 + 1 :
133 : TCount / 2> >
134 0 : class Queue : public LockingPolicy
135 : {
136 : typedef typename StoragePolicy::StorageType StorageType;
137 : typedef typename LockingPolicy::AutoLock AutoLock;
138 :
139 : StorageType mStorage1;
140 : StorageType mStorage2;
141 :
142 : StorageType* mFront;
143 : StorageType* mBack;
144 :
145 : public:
146 2 : Queue()
147 2 : : mFront(&mStorage1), mBack(&mStorage2)
148 2 : { }
149 :
150 60 : bool IsEmpty()
151 : {
152 120 : AutoLock lock(*this);
153 120 : return StoragePolicy::IsEmpty(*mFront) &&
154 180 : StoragePolicy::IsEmpty(*mBack);
155 : }
156 :
157 0 : bool Push(const T& aEntry)
158 : {
159 0 : AutoLock lock(*this);
160 0 : return StoragePolicy::Push(*mBack, aEntry);
161 : }
162 :
163 66 : bool Pop(T& aEntry)
164 : {
165 132 : AutoLock lock(*this);
166 66 : if (StoragePolicy::IsEmpty(*mFront)) {
167 66 : StoragePolicy::Compact(*mFront);
168 66 : StoragePolicy::Reverse(*mBack);
169 66 : StorageType* tmp = mFront;
170 66 : mFront = mBack;
171 66 : mBack = tmp;
172 : }
173 132 : return StoragePolicy::Pop(*mFront, aEntry);
174 : }
175 :
176 : void Clear()
177 : {
178 : AutoLock lock(*this);
179 : StoragePolicy::Clear(*mFront);
180 : StoragePolicy::Clear(*mBack);
181 : }
182 :
183 : // XXX Do we need this?
184 : void Lock()
185 : {
186 : LockingPolicy::Lock();
187 : }
188 :
189 : // XXX Do we need this?
190 : void Unlock()
191 : {
192 : LockingPolicy::Unlock();
193 : }
194 :
195 : private:
196 : // Queue is not copyable.
197 : Queue(const Queue&);
198 : Queue & operator=(const Queue&);
199 : };
200 :
201 : END_WORKERS_NAMESPACE
202 :
203 : #endif /* mozilla_dom_workers_queue_h__ */
|