-
Notifications
You must be signed in to change notification settings - Fork 100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix ApplicationListeners being skipped #158
Fix ApplicationListeners being skipped #158
Conversation
Isn't this kind of a memory leak? If you call add and remove in a loop, it will OOM eventually. |
Well, my reasoning was since it is used rarely and also too much changes, it would do the trick, but now that you mention it... I'll get back to it. |
Okay, if you don't mind making public abstract class AbstractApplication implements Application{
protected final Seq<ApplicationListener> listeners = new Seq<>();
protected boolean runningListeners = false;
protected final Seq<ApplicationListener> removing = new Seq<>();
@Override
public Seq<ApplicationListener> getListeners(){
return listeners;
}
@Override
public void addListener(ApplicationListener listener){
synchronized(listeners){
listeners.add(listener);
removing.remove(listener);
}
}
@Override
public void removeListener(ApplicationListener listener){
synchronized(listeners){
if (runningListeners) removing.add(listener);
else listeners.remove(listener);
}
}
@Override
public void forEachListener(Cons<ApplicationListener> cons){
synchronized(listeners){
runningListeners = true;
try{
for(ApplicationListener listener : listeners){
if(removing.contains(listener)) continue;
cons.get(listener);
}
}finally{
runningListeners = false;
}
listeners.removeAll(removing);
removing.clear();
}
}
} The |
Looks like I made things too complicated again, the solution was simply removing the listener when it's guaranteed the others are not used. |
Basically, when a
ApplicationListener
usesApplication#removeListener
while the application is iterating over the listener seq, the next listener in the iteration is skipped.This issue hasn't been noticed for so long since the only use of it is within the
dispose
ofTimer.TimerThread
, and that it runs before listeners that doesn't usedispose
.But in BE servers, it prevents my plugins from exiting since
Timer
is used early byBeControl
, running before my plugin shutdown listener thus skipping it.The fix is simply replacing the removed listener by an empty one.