Skip to content

Commit 1efa831

Browse files
Merge pull request #1682 from brettwooldridge/master
fixes #1681 merge reentrant locks into a single lock and eliminate synchronized blocks
2 parents 2711df9 + 1d3ceb7 commit 1efa831

File tree

1 file changed

+66
-58
lines changed

1 file changed

+66
-58
lines changed

src/com/sun/jna/Structure.java

Lines changed: 66 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -156,10 +156,7 @@ private static class NativeStringTracking {
156156
//public static final int ALIGN_8 = 6;
157157

158158
protected static final int CALCULATE_SIZE = -1;
159-
static final ReentrantReadWriteLock layoutInfoLock = new ReentrantReadWriteLock();
160-
static final ReentrantReadWriteLock fieldOrderLock = new ReentrantReadWriteLock();
161-
static final ReentrantReadWriteLock fieldListLock = new ReentrantReadWriteLock();
162-
static final ReentrantReadWriteLock validationLock = new ReentrantReadWriteLock();
159+
static final ReentrantReadWriteLock cacheStructureLock = new ReentrantReadWriteLock();
163160
static final Map<Class<?>, LayoutInfo> layoutInfo = new WeakHashMap<>();
164161
static final Map<Class<?>, List<String>> fieldOrder = new WeakHashMap<>();
165162
static final Map<Class<?>, List<Field>> fieldList = new WeakHashMap<>();
@@ -1024,18 +1021,18 @@ protected void sortFields(List<Field> fields, List<String> names) {
10241021
protected List<Field> getFieldList() {
10251022
Class<?> clazz = getClass();
10261023
// Try to read the value under the read lock
1027-
fieldListLock.readLock().lock();
1024+
cacheStructureLock.readLock().lock();
10281025
try {
10291026
List<Field> fields = fieldList.get(clazz);
10301027
if (fields != null) {
10311028
return fields; // Return the cached result if found
10321029
}
10331030
} finally {
1034-
fieldListLock.readLock().unlock();
1031+
cacheStructureLock.readLock().unlock();
10351032
}
10361033

10371034
// If not found, compute the value under the write lock
1038-
fieldListLock.writeLock().lock();
1035+
cacheStructureLock.writeLock().lock();
10391036
try {
10401037
// Double-check if another thread has computed the value before we do
10411038
return fieldList.computeIfAbsent(clazz, (c) -> {
@@ -1057,7 +1054,7 @@ protected List<Field> getFieldList() {
10571054
return flist;
10581055
});
10591056
} finally {
1060-
fieldListLock.writeLock().unlock();
1057+
cacheStructureLock.writeLock().unlock();
10611058
}
10621059
}
10631060

@@ -1067,23 +1064,23 @@ protected List<Field> getFieldList() {
10671064
private List<String> fieldOrder() {
10681065
Class<?> clazz = getClass();
10691066
// Try to read the value under the read lock
1070-
fieldOrderLock.readLock().lock();
1067+
cacheStructureLock.readLock().lock();
10711068
try {
10721069
List<String> order = fieldOrder.get(clazz);
10731070
if (order != null) {
10741071
return order; // Return the cached result if found
10751072
}
10761073
} finally {
1077-
fieldOrderLock.readLock().unlock();
1074+
cacheStructureLock.readLock().unlock();
10781075
}
10791076

10801077
// If not found, compute the value under the write lock
1081-
fieldOrderLock.writeLock().lock();
1078+
cacheStructureLock.writeLock().lock();
10821079
try {
10831080
// Double-check if another thread has computed the value before we do (see JavaDoc)
10841081
return fieldOrder.computeIfAbsent(clazz, (c) -> getFieldOrder());
10851082
} finally {
1086-
fieldOrderLock.writeLock().unlock();
1083+
cacheStructureLock.writeLock().unlock();
10871084
}
10881085
}
10891086

@@ -1198,11 +1195,11 @@ static int size(Class<? extends Structure> type) {
11981195
*/
11991196
static <T extends Structure> int size(Class<T> type, T value) {
12001197
LayoutInfo info;
1201-
layoutInfoLock.readLock().lock();
1198+
cacheStructureLock.readLock().lock();
12021199
try {
12031200
info = layoutInfo.get(type);
12041201
} finally {
1205-
layoutInfoLock.readLock().unlock();
1202+
cacheStructureLock.readLock().unlock();
12061203
}
12071204
int sz = (info != null && !info.variable) ? info.size : CALCULATE_SIZE;
12081205
if (sz == CALCULATE_SIZE) {
@@ -1225,11 +1222,11 @@ int calculateSize(boolean force, boolean avoidFFIType) {
12251222
int size = CALCULATE_SIZE;
12261223
Class<?> clazz = getClass();
12271224
LayoutInfo info;
1228-
layoutInfoLock.readLock().lock();
1225+
cacheStructureLock.readLock().lock();
12291226
try {
12301227
info = layoutInfo.get(clazz);
12311228
} finally {
1232-
layoutInfoLock.readLock().unlock();
1229+
cacheStructureLock.readLock().unlock();
12331230
}
12341231
if (info == null
12351232
|| this.alignType != info.alignType
@@ -1241,7 +1238,7 @@ int calculateSize(boolean force, boolean avoidFFIType) {
12411238
this.structFields = info.fields;
12421239

12431240
if (!info.variable) {
1244-
layoutInfoLock.readLock().lock();
1241+
cacheStructureLock.readLock().lock();
12451242
try {
12461243
// If we've already cached it, only override layout if
12471244
// we're using non-default values for alignment and/or
@@ -1252,17 +1249,17 @@ int calculateSize(boolean force, boolean avoidFFIType) {
12521249
|| this.alignType != ALIGN_DEFAULT
12531250
|| this.typeMapper != null) {
12541251
// Must release read lock before acquiring write lock (see JavaDoc lock escalation example)
1255-
layoutInfoLock.readLock().unlock();
1256-
layoutInfoLock.writeLock().lock();
1252+
cacheStructureLock.readLock().unlock();
1253+
cacheStructureLock.writeLock().lock();
12571254

12581255
layoutInfo.put(clazz, info);
12591256

12601257
// Downgrade by acquiring read lock before releasing write lock (again, see JavaDoc)
1261-
layoutInfoLock.readLock().lock();
1262-
layoutInfoLock.writeLock().unlock();;
1258+
cacheStructureLock.readLock().lock();
1259+
cacheStructureLock.writeLock().unlock();;
12631260
}
12641261
} finally {
1265-
layoutInfoLock.readLock().unlock();
1262+
cacheStructureLock.readLock().unlock();
12661263
}
12671264
}
12681265
size = info.size;
@@ -1307,17 +1304,17 @@ private void validateField(String name, Class<?> type) {
13071304
/** ensure all fields are of valid type. */
13081305
private void validateFields() {
13091306
// Try to read the value under the read lock
1310-
validationLock.readLock().lock();
1307+
cacheStructureLock.readLock().lock();
13111308
try {
13121309
if (validationMap.containsKey(getClass())) {
13131310
return; // Return because this Structure has already been validated
13141311
}
13151312
} finally {
1316-
validationLock.readLock().unlock();
1313+
cacheStructureLock.readLock().unlock();
13171314
}
13181315

13191316
// If not found, perform validation and update the cache under the write lock
1320-
validationLock.writeLock().lock();
1317+
cacheStructureLock.writeLock().lock();
13211318
try {
13221319
// Double-check if another thread has computed the value before we do (see JavaDoc)
13231320
validationMap.computeIfAbsent(getClass(), (cls) -> {
@@ -1327,7 +1324,7 @@ private void validateFields() {
13271324
return true;
13281325
});
13291326
} finally {
1330-
validationLock.writeLock().unlock();
1327+
cacheStructureLock.writeLock().unlock();
13311328
}
13321329
}
13331330

@@ -2214,9 +2211,7 @@ private void init(Pointer[] els) {
22142211
/** Obtain a pointer to the native FFI type descriptor for the given object. */
22152212
static FFIType get(Object obj) {
22162213
if (obj == null)
2217-
synchronized (typeInfoMap) {
2218-
return getTypeInfo(Pointer.class, 0);
2219-
}
2214+
return getTypeInfo(Pointer.class, 0);
22202215
if (obj instanceof Class)
22212216
return get(null, (Class<?>)obj);
22222217
return get(obj, obj.getClass());
@@ -2230,13 +2225,14 @@ private static FFIType get(Object obj, Class<?> cls) {
22302225
cls = nc.nativeType();
22312226
}
22322227
}
2233-
synchronized(typeInfoMap) {
2234-
FFIType o = getTypeInfo(cls, cls.isArray() ? Array.getLength(obj) : 0);
2235-
if (o != null) {
2236-
return o;
2237-
}
2228+
FFIType o = getTypeInfo(cls, cls.isArray() ? Array.getLength(obj) : 0);
2229+
if (o != null) {
2230+
return o;
2231+
}
2232+
cacheStructureLock.writeLock().lock();
2233+
try {
22382234
if ((Platform.HAS_BUFFERS && Buffer.class.isAssignableFrom(cls))
2239-
|| Callback.class.isAssignableFrom(cls)) {
2235+
|| Callback.class.isAssignableFrom(cls)) {
22402236
typeInfoMap.put(cls, typeInfoMap.get(Pointer.class));
22412237
return typeInfoMap.get(Pointer.class).get(0);
22422238
}
@@ -2246,30 +2242,42 @@ private static FFIType get(Object obj, Class<?> cls) {
22462242
typeInfoMap.put(cls, typeInfoMap.get(Pointer.class));
22472243
return typeInfoMap.get(Pointer.class).get(0);
22482244
}
2249-
FFIType type = new FFIType((Structure)obj);
2245+
FFIType type = new FFIType((Structure) obj);
22502246
storeTypeInfo(cls, type);
22512247
return type;
22522248
}
2253-
if (NativeMapped.class.isAssignableFrom(cls)) {
2254-
NativeMappedConverter c = NativeMappedConverter.getInstance(cls);
2255-
return get(c.toNative(obj, new ToNativeContext()), c.nativeType());
2256-
}
2257-
if (cls.isArray()) {
2258-
FFIType type = new FFIType(obj, cls);
2259-
// Store it in the map to prevent premature GC of type info
2260-
storeTypeInfo(cls, Array.getLength(obj), type);
2261-
return type;
2262-
}
2263-
throw new IllegalArgumentException("Unsupported type " + cls);
22642249
}
2250+
finally {
2251+
cacheStructureLock.writeLock().unlock();
2252+
}
2253+
2254+
if (NativeMapped.class.isAssignableFrom(cls)) {
2255+
NativeMappedConverter c = NativeMappedConverter.getInstance(cls);
2256+
return get(c.toNative(obj, new ToNativeContext()), c.nativeType());
2257+
}
2258+
2259+
if (cls.isArray()) {
2260+
FFIType type = new FFIType(obj, cls);
2261+
// Store it in the map to prevent premature GC of type info
2262+
storeTypeInfo(cls, Array.getLength(obj), type);
2263+
return type;
2264+
}
2265+
2266+
throw new IllegalArgumentException("Unsupported type " + cls);
22652267
}
22662268

22672269
private static FFIType getTypeInfo(Class clazz, int elementCount) {
2268-
Map<Integer,FFIType> typeMap = typeInfoMap.get(clazz);
2269-
if(typeMap != null) {
2270-
return typeMap.get(elementCount);
2271-
} else {
2272-
return null;
2270+
cacheStructureLock.readLock().lock();
2271+
try {
2272+
Map<Integer, FFIType> typeMap = typeInfoMap.get(clazz);
2273+
if (typeMap != null) {
2274+
return typeMap.get(elementCount);
2275+
} else {
2276+
return null;
2277+
}
2278+
}
2279+
finally {
2280+
cacheStructureLock.readLock().unlock();
22732281
}
22742282
}
22752283

@@ -2278,14 +2286,14 @@ private static void storeTypeInfo(Class clazz, FFIType type) {
22782286
}
22792287

22802288
private static void storeTypeInfo(Class clazz, int elementCount, FFIType type) {
2281-
synchronized (typeInfoMap) {
2282-
Map<Integer,FFIType> typeMap = typeInfoMap.get(clazz);
2283-
if(typeMap == null) {
2284-
typeMap = new HashMap<>();
2285-
typeInfoMap.put(clazz, typeMap);
2286-
}
2289+
cacheStructureLock.writeLock().lock();
2290+
try {
2291+
Map<Integer, FFIType> typeMap = typeInfoMap.computeIfAbsent(clazz, k -> new HashMap<>());
22872292
typeMap.put(elementCount, type);
22882293
}
2294+
finally {
2295+
cacheStructureLock.writeLock().unlock();
2296+
}
22892297
}
22902298
}
22912299

0 commit comments

Comments
 (0)