Esempio n. 1
0
/* --------------------------------------------------------------------
 * 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;
}
Esempio n. 2
0
/* --------------------------------------------------------------------
 * sleep for a given time or until the wakup semaphore is tickled.
 */
int
worker_sleep(
	blocking_child *	c,
	time_t			seconds
	)
{
	struct timespec	until;
	int		rc;

# ifdef HAVE_CLOCK_GETTIME
	if (0 != clock_gettime(CLOCK_REALTIME, &until)) {
		msyslog(LOG_ERR, "worker_sleep: clock_gettime() failed: %m");
		return -1;
	}
# else
	if (0 != getclock(TIMEOFDAY, &until)) {
		msyslog(LOG_ERR, "worker_sleep: getclock() failed: %m");
		return -1;
	}
# endif
	until.tv_sec += seconds;
	rc = wait_for_sem(c->wake_scheduled_sleep, &until);
	if (0 == rc)
		return -1;
	if (-1 == rc && ETIMEDOUT == errno)
		return 0;
	msyslog(LOG_ERR, "worker_sleep: sem_timedwait: %m");
	return -1;
}
Esempio n. 3
0
blocking_pipe_header *
receive_blocking_req_internal(
	blocking_child *	c
	)
{
	blocking_pipe_header *	req;
	int			rc;

	/*
	 * Child blocks here when idle.  SysV semaphores maintain a
	 * count and release from sem_wait() only when it reaches 0.
	 */
	do {
		rc = wait_for_sem(c->blocking_req_ready, NULL);
	} while (-1 == rc && EINTR == errno);
	INSIST(0 == rc);

	req = c->workitems[c->next_workeritem];
	INSIST(NULL != req);
	c->workitems[c->next_workeritem] = NULL;
	c->next_workeritem = (1 + c->next_workeritem) %
				c->workitems_alloc;

	if (CHILD_EXIT_REQ == req) {	/* idled out */
		send_blocking_resp_internal(c, CHILD_GONE_RESP);
		req = NULL;
	}

	return req;
}
Esempio n. 4
0
blocking_pipe_header *
receive_blocking_req_internal(
	blocking_child *	c
	)
{
	blocking_pipe_header *	req;
	int			rc;

	/*
	 * Child blocks here when idle.  SysV semaphores maintain a
	 * count and release from sem_wait() only when it reaches 0.
	 * Windows auto-reset events are simpler, and multiple SetEvent
	 * calls before any thread waits result in a single wakeup.
	 * On Windows, the child drains all workitems each wakeup, while
	 * with SysV semaphores wait_sem() is used before each item.
	 */
#ifdef SYS_WINNT
	while (NULL == c->workitems[c->next_workeritem]) {
		/* !!!! SetEvent(c->child_is_blocking); */
		rc = wait_for_sem(c->blocking_req_ready, NULL);
		INSIST(0 == rc);
		/* !!!! ResetEvent(c->child_is_blocking); */
	}
#else
	do {
		rc = wait_for_sem(c->blocking_req_ready, NULL);
	} while (-1 == rc && EINTR == errno);
	INSIST(0 == rc);
#endif

	req = c->workitems[c->next_workeritem];
	INSIST(NULL != req);
	c->workitems[c->next_workeritem] = NULL;
	c->next_workeritem = (1 + c->next_workeritem) %
				c->workitems_alloc;

	if (CHILD_EXIT_REQ == req) {	/* idled out */
		send_blocking_resp_internal(c, CHILD_GONE_RESP);
		req = NULL;
	}

	return req;
}
Esempio n. 5
0
/* --------------------------------------------------------------------
 * 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;
}
Esempio n. 6
0
void *thread_trigger(void *arg) {

    int trigger_no = *(int *) arg;

    while (!shutdown) {
        if (wait_for_sem(&trigger_update_sems[trigger_no]) == -1) {
            continue;
        }
        update_trigger(trigger_no);
        sem_post(&trigger_updated_sems[trigger_no]);

        notify_actions();
    }

    exit_thread("trigger", trigger_no, triggers[trigger_no].name);
}
Esempio n. 7
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;
}
Esempio n. 8
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;
}
Esempio n. 9
0
int
worker_sleep(
	blocking_child *	c,
	time_t			seconds
	)
{
	struct timespec	until;
	int		rc;

	if (0 != clock_gettime(CLOCK_REALTIME, &until)) {
		msyslog(LOG_ERR, "worker_sleep: clock_gettime() failed: %m");
		return -1;
	}
	until.tv_sec += seconds;
	do {
		rc = wait_for_sem(c->wake_scheduled_sleep, &until);
	} while (-1 == rc && EINTR == errno);
	if (0 == rc)
		return -1;
	if (-1 == rc && ETIMEDOUT == errno)
		return 0;
	msyslog(LOG_ERR, "worker_sleep: sem_timedwait: %m");
	return -1;
}