1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "Resource.hpp"
16 
17 #include "Memory.hpp"
18 #include "Debug.hpp"
19 
20 namespace sw
21 {
Resource(size_t bytes)22 	Resource::Resource(size_t bytes) : size(bytes)
23 	{
24 		blocked = 0;
25 
26 		accessor = PUBLIC;
27 		count = 0;
28 		orphaned = false;
29 
30 		buffer = allocate(bytes);
31 	}
32 
~Resource()33 	Resource::~Resource()
34 	{
35 		deallocate(buffer);
36 	}
37 
lock(Accessor claimer)38 	void *Resource::lock(Accessor claimer)
39 	{
40 		criticalSection.lock();
41 
42 		while(count > 0 && accessor != claimer)
43 		{
44 			blocked++;
45 			criticalSection.unlock();
46 
47 			unblock.wait();
48 
49 			criticalSection.lock();
50 			blocked--;
51 		}
52 
53 		accessor = claimer;
54 		count++;
55 
56 		criticalSection.unlock();
57 
58 		return buffer;
59 	}
60 
lock(Accessor relinquisher,Accessor claimer)61 	void *Resource::lock(Accessor relinquisher, Accessor claimer)
62 	{
63 		criticalSection.lock();
64 
65 		// Release
66 		while(count > 0 && accessor == relinquisher)
67 		{
68 			count--;
69 
70 			if(count == 0)
71 			{
72 				if(blocked)
73 				{
74 					unblock.signal();
75 				}
76 				else if(orphaned)
77 				{
78 					criticalSection.unlock();
79 
80 					delete this;
81 
82 					return 0;
83 				}
84 			}
85 		}
86 
87 		// Acquire
88 		while(count > 0 && accessor != claimer)
89 		{
90 			blocked++;
91 			criticalSection.unlock();
92 
93 			unblock.wait();
94 
95 			criticalSection.lock();
96 			blocked--;
97 		}
98 
99 		accessor = claimer;
100 		count++;
101 
102 		criticalSection.unlock();
103 
104 		return buffer;
105 	}
106 
unlock()107 	void Resource::unlock()
108 	{
109 		criticalSection.lock();
110 		ASSERT(count > 0);
111 
112 		count--;
113 
114 		if(count == 0)
115 		{
116 			if(blocked)
117 			{
118 				unblock.signal();
119 			}
120 			else if(orphaned)
121 			{
122 				criticalSection.unlock();
123 
124 				delete this;
125 
126 				return;
127 			}
128 		}
129 
130 		criticalSection.unlock();
131 	}
132 
unlock(Accessor relinquisher)133 	void Resource::unlock(Accessor relinquisher)
134 	{
135 		criticalSection.lock();
136 		ASSERT(count > 0);
137 
138 		while(count > 0 && accessor == relinquisher)
139 		{
140 			count--;
141 
142 			if(count == 0)
143 			{
144 				if(blocked)
145 				{
146 					unblock.signal();
147 				}
148 				else if(orphaned)
149 				{
150 					criticalSection.unlock();
151 
152 					delete this;
153 
154 					return;
155 				}
156 			}
157 		}
158 
159 		criticalSection.unlock();
160 	}
161 
destruct()162 	void Resource::destruct()
163 	{
164 		criticalSection.lock();
165 
166 		if(count == 0 && !blocked)
167 		{
168 			criticalSection.unlock();
169 
170 			delete this;
171 
172 			return;
173 		}
174 
175 		orphaned = true;
176 
177 		criticalSection.unlock();
178 	}
179 
data() const180 	const void *Resource::data() const
181 	{
182 		return buffer;
183 	}
184 }
185