HeavenMS icon indicating copy to clipboard operation
HeavenMS copied to clipboard

Another deadlock, CHARACTER_EFF

Open Arufonsu opened this issue 7 years ago • 8 comments

imagen

imagen

Arufonsu avatar Oct 20 '18 14:10 Arufonsu

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

(print from line 2650-2700)

asafgb avatar Oct 20 '18 17:10 asafgb

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;
        }
    }

Arufonsu avatar Oct 20 '18 17:10 Arufonsu

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

asafgb avatar Oct 20 '18 18:10 asafgb

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?

asafgb avatar Oct 20 '18 19:10 asafgb

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.

ronancpl avatar Oct 20 '18 19:10 ronancpl

but the error on the server return effLock as throw exeption

asafgb avatar Oct 20 '18 20:10 asafgb

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

whats the point of double locks in 1st place?

resinate avatar Nov 06 '18 18:11 resinate

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.

ronancpl avatar Nov 06 '18 22:11 ronancpl