1 /**
2 * Copyright (c) 2006-2016 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21 #include "Channel.h"
22 #include <map>
23 #include <string>
24
25 namespace
26 {
27 union uslong
28 {
29 unsigned long u;
30 long i;
31 };
32
33 // target <= current, but semi-wrapsafe, one wrap, anyway
past(unsigned int target,unsigned int current)34 inline bool past(unsigned int target, unsigned int current)
35 {
36 if (target > current)
37 return false;
38 if (target == current)
39 return true;
40
41 uslong t, c;
42 t.u = target;
43 c.u = current;
44
45 return !(t.i < 0 && c.i > 0);
46 }
47 }
48
49 namespace love
50 {
51 namespace thread
52 {
53 static std::map<std::string, Channel *> namedChannels;
54 static Mutex *namedChannelMutex;
55
getChannel(const std::string & name)56 Channel *Channel::getChannel(const std::string &name)
57 {
58 if (!namedChannelMutex)
59 namedChannelMutex = newMutex();
60
61 Lock lock(namedChannelMutex);
62
63 auto it = namedChannels.find(name);
64
65 if (it != namedChannels.end())
66 {
67 it->second->retain();
68 return it->second;
69 }
70
71 namedChannels[name] = new Channel(name);
72 return namedChannels[name];
73 }
74
Channel()75 Channel::Channel()
76 : named(false)
77 , sent(0)
78 , received(0)
79 {
80 }
81
Channel(const std::string & name)82 Channel::Channel(const std::string &name)
83 : named(true)
84 , name(name)
85 , sent(0)
86 , received(0)
87 {
88 }
89
~Channel()90 Channel::~Channel()
91 {
92 if (named)
93 {
94 Lock l(namedChannelMutex);
95 namedChannels.erase(name);
96 }
97 }
98
push(const Variant & var)99 unsigned long Channel::push(const Variant &var)
100 {
101 Lock l(mutex);
102
103 // Keep a reference to ourselves
104 // if we're non-empty and named.
105 if (named && queue.empty())
106 retain();
107
108 queue.push(var);
109 cond->broadcast();
110
111 return ++sent;
112 }
113
supply(const Variant & var)114 void Channel::supply(const Variant &var)
115 {
116 Lock l(mutex);
117 unsigned long id = push(var);
118
119 while (!past(id, received))
120 cond->wait(mutex);
121 }
122
pop(Variant * var)123 bool Channel::pop(Variant *var)
124 {
125 Lock l(mutex);
126
127 if (queue.empty())
128 return false;
129
130 *var = queue.front();
131 queue.pop();
132
133 received++;
134 cond->broadcast();
135
136 // Release our reference to ourselves
137 // if we're empty and named.
138 if (named && queue.empty())
139 release();
140
141 return true;
142 }
143
demand(Variant * var)144 void Channel::demand(Variant *var)
145 {
146 Lock l(mutex);
147
148 while (!pop(var))
149 cond->wait(mutex);
150 }
151
peek(Variant * var)152 bool Channel::peek(Variant *var)
153 {
154 Lock l(mutex);
155
156 if (queue.empty())
157 return false;
158
159 *var = queue.front();
160 return true;
161 }
162
getCount()163 int Channel::getCount()
164 {
165 Lock l(mutex);
166 return (int) queue.size();
167 }
168
clear()169 void Channel::clear()
170 {
171 Lock l(mutex);
172
173 // We're already empty.
174 if (queue.empty())
175 return;
176
177 while (!queue.empty())
178 queue.pop();
179
180 // Finish all the supply waits
181 received = sent;
182 cond->broadcast();
183
184 // Once again, release our own
185 // reference if we're named.
186 if (named)
187 release();
188 }
189
lockMutex()190 void Channel::lockMutex()
191 {
192 mutex->lock();
193 }
194
unlockMutex()195 void Channel::unlockMutex()
196 {
197 mutex->unlock();
198 }
199
200 } // thread
201 } // love
202