Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/nio/ch/FileLockTable.java
41159 views
1
/*
2
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.nio.ch;
27
28
import java.io.FileDescriptor;
29
import java.io.IOException;
30
import java.lang.ref.ReferenceQueue;
31
import java.lang.ref.WeakReference;
32
import java.nio.channels.Channel;
33
import java.nio.channels.FileLock;
34
import java.nio.channels.OverlappingFileLockException;
35
import java.util.ArrayList;
36
import java.util.HashSet;
37
import java.util.List;
38
import java.util.Set;
39
import java.util.concurrent.ConcurrentHashMap;
40
41
/**
42
* A file lock table that is over a system-wide map of all file locks.
43
*/
44
class FileLockTable {
45
/**
46
* A weak reference to a FileLock.
47
* <p>
48
* FileLockTable uses a list of file lock references to avoid keeping the
49
* FileLock (and FileChannel) alive.
50
*/
51
private static class FileLockReference extends WeakReference<FileLock> {
52
private FileKey fileKey;
53
54
FileLockReference(FileLock referent,
55
ReferenceQueue<FileLock> queue,
56
FileKey key) {
57
super(referent, queue);
58
this.fileKey = key;
59
}
60
61
FileKey fileKey() {
62
return fileKey;
63
}
64
}
65
66
// The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
67
// The map value is a list of file locks represented by FileLockReferences.
68
// All access to the list must be synchronized on the list.
69
private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
70
new ConcurrentHashMap<FileKey, List<FileLockReference>>();
71
72
// reference queue for cleared refs
73
private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
74
75
// The connection to which this table is connected
76
private final Channel channel;
77
78
// File key for the file that this channel is connected to
79
private final FileKey fileKey;
80
81
// Locks obtained for this channel
82
private final Set<FileLock> locks;
83
84
/**
85
* Creates a file lock table for a channel that is connected to the
86
* system-wide map of all file locks for the Java virtual machine.
87
*/
88
FileLockTable(Channel channel, FileDescriptor fd) throws IOException {
89
this.channel = channel;
90
this.fileKey = FileKey.create(fd);
91
this.locks = new HashSet<FileLock>();
92
}
93
94
void add(FileLock fl) throws OverlappingFileLockException {
95
List<FileLockReference> list = lockMap.get(fileKey);
96
97
for (;;) {
98
99
// The key isn't in the map so we try to create it atomically
100
if (list == null) {
101
list = new ArrayList<FileLockReference>(2);
102
List<FileLockReference> prev;
103
synchronized (list) {
104
prev = lockMap.putIfAbsent(fileKey, list);
105
if (prev == null) {
106
// we successfully created the key so we add the file lock
107
list.add(new FileLockReference(fl, queue, fileKey));
108
locks.add(fl);
109
break;
110
}
111
}
112
// someone else got there first
113
list = prev;
114
}
115
116
// There is already a key. It is possible that some other thread
117
// is removing it so we re-fetch the value from the map. If it
118
// hasn't changed then we check the list for overlapping locks
119
// and add the new lock to the list.
120
synchronized (list) {
121
List<FileLockReference> current = lockMap.get(fileKey);
122
if (list == current) {
123
checkList(list, fl.position(), fl.size());
124
list.add(new FileLockReference(fl, queue, fileKey));
125
locks.add(fl);
126
break;
127
}
128
list = current;
129
}
130
131
}
132
133
// process any stale entries pending in the reference queue
134
removeStaleEntries();
135
}
136
137
private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
138
assert Thread.holdsLock(list);
139
assert lockMap.get(fk) == list;
140
if (list.isEmpty()) {
141
lockMap.remove(fk);
142
}
143
}
144
145
void remove(FileLock fl) {
146
assert fl != null;
147
148
// the lock must exist so the list of locks must be present
149
List<FileLockReference> list = lockMap.get(fileKey);
150
if (list == null) return;
151
152
synchronized (list) {
153
int index = 0;
154
while (index < list.size()) {
155
FileLockReference ref = list.get(index);
156
FileLock lock = ref.get();
157
if (lock == fl) {
158
assert (lock != null) && (lock.acquiredBy() == channel);
159
ref.clear();
160
list.remove(index);
161
locks.remove(fl);
162
break;
163
}
164
index++;
165
}
166
}
167
}
168
169
List<FileLock> removeAll() {
170
List<FileLock> result = new ArrayList<FileLock>();
171
List<FileLockReference> list = lockMap.get(fileKey);
172
if (list != null) {
173
synchronized (list) {
174
int index = 0;
175
while (index < list.size()) {
176
FileLockReference ref = list.get(index);
177
FileLock lock = ref.get();
178
179
// remove locks obtained by this channel
180
if (lock != null && lock.acquiredBy() == channel) {
181
// remove the lock from the list
182
ref.clear();
183
list.remove(index);
184
185
// add to result
186
result.add(lock);
187
} else {
188
index++;
189
}
190
}
191
192
// once the lock list is empty we remove it from the map
193
removeKeyIfEmpty(fileKey, list);
194
195
locks.clear();
196
}
197
}
198
return result;
199
}
200
201
void replace(FileLock fromLock, FileLock toLock) {
202
// the lock must exist so there must be a list
203
List<FileLockReference> list = lockMap.get(fileKey);
204
assert list != null;
205
206
synchronized (list) {
207
for (int index=0; index<list.size(); index++) {
208
FileLockReference ref = list.get(index);
209
FileLock lock = ref.get();
210
if (lock == fromLock) {
211
ref.clear();
212
list.set(index, new FileLockReference(toLock, queue, fileKey));
213
locks.remove(fromLock);
214
locks.add(toLock);
215
break;
216
}
217
}
218
}
219
}
220
221
// Check for overlapping file locks
222
private void checkList(List<FileLockReference> list, long position, long size)
223
throws OverlappingFileLockException
224
{
225
assert Thread.holdsLock(list);
226
for (FileLockReference ref: list) {
227
FileLock fl = ref.get();
228
if (fl != null && fl.overlaps(position, size))
229
throw new OverlappingFileLockException();
230
}
231
}
232
233
// Process the reference queue
234
private void removeStaleEntries() {
235
FileLockReference ref;
236
while ((ref = (FileLockReference)queue.poll()) != null) {
237
FileKey fk = ref.fileKey();
238
List<FileLockReference> list = lockMap.get(fk);
239
if (list != null) {
240
synchronized (list) {
241
list.remove(ref);
242
removeKeyIfEmpty(fk, list);
243
}
244
}
245
}
246
}
247
}
248
249