/** * Pop an op from a queue. * * Locality: any thread. */ rd_kafka_op_t *rd_kafka_q_pop (rd_kafka_q_t *rkq, int timeout_ms, int32_t version) { rd_kafka_op_t *rko; if (timeout_ms == RD_POLL_INFINITE) timeout_ms = INT_MAX; mtx_lock(&rkq->rkq_lock); if (!rkq->rkq_fwdq) { do { /* Filter out outdated ops */ while ((rko = TAILQ_FIRST(&rkq->rkq_q)) && !(rko = rd_kafka_op_filter(rkq, rko))) ; if (rko) { /* Proper versioned op */ rd_kafka_q_deq0(rkq, rko); break; } /* No op, wait for one */ rd_ts_t pre = rd_clock(); if (cnd_timedwait_ms(&rkq->rkq_cond, &rkq->rkq_lock, timeout_ms) == thrd_timedout) { mtx_unlock(&rkq->rkq_lock); return NULL; } /* Remove spent time */ timeout_ms -= (int) (rd_clock()-pre) / 1000; if (timeout_ms < 0) timeout_ms = RD_POLL_NOWAIT; } while (timeout_ms != RD_POLL_NOWAIT); mtx_unlock(&rkq->rkq_lock); } else { rd_kafka_q_t *fwdq = rkq->rkq_fwdq; rd_kafka_q_keep(fwdq); /* Since the q_pop may block we need to release the parent * queue's lock. */ mtx_unlock(&rkq->rkq_lock); rko = rd_kafka_q_pop(fwdq, timeout_ms, version); rd_kafka_q_destroy(fwdq); } return rko; }
/** * Serve q like rd_kafka_q_serve() until an op is found that can be returned * as an event to the application. * * @returns the first event:able op, or NULL on timeout. * * Locality: any thread */ rd_kafka_op_t *rd_kafka_q_pop_serve (rd_kafka_q_t *rkq, int timeout_ms, int32_t version, int cb_type, int (*callback) (rd_kafka_t *rk, rd_kafka_op_t *rko, int cb_type, void *opaque), void *opaque) { rd_kafka_op_t *rko; if (timeout_ms == RD_POLL_INFINITE) timeout_ms = INT_MAX; mtx_lock(&rkq->rkq_lock); if (!rkq->rkq_fwdq) { do { /* Filter out outdated ops */ while ((rko = TAILQ_FIRST(&rkq->rkq_q)) && !(rko = rd_kafka_op_filter(rkq, rko, version))) ; if (rko) { int handled; /* Proper versioned op */ rd_kafka_q_deq0(rkq, rko); /* Ops with callbacks are considered handled * and we move on to the next op, if any. * Ops w/o callbacks are returned immediately */ if (callback) { handled = callback(rkq->rkq_rk, rko, cb_type, opaque); if (handled) { rd_kafka_op_destroy(rko); rko = NULL; } } else handled = 0; if (!handled) break; } /* No op, wait for one */ rd_ts_t pre = rd_clock(); if (cnd_timedwait_ms(&rkq->rkq_cond, &rkq->rkq_lock, timeout_ms) == thrd_timedout) { mtx_unlock(&rkq->rkq_lock); return NULL; } /* Remove spent time */ timeout_ms -= (int) (rd_clock()-pre) / 1000; if (timeout_ms < 0) timeout_ms = RD_POLL_NOWAIT; } while (timeout_ms != RD_POLL_NOWAIT); mtx_unlock(&rkq->rkq_lock); } else { rd_kafka_q_t *fwdq = rkq->rkq_fwdq; rd_kafka_q_keep(fwdq); /* Since the q_pop may block we need to release the parent * queue's lock. */ mtx_unlock(&rkq->rkq_lock); rko = rd_kafka_q_pop_serve(fwdq, timeout_ms, version, cb_type, callback, opaque); rd_kafka_q_destroy(fwdq); } return rko; }