Files
nuttx/sched/irq/irq_attach_thread.c
pangzhen1andXiang Xiao 7b154402fb sched/irq: Consolidate IRQ bounds checking into IRQ_TO_NDX macro
Previously, IRQ bounds checking (irq >= 0 && irq < NR_IRQS) was duplicated
across multiple IRQ subsystem functions before calling IRQ_TO_NDX(). This
led to code duplication and inconsistency.

This patch consolidates all IRQ bounds checking into the IRQ_TO_NDX() macro
itself, which now returns -EINVAL for out-of-bounds IRQ numbers. This approach:

1. Eliminates duplicated bounds checking code
2. Ensures consistent error handling across all IRQ functions
3. Simplifies caller code - just check if IRQ_TO_NDX() returns negative
4. Makes the macro behavior more predictable and self-contained

Changes:
- Modified IRQ_TO_NDX() to check (irq < 0 || irq >= NR_IRQS) and return -EINVAL
- Removed redundant IRQ range checks in irq_attach(), irq_attach_thread(),
  irq_attach_wqueue(), and irqchain_detach()
- Simplified error handling to check ndx < 0 after IRQ_TO_NDX() call

This consolidation reduces code size and improves maintainability while
preserving all existing error checking functionality.

Signed-off-by: pangzhen1 <pangzhen1@xiaomi.com>
2026-01-28 13:35:30 +08:00

201 lines
5.6 KiB
C

/****************************************************************************
* sched/irq/irq_attach_thread.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <errno.h>
#include <stdio.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/kthread.h>
#include "irq/irq.h"
#include "sched/sched.h"
/****************************************************************************
* Private Types
****************************************************************************/
/* This is the type of the list of interrupt handlers, one for each IRQ.
* This type provided all of the information necessary to irq_dispatch to
* transfer control to interrupt handlers after the occurrence of an
* interrupt.
*/
struct irq_thread_info_s
{
xcpt_t handler; /* Address of the interrupt handler */
FAR void *arg; /* The argument provided to the interrupt handler. */
FAR sem_t *sem; /* irq sem used to notify irq thread */
};
/****************************************************************************
* Private Functions
****************************************************************************/
/* Default interrupt handler for threaded interrupts.
* Useful for oneshot interrupts.
*/
static int irq_thread_default_handler(int irq, FAR void *context,
FAR void *arg)
{
FAR struct irq_thread_info_s *info = arg;
int ret = IRQ_WAKE_THREAD;
if (info->handler != NULL)
{
ret = info->handler(irq, context, info->arg);
}
if (ret == IRQ_WAKE_THREAD)
{
nxsem_post(info->sem);
ret = OK;
}
return ret;
}
static int isr_thread_main(int argc, FAR char *argv[])
{
int irq = atoi(argv[1]);
xcpt_t isr = (xcpt_t)((uintptr_t)strtoul(argv[2], NULL, 16));
xcpt_t isrthread = (xcpt_t)((uintptr_t)strtoul(argv[3], NULL, 16));
FAR void *arg = (FAR char *)((uintptr_t)strtoul(argv[4], NULL, 16));
struct irq_thread_info_s info;
sem_t sem;
info.sem = &sem;
info.arg = arg;
info.handler = isr;
nxsem_init(&sem, 0, 0u);
irq_attach(irq, irq_thread_default_handler, &info);
#if !defined(CONFIG_ARCH_NOINTC)
up_enable_irq(irq);
#endif
for (; ; )
{
if (nxsem_wait_uninterruptible(&sem) < 0)
{
continue;
}
isrthread(irq, NULL, arg);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: irq_attach_thread
*
* Description:
* Configure the IRQ subsystem so that IRQ number 'irq' is dispatched to
* 'isrthread' and up_enable_irq will be invoked after isrthread started.
*
* Input Parameters:
* irq - Irq num
* isr - Function to be called when the IRQ occurs, called in interrupt
* context.
* If isr is NULL, isrthread will be called.
* isrthread - called in thread context, If the isrthread is NULL,
* then the ISR is being detached.
* arg - privdate data
* priority - Priority of the new task
* stack_size - size (in bytes) of the stack needed
*
* Returned Value:
* Zero on success; a negated errno value on failure.
*
****************************************************************************/
int irq_attach_thread(int irq, xcpt_t isr, xcpt_t isrthread, FAR void *arg,
int priority, int stack_size)
{
int ret = OK;
#if NR_IRQS > 0
static pid_t irq_thread_pid[NR_IRQS];
FAR char *argv[5];
char arg1[32]; /* irq */
char arg2[32]; /* isr */
char arg3[32]; /* isrthread */
char arg4[32]; /* arg */
pid_t pid;
int ndx = IRQ_TO_NDX(irq);
if (ndx < 0)
{
ret = ndx;
}
else if(isrthread == NULL)
{
/* If the isrthread is NULL, then the ISR is being detached. */
irq_detach(irq);
DEBUGASSERT(irq_thread_pid[ndx] != 0);
kthread_delete(irq_thread_pid[ndx]);
irq_thread_pid[ndx] = 0;
}
else if(irq_thread_pid[ndx] != 0)
{
ret = -EINVAL;
}
else
{
snprintf(arg1, sizeof(arg1), "%d", irq);
snprintf(arg2, sizeof(arg2), "%p", isr);
snprintf(arg3, sizeof(arg3), "%p", isrthread);
snprintf(arg4, sizeof(arg4), "%p", arg);
argv[0] = arg1;
argv[1] = arg2;
argv[2] = arg3;
argv[3] = arg4;
argv[4] = NULL;
pid = kthread_create("isr_thread", priority, stack_size,
isr_thread_main, argv);
if (pid < 0)
{
ret = pid;
}
irq_thread_pid[ndx] = pid;
}
#endif /* NR_IRQS */
return ret;
}