]> git.lizzy.rs Git - minetest.git/blob - src/util/thread.h
Replace SimpleThread by JThread now implementing same features
[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
28 template<typename T>
29 class MutexedVariable
30 {
31 public:
32         MutexedVariable(T value):
33                 m_value(value)
34         {
35         }
36
37         T get()
38         {
39                 JMutexAutoLock lock(m_mutex);
40                 return m_value;
41         }
42
43         void set(T value)
44         {
45                 JMutexAutoLock lock(m_mutex);
46                 m_value = value;
47         }
48         
49         // You'll want to grab this in a SharedPtr
50         JMutexAutoLock * getLock()
51         {
52                 return new JMutexAutoLock(m_mutex);
53         }
54         
55         // You pretty surely want to grab the lock when accessing this
56         T m_value;
57
58 private:
59         JMutex m_mutex;
60 };
61
62 /*
63         A single worker thread - multiple client threads queue framework.
64 */
65 template<typename Key, typename T, typename Caller, typename CallerData>
66 class GetResult
67 {
68 public:
69         Key key;
70         T item;
71         std::pair<Caller, CallerData> caller;
72 };
73
74 template<typename Key, typename T, typename Caller, typename CallerData>
75 class ResultQueue: public MutexedQueue< GetResult<Key, T, Caller, CallerData> >
76 {
77 };
78
79 template<typename Caller, typename Data, typename Key, typename T>
80 class CallerInfo
81 {
82 public:
83         Caller caller;
84         Data data;
85         ResultQueue< Key, T, Caller, Data>* dest;
86 };
87
88 template<typename Key, typename T, typename Caller, typename CallerData>
89 class GetRequest
90 {
91 public:
92         GetRequest()
93         {
94         }
95         GetRequest(Key a_key)
96         {
97                 key = a_key;
98         }
99         ~GetRequest()
100         {
101         }
102         
103         Key key;
104         std::list<CallerInfo<Caller, CallerData, Key, T> > callers;
105 };
106
107 /**
108  * Notes for RequestQueue usage
109  * @param Key unique key to identify a request for a specific resource
110  * @param T ?
111  * @param Caller unique id of calling thread
112  * @param CallerData data passed back to caller
113  */
114 template<typename Key, typename T, typename Caller, typename CallerData>
115 class RequestQueue
116 {
117 public:
118         bool empty()
119         {
120                 return m_queue.empty();
121         }
122
123         void add(Key key, Caller caller, CallerData callerdata,
124                         ResultQueue<Key, T, Caller, CallerData> *dest)
125         {
126                 JMutexAutoLock lock(m_queue.getMutex());
127                 
128                 /*
129                         If the caller is already on the list, only update CallerData
130                 */
131                 for(typename std::list< GetRequest<Key, T, Caller, CallerData> >::iterator
132                                 i = m_queue.getList().begin();
133                                 i != m_queue.getList().end(); ++i)
134                 {
135                         GetRequest<Key, T, Caller, CallerData> &request = *i;
136
137                         if(request.key == key)
138                         {
139                                 for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
140                                                 i = request.callers.begin();
141                                                 i != request.callers.end(); ++i)
142                                 {
143                                         CallerInfo<Caller, CallerData, Key, T> &ca = *i;
144                                         if(ca.caller == caller)
145                                         {
146                                                 ca.data = callerdata;
147                                                 return;
148                                         }
149                                 }
150                                 CallerInfo<Caller, CallerData, Key, T> ca;
151                                 ca.caller = caller;
152                                 ca.data = callerdata;
153                                 ca.dest = dest;
154                                 request.callers.push_back(ca);
155                                 return;
156                         }
157                 }
158
159                 /*
160                         Else add a new request to the queue
161                 */
162
163                 GetRequest<Key, T, Caller, CallerData> request;
164                 request.key = key;
165                 CallerInfo<Caller, CallerData, Key, T> ca;
166                 ca.caller = caller;
167                 ca.data = callerdata;
168                 ca.dest = dest;
169                 request.callers.push_back(ca);
170                 
171                 m_queue.getList().push_back(request);
172         }
173
174         GetRequest<Key, T, Caller, CallerData> pop(bool wait_if_empty=false)
175         {
176                 return m_queue.pop_front(wait_if_empty);
177         }
178
179         void pushResult(GetRequest<Key, T, Caller, CallerData> req,
180                                         T res) {
181
182                 for(typename std::list< CallerInfo<Caller, CallerData, Key, T> >::iterator
183                                 i = req.callers.begin();
184                                 i != req.callers.end(); ++i)
185                 {
186                         CallerInfo<Caller, CallerData, Key, T> &ca = *i;
187
188                         GetResult<Key,T,Caller,CallerData> result;
189
190                         result.key = req.key;
191                         result.item = res;
192                         result.caller.first = ca.caller;
193                         result.caller.second = ca.data;
194
195                         ca.dest->push_back(result);
196                 }
197         }
198
199 private:
200         MutexedQueue< GetRequest<Key, T, Caller, CallerData> > m_queue;
201 };
202
203 #endif
204