/* -------------------------------------------------------------------- * Push a response into the return queue and eventually tickle the * receiver. */ int send_blocking_resp_internal( blocking_child * c, blocking_pipe_header * resp ) { size_t qhead; int empty; /* >>>> ACCESS LOCKING STARTS >>>> */ wait_for_sem(c->accesslock, NULL); empty = ensure_workresp_empty_slot(c); qhead = c->head_response; c->responses[qhead % c->responses_alloc] = resp; c->head_response = 1 + qhead; tickle_sem(c->accesslock); /* <<<< ACCESS LOCKING ENDS <<<< */ /* queue consumer wake-up notification */ if (empty) { # ifdef WORK_PIPE write(c->resp_write_pipe, "", 1); # else tickle_sem(c->responses_pending); # endif } return 0; }
/* -------------------------------------------------------------------- * queue_req_pointer() - append a work item or idle exit request to * blocking_workitems[]. Employ proper locking. */ static int queue_req_pointer( blocking_child * c, blocking_pipe_header * hdr ) { size_t qhead; /* >>>> ACCESS LOCKING STARTS >>>> */ wait_for_sem(c->accesslock, NULL); ensure_workitems_empty_slot(c); qhead = c->head_workitem; c->workitems[qhead % c->workitems_alloc] = hdr; c->head_workitem = 1 + qhead; tickle_sem(c->accesslock); /* <<<< ACCESS LOCKING ENDS <<<< */ /* queue consumer wake-up notification */ tickle_sem(c->workitems_pending); return 0; }
/* -------------------------------------------------------------------- * Wake up a worker that takes a nap. */ void interrupt_worker_sleep(void) { u_int idx; blocking_child * c; for (idx = 0; idx < blocking_children_alloc; idx++) { c = blocking_children[idx]; if (NULL == c || NULL == c->wake_scheduled_sleep) continue; tickle_sem(c->wake_scheduled_sleep); } }
int send_blocking_resp_internal( blocking_child * c, blocking_pipe_header * resp ) { ensure_workresp_empty_slot(c); c->responses[c->next_response] = resp; c->next_response = (1 + c->next_response) % c->responses_alloc; #ifdef WORK_PIPE write(c->resp_write_pipe, "", 1); #else tickle_sem(c->blocking_response_ready); #endif return 0; }
/* * queue_req_pointer() - append a work item or idle exit request to * blocking_workitems[]. */ static int queue_req_pointer( blocking_child * c, blocking_pipe_header * hdr ) { c->workitems[c->next_workitem] = hdr; c->next_workitem = (1 + c->next_workitem) % c->workitems_alloc; /* * We only want to signal the wakeup event if the child is * blocking on it, which is indicated by setting the blocking * event. Wait with zero timeout to test. */ /* !!!! if (WAIT_OBJECT_0 == WaitForSingleObject(c->child_is_blocking, 0)) */ tickle_sem(c->blocking_req_ready); return 0; }
/* -------------------------------------------------------------------- * Fetch the next response from the return queue. In case of signalling * via pipe, make sure the pipe is flushed, too. */ blocking_pipe_header * receive_blocking_resp_internal( blocking_child * c ) { blocking_pipe_header * removed; size_t qhead, qtail, slot; #ifdef WORK_PIPE int rc; char scratch[32]; do rc = read(c->resp_read_pipe, scratch, sizeof(scratch)); while (-1 == rc && EINTR == errno); #endif /* >>>> ACCESS LOCKING STARTS >>>> */ wait_for_sem(c->accesslock, NULL); qhead = c->head_response; qtail = c->tail_response; for (removed = NULL; !removed && (qhead != qtail); ++qtail) { slot = qtail % c->responses_alloc; removed = c->responses[slot]; c->responses[slot] = NULL; } c->tail_response = qtail; tickle_sem(c->accesslock); /* <<<< ACCESS LOCKING ENDS <<<< */ if (NULL != removed) { DEBUG_ENSURE(CHILD_GONE_RESP == removed || BLOCKING_RESP_MAGIC == removed->magic_sig); } if (CHILD_GONE_RESP == removed) { cleanup_after_child(c); removed = NULL; } return removed; }
/* -------------------------------------------------------------------- * Wait for the 'incoming queue no longer empty' signal, lock the shared * structure and dequeue an item. */ blocking_pipe_header * receive_blocking_req_internal( blocking_child * c ) { blocking_pipe_header * req; size_t qhead, qtail; req = NULL; do { /* wait for tickle from the producer side */ wait_for_sem(c->workitems_pending, NULL); /* >>>> ACCESS LOCKING STARTS >>>> */ wait_for_sem(c->accesslock, NULL); qhead = c->head_workitem; do { qtail = c->tail_workitem; if (qhead == qtail) break; c->tail_workitem = qtail + 1; qtail %= c->workitems_alloc; req = c->workitems[qtail]; c->workitems[qtail] = NULL; } while (NULL == req); tickle_sem(c->accesslock); /* <<<< ACCESS LOCKING ENDS <<<< */ } while (NULL == req); INSIST(NULL != req); if (CHILD_EXIT_REQ == req) { /* idled out */ send_blocking_resp_internal(c, CHILD_GONE_RESP); req = NULL; } return req; }