Skip to content

Commit ab0b4e0

Browse files
committed
GT-3535 changes from review
1 parent 0536335 commit ab0b4e0

File tree

4 files changed

+35
-26
lines changed

4 files changed

+35
-26
lines changed

Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -636,29 +636,31 @@ public List<DataType> getDataTypesByBaseName(String dataTypeName) {
636636
list.add(baseType);
637637
}
638638

639-
List<DataType> relatedNameDataTypes = conflictMap.getDataTypesForBaseName(baseName);
639+
List<DataType> relatedNameDataTypes = conflictMap.getDataTypesByBaseName(baseName);
640640
list.addAll(relatedNameDataTypes);
641641
return list;
642642
}
643643

644644
/**
645-
* Class to handle complexities of having a map as the value in a LazyLoadingCachingMap
646-
* This map uses data type's base name as the key (i.e. all .conflict suffixex stripped off.)
647-
* The value is another map that maps the actual data type's name to the datatype. This map
645+
* Class to handle the complexities of having a map as the value in a LazyLoadingCachingMap
646+
* This map uses the data type's base name as the key (i.e. all .conflict suffixes stripped off.)
647+
* The value is another map that maps the actual data type's name to the data type. This map
648648
* effectively provides an efficient way to get all data types in a category that have the
649649
* same name, but possibly have had their name modified (by appending .conflict) to get around
650650
* the requirement that names have to be unique in the same category.
651651
*/
652-
class ConflictMap extends LazyLoadingCachingMap<String, Map<String, DataType>> {
652+
private class ConflictMap extends LazyLoadingCachingMap<String, Map<String, DataType>> {
653653

654654
ConflictMap(Lock lock) {
655655
super(lock);
656656
}
657657

658658
/**
659659
* Creates a map of all data types whose name has a .conflict suffix where the key
660-
* is the base name and the value is a map of actual name to data type. This mapping is
661-
* maintained as a lazy cache map.
660+
* is the base name and {@link LazyLoadingCachingMap} the value is a map of actual name to data type. This mapping is
661+
* maintained as a lazy cache map. This is only called by the super class when the
662+
* cached needs to be populated and we are depending on it to acquire the necessary
663+
* database lock. (See {@link LazyLoadingCachingMap#loadMap()}
662664
* @return the loaded map
663665
*/
664666
@Override
@@ -670,10 +672,7 @@ protected Map<String, Map<String, DataType>> loadMap() {
670672
if (isConflictName(dataTypeName)) {
671673
String baseName = getBaseName(dataTypeName);
672674
Map<String, DataType> innerMap = map.get(baseName);
673-
if (innerMap == null) {
674-
innerMap = new HashMap<>();
675-
map.put(baseName, innerMap);
676-
}
675+
map.computeIfAbsent(baseName, b -> new HashMap<>());
677676
innerMap.put(dataTypeName, dataType);
678677
}
679678
}
@@ -682,28 +681,27 @@ protected Map<String, Map<String, DataType>> loadMap() {
682681

683682
/**
684683
* Adds the data type to the conflict mapping structure. If the mapping is currently not
685-
* loaded then this method can safely do nothing.
684+
* loaded then this method can safely do nothing. This method is synchronized to provide
685+
* thread safe access/manipulation of the map.
686686
* @param dataType the data type to add to the mapping if the mapping is already loaded
687687
*/
688688
synchronized void addDataType(DataType dataType) {
689+
// if the cache is not currently populated, don't need to do anything
689690
Map<String, Map<String, DataType>> map = getMap();
690691
if (map == null) {
691692
return;
692693
}
693694

694695
String dataTypeName = dataType.getName();
695696
String baseName = getBaseName(dataTypeName);
696-
Map<String, DataType> innerMap = map.get(baseName);
697-
if (innerMap == null) {
698-
innerMap = new HashMap<>();
699-
put(baseName, innerMap);
700-
}
697+
Map<String, DataType> innerMap = map.computeIfAbsent(baseName, b -> new HashMap<>());
701698
innerMap.put(dataTypeName, dataType);
702699
}
703700

704701
/**
705702
* Removes the data type with the given name from the conflict mapping structure. If the
706-
* mapping is currently not loaded then this method can safely do nothing.
703+
* mapping is currently not loaded then this method can safely do nothing. This method is
704+
* synchronized to provide thread safe access/manipulate of the map.
707705
* @param dataTypeName the name of the data type to remove from this mapping
708706
*/
709707
synchronized void removeDataTypeName(String dataTypeName) {
@@ -725,11 +723,19 @@ synchronized void removeDataTypeName(String dataTypeName) {
725723
* @return a list of all conflict named data types that would have the given base name if
726724
* no conflicts existed
727725
*/
728-
List<DataType> getDataTypesForBaseName(String baseName) {
726+
List<DataType> getDataTypesByBaseName(String baseName) {
727+
728+
// Note that the following call to get MUST NOT be in a synchronized block because
729+
// it may trigger a loading of the cache which requires a database lock and you
730+
// can't be synchronized on this class when acquiring a database lock or else a
731+
// deadlock will occur.
729732
Map<String, DataType> map = get(baseName);
730733
if (map == null) {
731734
return Collections.emptyList();
732735
}
736+
737+
// the following must be synchronized so that the implied iterator can complete without
738+
// another thread changing the map's values.
733739
synchronized (this) {
734740
return new ArrayList<>(map.values());
735741
}

Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3206,7 +3206,6 @@ List<DataType> getParentDataTypes(long childID) {
32063206
lock.acquire();
32073207
try {
32083208
long[] ids = parentChildAdapter.getParentIds(childID);
3209-
// TODO: consider deduping ids using Set
32103209
List<DataType> dts = new ArrayList<>();
32113210
for (long id : ids) {
32123211
DataType dt = getDataType(id);

Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ protected LazyLoadingCachingMap(Lock lock) {
4444
}
4545

4646
/**
47-
* This method will reload the map data from scratch.
47+
* This method will reload the map data from scratch. Subclass may assume that the database
48+
* lock has been acquired.
4849
* @return a map containing all current key, value pairs.
4950
*/
5051
protected abstract Map<K, V> loadMap();
@@ -113,7 +114,8 @@ private Map<K, V> getOrLoadMap() {
113114

114115
// We must get the database lock before calling loadMap(). Also, we can't get the
115116
// database lock while having the synchronization lock for this class or a deadlock can
116-
// occur. Note: all other places where the map is being used or manipulated, it must be done
117+
// occur, since the other methods may be called while the client has the db lock.
118+
// Note: all other places where the map is being used or manipulated, it must be done
117119
// while having the class's synchronization lock since the map itself is not thread safe.
118120
// It should be safe here since it creates a new map and then in one operation it sets it
119121
// as the map to be used elsewhere.

Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,13 @@ public interface Category extends Comparable<Category> {
5252

5353
/**
5454
* Get all data types in this category whose base name matches the base name of the given name.
55-
* The base name of a name if the first part of the string up to where the first ".conflict"
56-
* occurs. In other words find all data types whose name matches the given name once
57-
* any conflict suffixes have been removed from both both the given name and the data types
55+
* The base name of a name is the first part of the string up to where the first ".conflict"
56+
* occurs. In other words, finds all data types whose name matches the given name once
57+
* any conflict suffixes have been removed from both the given name and the data types
5858
* that are being scanned.
59-
* @param name the name for which to get conflict related data types in this category
59+
* @param name the name for which to get conflict related data types in this category. Note: the
60+
* name that is passed in will be normalized to its base name, so you may pass in names with .conflict
61+
* appended as a convenience.
6062
* @return a list of data types that have the same base name as the base name of the given name
6163
*/
6264
public abstract List<DataType> getDataTypesByBaseName(String name);

0 commit comments

Comments
 (0)