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
19namespace sw
20{
21	Resource::Resource(size_t bytes) : size(bytes)
22	{
23		blocked = 0;
24
25		accessor = PUBLIC;
26		count = 0;
27		orphaned = false;
28
29		buffer = allocateZero(bytes);
30	}
31
32	Resource::~Resource()
33	{
34		deallocate(buffer);
35	}
36
37	void *Resource::lock(Accessor claimer)
38	{
39		criticalSection.lock();
40
41		while(count != 0 && accessor != claimer)
42		{
43			blocked++;
44			criticalSection.unlock();
45
46			unblock.wait();
47
48			criticalSection.lock();
49			blocked--;
50		}
51
52		accessor = claimer;
53		count++;
54
55		criticalSection.unlock();
56
57		return buffer;
58	}
59
60	void *Resource::lock(Accessor relinquisher, Accessor claimer)
61	{
62		criticalSection.lock();
63
64		// Release
65		while(count > 0 && accessor == relinquisher)
66		{
67			count--;
68
69			if(count == 0)
70			{
71				if(blocked)
72				{
73					unblock.signal();
74				}
75				else if(orphaned)
76				{
77					criticalSection.unlock();
78
79					delete this;
80
81					return 0;
82				}
83			}
84		}
85
86		// Acquire
87		while(count != 0 && accessor != claimer)
88		{
89			blocked++;
90			criticalSection.unlock();
91
92			unblock.wait();
93
94			criticalSection.lock();
95			blocked--;
96		}
97
98		accessor = claimer;
99		count++;
100
101		criticalSection.unlock();
102
103		return buffer;
104	}
105
106	void Resource::unlock()
107	{
108		criticalSection.lock();
109
110		count--;
111
112		if(count == 0)
113		{
114			if(blocked)
115			{
116				unblock.signal();
117			}
118			else if(orphaned)
119			{
120				criticalSection.unlock();
121
122				delete this;
123
124				return;
125			}
126		}
127
128		criticalSection.unlock();
129	}
130
131	void Resource::unlock(Accessor relinquisher)
132	{
133		criticalSection.lock();
134
135		while(count > 0 && accessor == relinquisher)
136		{
137			count--;
138
139			if(count == 0)
140			{
141				if(blocked)
142				{
143					unblock.signal();
144				}
145				else if(orphaned)
146				{
147					criticalSection.unlock();
148
149					delete this;
150
151					return;
152				}
153			}
154		}
155
156		criticalSection.unlock();
157	}
158
159	void Resource::destruct()
160	{
161		criticalSection.lock();
162
163		if(count == 0 && !blocked)
164		{
165			criticalSection.unlock();
166
167			delete this;
168
169			return;
170		}
171
172		orphaned = true;
173
174		criticalSection.unlock();
175	}
176
177	const void *Resource::data() const
178	{
179		return buffer;
180	}
181}
182