int ub_wait(struct ub_ctx* ctx) { int err; ub_callback_t cb; void* cbarg; struct ub_result* res; int r; uint8_t* msg; uint32_t len; /* this is basically the same loop as _process(), but with changes. * holds the rrpipe lock and waits with tube_wait */ while(1) { lock_basic_lock(&ctx->rrpipe_lock); lock_basic_lock(&ctx->cfglock); if(ctx->num_async == 0) { lock_basic_unlock(&ctx->cfglock); lock_basic_unlock(&ctx->rrpipe_lock); break; } lock_basic_unlock(&ctx->cfglock); /* keep rrpipe locked, while * o waiting for pipe readable * o parsing message * o possibly decrementing num_async * do callback without lock */ r = tube_wait(ctx->rr_pipe); if(r) { r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1); if(r == 0) { lock_basic_unlock(&ctx->rrpipe_lock); return UB_PIPE; } if(r == -1) { lock_basic_unlock(&ctx->rrpipe_lock); continue; } r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res); lock_basic_unlock(&ctx->rrpipe_lock); free(msg); if(r == 0) return UB_PIPE; if(r == 2) (*cb)(cbarg, err, res); } else { lock_basic_unlock(&ctx->rrpipe_lock); } } return UB_NOERROR; }
int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len, int nonblock) { struct tube_res_list* item = NULL; verbose(VERB_ALGO, "tube read_msg %s", nonblock?"nonblock":"blocking"); *buf = NULL; if(!tube_poll(tube)) { verbose(VERB_ALGO, "tube read_msg nodata"); /* nothing ready right now, wait if we want to */ if(nonblock) return -1; /* would block waiting for items */ if(!tube_wait(tube)) return 0; } lock_basic_lock(&tube->res_lock); if(tube->res_list) { item = tube->res_list; tube->res_list = item->next; if(tube->res_last == item) { /* the list is now empty */ tube->res_last = NULL; verbose(VERB_ALGO, "tube read_msg lastdata"); if(!WSAResetEvent(tube->event)) { log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError())); } } } lock_basic_unlock(&tube->res_lock); if(!item) return 0; /* would block waiting for items */ *buf = item->buf; *len = item->len; free(item); verbose(VERB_ALGO, "tube read_msg len %d", (int)*len); return 1; }