]> git.lizzy.rs Git - dragonfireclient.git/blob - src/util/thread.h
Mapgen V6: Respect water_level setting
[dragonfireclient.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
28 template<typename T>
29 class MutexedVariable
30 {
31 public:
32         MutexedVariable(T value):
33                 m_value(value)
34         {
35                 m_mutex.Init();
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 base class for simple background thread implementation
65 */
66
67 class SimpleThread : public JThread
68 {
69         bool run;
70         JMutex run_mutex;
71
72 public:
73
74         SimpleThread():
75                 JThread(),
76                 run(true)
77         {
78                 run_mutex.Init();
79         }
80
81         virtual ~SimpleThread()
82         {}
83
84         virtual void * Thread() = 0;
85
86         bool getRun()
87         {
88                 JMutexAutoLock lock(run_mutex);
89                 return run;
90         }
91         void setRun(bool a_run)
92         {
93                 JMutexAutoLock lock(run_mutex);
94                 run = a_run;
95         }
96
97         void stop()
98         {
99                 setRun(false);
100                 while(IsRunning())
101                         sleep_ms(100);
102         }
103 };
104
105 /*
106         A single worker thread - multiple client threads queue framework.
107 */
108
109
110
111 template<typename Key, typename T, typename Caller, typename CallerData>
112 class GetResult
113 {
114 public:
115         Key key;
116         T item;
117         std::pair<Caller, CallerData> caller;
118 };
119
120 template<typename Key, typename T, typename Caller, typename CallerData>
121 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
122 {
123 };
124
125 template<typename Caller, typename Data, typename Key, typename T>
126 class CallerInfo
127 {
128 public:
129         Caller caller;
130         Data data;
131         ResultQueue< Key, T, Caller, Data>* dest;
132 };
133
134 template<typename Key, typename T, typename Caller, typename CallerData>
135 class GetRequest
136 {
137 public:
138         GetRequest()
139         {
140         }
141         GetRequest(Key a_key)
142         {
143                 key = a_key;
144         }
145         ~GetRequest()
146         {
147         }
148         
149         Key key;
150         std::list<CallerInfo<Caller, CallerData, Key, T> > callers;
151 };
152
153 /**
154  * Notes for RequestQueue usage
155  * @param Key unique key to identify a request for a specific resource
156  * @param T ?
157  * @param Caller unique id of calling thread
158  * @param CallerData data passed back to caller
159  */
160 template<typename Key, typename T, typename Caller, typename CallerData>
161 class RequestQueue
162 {
163 public:
164         bool empty()
165         {
166                 return m_queue.empty();
167         }
168
169         void add(Key key, Caller caller, CallerData callerdata,
170                         ResultQueue<Key, T, Caller, CallerData> *dest)
171         {
172                 JMutexAutoLock lock(m_queue.getMutex());
173                 
174                 /*
175                         If the caller is already on the list, only update CallerData
176                 */
177                 for(typename std::list< GetRequest<Key, T, Caller, CallerData> >::iterator
178                                 i = m_queue.getList().begin();
179                                 i != m_queue.getList().end(); ++i)
180                 {
181                         GetRequest<Key, T, Caller, CallerData> &request = *i;
182
183                         if(request.key == key)
184                         {
185                                 for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
186                                                 i = request.callers.begin();
187                                                 i != request.callers.end(); ++i)
188                                 {
189                                         CallerInfo<Caller, CallerData, Key, T> &ca = *i;
190                                         if(ca.caller == caller)
191                                         {
192                                                 ca.data = callerdata;
193                                                 return;
194                                         }
195                                 }
196                                 CallerInfo<Caller, CallerData, Key, T> ca;
197                                 ca.caller = caller;
198                                 ca.data = callerdata;
199                                 ca.dest = dest;
200                                 request.callers.push_back(ca);
201                                 return;
202                         }
203                 }
204
205                 /*
206                         Else add a new request to the queue
207                 */
208
209                 GetRequest<Key, T, Caller, CallerData> request;
210                 request.key = key;
211                 CallerInfo<Caller, CallerData, Key, T> ca;
212                 ca.caller = caller;
213                 ca.data = callerdata;
214                 ca.dest = dest;
215                 request.callers.push_back(ca);
216                 
217                 m_queue.getList().push_back(request);
218         }
219
220         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
221         {
222                 return m_queue.pop_front(wait_if_empty);
223         }
224
225         void pushResult(GetRequest<Key, T, Caller, CallerData> req,
226                                         T res) {
227
228                 for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
229                                 i = req.callers.begin();
230                                 i != req.callers.end(); ++i)
231                 {
232                         CallerInfo<Caller, CallerData, Key, T> &ca = *i;
233
234                         GetResult<Key,T,Caller,CallerData> result;
235
236                         result.key = req.key;
237                         result.item = res;
238                         result.caller.first = ca.caller;
239                         result.caller.second = ca.data;
240
241                         ca.dest->push_back(result);
242                 }
243         }
244
245 private:
246         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
247 };
248
249 #endif
250