int send_blocking_req_internal( blocking_child * c, blocking_pipe_header * hdr, void * data ) { blocking_pipe_header * threadcopy; size_t payload_octets; REQUIRE(hdr != NULL); REQUIRE(data != NULL); DEBUG_REQUIRE(BLOCKING_REQ_MAGIC == hdr->magic_sig); if (hdr->octets <= sizeof(*hdr)) return 1; /* failure */ payload_octets = hdr->octets - sizeof(*hdr); ensure_workitems_empty_slot(c); if (NULL == c->thread_ref) { ensure_workresp_empty_slot(c); start_blocking_thread(c); } threadcopy = emalloc(hdr->octets); memcpy(threadcopy, hdr, sizeof(*hdr)); memcpy((char *)threadcopy + sizeof(*hdr), data, payload_octets); return queue_req_pointer(c, threadcopy); }
/* -------------------------------------------------------------------- * 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; }