blob: 4baaf8154b3e7ff9378de3bb9d65f3a441519bc6 [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
#pragma once
#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);
thread_t* current_thread = get_current_thread();
// Save the value of preempt_pending for restoring later.
state->old_preempt_pending = current_thread->preempt_pending;
// Clear preempt_pending so that we can later detect whether a
// reschedule is made pending during the interrupt handler.
current_thread->preempt_pending = false;
thread_preempt_disable();
}
// 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) {
thread_t* current_thread = get_current_thread();
thread_preempt_reenable_no_resched();
bool do_preempt = false;
if (current_thread->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 (thread_preempt_disable_count() == 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.
current_thread->preempt_pending = state->old_preempt_pending;
}
arch_set_blocking_disallowed(false);
return do_preempt;
}