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
20namespace sw
21{
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
33	Resource::~Resource()
34	{
35		deallocate(buffer);
36	}
37
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
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
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
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
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
180	const void *Resource::data() const
181	{
182		return buffer;
183	}
184}
185