示例#1
0
/*
 * Cancel multiple timeouts at once.
 *
 * The timeouts' I've-been-fired indicators are reset,
 * unless timeouts[i].keep_indicator is true.
 *
 * This works like calling disable_timeout() multiple times.
 * Use this to reduce the number of GetCurrentTimestamp()
 * and setitimer() calls needed to cancel multiple timeouts.
 */
void
disable_timeouts(const DisableTimeoutParams *timeouts, int count)
{
	int			i;

	Assert(all_timeouts_initialized);

	/* Disable timeout interrupts for safety. */
	disable_alarm();

	/* Cancel the timeout(s). */
	for (i = 0; i < count; i++)
	{
		TimeoutId	id = timeouts[i].id;
		int			idx;

		Assert(all_timeouts[id].timeout_handler != NULL);

		idx = find_active_timeout(id);
		if (idx >= 0)
			remove_timeout_index(idx);

		if (!timeouts[i].keep_indicator)
			all_timeouts[id].indicator = false;
	}

	/* Reschedule the interrupt, if any timeouts remain active. */
	if (num_active_timeouts > 0)
		schedule_alarm(GetCurrentTimestamp());
}
示例#2
0
/*
 * Cancel the specified timeout.
 *
 * The timeout's I've-been-fired indicator is reset,
 * unless keep_indicator is true.
 *
 * When a timeout is canceled, any other active timeout remains in force.
 * It's not an error to disable a timeout that is not enabled.
 */
void
disable_timeout(TimeoutId id, bool keep_indicator)
{
	int			i;

	/* Assert request is sane */
	Assert(all_timeouts_initialized);
	Assert(all_timeouts[id].timeout_handler != NULL);

	/* Disable timeout interrupts for safety. */
	disable_alarm();

	/* Find the timeout and remove it from the active list. */
	i = find_active_timeout(id);
	if (i >= 0)
		remove_timeout_index(i);

	/* Mark it inactive, whether it was active or not. */
	if (!keep_indicator)
		all_timeouts[id].indicator = false;

	/* Reschedule the interrupt, if any timeouts remain active. */
	if (num_active_timeouts > 0)
		schedule_alarm(GetCurrentTimestamp());
}
示例#3
0
/*
 * Enable the specified timeout reason
 */
static void
enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
{
	int			i;

	/* Assert request is sane */
	Assert(all_timeouts_initialized);
	Assert(all_timeouts[id].timeout_handler != NULL);

	/*
	 * If this timeout was already active, momentarily disable it.  We
	 * interpret the call as a directive to reschedule the timeout.
	 */
	i = find_active_timeout(id);
	if (i >= 0)
		remove_timeout_index(i);

	/*
	 * Find out the index where to insert the new timeout.  We sort by
	 * fin_time, and for equal fin_time by priority.
	 */
	for (i = 0; i < num_active_timeouts; i++)
	{
		timeout_params *old_timeout = active_timeouts[i];

		if (fin_time < old_timeout->fin_time)
			break;
		if (fin_time == old_timeout->fin_time && id < old_timeout->index)
			break;
	}

	/*
	 * Mark the timeout active, and insert it into the active list.
	 */
	all_timeouts[id].indicator = false;
	all_timeouts[id].start_time = now;
	all_timeouts[id].fin_time = fin_time;

	insert_timeout(id, i);
}
示例#4
0
/*
 * Signal handler for SIGALRM
 *
 * Process any active timeout reasons and then reschedule the interrupt
 * as needed.
 */
static void
handle_sig_alarm(SIGNAL_ARGS)
{
	int			save_errno = errno;
	bool		save_ImmediateInterruptOK = ImmediateInterruptOK;

	/*
	 * We may be executing while ImmediateInterruptOK is true (e.g., when
	 * mainline is waiting for a lock).  If SIGINT or similar arrives while
	 * this code is running, we'd lose control and perhaps leave our data
	 * structures in an inconsistent state.  Disable immediate interrupts, and
	 * just to be real sure, bump the holdoff counter as well.  (The reason
	 * for this belt-and-suspenders-too approach is to make sure that nothing
	 * bad happens if a timeout handler calls code that manipulates
	 * ImmediateInterruptOK.)
	 *
	 * Note: it's possible for a SIGINT to interrupt handle_sig_alarm before
	 * we manage to do this; the net effect would be as if the SIGALRM event
	 * had been silently lost.  Therefore error recovery must include some
	 * action that will allow any lost interrupt to be rescheduled.  Disabling
	 * some or all timeouts is sufficient, or if that's not appropriate,
	 * reschedule_timeouts() can be called.  Also, the signal blocking hazard
	 * described below applies here too.
	 */
	ImmediateInterruptOK = false;
	HOLD_INTERRUPTS();

	/*
	 * SIGALRM is always cause for waking anything waiting on the process
	 * latch.  Cope with MyProc not being there, as the startup process also
	 * uses this signal handler.
	 */
	if (MyProc)
		SetLatch(&MyProc->procLatch);

	/*
	 * Fire any pending timeouts, but only if we're enabled to do so.
	 */
	if (alarm_enabled)
	{
		/*
		 * Disable alarms, just in case this platform allows signal handlers
		 * to interrupt themselves.  schedule_alarm() will re-enable if
		 * appropriate.
		 */
		disable_alarm();

		if (num_active_timeouts > 0)
		{
			TimestampTz now = GetCurrentTimestamp();

			/* While the first pending timeout has been reached ... */
			while (num_active_timeouts > 0 &&
				   now >= active_timeouts[0]->fin_time)
			{
				timeout_params *this_timeout = active_timeouts[0];

				/* Remove it from the active list */
				remove_timeout_index(0);

				/* Mark it as fired */
				this_timeout->indicator = true;

				/* And call its handler function */
				(*this_timeout->timeout_handler) ();

				/*
				 * The handler might not take negligible time (CheckDeadLock
				 * for instance isn't too cheap), so let's update our idea of
				 * "now" after each one.
				 */
				now = GetCurrentTimestamp();
			}

			/* Done firing timeouts, so reschedule next interrupt if any */
			schedule_alarm(now);
		}
	}

	/*
	 * Re-allow query cancel, and then try to service any cancel request that
	 * arrived meanwhile (this might in particular include a cancel request
	 * fired by one of the timeout handlers).  Since we are in a signal
	 * handler, we mustn't call ProcessInterrupts unless ImmediateInterruptOK
	 * is set; if it isn't, the cancel will happen at the next mainline
	 * CHECK_FOR_INTERRUPTS.
	 *
	 * Note: a longjmp from here is safe so far as our own data structures are
	 * concerned; but on platforms that block a signal before calling the
	 * handler and then un-block it on return, longjmping out of the signal
	 * handler leaves SIGALRM still blocked.  Error cleanup is responsible for
	 * unblocking any blocked signals.
	 */
	RESUME_INTERRUPTS();
	ImmediateInterruptOK = save_ImmediateInterruptOK;
	if (save_ImmediateInterruptOK)
		CHECK_FOR_INTERRUPTS();

	errno = save_errno;
}
示例#5
0
/*
 * Signal handler for SIGALRM
 *
 * Process any active timeout reasons and then reschedule the interrupt
 * as needed.
 */
static void
handle_sig_alarm(SIGNAL_ARGS)
{
	int			save_errno = errno;

	/*
	 * Bump the holdoff counter, to make sure nothing we call will process
	 * interrupts directly. No timeout handler should do that, but these
	 * failures are hard to debug, so better be sure.
	 */
	HOLD_INTERRUPTS();

	/*
	 * SIGALRM is always cause for waking anything waiting on the process
	 * latch.
	 */
	SetLatch(MyLatch);

	/*
	 * Fire any pending timeouts, but only if we're enabled to do so.
	 */
	if (alarm_enabled)
	{
		/*
		 * Disable alarms, just in case this platform allows signal handlers
		 * to interrupt themselves.  schedule_alarm() will re-enable if
		 * appropriate.
		 */
		disable_alarm();

		if (num_active_timeouts > 0)
		{
			TimestampTz now = GetCurrentTimestamp();

			/* While the first pending timeout has been reached ... */
			while (num_active_timeouts > 0 &&
				   now >= active_timeouts[0]->fin_time)
			{
				timeout_params *this_timeout = active_timeouts[0];

				/* Remove it from the active list */
				remove_timeout_index(0);

				/* Mark it as fired */
				this_timeout->indicator = true;

				/* And call its handler function */
				(*this_timeout->timeout_handler) ();

				/*
				 * The handler might not take negligible time (CheckDeadLock
				 * for instance isn't too cheap), so let's update our idea of
				 * "now" after each one.
				 */
				now = GetCurrentTimestamp();
			}

			/* Done firing timeouts, so reschedule next interrupt if any */
			schedule_alarm(now);
		}
	}

	RESUME_INTERRUPTS();

	errno = save_errno;
}