mirror of
https://git.freebsd.org/src.git
synced 2026-01-16 23:02:24 +00:00
ithread: Allow some ithreads to sleep
Some ithreads need to hold a sleep mutex, e.g. when calling ACPI methods. Allow ithreads to be marked as sleepable when this is known to be safe. Reviewed by: markj, jhb Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D48283
This commit is contained in:
parent
ca81304f7c
commit
0863dc1035
4 changed files with 24 additions and 6 deletions
|
|
@ -27,7 +27,7 @@
|
|||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.Dd October 30, 2022
|
||||
.Dd January 24, 2025
|
||||
.Dt INTR_EVENT 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
|
|
@ -295,6 +295,14 @@ from the handler's source triggers.
|
|||
Presently, the
|
||||
.Dv INTR_ENTROPY
|
||||
flag is not valid for software interrupt handlers.
|
||||
The
|
||||
.Dv INTR_SLEEPABLE
|
||||
flag specifies that the interrupt ithread may sleep.
|
||||
Presently, the
|
||||
.Dv INTR_SLEEPABLE
|
||||
flag requires the
|
||||
.Dv INTR_EXCL
|
||||
flag to be set.
|
||||
.Ss Handler Callbacks
|
||||
Each
|
||||
.Vt struct intr_event
|
||||
|
|
|
|||
|
|
@ -610,6 +610,12 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
|
|||
if (ie == NULL || name == NULL || (handler == NULL && filter == NULL))
|
||||
return (EINVAL);
|
||||
|
||||
if ((flags & INTR_SLEEPABLE) != 0 && (flags & INTR_EXCL) == 0) {
|
||||
printf("%s: INTR_SLEEPABLE requires INTR_EXCL to be set\n",
|
||||
__func__);
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
/* Allocate and populate an interrupt handler structure. */
|
||||
ih = malloc(sizeof(struct intr_handler), M_ITHREAD, M_WAITOK | M_ZERO);
|
||||
ih->ih_filter = filter;
|
||||
|
|
@ -627,16 +633,18 @@ intr_event_add_handler(struct intr_event *ie, const char *name,
|
|||
if (flags & INTR_TYPE_NET)
|
||||
ih->ih_flags |= IH_NET;
|
||||
|
||||
/* We can only have one exclusive handler in a event. */
|
||||
/* We can only have one exclusive or sleepable handler in a event. */
|
||||
mtx_lock(&ie->ie_lock);
|
||||
if (!CK_SLIST_EMPTY(&ie->ie_handlers)) {
|
||||
if ((flags & INTR_EXCL) ||
|
||||
if ((flags & (INTR_EXCL | INTR_SLEEPABLE)) ||
|
||||
(CK_SLIST_FIRST(&ie->ie_handlers)->ih_flags & IH_EXCLUSIVE)) {
|
||||
mtx_unlock(&ie->ie_lock);
|
||||
free(ih, M_ITHREAD);
|
||||
return (EINVAL);
|
||||
}
|
||||
}
|
||||
if (flags & INTR_SLEEPABLE)
|
||||
ie->ie_flags |= IE_SLEEPABLE;
|
||||
|
||||
/* Create a thread if we need one. */
|
||||
while (ie->ie_thread == NULL && handler != NULL) {
|
||||
|
|
@ -1190,11 +1198,11 @@ static void
|
|||
ithread_execute_handlers(struct proc *p, struct intr_event *ie)
|
||||
{
|
||||
|
||||
/* Interrupt handlers should not sleep. */
|
||||
if (!(ie->ie_flags & IE_SOFT))
|
||||
/* Only specifically marked sleepable interrupt handlers can sleep. */
|
||||
if (!(ie->ie_flags & (IE_SOFT | IE_SLEEPABLE)))
|
||||
THREAD_NO_SLEEPING();
|
||||
intr_event_execute_handlers(p, ie);
|
||||
if (!(ie->ie_flags & IE_SOFT))
|
||||
if (!(ie->ie_flags & (IE_SOFT | IE_SLEEPABLE)))
|
||||
THREAD_SLEEPING_OK();
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ enum intr_type {
|
|||
INTR_EXCL = 256, /* exclusive interrupt */
|
||||
INTR_MPSAFE = 512, /* this interrupt is SMP safe */
|
||||
INTR_ENTROPY = 1024, /* this interrupt provides entropy */
|
||||
INTR_SLEEPABLE = 2048, /* this interrupt handler can sleep */
|
||||
INTR_MD1 = 4096, /* flag reserved for MD use */
|
||||
INTR_MD2 = 8192, /* flag reserved for MD use */
|
||||
INTR_MD3 = 16384, /* flag reserved for MD use */
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ struct intr_event {
|
|||
|
||||
/* Interrupt event flags kept in ie_flags. */
|
||||
#define IE_SOFT 0x000001 /* Software interrupt. */
|
||||
#define IE_SLEEPABLE 0x000002 /* Sleepable ithread */
|
||||
#define IE_ADDING_THREAD 0x000004 /* Currently building an ithread. */
|
||||
|
||||
/* Flags to pass to swi_sched. */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue