]> git.lizzy.rs Git - minetest.git/blob - src/util/thread.h
MutexedQueue inherits must use std::deque instead of std::list
[minetest.git] / src / util / thread.h
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #ifndef UTIL_THREAD_HEADER
21 #define UTIL_THREAD_HEADER
22
23 #include "../irrlichttypes.h"
24 #include "../jthread/jthread.h"
25 #include "../jthread/jmutex.h"
26 #include "../jthread/jmutexautolock.h"
27 #include "porting.h"
28
29 template<typename T>
30 class MutexedVariable
31 {
32 public:
33         MutexedVariable(T value):
34                 m_value(value)
35         {
36         }
37
38         T get()
39         {
40                 JMutexAutoLock lock(m_mutex);
41                 return m_value;
42         }
43
44         void set(T value)
45         {
46                 JMutexAutoLock lock(m_mutex);
47                 m_value = value;
48         }
49         
50         // You'll want to grab this in a SharedPtr
51         JMutexAutoLock * getLock()
52         {
53                 return new JMutexAutoLock(m_mutex);
54         }
55         
56         // You pretty surely want to grab the lock when accessing this
57         T m_value;
58
59 private:
60         JMutex m_mutex;
61 };
62
63 /*
64         A single worker thread - multiple client threads queue framework.
65 */
66 template<typename Key, typename T, typename Caller, typename CallerData>
67 class GetResult
68 {
69 public:
70         Key key;
71         T item;
72         std::pair<Caller, CallerData> caller;
73 };
74
75 template<typename Key, typename T, typename Caller, typename CallerData>
76 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
77 {
78 };
79
80 template<typename Caller, typename Data, typename Key, typename T>
81 class CallerInfo
82 {
83 public:
84         Caller caller;
85         Data data;
86         ResultQueue< Key, T, Caller, Data>* dest;
87 };
88
89 template<typename Key, typename T, typename Caller, typename CallerData>
90 class GetRequest
91 {
92 public:
93         GetRequest()
94         {
95         }
96         GetRequest(Key a_key)
97         {
98                 key = a_key;
99         }
100         ~GetRequest()
101         {
102         }
103         
104         Key key;
105         std::list<CallerInfo<Caller, CallerData, Key, T> > callers;
106 };
107
108 /**
109  * Notes for RequestQueue usage
110  * @param Key unique key to identify a request for a specific resource
111  * @param T ?
112  * @param Caller unique id of calling thread
113  * @param CallerData data passed back to caller
114  */
115 template<typename Key, typename T, typename Caller, typename CallerData>
116 class RequestQueue
117 {
118 public:
119         bool empty()
120         {
121                 return m_queue.empty();
122         }
123
124         void add(Key key, Caller caller, CallerData callerdata,
125                         ResultQueue<Key, T, Caller, CallerData> *dest)
126         {
127                 {
128                         JMutexAutoLock lock(m_queue.getMutex());
129
130                         /*
131                                 If the caller is already on the list, only update CallerData
132                         */
133                         for(typename std::deque< GetRequest<Key, T, Caller, CallerData> >::iterator
134                                         i = m_queue.getQueue().begin();
135                                         i != m_queue.getQueue().end(); ++i)
136                         {
137                                 GetRequest<Key, T, Caller, CallerData> &request = *i;
138
139                                 if(request.key == key)
140                                 {
141                                         for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
142                                                         i = request.callers.begin();
143                                                         i != request.callers.end(); ++i)
144                                         {
145                                                 CallerInfo<Caller, CallerData, Key, T> &ca = *i;
146                                                 if(ca.caller == caller)
147                                                 {
148                                                         ca.data = callerdata;
149                                                         return;
150                                                 }
151                                         }
152                                         CallerInfo<Caller, CallerData, Key, T> ca;
153                                         ca.caller = caller;
154                                         ca.data = callerdata;
155                                         ca.dest = dest;
156                                         request.callers.push_back(ca);
157                                         return;
158                                 }
159                         }
160                 }
161
162                 /*
163                         Else add a new request to the queue
164                 */
165
166                 GetRequest<Key, T, Caller, CallerData> request;
167                 request.key = key;
168                 CallerInfo<Caller, CallerData, Key, T> ca;
169                 ca.caller = caller;
170                 ca.data = callerdata;
171                 ca.dest = dest;
172                 request.callers.push_back(ca);
173                 
174                 m_queue.push_back(request);
175         }
176
177         GetRequest<Key, T, Caller, CallerData> pop(unsigned int timeout_ms)
178         {
179                 return m_queue.pop_front(timeout_ms);
180         }
181
182         GetRequest<Key, T, Caller, CallerData> pop()
183         {
184                 return m_queue.pop_frontNoEx();
185         }
186
187         void pushResult(GetRequest<Key, T, Caller, CallerData> req,
188                                         T res) {
189
190                 for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
191                                 i = req.callers.begin();
192                                 i != req.callers.end(); ++i)
193                 {
194                         CallerInfo<Caller, CallerData, Key, T> &ca = *i;
195
196                         GetResult<Key,T,Caller,CallerData> result;
197
198                         result.key = req.key;
199                         result.item = res;
200                         result.caller.first = ca.caller;
201                         result.caller.second = ca.data;
202
203                         ca.dest->push_back(result);
204                 }
205         }
206
207 private:
208         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
209 };
210
211 #endif
212