// File: /workspace/github_c_makefile_star2_O0/nilyang[P]redis-tdd-annotation/src/t_list.c
// Function: handleClientsBlockedOnLists
void handleClientsBlockedOnLists(void) {

    // 遍历整个 ready_keys 链表
    while(listLength(server.ready_keys) != 0) {
        list *l;

        /* Point server.ready_keys to a fresh list and save the current one
         * locally. This way as we run the old list we are free to call
         * signalListAsReady() that may push new elements in server.ready_keys
         * when handling clients blocked into BRPOPLPUSH. */
        // 备份旧的 ready_keys ，再给服务器端赋值一个新的
        l = server.ready_keys;
        server.ready_keys = listCreate();

        while(listLength(l) != 0) {

            // 取出 ready_keys 中的首个链表节点
            listNode *ln = listFirst(l);

            // 指向 readyList 结构
            readyList *rl = ln->value;

            /* First of all remove this key from db->ready_keys so that
             * we can safely call signalListAsReady() against this key. */
            // 从 ready_keys 中移除就绪的 key
            dictDelete(rl->db->ready_keys,rl->key);

            /* If the key exists and it's a list, serve blocked clients
             * with data. */
            // 获取键对象，这个对象应该是非空的，并且是列表
            robj *o = lookupKeyWrite(rl->db,rl->key);
            if (o != NULL && o->type == REDIS_LIST) {
                dictEntry *de;

                /* We serve clients in the same order they blocked for
                 * this key, from the first blocked to the last. */
                // 取出所有被这个 key 阻塞的客户端
                de = dictFind(rl->db->blocking_keys,rl->key);
                if (de) {
                    list *clients = dictGetVal(de);
                    int numclients = listLength(clients);

                    while(numclients--) {
                        // 取出客户端
                        listNode *clientnode = listFirst(clients);
                        redisClient *receiver = clientnode->value;

                        // 设置弹出的目标对象（只在 BRPOPLPUSH 时使用）
                        robj *dstkey = receiver->bpop.target;

                        // 从列表中弹出元素
                        // 弹出的位置取决于是执行 BLPOP 还是 BRPOP 或者 BRPOPLPUSH
                        int where = (receiver->lastcmd &&
                                     receiver->lastcmd->proc == blpopCommand) ?
                                    REDIS_HEAD : REDIS_TAIL;
                        robj *value = listTypePop(o,where);

                        // 还有元素可弹出（非 NULL）
                        if (value) {
                            /* Protect receiver->bpop.target, that will be
                             * freed by the next unblockClient()
                             * call. */
                            if (dstkey) incrRefCount(dstkey);

                            // 取消客户端的阻塞状态
                            unblockClient(receiver);

                            // 将值 value 推入到造成客户度 receiver 阻塞的 key 上
                            if (serveClientBlockedOnList(receiver,
                                rl->key,dstkey,rl->db,value,
                                where) == REDIS_ERR)
                            {
                                /* If we failed serving the client we need
                                 * to also undo the POP operation. */
                                    listTypePush(o,value,where);
                            }

                            if (dstkey) decrRefCount(dstkey);
                            decrRefCount(value);
                        } else {
                            // 如果执行到这里，表示还有至少一个客户端被键所阻塞
                            // 这些客户端要等待对键的下次 PUSH
                            break;
                        }
                    }
                }
                
                // 如果列表元素已经为空，那么从数据库中将它删除
                if (listTypeLength(o) == 0) dbDelete(rl->db,rl->key);
                /* We don't call signalModifiedKey() as it was already called
                 * when an element was pushed on the list. */
            }

            /* Free this item. */
            decrRefCount(rl->key);
            zfree(rl);
            listDelNode(l,ln);
        }
        listRelease(l); /* We have the new list on place at this point. */
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
leaq 0xc92d9(%rip), %rax     # 0x1138f8
movq 0x740(%rax), %rax
cmpq $0x0, 0x28(%rax)
je 0x4a868
leaq 0xc92c0(%rip), %rax     # 0x1138f8
movq 0x740(%rax), %rax
movq %rax, -0x8(%rbp)
callq 0x1fdb0
movq %rax, %rcx
leaq 0xc92a6(%rip), %rax     # 0x1138f8
movq %rcx, 0x740(%rax)
movq -0x8(%rbp), %rax
cmpq $0x0, 0x28(%rax)
je 0x4a85a
movq -0x8(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x10(%rbp)
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x18(%rbp)
movq -0x18(%rbp), %rax
movq (%rax), %rax
movq 0x18(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x23c30
movq -0x18(%rbp), %rax
movq (%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x3c090
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
je 0x4a832
movq -0x20(%rbp), %rax
movl (%rax), %eax
andl $0xf, %eax
cmpl $0x1, %eax
jne 0x4a832
movq -0x18(%rbp), %rax
movq (%rax), %rax
movq 0x10(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x23aa0
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0x4a80d
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq 0x28(%rax), %rax
movl %eax, -0x34(%rbp)
movl -0x34(%rbp), %eax
movl %eax, %ecx
addl $-0x1, %ecx
movl %ecx, -0x34(%rbp)
cmpl $0x0, %eax
je 0x4a80b
movq -0x30(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movq 0x10(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movq 0x130(%rax), %rax
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rcx
xorl %eax, %eax
cmpq $0x0, 0x48(%rcx)
movb %al, -0x61(%rbp)
je 0x4a76d
movq -0x48(%rbp), %rax
movq 0x48(%rax), %rax
leaq 0x10d(%rip), %rcx       # 0x4a870
cmpq %rcx, 0x8(%rax)
sete %al
movb %al, -0x61(%rbp)
movb -0x61(%rbp), %dl
movl $0x1, %eax
xorl %ecx, %ecx
testb $0x1, %dl
cmovnel %ecx, %eax
movl %eax, -0x54(%rbp)
movq -0x20(%rbp), %rdi
movl -0x54(%rbp), %esi
callq 0x47fa0
movq %rax, -0x60(%rbp)
cmpq $0x0, -0x60(%rbp)
je 0x4a804
cmpq $0x0, -0x50(%rbp)
je 0x4a7a7
movq -0x50(%rbp), %rdi
callq 0x3a3f0
movq -0x48(%rbp), %rdi
callq 0x81f80
movq -0x48(%rbp), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0x50(%rbp), %rdx
movq -0x18(%rbp), %rax
movq (%rax), %rcx
movq -0x60(%rbp), %r8
movl -0x54(%rbp), %r9d
callq 0x4a430
cmpl $-0x1, %eax
jne 0x4a7e9
movq -0x20(%rbp), %rdi
movq -0x60(%rbp), %rsi
movl -0x54(%rbp), %edx
callq 0x47e50
cmpq $0x0, -0x50(%rbp)
je 0x4a7f9
movq -0x50(%rbp), %rdi
callq 0x3aaa0
movq -0x60(%rbp), %rdi
callq 0x3aaa0
jmp 0x4a806
jmp 0x4a80b
jmp 0x4a70a
jmp 0x4a80d
movq -0x20(%rbp), %rdi
callq 0x480f0
cmpq $0x0, %rax
jne 0x4a830
movq -0x18(%rbp), %rax
movq (%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x3c4f0
jmp 0x4a832
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rdi
callq 0x3aaa0
movq -0x18(%rbp), %rdi
callq 0x2e3a0
movq -0x8(%rbp), %rdi
movq -0x10(%rbp), %rsi
callq 0x20170
jmp 0x4a659
movq -0x8(%rbp), %rdi
callq 0x1fe30
jmp 0x4a618
addq $0x70, %rsp
popq %rbp
retq
nop