+ clients = dictGetVal(de);
+ numclients = listLength(clients);
+
+ /* Try to handle the push as long as there are clients waiting for a push.
+ * Note that "numclients" is used because the list of clients waiting for a
+ * push on "key" is deleted by unblockClient() when empty.
+ *
+ * This loop will have more than 1 iteration when there is a BRPOPLPUSH
+ * that cannot push the target list because it does not contain a list. If
+ * this happens, it simply tries the next client waiting for a push. */
+ while (numclients--) {
+ ln = listFirst(clients);
+ redisAssertWithInfo(c,key,ln != NULL);
+ receiver = ln->value;
+ dstkey = receiver->bpop.target;
+
+ /* Protect receiver->bpop.target, that will be freed by
+ * the next unblockClientWaitingData() call. */
+ if (dstkey) incrRefCount(dstkey);
+
+ /* This should remove the first element of the "clients" list. */
+ unblockClientWaitingData(receiver);
+
+ if (dstkey == NULL) {
+ /* BRPOP/BLPOP */
+ addReplyMultiBulkLen(receiver,2);
+ addReplyBulk(receiver,key);
+ addReplyBulk(receiver,ele);
+ return 1; /* Serve just the first client as in B[RL]POP semantics */
+ } else {
+ /* BRPOPLPUSH, note that receiver->db is always equal to c->db. */
+ dstobj = lookupKeyWrite(receiver->db,dstkey);
+ if (!(dstobj && checkType(receiver,dstobj,REDIS_LIST))) {
+ rpoplpushHandlePush(c,receiver,dstkey,dstobj,ele);
+ decrRefCount(dstkey);
+ return 1;
+ }
+ decrRefCount(dstkey);
+ }
+ }
+
+ return 0;
+}
+
+int getTimeoutFromObjectOrReply(redisClient *c, robj *object, time_t *timeout) {
+ long tval;
+
+ if (getLongFromObjectOrReply(c,object,&tval,
+ "timeout is not an integer or out of range") != REDIS_OK)
+ return REDIS_ERR;
+
+ if (tval < 0) {
+ addReplyError(c,"timeout is negative");
+ return REDIS_ERR;
+ }
+
+ if (tval > 0) tval += time(NULL);
+ *timeout = tval;