Disconnection __linux in Linux

Source: Internet
Author: User
Tags goto

Why do I have to interrupt the process?
in Linux, interrupts have the highest priority. Whenever an interrupt event is generated at any point, the kernel immediately executes the appropriate interrupt handler, and waits until all pending interrupts and soft interrupts are processed to perform normal tasks, which may result in immediate tasks not being processed in a timely manner. Interrupts are run as kernel threads and given different real-time priorities, and real-time tasks can have a higher priority than the thread threads. In this way, a real-time task with the highest priority can be prioritized, even if there is a real time guarantee under severe load. However, not all interrupts can be threaded, such as clock interruption, mainly used to maintain system time and timer, in which the timer is the pulse of the operating system, once threaded, it may be suspended, so the consequences will be disastrous, so should not be threaded.

In the process of disconnection in the implementation method is: For IRQ, in the kernel initialization phase init (which is defined in the kernel source tree file init/main.c) call Init_hardirqs (the function in the kernel source tree file kernel/irq/ MANAGE.C) to create a kernel thread for each IRQ, an interrupt with an IRQ number of 0 gives the real-time priority 49,IRQ number 1 The given real-time priority 48, and so on until 25, so that any IRQ thread has a minimum real-time priority of 25. The original DO_IRQ is broken down into two parts, the schema is related to a arch/*/kernel/irq.c file, the name is still DO_IRQ, and the part of the architecture is placed in the position of the IRQ subsystem kernel/irq/handle.c, the name is _DO _irq. When the interrupt occurs, the CPU executes the DO_IRQ to handle the corresponding interrupt, DO_IRQ will do the necessary schema-related processing after invoking the _DO_IRQ. The function _do_irq will determine whether the interrupt has been threaded (if the state field of the interrupt descriptor does not contain a Sa_nodelay flag indicating that the interrupt was threaded), then the corresponding processing thread will be invoked directly if the Handle_irq_ Event (in the Kernel/irq/handle.c file at the location of the IRQ subsystem) to process. For an already threaded situation, the interrupt processing thread is awakened and starts to run, and the DO_HARDIRQ (defined in the file kernel/irq/manage.c in the location of the IRQ subsystem in the source tree) is invoked to handle the corresponding interrupts. The function will determine if there is an interrupt to be processed (the interrupt Descriptor's status flag irq_inprogress), and if so, call handle_irq_event to process it. Handle_irq_event will call the appropriate interrupt handling handle directly to complete the interrupt processing.

The difference between the application interrupt Request_irq () and the REQUEST_THREADED_IRQ ().

static inline int __must_check
REQUEST_IRQ (unsigned int IRQ, irq_handler_t handler, unsigned long flags,
    const CH Ar *name, void *dev)
{return
REQUEST_THREADED_IRQ (IRQ, Handler, NULL, flags, name, dev);
}

int REQUEST_THREADED_IRQ (unsigned int IRQ, irq_handler_t handler,
         irq_handler_t thread_fn, unsigned long irqflags,< C7/>const Char *devname, void *dev_id)

From the definition, you can see that REQUEST_IRQ is a wrapper of REQUEST_THREADED_IRQ, but only the thread_fn is empty.

REQUEST_THREADED_IRQ function Implementation:

/** * Request_threaded_irq-allocate a interrupt line * @irq: Interrupt line to allocate * @handler: Function to
 Be called when the IRQ occurs. * Primary handler for threaded interrupts * If null and THREAD_FN!= NULL the default * Primary Han Dler is installed * @thread_fn: Function called to the IRQ handler thread * If NULL, no IRQ thread is create D * @irqflags: Interrupt Type Flags * @devname: An ASCII name for the claiming device * @dev_id: A Cookie passed BAC  K to the handler function */int REQUEST_THREADED_IRQ (unsigned int IRQ, irq_handler_t handler, irq_handler_t
    THREAD_FN, unsigned long irqflags, const char *devname, void *dev_id) {struct irqaction *action;
    struct IRQ_DESC *desc;

    int retval;

    if (IRQ = = irq_notconnected) return-enotconn; * * Sanity-check:shared interrupts must pass in a real dev-id, * Otherwise we'll have trouble later trying to
 Figure out    * Which interrupt is which (messes up interrupt freeing * logic etc). * * Also irqf_cond_suspend only makes sense for shared interrupts and * it cannot is set along with Irqf_no_susp
     End.
        */if ((Irqflags & irqf_shared) &&!dev_id) | | (!
        (Irqflags & irqf_shared) && (Irqflags & irqf_cond_suspend)) | |
        ((Irqflags & Irqf_no_suspend) && (Irqflags & Irqf_cond_suspend))

    Return-einval;
    desc = Irq_to_desc (IRQ);

    if (!DESC) Return-einval;
        if (!irq_settings_can_request (desc) | |

    warn_on (Irq_settings_is_per_cpu_devid (DESC)) Return-einval;
        if (!handler) {if (!THREAD_FN) Return-einval;
    handler = Irq_default_primary_handler;
    Action = kzalloc (sizeof (struct irqaction), gfp_kernel);

    if (!action) Return-enomem;
    Action->handler = handler;
    ACTION-&GT;THREAD_FN = THREAD_FN; Action->flags= Irqflags;
    Action->name = Devname;

    action->dev_id = dev_id;
    Chip_bus_lock (DESC);
    retval = __SETUP_IRQ (IRQ, DESC, action);

    Chip_bus_sync_unlock (DESC);
        if (retval) {kfree (action->secondary);
    Kfree (action);  #ifdef config_debug_shirq_fixme if (!retval && (Irqflags & irqf_shared)) {/* * It ' s A Shared IRQ--the driver ought to is prepared for it * to happen immediately, so let's make sure ... *
         We disable the IRQ to make sure this a ' real ' IRQ doesn ' t-run in parallel with our fake.

        * * unsigned long flags;
        DISABLE_IRQ (IRQ);

        Local_irq_save (flags);

        Handler (IRQ, dev_id);
        Local_irq_restore (flags);
    ENABLE_IRQ (IRQ);
#endif return retval; }

Where the __SETUP_IRQ function is called, the function reads as follows:

* * Internal function to register a irqaction-typically used to * Allocate special interrupts that are part of the A
 Rchitecture. */static int __SETUP_IRQ (unsigned int IRQ, struct irq_desc *desc, struct irqaction *new) {struct irqaction *old, **o
    Ld_ptr;
    unsigned long flags, thread_mask = 0;
    int ret, nested, shared = 0;

    cpumask_var_t Mask;

    if (!DESC) Return-einval;
    if (desc->irq_data.chip = = &no_irq_chip) Return-enosys;

    if (!try_module_get (Desc->owner)) Return-enodev;

    NEW-&GT;IRQ = IRQ;
     /* Check whether the interrupt nests into another interrupt * thread.
    * * nested = Irq_settings_is_nested_thread (DESC);
            if (nested) {if (!NEW-&GT;THREAD_FN) {ret =-einval;
        Goto Out_mput;  } * * Replace the primary handler which is provided from * Driver for non nested Handling by the * dummy function which warns when called.
    * * New->handler = Irq_nested_primary_handler;
            else {if (Irq_settings_can_thread (desc)) {ret = irq_setup_forced_threading (new);
        if (ret) goto out_mput; } * * Create a handler thread when a thread function was supplied * and the interrupt does not nest I
     Nto another interrupt * thread.
        */if (NEW-&GT;THREAD_FN &&!nested) {ret = Setup_irq_thread (new, IRQ, false);
        if (ret) goto out_mput;
            if (new->secondary) {ret = Setup_irq_thread (new->secondary, IRQ, True);
        if (ret) goto out_thread;
        } if (!alloc_cpumask_var (&mask, Gfp_kernel)) {ret =-enomem;
    Goto Out_thread;  } * * Drivers are often written to work w/o knowledge about the * underlying IRQ chip implementation Request for A * threaded IRQ WithoUT a primary hard IRQ handler * requires the ONESHOT flag to be set. Some IRQ chips like * MSI based interrupts are/SE one shot safe.
     Check the * chip flags, so we can avoid the unmask dance at the "End of *" threaded handler for those.

    */if (Desc->irq_data.chip->flags & Irqchip_oneshot_safe) new->flags &= ~irqf_oneshot; * * The following block of code has to be executed atomically/Raw_spin_lock_irqsave (&desc->lock,
    Flags);
    Old_ptr = &desc->action;
    Old = *old_ptr; if (old) {/* Can ' t share interrupts unless both agree to and are * the same type (level, Edge , polarity). So both flag * fields must have irqf_shared set and the bits which * set the trigger type must match.
         Also all must * agree on ONESHOT. */if (!) (
            (Old->flags & New->flags) & irqf_shared) | | ((old->flags ^ new->flags) & Irqf_trigger_mask) | |
            ((old->flags ^ new->flags) & Irqf_oneshot))

        Goto mismatch; /* All handlers must agree on Per-cpuness */if (Old->flags & irqf_percpu)!= (New->flags & Amp

        IRQF_PERCPU)) goto mismatch; /* Add new interrupt at end of IRQ \ */DO {/* * Or all existing action->thread_m
             Ask Bits, * so we can find the next zero bit for this * new action.
            * * Thread_mask |= old->thread_mask;
            Old_ptr = &old->next;
        Old = *old_ptr;
        (old);
    shared = 1; /* * Setup the thread mask for this irqaction for ONESHOT. for *!
     ONESHOT IRQs The thread mask is 0, we can avoid a * conditional in irq_wake_thread (). */if (New->flags & irqf_oneshot) {* * unlikely to have RESPSharing one line, * but who knows.
            */if (Thread_mask = = ~0ul) {ret =-ebusy;
        Goto Out_mask;
         }/* The Thread_mask for the "Action is or" ed to * desc->thread_active to indicate * Irqf_oneshot Thread handler has been woken, but not * yet finished. The bit is cleared when a thread * completes. When all threads the A shared interrupt * line have completed desc->threads_active becomes * zero and The interrupt line is unmasked.
         The * Handle.c:irq_wake_thread () for further information. * * If no thread is woken by primary (hard IRQ context) * Interrupt handlers, then DESC-&GT;THREADS_ACTI  ve is * also checked for zero to unmask the IRQ line in the * affected hard IRQ Flow handlers *
         (HANDLE_[FASTEOI|LEVEL]_IRQ). * * The new action gets the ' the ' the ' the ' the ' the ' the 'Ead_mask assigned.
         The loop above which or ' s * all existing action->thread_mask bits.

    * * New->thread_mask = 1 << ffz (thread_mask); else if (New->handler = Irq_default_primary_handler &&! ( Desc->irq_data.chip->flags & Irqchip_oneshot_safe)) {* * The interrupt was requested with Han Dler = NULL, so * We use the default primary handler for it. But it * does not have the ONESHOT flag set. In combination * With level interrupts this is deadly, because the * default primary handler just wakes The thread, then * the IRQ lines is reenabled, but the device still * has the level IRQ asserted. Rinse and repeat ... * * While this works for edge type interrupts, we * it safe and REJEC T unconditionally because we can ' t * say for sure which type this interrupt really * has. The type flags are Unreliable as the * underlying chip implementation can override them. */Pr_err ("threaded IRQ requested with handler=null and!")
        ONESHOT for IRQ%d\n ", IRQ);
        ret =-einval;
    Goto Out_mask;
        } if (!shared) {ret = irq_request_resources (DESC); if (ret) {pr_err (' Failed to request ' for%s ' (IRQ%d) on Irqchip%s\n ', New->na
            Me, IRQ, desc->irq_data.chip->name);
        Goto Out_mask;

        } init_waitqueue_head (&desc->wait_for_threads);
            /* Setup The type (level, edge polarity) if configured: */if (New->flags & Irqf_trigger_mask) {

            ret = __irq_set_trigger (desc, new->flags & Irqf_trigger_mask);
        if (ret) goto out_mask; Desc->istate &= ~ (Irqs_autodetect | irqs_spurious_disabled | \ irqs_oneshot |
      irqs_waiting);  Irqd_clear (&desc->irq_data, irqd_irq_inprogress);
            if (New->flags & irqf_percpu) {Irqd_set (&desc->irq_data, IRQD_PER_CPU);
        IRQ_SETTINGS_SET_PER_CPU (DESC);

        } if (New->flags & irqf_oneshot) desc->istate |= irqs_oneshot;
        if (irq_settings_can_autoenable (DESC)) Irq_startup (DESC, true);

        else/* Undo nested disables: * * desc->depth = 1; /* Exclude IRQ from balancing if requested/if (New->flags & irqf_nobalancing) {irq_settings
            _set_no_balancing (DESC);
        Irqd_set (&desc->irq_data, irqd_no_balancing);

    }/* Set default affinity mask Once everything is setup */setup_affinity (DESC, mask);
        else if (New->flags & irqf_trigger_mask) {unsigned int nmsk = new->flags & irqf_trigger_mask; unsigned int omsk = Irq_settings_get_trigger_mask (deSC); if (Nmsk!= Omsk)/* Hope the handler works with current trigger mode */Pr_warn ("IRQ%d uses tri Gger mode%u;
    Requested%u\n ", IRQ, Nmsk, Omsk);

    } *old_ptr = new;

    Irq_pm_install_action (desc, new);
    * Reset broken IRQ Detection when installing new handler * * Desc->irq_count = 0;

    desc->irqs_unhandled = 0; * * Check Whether we disabled the IRQ via the spurious handler * before.
     Reenable it and give it another chance. */if (Shared && (Desc->istate & irqs_spurious_disabled)) {desc->istate &= ~irqs_spurio
        us_disabled;
    __ENABLE_IRQ (DESC);

    } raw_spin_unlock_irqrestore (&desc->lock, flags);
     * * Strictly no need to wake it up, but Hung_task complains the "When no hard interrupt the" thread up.
    */if (new->thread) wake_up_process (New->thread); if (new->secondary) Wake_up_proceSS (New->secondary->thread);
    Register_irq_proc (IRQ, DESC);
    New->dir = NULL;
    Register_handler_proc (IRQ, new);

    Free_cpumask_var (mask);

return 0; Mismatch:if (!) (
               New->flags & irqf_probe_shared)) {Pr_err ("Flags mismatch IRQ%d.%08x (%s) vs.%08x (%s) \ n",
IRQ, New->flags, New->name, Old->flags, old->name);
#ifdef CONFIG_DEBUG_SHIRQ dump_stack ();

#endif} ret =-ebusy;
    Out_mask:raw_spin_unlock_irqrestore (&desc->lock, flags);

Free_cpumask_var (mask);

        Out_thread:if (new->thread) {struct Task_struct *t = new->thread;
        New->thread = NULL;
        Kthread_stop (t);
    Put_task_struct (t); } if (New->secondary && new->secondary->thread) {struct Task_struct *t = new->secondary-&

        Gt;thread;
        New->secondary->thread = NULL;
        Kthread_stop (t);
    Put_task_struct (t); } out_mput:module_put (DESc->owner);
return ret; }

Where function Setup_irq_thread creates a thread for interrupts, the function reads as follows:

static int setup_irq_thread (struct irqaction *new, unsigned int IRQ, bool secondary) {struct task_struct;

    struct Sched_param param = {. sched_priority = MAX_USER_RT_PRIO/2,};
    if (!secondary) {t = kthread_create (Irq_thread, New, "irq/%d-%s", IRQ, New->name);
        else {t = kthread_create (Irq_thread, New, "irq/%d-s-%s", IRQ, New->name);
    Param.sched_priority-= 1;

    } if (Is_err (t)) return Ptr_err (t);

    Sched_setscheduler_nocheck (t, Sched_fifo, &param); * * We Keep the reference to the task struct even if * the thread dies to avoid the interrupt code *
     References an already freed task_struct.
    * * GET_TASK_STRUCT (t);
    New->thread = t; /* Tell the thread to set its affinity.
     This are * important for shared interrupt handlers as we did * not invoke setup_affinity () for the secondary * Handlers as everything is already set up.
     Even for * interrupts marked and irqf_no_balance this are * correct as we want the thread to move to the CPU (s)
     * on which the requesting code placed the interrupt.
    * * Set_bit (irqtf_affinity, &new->thread_flags);
return 0; }

You can see from the function that Kthread_create implements the creation of the interrupt thread.

Request interrupt other function prototypes and DEVM_REQUEST_THREADED_IRQ.

/**
 *  devm_request_threaded_irq-allocate a interrupt line for a managed device
 /
int Devm_request_ THREADED_IRQ (struct device *dev, unsigned int IRQ,
                  irq_handler_t handler, irq_handler_t thread_fn,
                  unsigned Long irqflags, const char *devname,
                  void *dev_id)
{
    struct irq_devres *dr;
    int RC;

    Dr = Devres_alloc (devm_irq_release, sizeof (struct irq_devres),
              gfp_kernel);
    if (!DR)
        Return-enomem;

    rc = REQUEST_THREADED_IRQ (IRQ, Handler, THREAD_FN, Irqflags, Devname,
                  dev_id);
    if (RC) {
        devres_free (DR);
        return RC;
    }

    DR->IRQ = IRQ;
    dr->dev_id = dev_id;
    Devres_add (Dev, Dr);

    return 0;
}

You can see that the devm_request_threaded is also through the IRQREQUEST_THREADED_IRQ to achieve the interrupt path.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.