Linux系统中断处理框架(3)【转】

//init/main.casmlinkage void __init start_kernel(void){......    trap_init(); //空函数......   early_irq_init();   init_IRQ();......}

在start_kernel()函数中调用了early_irq_init()函数,根据内核配置时是否选择了CONFIG_SPARSE_IRQ,而可以选择两个不同版本的该函数early_irq_init()中的一个进行编译。CONFIG_SPARSE_IRQ配置项,用于支持稀疏irq号,对于发行版的内核很有用,它允许定义一个高CONFIG_NR_CPUS值,但仍然不希望消耗太多内存的情况。

//arch/arm/kernel/irq/irqdesc.c/int __init early_irq_init(void){        int i, initcnt, node = first_online_node;        struct irq_desc *desc;        init_irq_default_affinity();  //由CONFIG_SMP宏决定是否为空函数,见下面分析一        /* Let arch update nr_irqs and return the nr of preallocated irqs */        initcnt = arch_probe_nr_irqs();//体系结构相关的代码来决定预先分配的中断描述符的个数见分析二        if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))  //见下面分析三                nr_irqs = IRQ_BITMAP_BITS;        if (WARN_ON(initcnt > IRQ_BITMAP_BITS))                initcnt = IRQ_BITMAP_BITS;        if (initcnt > nr_irqs)                nr_irqs = initcnt;        for (i = 0; i < initcnt; i++) {                desc = alloc_desc(i, node, NULL);  //分配 struct irq_desc结构,分析四                set_bit(i, allocated_irqs);  //设置相应的位数组,分析三                irq_insert_desc(i, desc);  //保存irq_desc指针,分析四        }        return arch_early_irq_init(); //kernel/softirq.c中定义,为空函数}
//arch/arm/kernel/irq.cvoid __init init_IRQ(void){        int ret;        /*         *在.config文件中CONFIG_OF有定义,并且通过分析2可知machine_desc->init_irq为空。         *         */        if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)                 irqchip_init(); //函数被执行,分析五        else                machine_desc->init_irq();       //machine_desc->l2c_aux_mask和machine_desc->l2c_aux_val初始化为零所以下面不执行        if (IS_ENABLED(CONFIG_OF) && IS_ENABLED(CONFIG_CACHE_L2X0) &&              (machine_desc->l2c_aux_mask || machine_desc->l2c_aux_val)) {                if (!outer_cache.write_sec)                        outer_cache.write_sec = machine_desc->l2c_write_sec;                ret = l2x0_of_init(machine_desc->l2c_aux_val,                                   machine_desc->l2c_aux_mask);                if (ret)                        pr_err("L2C: failed to init: %d\n", ret);        }        uniphier_cache_init();  //arch/arm/include/asm/hardware/cache-uniphier.h 为空}
//arch/arm/kernel/irq/irqdesc.c#if defined(CONFIG_SMP)static void __init init_irq_default_affinity(void){        alloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT);        cpumask_setall(irq_default_affinity);}#elsestatic void __init init_irq_default_affinity(void){}#endif
//arch/arm/kernel/irq.c#ifdef CONFIG_SPARSE_IRQint __init arch_probe_nr_irqs(void){        nr_irqs = machine_desc->nr_irqs ? machine_desc->nr_irqs : NR_IRQS;//NR_IRQS   16        return nr_irqs;  //分析下面的分析,得知返回的是NR_IRQS}#endif/* *NR_IRQS //体系结构相关的代码来决定预先分配的中断描述符的个数 *arch/arm/kernel/irq.c中包含#include  *///arch/arm/include/asm/irq.h#define NR_IRQS_LEGACY  16#ifndef CONFIG_SPARSE_IRQ#include #else#define NR_IRQS NR_IRQS_LEGACY#endif/* *machine_desc在setup_arch中赋值,machine_desc指向了arch/arm/mach-s5pv210/s5pv210.c中定义的 *DT_MACHINE_START(S5PV210_DT, "Samsung S5PC110/S5PV210-based board") *具体分析如下 *///arch/arm/kernel/setup.cconst struct machine_desc *machine_desc __initdata;//arch/arm/mach-s5pv210/s5pv210.cDT_MACHINE_START(S5PV210_DT, "Samsung S5PC110/S5PV210-based board")        .dt_compat = s5pv210_dt_compat,        .map_io = s5pv210_dt_map_io,        .restart = s5pv210_dt_restart,        .init_late = s5pv210_dt_init_late,MACHINE_END/* * Set of macros to define architecture features.  This is built into * a table by the linker. */#define MACHINE_START(_type,_name)                      \static const struct machine_desc __mach_desc_##_type    \ __used                                                 \ __attribute__((__section__(".arch.info.init"))) = {    \        .nr             = MACH_TYPE_##_type,            \        .name           = _name,#define MACHINE_END                             \};#define DT_MACHINE_START(_name, _namestr)               \static const struct machine_desc __mach_desc_##_name    \ __used                                                 \ __attribute__((__section__(".arch.info.init"))) = {    \        .nr             = ~0,                           \        .name           = _namestr,#endif//arch/arm/include/asm/mach/arch.hstruct machine_desc {        unsigned int            nr;             /* architecture number  */        const char              *name;          /* architecture name    */        unsigned long           atag_offset;    /* tagged list (relative) */        const char *const       *dt_compat;     /* array of device tree                                                 * 'compatible' strings */        unsigned int            nr_irqs;        /* number of IRQs */#ifdef CONFIG_ZONE_DMA        phys_addr_t             dma_zone_size;  /* size of DMA-able area */#endif        unsigned int            video_start;    /* start of video RAM   */        unsigned int            video_end;      /* end of video RAM     */        unsigned char           reserve_lp0 :1; /* never has lp0        */        unsigned char           reserve_lp1 :1; /* never has lp1        */        unsigned char           reserve_lp2 :1; /* never has lp2        */        enum reboot_mode        reboot_mode;    /* default restart mode */        unsigned                l2c_aux_val;    /* L2 cache aux value   */        unsigned                l2c_aux_mask;   /* L2 cache aux mask    */        void                    (*l2c_write_sec)(unsigned long, unsigned);        const struct smp_operations     *smp;   /* SMP operations       */        bool                    (*smp_init)(void);        void                    (*fixup)(struct tag *, char **);        void                    (*dt_fixup)(void);        long long               (*pv_fixup)(void);        void                    (*reserve)(void);/* reserve mem blocks  */        void                    (*map_io)(void);/* IO mapping function  */        void                    (*init_early)(void);        void                    (*init_irq)(void);        void                    (*init_time)(void);        void                    (*init_machine)(void);        void                    (*init_late)(void);#ifdef CONFIG_MULTI_IRQ_HANDLER        void                    (*handle_irq)(struct pt_regs *);#endif        void                    (*restart)(enum reboot_mode, const char *);};
//kernel/irq/internals.h#ifdef CONFIG_SPARSE_IRQ#define IRQ_BITMAP_BITS (NR_IRQS + 8196)#else#define IRQ_BITMAP_BITS NR_IRQS#endif//include/linux/types.h#define DECLARE_BITMAP(name,bits) \        unsigned long name[BITS_TO_LONGS(bits)]//arch/arm/include/asm/bitops.h#define set_bit(nr,p)                   ATOMIC_BITOP(set_bit,nr,p)    //_set_bit#define clear_bit(nr,p)                 ATOMIC_BITOP(clear_bit,nr,p)#define change_bit(nr,p)                ATOMIC_BITOP(change_bit,nr,p)#define test_and_set_bit(nr,p)          ATOMIC_BITOP(test_and_set_bit,nr,p)#define test_and_clear_bit(nr,p)        ATOMIC_BITOP(test_and_clear_bit,nr,p)#define test_and_change_bit(nr,p)       ATOMIC_BITOP(test_and_change_bit,nr,p)/* * __builtin_constant_p 是编译器gcc内置函数,用于判断一个值是否为编译时常量, * 如果是常数,函数返回1 ,否则返回0。此内置函数的典型用法是在宏中用于手动编译时优化 */#ifndef CONFIG_SMP  //此宏在.config中未定义/* * The __* form of bitops are non-atomic and may be reordered. */#define ATOMIC_BITOP(name,nr,p)                 \        (__builtin_constant_p(nr) ? ____atomic_##name(nr, p) : _##name(nr,p))  #else#define ATOMIC_BITOP(name,nr,p)         _##name(nr,p)#endif//set_bit函数实现分析#define set_bit(nr,p)                   ATOMIC_BITOP(set_bit,nr,p)    //_set_bit//arch/arm/lib/setbit.S/* *  linux/arch/arm/lib/setbit.S * *  Copyright (C) 1995-1996 Russell King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include #include "bitops.h"                .textbitop   _set_bit, orr //arch/arm/lib/bitops.h        .macro  bitop, name, instrENTRY(  \name           )UNWIND( .fnstart        )        ands    ip, r1, #3        strneb  r1, [ip]                @ assert word-aligned        mov     r2, #1        and     r3, r0, #31             @ Get bit offset        mov     r0, r0, lsr #5        add     r1, r1, r0, lsl #2      @ Get word offset#if __LINUX_ARM_ARCH__ >= 7 && defined(CONFIG_SMP)        .arch_extension mp        ALT_SMP(W(pldw) [r1])        ALT_UP(W(nop))#endif        mov     r3, r2, lsl r31:      ldrex   r2, [r1]        \instr  r2, r2, r3        strex   r0, r2, [r1]        cmp     r0, #0        bne     1b          bx      lr  UNWIND( .fnend          )ENDPROC(\name           )        .endm

分析四 alloc_desc

//kernel/irq/irqdesc.cstatic RADIX_TREE(irq_desc_tree, GFP_KERNEL);  //基数树static void irq_insert_desc(unsigned int irq, struct irq_desc *desc){        radix_tree_insert(&irq_desc_tree, irq, desc);}struct irq_desc *irq_to_desc(unsigned int irq){        return radix_tree_lookup(&irq_desc_tree, irq);}EXPORT_SYMBOL(irq_to_desc);static void delete_irq_desc(unsigned int irq){        radix_tree_delete(&irq_desc_tree, irq);}static struct irq_desc *alloc_desc(int irq, int node, struct module *owner){        struct irq_desc *desc;        gfp_t gfp = GFP_KERNEL;        desc = kzalloc_node(sizeof(*desc), gfp, node);        if (!desc)                return NULL;        /* allocate based on nr_cpu_ids */        desc->kstat_irqs = alloc_percpu(unsigned int);        if (!desc->kstat_irqs)                goto err_desc;        if (alloc_masks(desc, gfp, node))                goto err_kstat;        raw_spin_lock_init(&desc->lock);        lockdep_set_class(&desc->lock, &irq_desc_lock_class);        desc_set_defaults(irq, desc, node, owner);        return desc;err_kstat:        free_percpu(desc->kstat_irqs);err_desc:        kfree(desc);        return NULL;}static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node,struct module *owner)                {        int cpu;        desc->irq_common_data.handler_data = NULL;        desc->irq_common_data.msi_desc = NULL;        desc->irq_data.common = &desc->irq_common_data;        desc->irq_data.irq = irq;        desc->irq_data.chip = &no_irq_chip;        desc->irq_data.chip_data = NULL;        irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS);        irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED);        desc->handle_irq = handle_bad_irq;        desc->depth = 1;        desc->irq_count = 0;        desc->irqs_unhandled = 0;        desc->name = NULL;        desc->owner = owner;        for_each_possible_cpu(cpu)                *per_cpu_ptr(desc->kstat_irqs, cpu) = 0;        desc_smp_init(desc, node);}//include/linux/irqdesc.h/** * struct irq_desc - interrupt descriptor * @irq_common_data:    per irq and chip data passed down to chip functions * @kstat_irqs:         irq stats per cpu * @handle_irq:         highlevel irq-events handler * @preflow_handler:    handler called before the flow handler (currently used by sparc) * @action:             the irq action chain * @status:             status information * @core_internal_state__do_not_mess_with_it: core internal status information * @depth:              disable-depth, for nested irq_disable() calls * @wake_depth:         enable depth, for multiple irq_set_irq_wake() callers * @irq_count:          stats field to detect stalled irqs * @last_unhandled:     aging timer for unhandled count * @irqs_unhandled:     stats field for spurious unhandled interrupts * @threads_handled:    stats field for deferred spurious detection of threaded handlers * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers * @lock:               locking for SMP * @affinity_hint:      hint to user space for preferred irq affinity * @affinity_notify:    context for notification of affinity changes * @pending_mask:       pending rebalanced interrupts * @threads_oneshot:    bitfield to handle shared oneshot threads * @threads_active:     number of irqaction threads currently running * @wait_for_threads:   wait queue for sync_irq to wait for threaded handlers * @nr_actions:         number of installed actions on this descriptor * @no_suspend_depth:   number of irqactions on a irq descriptor with *                      IRQF_NO_SUSPEND set * @force_resume_depth: number of irqactions on a irq descriptor with *                      IRQF_FORCE_RESUME set * @dir:                /proc/irq/ procfs entry * @name:               flow handler name for /proc/interrupts output */struct irq_desc {        struct irq_common_data  irq_common_data;        struct irq_data         irq_data;        unsigned int __percpu   *kstat_irqs;        irq_flow_handler_t      handle_irq;#ifdef CONFIG_IRQ_PREFLOW_FASTEOI        irq_preflow_handler_t   preflow_handler;#endif        struct irqaction        *action;        /* IRQ action list */        unsigned int            status_use_accessors;        unsigned int            core_internal_state__do_not_mess_with_it;        unsigned int            depth;          /* nested irq disables */        unsigned int            wake_depth;     /* nested wake enables */        unsigned int            irq_count;      /* For detecting broken IRQs */        unsigned long           last_unhandled; /* Aging timer for unhandled count */        unsigned int            irqs_unhandled;        atomic_t                threads_handled;        int                     threads_handled_last;        raw_spinlock_t          lock;        struct cpumask          *percpu_enabled;#ifdef CONFIG_SMP        const struct cpumask    *affinity_hint;        struct irq_affinity_notify *affinity_notify;#ifdef CONFIG_GENERIC_PENDING_IRQ        cpumask_var_t           pending_mask;#endif#endif        unsigned long           threads_oneshot;  atomic_t                threads_active;        wait_queue_head_t       wait_for_threads;#ifdef CONFIG_PM_SLEEP        unsigned int            nr_actions;        unsigned int            no_suspend_depth;        unsigned int            cond_suspend_depth;        unsigned int            force_resume_depth;#endif#ifdef CONFIG_PROC_FS        struct proc_dir_entry   *dir;#endif        int                     parent_irq;        struct module           *owner;        const char              *name;} ____cacheline_internodealigned_in_smp;

分析五

//drivers/irqchip/irqchip.c/* * Copyright (C) 2012 Thomas Petazzoni * * Thomas Petazzoni  * * This file is licensed under the terms of the GNU General Public * License version 2.  This program is licensed "as is" without any * warranty of any kind, whether express or implied. */#include #include #include #include /* * This special of_device_id is the sentinel at the end of the * of_device_id[] array of all irqchips. It is automatically placed at * the end of the array by the linker, thanks to being part of a * special section. */static const struct of_device_idirqchip_of_match_end __used __section(__irqchip_of_table_end);//__irqchip_of_table定义在链接脚本arch/arm/kernel/vmlinux.ldsextern struct of_device_id __irqchip_of_table[];void __init irqchip_init(void){        of_irq_init(__irqchip_of_table);  //分析六        acpi_probe_device_table(irqchip);}/* *__irqchip_of_table实际上是一个struct of_device_id结构体的数组, *__irqchip_of_table数组里的每一个元素使用IRQCHIP_DECLARE宏定义而来, *数组的每个元素都被放在了__irqchip_of_table段中 *//* * include/linux/irqchip.h * @name: name that must be unique accross all IRQCHIP_DECLARE of the * same file. * @compstr: compatible string of the irqchip driver * @fn: initialization function */#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)//include/linux/of.h#ifdef CONFIG_OF#define _OF_DECLARE(table, name, compat, fn, fn_type)                   \        static const struct of_device_id __of_table_##name              \                __used __section(__##table##_of_table)                  \                 = { .compatible = compat,                              \                     .data = (fn == (fn_type)NULL) ? fn : fn  }#else#define _OF_DECLARE(table, name, compat, fn, fn_type)                   \        static const struct of_device_id __of_table_##name              \                __attribute__((unused))                                 \                 = { .compatible = compat,                              \                     .data = (fn == (fn_type)NULL) ? fn : fn }#endiftypedef int (*of_init_fn_2)(struct device_node *, struct device_node *);typedef void (*of_init_fn_1)(struct device_node *);#define OF_DECLARE_1(table, name, compat, fn) \                _OF_DECLARE(table, name, compat, fn, of_init_fn_1)#define OF_DECLARE_2(table, name, compat, fn) \                _OF_DECLARE(table, name, compat, fn, of_init_fn_2)

分析六 of_irq_init

//drivers/of/irq.cstruct of_intc_desc {        struct list_head        list;        struct device_node      *dev;        struct device_node      *interrupt_parent;};/** * of_irq_init - Scan and init matching interrupt controllers in DT * @matches: 0 terminated array of nodes to match and init function to call * * This function scans the device tree for matching interrupt controller nodes, * and calls their initialization functions in order with parents first. */void __init of_irq_init(const struct of_device_id *matches){        struct device_node *np, *parent = NULL;        struct of_intc_desc *desc, *temp_desc;        struct list_head intc_desc_list, intc_parent_list;        INIT_LIST_HEAD(&intc_desc_list);        INIT_LIST_HEAD(&intc_parent_list);        for_each_matching_node(np, matches) {                if (!of_find_property(np, "interrupt-controller", NULL) ||                                !of_device_is_available(np))                        continue;                /*                 * Here, we allocate and populate an of_intc_desc with the node                 * pointer, interrupt-parent device_node etc.                 */                desc = kzalloc(sizeof(*desc), GFP_KERNEL);                if (WARN_ON(!desc)) {                        of_node_put(np);                        goto err;                }                desc->dev = of_node_get(np);                desc->interrupt_parent = of_irq_find_parent(np);                if (desc->interrupt_parent == np)                        desc->interrupt_parent = NULL;                list_add_tail(&desc->list, &intc_desc_list);        } /*         * The root irq controller is the one without an interrupt-parent.         * That one goes first, followed by the controllers that reference it,         * followed by the ones that reference the 2nd level controllers, etc.         */        while (!list_empty(&intc_desc_list)) {                /*                 * Process all controllers with the current 'parent'.                 * First pass will be looking for NULL as the parent.                 * The assumption is that NULL parent means a root controller.                 */                list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {                        const struct of_device_id *match;                        int ret;                        of_irq_init_cb_t irq_init_cb;                        if (desc->interrupt_parent != parent)                                continue;                        list_del(&desc->list);                        match = of_match_node(matches, desc->dev);                        if (WARN(!match->data,                            "of_irq_init: no init function for %s\n",                            match->compatible)) {                                kfree(desc);                                continue;                        }                        pr_debug("of_irq_init: init %s @ %p, parent %p\n",                                 match->compatible,                                 desc->dev, desc->interrupt_parent);                        irq_init_cb = (of_irq_init_cb_t)match->data;                        /*                         *执行IRQCHIP_DECLARE宏定义全局变量里的函数,                         *此函数就是驱动代码了,这部分驱动代对arm一般                         *gic驱动或者vic(pl192)的驱动。                         */                        ret = irq_init_cb(desc->dev, desc->interrupt_parent);                         if (ret) {                                kfree(desc);                                continue;                        }                        /*                         * This one is now set up; add it to the parent list so                         * its children can get processed in a subsequent pass.                         */                        list_add_tail(&desc->list, &intc_parent_list);                }                /* Get the next pending parent that might have children */                desc = list_first_entry_or_null(&intc_parent_list,                                                typeof(*desc), list);                if (!desc) {                        pr_err("of_irq_init: children remain, but no parents\n");                        break;                }                list_del(&desc->list);                parent = desc->dev;                kfree(desc);        }        list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {                list_del(&desc->list);                kfree(desc);        }err:        list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {                list_del(&desc->list);                of_node_put(desc->dev);                kfree(desc);        }}

Original: https://www.cnblogs.com/yifeichongtian2021/p/15512288.html
Author: 壹飞冲天
Title: Linux系统中断处理框架(3)【转】

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/585775/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 正态分布

    用来计算连续变量的发生率,说的很抽象,简单说就是单独拿出来没什么太大用,但并不是说这个没什么用,相反这个太重要了,这玩意能让你看清世界的真相 先看个图,像这样的线性就是正太分布 正…

    Linux 2023年6月6日
    0115
  • OpenStack-iaas之“先点”云平台安装

    1.认识OpenStack 1.云计算的起源 早在2006年3月,亚马逊公司首先提出弹性计算云服务。2006年8月9日,谷歌公司首席执行官埃里克·施密特(Eric Schmidt)…

    Linux 2023年6月13日
    092
  • ssh远程连接服务

    TCP/22 SSH 应用层协议 作用:远程连接设备, 方便操作 1、本地管理方式 安装系统、故障修复 2、远程连接的方式 centos7.x版本中的ssh默认是开启的,所以查看一…

    Linux 2023年6月7日
    092
  • 【论文笔记】(2017,BIM)Adversarial Machine Learning at Scale

    本文主要是给出了两类多个对抗攻击方法:one-step 攻击和 multi-step 攻击,并在大型模型和大型数据集上对这些方法进行对比实验,实验结果发现使用 one-step 样…

    Linux 2023年6月7日
    088
  • python截取字符串(字符串切片)

    python中使用 []来截取字符串,语法: &#x5B57;&#x7B26;&#x4E32;[&#x8D77;&#x59CB;&#…

    Linux 2023年6月6日
    0131
  • tomcat

    tomcat 一.简介 二.部署tomcat 一.简介 Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场…

    Linux 2023年6月7日
    0109
  • 配置管理docker对象和守护进程

    使用 Docker 的主要工作是创建和使用各类对象:镜像、容器、网络、卷等。 1、Docker对象的标记 标记(Label):是一种将元数据应用于Docker对象(镜像、容器、网络…

    Linux 2023年6月8日
    086
  • 在linux中使用tcpdump抓包的方法:

    在linux中使用tcpdump抓包的方法: 1,运行下面命令来从所有网卡中捕获数据包: tcpdump -i any 2,从指定网卡中捕获数据包 tcpdump -i eth0 …

    Linux 2023年5月27日
    0122
  • Dockerfile

    基本结构 Dockerfile 是一个文本格式的配置文件,用户可以使用 Dockerfile 快速创建自定义镜像。 Dockerfile 由一行行命令语句组成,并且支持以 # 开头…

    Linux 2023年6月13日
    0103
  • 剑指offer计划23( 数学简单)—java

    1.1、题目1 剑指 Offer 39. 数组中出现次数超过一半的数字 1.2、解法 万能哈希表,数学方法看到我要吐血。。。 1.3、代码 class Solution { pub…

    Linux 2023年6月11日
    0104
  • 正则表达式在grep中的使用

    GREP用法 grep "after" profile #查找文件内的包含after单词的行 grep -n "after" profile…

    Linux 2023年6月11日
    099
  • docker安装redis

    Redis configuration file example. # Note that in order to read the configuration file, Red…

    Linux 2023年5月28日
    095
  • 如何在Windows 10 上定时备份线上Minio 资源

    @ 一、系统环境 二、软件安装 三、设置定时任务 3.1 创建账号 3.2 同步测试 3.3 编写同步脚本 3.4 脚本测试 3.5 创建定时任务 3.6 定时任务测试 四、总结 …

    Linux 2023年5月27日
    0186
  • 【MQTT】cJSON协议的安装和使用

    cJSON的使用 * – cJSON的简介 – + JSON 名称/值对 + JSON 数字 + JSON 对象 + JSON 数组 – cJS…

    Linux 2023年6月13日
    0114
  • Linux 查看运行中进程的 umask

    线上某台虚机因为故障重装了系统(基线 CentOS 6.9 内核 2.6.x),重新部署了应用。这个应用会生成一个文件,到NFS挂载目录。 而这个 NFS 挂载目录是一个 FTP …

    Linux 2023年6月14日
    095
  • vm-tools安装

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Linux 2023年6月6日
    077
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球