Skip to content
This repository has been archived by the owner on Dec 28, 2019. It is now read-only.

Another deadlock, CHARACTER_EFF #263

Open
Arufonsu opened this issue Oct 20, 2018 · 8 comments
Open

Another deadlock, CHARACTER_EFF #263

Arufonsu opened this issue Oct 20, 2018 · 8 comments
Labels

Comments

@Arufonsu
Copy link
Contributor

Arufonsu commented Oct 20, 2018

imagen

imagen

@asafgb
Copy link
Contributor

asafgb commented Oct 20, 2018

can you show in your code:
in File:
src>client> maplecharacter>

(print from line 2650-2700)

@Arufonsu
Copy link
Contributor Author

2630-2703 from maplecharacter:

    public void buffExpireTask() {
        if (buffExpireTask == null) {
            buffExpireTask = TimerManager.getInstance().register(new Runnable() {
                @Override
                public void run() {
                    Set<Entry<Integer, Long>> es;
                    List<MapleBuffStatValueHolder> toCancel = new ArrayList<>();
                    
                    effLock.lock();
                    chrLock.lock();
                    try {
                        es = new LinkedHashSet<>(buffExpires.entrySet());
                        
                        long curTime = Server.getInstance().getCurrentTime();
                        for(Entry<Integer, Long> bel : es) {
                            if(curTime >= bel.getValue()) {
                                toCancel.add(buffEffects.get(bel.getKey()).entrySet().iterator().next().getValue());    //rofl
                            }
                        }
                    } finally {
                        chrLock.unlock();
                        effLock.unlock();
                    }
                    
                    for(MapleBuffStatValueHolder mbsvh : toCancel) {
                        cancelEffect(mbsvh.effect, false, mbsvh.startTime);
                    }
                }
            }, 1500);
        }
    }
    
    public void cancelSkillCooldownTask() {
        if (skillCooldownTask != null) {
            skillCooldownTask.cancel(false);
            skillCooldownTask = null;
        }
    }

    public void skillCooldownTask() {
        if (skillCooldownTask == null) {
            skillCooldownTask = TimerManager.getInstance().register(new Runnable() {
                @Override
                public void run() {
                    Set<Entry<Integer, MapleCoolDownValueHolder>> es;
                    
                    effLock.lock();
                    chrLock.lock();
                    try {
                        es = new LinkedHashSet<>(coolDowns.entrySet());
                    } finally {
                        chrLock.unlock();
                        effLock.unlock();
                    }
                    
                    long curTime = System.currentTimeMillis();
                    for(Entry<Integer, MapleCoolDownValueHolder> bel : es) {
                        MapleCoolDownValueHolder mcdvh = bel.getValue();
                        if(curTime >= mcdvh.startTime + mcdvh.length) {
                            removeCooldown(mcdvh.skillId);
                            client.announce(MaplePacketCreator.skillCooldown(mcdvh.skillId, 0));
                        }
                    }
                }
            }, 1500);
        }
    }
    
    public void cancelExpirationTask() {
        if (itemExpireTask != null) {
            itemExpireTask.cancel(false);
            itemExpireTask = null;
        }
    }

@asafgb
Copy link
Contributor

asafgb commented Oct 20, 2018

Just wonder
in which case it happen
you did some skill and then logout? maybe

@asafgb
Copy link
Contributor

asafgb commented Oct 20, 2018

I tell you what i think that happen:
you use some skill with cooldown
and then there skillCooldownTask that runnable at any time
there function that called: "cancelSkillCooldownTask"
that cansel that Task runnable,
even if the CharLock is locked
and the cancelSkillCooldownTask is run when

  1. you change channel

  2. you enter to CashShop

but there 0.0001% that really happen because you need to have a lot Skill in cooldown that
es = new LinkedHashSet<>(coolDowns.entrySet());
still didnt finish and while it still running
you did one of thing i said before
that can create DeadLock
@ronancpl what you think?

@ronancpl
Copy link
Owner

ronancpl commented Oct 20, 2018

I think this:

Somewhere around the server execution task, chrLock (or something else) is being locked before effLock. The locking chain pattern always expects one lock type to be locked before another, in order, else a deadlock configures.

The pattern is: effLock always precedes chrLock. However, in some point on the code, chrLock or some other lock is preceding effLock. That's a fault, and will generate deadlock sometime.

@asafgb
Copy link
Contributor

asafgb commented Oct 20, 2018

but the error on the server
return effLock as throw exeption

@resinate
Copy link

resinate commented Nov 6, 2018

                effLock.lock();
                chrLock.lock();
                try {
                    es = new LinkedHashSet<>(coolDowns.entrySet());
                } finally {
                    chrLock.unlock();
                    effLock.unlock();
                }

whats the point of double locks in 1st place?

@ronancpl
Copy link
Owner

ronancpl commented Nov 6, 2018

Some design decisions were made around effLocks that, since some effLock-protected code eventually executes chrLock locking, for whatever reason it is, now every effLock requires immediate chrLock as well to secure effLock-into-chrLock stability.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

4 participants