blob: b8daec093de5bb8d2bc8017034bebe8ee4d1b747 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#ifndef ZIRCON_KERNEL_INCLUDE_KERNEL_INTERRUPT_H_
#define ZIRCON_KERNEL_INCLUDE_KERNEL_INTERRUPT_H_
#include <kernel/thread.h>
typedef struct int_handler_saved_state {
bool old_preempt_pending;
} int_handler_saved_state_t;
// Start the main part of handling an interrupt in which preemption and
// blocking are disabled. This must be matched by a later call to
// int_handler_finish().
static inline void int_handler_start(int_handler_saved_state_t* state) {
arch_set_blocking_disallowed(true);
PreemptionState& preemption_state = Thread::Current::preemption_state();
// Save the value of preempt_pending for restoring later.
state->old_preempt_pending = preemption_state.preempt_pending();
// Clear preempt_pending so that we can later detect whether a
// reschedule is made pending during the interrupt handler.
preemption_state.preempt_pending() = false;
preemption_state.PreemptDisable();
}
// Leave the main part of handling an interrupt, following a call to
// int_handler_start().
//
// This returns whether the caller should call thread_preempt().
static inline bool int_handler_finish(int_handler_saved_state_t* state) {
PreemptionState& preemption_state = Thread::Current::preemption_state();
preemption_state.PreemptReenableNoResched();
bool do_preempt = false;
if (preemption_state.preempt_pending()) {
// A preemption became pending during the interrupt handler. If
// preemption is now enabled, indicate that the caller should now
// do the preemption.
if (preemption_state.PreemptDisableCount() == 0) {
do_preempt = true;
}
} else {
// No preemption became pending during the interrupt handler.
//
// Restore the old value of preempt_pending. This may be true if
// resched_disable is non-zero.
preemption_state.preempt_pending() = state->old_preempt_pending;
}
arch_set_blocking_disallowed(false);
return do_preempt;
}
#endif // ZIRCON_KERNEL_INCLUDE_KERNEL_INTERRUPT_H_