Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/nio/ch/FileLockTable.java
38918 views
1
/*
2
* Copyright (c) 2005, 2009, 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.nio.channels.*;
29
import java.util.*;
30
import java.util.concurrent.ConcurrentHashMap;
31
import java.lang.ref.*;
32
import java.io.FileDescriptor;
33
import java.io.IOException;
34
35
abstract class FileLockTable {
36
protected FileLockTable() {
37
}
38
39
/**
40
* Creates and returns a file lock table for a channel that is connected to
41
* the a system-wide map of all file locks for the Java virtual machine.
42
*/
43
public static FileLockTable newSharedFileLockTable(Channel channel,
44
FileDescriptor fd)
45
throws IOException
46
{
47
return new SharedFileLockTable(channel, fd);
48
}
49
50
/**
51
* Adds a file lock to the table.
52
*
53
* @throws OverlappingFileLockException if the file lock overlaps
54
* with an existing file lock in the table
55
*/
56
public abstract void add(FileLock fl) throws OverlappingFileLockException;
57
58
/**
59
* Remove an existing file lock from the table.
60
*/
61
public abstract void remove(FileLock fl);
62
63
/**
64
* Removes all file locks from the table.
65
*
66
* @return The list of file locks removed
67
*/
68
public abstract List<FileLock> removeAll();
69
70
/**
71
* Replaces an existing file lock in the table.
72
*/
73
public abstract void replace(FileLock fl1, FileLock fl2);
74
}
75
76
77
/**
78
* A file lock table that is over a system-wide map of all file locks.
79
*/
80
class SharedFileLockTable extends FileLockTable {
81
82
/**
83
* A weak reference to a FileLock.
84
* <p>
85
* SharedFileLockTable uses a list of file lock references to avoid keeping the
86
* FileLock (and FileChannel) alive.
87
*/
88
private static class FileLockReference extends WeakReference<FileLock> {
89
private FileKey fileKey;
90
91
FileLockReference(FileLock referent,
92
ReferenceQueue<FileLock> queue,
93
FileKey key) {
94
super(referent, queue);
95
this.fileKey = key;
96
}
97
98
FileKey fileKey() {
99
return fileKey;
100
}
101
}
102
103
// The system-wide map is a ConcurrentHashMap that is keyed on the FileKey.
104
// The map value is a list of file locks represented by FileLockReferences.
105
// All access to the list must be synchronized on the list.
106
private static ConcurrentHashMap<FileKey, List<FileLockReference>> lockMap =
107
new ConcurrentHashMap<FileKey, List<FileLockReference>>();
108
109
// reference queue for cleared refs
110
private static ReferenceQueue<FileLock> queue = new ReferenceQueue<FileLock>();
111
112
// The connection to which this table is connected
113
private final Channel channel;
114
115
// File key for the file that this channel is connected to
116
private final FileKey fileKey;
117
118
SharedFileLockTable(Channel channel, FileDescriptor fd) throws IOException {
119
this.channel = channel;
120
this.fileKey = FileKey.create(fd);
121
}
122
123
@Override
124
public void add(FileLock fl) throws OverlappingFileLockException {
125
List<FileLockReference> list = lockMap.get(fileKey);
126
127
for (;;) {
128
129
// The key isn't in the map so we try to create it atomically
130
if (list == null) {
131
list = new ArrayList<FileLockReference>(2);
132
List<FileLockReference> prev;
133
synchronized (list) {
134
prev = lockMap.putIfAbsent(fileKey, list);
135
if (prev == null) {
136
// we successfully created the key so we add the file lock
137
list.add(new FileLockReference(fl, queue, fileKey));
138
break;
139
}
140
}
141
// someone else got there first
142
list = prev;
143
}
144
145
// There is already a key. It is possible that some other thread
146
// is removing it so we re-fetch the value from the map. If it
147
// hasn't changed then we check the list for overlapping locks
148
// and add the new lock to the list.
149
synchronized (list) {
150
List<FileLockReference> current = lockMap.get(fileKey);
151
if (list == current) {
152
checkList(list, fl.position(), fl.size());
153
list.add(new FileLockReference(fl, queue, fileKey));
154
break;
155
}
156
list = current;
157
}
158
159
}
160
161
// process any stale entries pending in the reference queue
162
removeStaleEntries();
163
}
164
165
private void removeKeyIfEmpty(FileKey fk, List<FileLockReference> list) {
166
assert Thread.holdsLock(list);
167
assert lockMap.get(fk) == list;
168
if (list.isEmpty()) {
169
lockMap.remove(fk);
170
}
171
}
172
173
@Override
174
public void remove(FileLock fl) {
175
assert fl != null;
176
177
// the lock must exist so the list of locks must be present
178
List<FileLockReference> list = lockMap.get(fileKey);
179
if (list == null) return;
180
181
synchronized (list) {
182
int index = 0;
183
while (index < list.size()) {
184
FileLockReference ref = list.get(index);
185
FileLock lock = ref.get();
186
if (lock == fl) {
187
assert (lock != null) && (lock.acquiredBy() == channel);
188
ref.clear();
189
list.remove(index);
190
break;
191
}
192
index++;
193
}
194
}
195
}
196
197
@Override
198
public List<FileLock> removeAll() {
199
List<FileLock> result = new ArrayList<FileLock>();
200
List<FileLockReference> list = lockMap.get(fileKey);
201
if (list != null) {
202
synchronized (list) {
203
int index = 0;
204
while (index < list.size()) {
205
FileLockReference ref = list.get(index);
206
FileLock lock = ref.get();
207
208
// remove locks obtained by this channel
209
if (lock != null && lock.acquiredBy() == channel) {
210
// remove the lock from the list
211
ref.clear();
212
list.remove(index);
213
214
// add to result
215
result.add(lock);
216
} else {
217
index++;
218
}
219
}
220
221
// once the lock list is empty we remove it from the map
222
removeKeyIfEmpty(fileKey, list);
223
}
224
}
225
return result;
226
}
227
228
@Override
229
public void replace(FileLock fromLock, FileLock toLock) {
230
// the lock must exist so there must be a list
231
List<FileLockReference> list = lockMap.get(fileKey);
232
assert list != null;
233
234
synchronized (list) {
235
for (int index=0; index<list.size(); index++) {
236
FileLockReference ref = list.get(index);
237
FileLock lock = ref.get();
238
if (lock == fromLock) {
239
ref.clear();
240
list.set(index, new FileLockReference(toLock, queue, fileKey));
241
break;
242
}
243
}
244
}
245
}
246
247
// Check for overlapping file locks
248
private void checkList(List<FileLockReference> list, long position, long size)
249
throws OverlappingFileLockException
250
{
251
assert Thread.holdsLock(list);
252
for (FileLockReference ref: list) {
253
FileLock fl = ref.get();
254
if (fl != null && fl.overlaps(position, size))
255
throw new OverlappingFileLockException();
256
}
257
}
258
259
// Process the reference queue
260
private void removeStaleEntries() {
261
FileLockReference ref;
262
while ((ref = (FileLockReference)queue.poll()) != null) {
263
FileKey fk = ref.fileKey();
264
List<FileLockReference> list = lockMap.get(fk);
265
if (list != null) {
266
synchronized (list) {
267
list.remove(ref);
268
removeKeyIfEmpty(fk, list);
269
}
270
}
271
}
272
}
273
}
274
275