summary |
shortlog |
log |
commit | commitdiff |
review |
tree
raw |
patch |
inline | side by side (from parent 1:
8daf1d9)
gitlab #12
Change-Id: I0b0aec3bb71138a5033ae2337178c86ff04f5e59
@Override
public Type applyExact(MethodBuilder mb, Val[] parameters) {
@Override
public Type applyExact(MethodBuilder mb, Val[] parameters) {
- if(returnTypeDesc == null) {
+ if(returnTypeDesc == null || parameterTypeDescs == null) {
+ // This method may be called from multiple threads at the same time when returnTypeDesc
+ // and parameterTypeDescs are uninitialized. Double initialization is OK in this case,
+ // but because there are two fields, we have to check that both are initialized.
JavaTypeTranslator tt = mb.getJavaTypeTranslator();
returnTypeDesc = tt.toTypeDesc(returnType);
parameterTypeDescs = JavaTypeTranslator.filterVoid(
JavaTypeTranslator tt = mb.getJavaTypeTranslator();
returnTypeDesc = tt.toTypeDesc(returnType);
parameterTypeDescs = JavaTypeTranslator.filterVoid(
private static void finishModuleCompilation(String moduleName) {
PENDING_MODULES.get().remove(moduleName);
}
private static void finishModuleCompilation(String moduleName) {
PENDING_MODULES.get().remove(moduleName);
}
private class ModuleEntry extends UpdateListener implements Observable {
final String moduleName;
private class ModuleEntry extends UpdateListener implements Observable {
final String moduleName;
- THashSet<UpdateListener> listeners = new THashSet<UpdateListener>();
+ THashSet<UpdateListener> listeners = new THashSet<UpdateListener>(); // listeners == null is used as a marker that this entry is disposed
+ // should be handled only inside synchronized code
ModuleSource source;
Failable<Module> compilationResult;
ModuleSource source;
Failable<Module> compilationResult;
@Override
public void notifyAboutUpdate() {
@Override
public void notifyAboutUpdate() {
+ // There is a chance that another observable calls notifyAboutUpdate() before stopListening has been completed,
+ // but notifyAboutUpdate(ArrayList<UpdateListener>) lets only one thread to do the notification of dependencies
+ // by clearing listeners field.
+ stopListening();
ArrayList<UpdateListener> externalListeners = new ArrayList<UpdateListener>();
notifyAboutUpdate(externalListeners);
for(UpdateListener listener : externalListeners)
listener.notifyAboutUpdate();
}
ArrayList<UpdateListener> externalListeners = new ArrayList<UpdateListener>();
notifyAboutUpdate(externalListeners);
for(UpdateListener listener : externalListeners)
listener.notifyAboutUpdate();
}
- synchronized void notifyAboutUpdate(ArrayList<UpdateListener> externalListeners) {
- stopListening();
- if (listeners == null)
- return;
+ void notifyAboutUpdate(ArrayList<UpdateListener> externalListeners) {
+ THashSet<UpdateListener> listenersCopy;
+ synchronized(this) {
+ listenersCopy = listeners;
+ if (listenersCopy == null)
+ return;
+ listeners = null;
+ }
if(moduleCache.get(moduleName) == this) {
moduleCache.remove(moduleName);
if(SCLCompilerConfiguration.TRACE_MODULE_UPDATE) {
System.out.println("Invalidate " + moduleName);
if(moduleCache.get(moduleName) == this) {
moduleCache.remove(moduleName);
if(SCLCompilerConfiguration.TRACE_MODULE_UPDATE) {
System.out.println("Invalidate " + moduleName);
- for(UpdateListener l : listeners)
+ for(UpdateListener l : listenersCopy)
System.out.println(" " + l);
}
System.out.println(" " + l);
}
- THashSet<UpdateListener> listenersCopy = listeners;
- listeners = null;
- for(UpdateListener l : listenersCopy)
- l.stopListening();
for(UpdateListener l : listenersCopy)
for(UpdateListener l : listenersCopy)
- if(l instanceof ModuleEntry)
+ if(!l.stopListening())
+ ;
+ else if(l instanceof ModuleEntry)
((ModuleEntry)l).notifyAboutUpdate(externalListeners);
((ModuleEntry)l).notifyAboutUpdate(externalListeners);
externalListeners.add(l);
externalListeners.add(l);
}
public synchronized void dispose() {
}
public synchronized void dispose() {
- if (listeners != null)
- listeners.clear();
listeners = null;
stopListening();
source = null;
listeners = null;
stopListening();
source = null;
+ /**
+ * Flush clears module repository cache completely. It should not be called in
+ * normal operation, but may be useful during testing for clearing repositories
+ * that are statically defined.
+ */
public void flush() {
if (parentRepository != null)
parentRepository.flush();
public void flush() {
if (parentRepository != null)
parentRepository.flush();
- if (moduleCache != null) {
- for (ModuleEntry entry : moduleCache.values()) {
+ if (moduleCache != null)
+ for (ModuleEntry entry : moduleCache.values())
- }
- moduleCache.clear();
- }
+ /**
+ * Gets the map of all modules that have been currently compiled successfully.
+ * Not that the method does not return all possible modules in the source repository.
+ */
public Map<String, Module> getModules() {
Map<String, Module> result = new HashMap<>(moduleCache.size());
for (Map.Entry<String, ModuleEntry> entry : moduleCache.entrySet()) {
public Map<String, Module> getModules() {
Map<String, Module> result = new HashMap<>(moduleCache.size());
for (Map.Entry<String, ModuleEntry> entry : moduleCache.entrySet()) {
- * Stops listening changes.
+ * Stops listening changes. Returns true, if the listener was listening something.
- public void stopListening() {
+ public boolean stopListening() {
synchronized(observables) {
synchronized(observables) {
+ if(observables.isEmpty())
+ return false;
for(Observable observable : observables)
observable.removeListener(this);
observables.clear();
for(Observable observable : observables)
observable.removeListener(this);
observables.clear();