当前位置: 首页 > news >正文

记录一种在内核空间向用户空间通知中断的方法

记录一种在内核空间向用户空间通知中断的方法

  • 0.前言
  • 1.代码实现
    • 1)内核设备驱动实现
    • 2)消息通知实现
    • 3)测试程序
  • 2.解析


参考文章:Linux驱动实践:中断处理函数如何【发送信号】给应用层?

0.前言

  最近在项目中遇到一个需求,需要将一个设备的中断状态通知到用户态的一个指定程序中,该设备的整体架构如下:
在这里插入图片描述
  CPU通过SPI与设备通信,在设备中存在一个ISR控制单元,当设备发生中断时,会在ISR单元中给对应的寄存器置位,CPU可以通过轮询这些寄存器单元来判断这些中断是否发生。但这样做就失去了中断的意义,内核依旧是通过轮询方式来扫描中断。
  在原先的实现方案中,SPI device通过内核通用接口挂载成了一个内核设备spidev,笔者在此设备基础上,重新在内核中创建了一个影子设备,用来实现用户态程序的读写接口,包括open()、release()、ioctl()接口等,但笔者在后续尝试为这段ISR寄存器地址申请内核中断时,发现官方驱动似乎存在一些问题,会出现设备无法挂载,或挂载后无法正常感知中断的结果。
  所以笔者在同事的帮助下,重新做了一个解决方案,SPI device依旧通过内核通用接口挂载成内核设备,但不创建影子设备,用户态直接操作原设备;此外,为这段ISR地址单独实现一个platform driver,将地址重映射到内存地址中,这样当中断发生时,通过内核的netlink函数通知指定的端口。

1.代码实现

1)内核设备驱动实现

spidev.h:

#ifndef __SPIDEV_H__
#define __SPIDEV_H__#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
#include <linux/uaccess.h>
#include <linux/phy.h>
#include <net/dsa.h>struct spidev_switch{dev_t devid;struct cdev cdev;struct class *class;struct device *device;struct device *parent;void __iomem * vir_base_addr;unsigned long spi_base_addr;unsigned long mem_size;struct spi_device *spidev;uint32_t		    speed_hz;struct mutex		spi_api_lock;struct mii_bus*     stmmac_mii;int			irq;struct gpio_irq_dev *gpioDev;};typedef struct{uint32_t addr;uint32_t *data;uint32_t regCnt;uint32_t burstType;uint32_t crcFlag;int32_t ret;
}switch_reg_t;struct gpio_irq_dev {struct gpio_desc *gpiod;int irq;char irq_name[10];char irq_drv_name[20];
}gpio_irq_dev_t;#define  SWI_DEVICE_NAME    "spi-dev" 
#define  SWI_DEVICE_CNT     1
#define  SWI_IOC_MAGIC      'k'#define  DRV_NAME            "2404-spi"
#define  DRV_VERSION         "0.1.1"
#define  GPIO_INTR_NUM   3#define SPI_MODE_MASK		(SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \| SPI_NO_CS | SPI_READY | SPI_TX_DUAL \| SPI_TX_QUAD | SPI_TX_OCTAL | SPI_RX_DUAL \| SPI_RX_QUAD | SPI_RX_OCTAL)#define WITCH_IOC_SYS_BUS_REG_RD	    	_IOWR(SWI_IOC_MAGIC, 8, switch_reg_t)
#define WITCH_IOC_SYS_BUS_REG_WR	    	_IOWR(SWI_IOC_MAGIC, 9, switch_reg_t)
#define WITCH_IOC_SPI_INNER_REG_RD	    	_IOWR(SWI_IOC_MAGIC, 12, switch_reg_t)
#define WITCH_IOC_SPI_INNER_REG_WR	    	_IOWR(SWI_IOC_MAGIC, 13, switch_reg_t)
#define WITCH_IOC_SPI_BURST_REG_RD	    	_IOWR(SWI_IOC_MAGIC, 14, switch_reg_t)
#define WITCH_IOC_SPI_BURST_REG_WR	    	_IOWR(SWI_IOC_MAGIC, 15, switch_reg_t)
#define SWITCH_IOC_GPIO_ISR_EN    	    	_IOWR(SWI_IOC_MAGIC, 16, switch_reg_t)
#endif

spidev.c:

#include "spidev.h"
#include "my-netlink.h"
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/irq.h>static int spi_module_open (struct inode *node, struct file *filp)
{struct cdev* cdev_t;cdev_t = node->i_cdev;filp->private_data = container_of(cdev_t, struct spidev_switch, cdev);return 0;
}static ssize_t spi_module_read(struct file *filp, char *buff, size_t count, loff_t *offp)
{return 0;
}static ssize_t spi_module_write(struct file *filp, const char __user *buf, size_t count, loff_t *off)
{return 0;
}static int spi_module_release(struct inode *node, struct file *filp)
{return 0;
}static long int spi_module_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{int32_t retval = 0;int32_t len;switch_reg_t switch_reg;uint32_t g_mem_reg_data[256] = {0};struct spidev_switch* kgsw = file->private_data;spidev_dbg_printf(spidev_LOG_DEBUG,"%s:cmd:%x,arg:%x\n",__func__,cmd,arg);switch (cmd) {case WITCH_IOC_SYS_BUS_REG_RD:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);spidev_dbg_printf(spidev_LOG_DEBUG,"%s:retval:%x\n",__func__,retval);if (retval == 0){switch_reg.ret = spidev_apb_reg_read32(kgsw,switch_reg.addr, \switch_reg.regCnt,switch_reg.burstType,g_mem_reg_data);retval = copy_to_user((void __user *)switch_reg.data, g_mem_reg_data, switch_reg.regCnt*sizeof(uint32_t));spidev_dbg_printf(spidev_LOG_DEBUG,"%s:retval:%x\n",__func__,retval);}	   break;case WITCH_IOC_SYS_BUS_REG_WR:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);if (retval == 0){retval = copy_from_user(g_mem_reg_data, (const void __user *)switch_reg.data, switch_reg.regCnt*sizeof(uint32_t));if (retval == 0){switch_reg.ret = spidev_apb_reg_write32(kgsw,switch_reg.addr, \switch_reg.regCnt,switch_reg.burstType,g_mem_reg_data);spidev_dbg_printf(spidev_LOG_DEBUG,"%s:retval:%x\n",__func__,retval);}}	   break;case WITCH_IOC_SPI_INNER_REG_RD:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);if (retval == 0){switch_reg.ret = spi_inner_reg_read32(kgsw,switch_reg.addr,g_mem_reg_data);retval = copy_to_user((void __user *)switch_reg.data, g_mem_reg_data, switch_reg.regCnt*sizeof(uint32_t));}break;case WITCH_IOC_SPI_INNER_REG_WR:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);if (retval == 0){retval = copy_from_user(g_mem_reg_data, (const void __user *)switch_reg.data, switch_reg.regCnt*sizeof(uint32_t));if (retval == 0){switch_reg.ret = spi_inner_reg_write32(kgsw,switch_reg.addr,g_mem_reg_data);}}break;case WITCH_IOC_SPI_BURST_REG_RD:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);if (retval == 0){switch_reg.ret = spi_burst_reg_read32(kgsw,switch_reg.addr, \switch_reg.regCnt,switch_reg.burstType,g_mem_reg_data);retval = copy_to_user((void __user *)switch_reg.data, g_mem_reg_data, switch_reg.regCnt*sizeof(uint32_t));}break;case WITCH_IOC_SPI_BURST_REG_WR:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);if (retval == 0){retval = copy_from_user(g_mem_reg_data, (const void __user *)switch_reg.data, switch_reg.regCnt*sizeof(uint32_t));if (retval == 0){switch_reg.ret = spi_burst_reg_write32(kgsw,switch_reg.addr, \switch_reg.regCnt,switch_reg.burstType,g_mem_reg_data);}}break;case SWITCH_IOC_GPIO_ISR_EN:len = _IOC_SIZE(cmd);retval = copy_from_user(&switch_reg, (const void __user *)arg, len);if (retval == 0){retval = copy_from_user(g_mem_reg_data, (const void __user *)switch_reg.data, switch_reg.regCnt*sizeof(uint32_t));if (retval == 0){switch_reg.ret = gpio_irq_enable(kgsw, switch_reg.addr);}}break;default:spidev_dbg_printf(spidev_LOG_ERROR, "%s nuknow cmd type\n",__func__);break;}return retval;
}static struct file_operations switch_module_opts = {.owner = THIS_MODULE,.open  = spi_module_open,.read  = spi_module_read,.write = spi_module_write,.unlocked_ioctl = spi_module_ioctl,.release = spi_module_release,
};static int is_dev_creat = 0;
int spidev_dev_creat(struct spidev_switch* kgsw)
{int major;int ret;if(is_dev_creat)return 0;/*alloc devid*/alloc_chrdev_region(&kgsw->devid, 0, SWI_DEVICE_CNT, SWI_DEVICE_NAME);major = MAJOR(kgsw->devid);/*register char dev*/cdev_init(&kgsw->cdev, &switch_module_opts);ret = cdev_add(&kgsw->cdev, kgsw->devid, SWI_DEVICE_CNT);if (ret) {goto del_unrigister;}/*creat device node*/kgsw->class = class_create(THIS_MODULE, SWI_DEVICE_NAME);if (IS_ERR(kgsw->class)) {goto del_cdev;} kgsw->device = device_create(kgsw->class, NULL, kgsw->devid, NULL, SWI_DEVICE_NAME);if (IS_ERR(kgsw->device)) {goto destroy_class;}find_spi_dev(kgsw);of_parse_spidev_reg_addr(kgsw);is_dev_creat = 1;return 0;destroy_class:device_destroy(kgsw->class, kgsw->devid);
del_cdev:cdev_del(&kgsw->cdev);
del_unrigister:unregister_chrdev_region(kgsw->devid, SWI_DEVICE_CNT);is_dev_creat = 0;return -EIO;
}static irqreturn_t switch_2404_isr_func(int irq, void *dev_id)
{//printk(KERN_NOTICE "Enter switch 2404 irq(%d) function\n", irq);struct spidev_switch*  kgsw = (struct spidev_switch*)dev_id;netlink_msg_t nlg;memset(&nlg, 0, sizeof(netlink_msg_t));void __iomem* vir_addr2 = 0x30800068 - kgsw->spi_base_addr  + kgsw->vir_base_addr;writel(1,vir_addr2);nlg.cmd_type = REPORT_IRQ_TO_USER;nlg.irq_type = SWITCH_INTERRUPT_TYPE;nlg.irq_number = irq;printk(KERN_NOTICE "Kernel netlink send to user: irq_type(0x%x)  irq_number(%x)\n", nlg.irq_type, nlg.irq_number);myspi_send_to_usr_msg(&nlg);return IRQ_HANDLED;
}static irqreturn_t myspi_gpio_isr_func(int irq, void *dev_id)
{netlink_msg_t nlg;memset(&nlg, 0, sizeof(netlink_msg_t));//disable_irq_nosync(irq);nlg.cmd_type = REPORT_IRQ_TO_USER;nlg.irq_type = GPIO_INTR_TYPE;nlg.irq_number = irq;printk(KERN_NOTICE "Kernel netlink send to user: irq_type(0x%x)  irq_number(%x)\n", nlg.irq_type, nlg.irq_number);myspi_send_to_usr_msg(&nlg);return IRQ_HANDLED;
}static int myspi_gpio_irq_init(struct spidev_switch* kgsw)
{int rc;struct gpio_irq_dev *gpio_dev = NULL;struct device *dev = kgsw->parent;int index = 0;gpio_dev = devm_kzalloc(dev, sizeof(*gpio_dev) * GPIO_INTR_NUM, GFP_KERNEL);if (!gpio_dev){dev_err(dev, "no memory.\n");return -ENOMEM;}for (index = 0; index < GPIO_INTR_NUM; index++){sprintf(gpio_dev[index].irq_name, "%d", index);sprintf(gpio_dev[index].irq_drv_name, "%d-gpio-irq", index);gpio_dev[index].gpiod = devm_gpiod_get(dev, gpio_dev[index].irq_name, GPIOD_IN);if (IS_ERR(gpio_dev[index].gpiod)) {rc = PTR_ERR(gpio_dev[index].gpiod);if (rc != -EPROBE_DEFER)dev_err(dev, "error getting gpio (%d)\n", rc);goto irq_err;}gpio_dev[index].irq = gpiod_to_irq(gpio_dev[index].gpiod);if (gpio_dev[index].irq < 0){goto irq_err;} rc = devm_request_irq(dev, gpio_dev[index].irq, myspi_gpio_isr_func, IRQF_TRIGGER_RISING, gpio_dev[index].irq_drv_name, &gpio_dev[index]); if (rc){dev_err(dev, "unable to claim IRQ %d\n", gpio_dev[index].irq);goto irq_err;}else{printk(KERN_NOTICE " gpio-irq%d %s request success!\n", gpio_dev[index].irq, gpio_dev[index].irq_drv_name);}}kgsw->gpioDev = gpio_dev;return 0;irq_err:devm_kfree(dev, gpio_dev);return rc;
}static int spidev_probe(struct platform_device *pdev)
{struct spidev_switch*  kgsw;int ret = 0;kgsw = devm_kzalloc(&pdev->dev, sizeof(struct spidev_switch), GFP_KERNEL);kgsw->parent = &pdev->dev;kgsw->irq = platform_get_irq(pdev, 0);if (kgsw->irq < 0){dev_err(&pdev->dev, "irq number invalid\n");goto err_out;}ret = spidev_dev_creat(kgsw);if (ret < 0) {dev_err(&pdev->dev, "device create fail!\n");goto err_out;}    ret = request_irq(kgsw->irq, switch_2404_isr_func, IRQF_SHARED, dev_name(&pdev->dev), &kgsw->devid);if (ret < 0 && ret != -ENOTCONN) {dev_err(&pdev->dev, "can not get IRQ\n");goto err_out;}platform_set_drvdata(pdev, kgsw);myspi_gpio_irq_init(kgsw);myspi_netlink_init();spidev_dbg_printf(spidev_LOG_INFO, "%s probe done\n", DRV_NAME);return 0;err_out:return -ENXIO;
}static int spidev_remove(struct platform_device *pdev)
{struct spidev_switch*  kgsw = dev_get_drvdata(&pdev->dev);printk(KERN_NOTICE " Delete device files\n");device_destroy(kgsw->class, kgsw->devid);printk(KERN_NOTICE " Delete class files\n");class_destroy(kgsw->class);printk(KERN_NOTICE " Deregister the character device driver\n");cdev_del(&kgsw->cdev);//Indicates device numbers for deregistering applicationsunregister_chrdev_region(kgsw->devid, SWI_DEVICE_CNT);myspi_netlink_exit();free_irq(kgsw->irq, &kgsw->devid);is_dev_creat = 0;return 0;
}static const struct of_device_id spidev_switch_of_match[] = {{ .compatible = "my-spidev" },{ },
};MODULE_DEVICE_TABLE(of, spidev_switch_of_match);static struct platform_driver spidev_driver = {.probe = spidev_probe,.remove = spidev_remove,.driver = {.name = "spidev switch driver",.of_match_table = spidev_switch_of_match,},
};static int __init spidev_switch_init(void)
{printk(KERN_NOTICE DRV_NAME ": version %s loaded\n", DRV_VERSION);return platform_driver_register(&spidev_switch_driver);
}static void __exit spidev_switch_exit(void)
{printk(KERN_NOTICE DRV_NAME ": version %s unloaded\n", DRV_VERSION);platform_driver_unregister(&spidev_switch_driver);
}module_init(spidev_switch_init);
module_exit(spidev_switch_exit);MODULE_DESCRIPTION("Driver for myspi switch");
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL v2");

2)消息通知实现

my_netlink.h:

#ifndef __MYSPI_SWITCH_NETLINK_H__
#define __MYSPI_SWITCH_NETLINK_H__#define NETLINK_IRQ_REPORT_USER      (MAX_LINKS-1)
#define NETLINK_DEFAULT_PORT_ID      0
#define NETLINK_DEFAULT_SEQ          0
#define NETLINK_DEFAULT_FLAGS        0
#define NETLINK_USER_PORT            100#define INTERRUPT_TYPE        0x24040000
#define PHY_GPIO_INTR_FMC0_TYPE      0x24040001
#define PHY_GPIO_INTR_FMC1_TYPE      0x24040002
#define PHY_GPIO_INTR_FMC2_TYPE      0x24040003enum {ASYNC_READ_CMD = 1,ASYNC_WRITE_CMD = 2,SHARE_MEM_REG_UPDATE = 3,SHARE_MEM_REG_UPDATE_STOP = 4,REPORT_IRQ_TO_USER = 5,
};typedef struct netlink_msg
{int  cmd_type;int  irq_type;int  irq_number;               
}netlink_msg_t;int myspi_netlink_init(void);
void myspi_netlink_exit(void);
int myspi_send_to_usr_msg(netlink_msg_t* reg);
#endif

my_netlink.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <net/sock.h>
#include <linux/netlink.h>
#include "myspi_switch_netlink.h"static struct sock *nlsk = NULL;int myspi_send_to_usr_msg(netlink_msg_t* msg)
{struct sk_buff *nl_skb;struct nlmsghdr *nlh;int ret;//creat sk_buffnl_skb = nlmsg_new(sizeof(netlink_msg_t), GFP_ATOMIC);//what time to free;if(!nl_skb){printk("netlink alloc failure\n");return -1;}// set netlink head msg// 填充nlmsg报文头,并最终将报文填充到sk_buff发送出去nlh = nlmsg_put(nl_skb, NETLINK_DEFAULT_PORT_ID, NETLINK_DEFAULT_SEQ, NETLINK_IRQ_REPORT_USER, sizeof(netlink_msg_t), NETLINK_DEFAULT_FLAGS); if(nlh == NULL){printk("nlmsg_put failaure \n");nlmsg_free(nl_skb);return -1;}//send msg; nl_skb will free automaticmemcpy(nlmsg_data(nlh), msg, sizeof(netlink_msg_t));ret = netlink_unicast(nlsk, nl_skb, NETLINK_USER_PORT, MSG_DONTWAIT); // 指定端口号,端口号是唯一识别目的地址的标识,广播非阻塞式发送return ret;
}static void netlink_rcv_msg(struct sk_buff *skb)
{struct nlmsghdr *nlh = NULL;netlink_msg_t *reg_data = NULL;if(skb->len >= nlmsg_total_size(0)){nlh = nlmsg_hdr(skb); // 取出报文头reg_data = NLMSG_DATA(nlh); // 取出报文内容if(reg_data){//print_regdata(__func__,__LINE__,reg_data);}}
}static struct netlink_kernel_cfg cfg = { .input  = netlink_rcv_msg, /* set recv callback */
};int myspi_netlink_init(void)
{/* create netlink socket */printk(" Kernel netlink create");nlsk = (struct sock *)netlink_kernel_create(&init_net, NETLINK_IRQ_REPORT_USER, &cfg);if(nlsk == NULL){   printk("Kernel netlink create error!\n");return -1; }   return 0;
}void myspi_netlink_exit(void)
{printk(" Kernel netlink exit!\n");if (nlsk){netlink_kernel_release(nlsk); /* release ..*/nlsk = NULL;}   
}

3)测试程序

test.c:

#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <string.h>
#include <linux/netlink.h>
#include <stdint.h>
#include <unistd.h>
#include <errno.h>#define NETLINK_REG_ASYNC_RW     (MAX_LINKS-1)    //31
#define NETLINK_USER_PORT        100enum {ASYNC_READ_CMD = 1,ASYNC_WRITE_CMD = 2,SHARE_MEM_REG_UPDATE = 3,SHARE_MEM_REG_UPDATE_STOP = 4,REPORT_IRQ_TO_USER = 5,
};typedef struct netlink_msg
{struct nlmsghdr hdr;int             cmd;int  irq_type;int  irq_number;     
}netlink_msg_t;typedef struct netlink_handle
{int skfd;struct sockaddr_nl saddr;struct sockaddr_nl daddr; 
} netlink_handle_t;static netlink_handle_t async_netlink_handle;netlink_handle_t* get_async_netlink_handle(void)
{return &async_netlink_handle;
}int switch_netlink_init(void)
{int skfd;struct sockaddr_nl* saddr; //saddr 表示源端口地址,daddr表示目的端口地址struct sockaddr_nl* daddr;netlink_handle_t* handle;handle = get_async_netlink_handle();saddr = &(handle->saddr);daddr = &(handle->daddr);/* 创建NETLINK socket */skfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_REG_ASYNC_RW);if(skfd == -1){perror("create socket error\n");return -1;}memset(saddr, 0, sizeof(struct sockaddr_nl));saddr->nl_family = AF_NETLINK; //AF_NETLINKsaddr->nl_pid = NETLINK_USER_PORT;  //端口号(port ID) saddr->nl_groups = 0;if(bind(skfd, (struct sockaddr *)saddr, sizeof(struct sockaddr_nl)) != 0){perror("bind() error\n");close(skfd);return -1;}memset(daddr, 0, sizeof(struct sockaddr_nl));daddr->nl_family = AF_NETLINK;daddr->nl_pid = 0; // to kernel daddr->nl_groups = 0;handle->skfd = skfd;return 0;
}int switch_recv_reg_msg(void)
{int ret;netlink_msg_t recv_msg;socklen_t len;netlink_handle_t* handle;handle = get_async_netlink_handle();memset(&recv_msg, 0, sizeof(netlink_msg_t));len = sizeof(struct sockaddr_nl);ret = recvfrom(handle->skfd, &recv_msg, sizeof(netlink_msg_t), 0, (struct sockaddr *)&(handle->daddr), &len);if(!ret){printf("%s,%d, err\n",__func__,__LINE__);return -1;}switch(recv_msg.cmd){case REPORT_IRQ_TO_USER:printf("User netlink recv from kernel: irq_type(%x), irq_number(%d)\n",recv_msg.irq_type, recv_msg.irq_number);break;default:printf("Unknown command\n");break;}return 0;
}int main(int argc, char *argv[]){if (fork() == 0){printf("Create a child process, pid = %d\n", getpid());int ret = 0;ret = switch_netlink_init();if (ret){return ret;}while(1){switch_recv_reg_msg();}printf("main end\n");}else{printf("Father process, pid = %d\n", getpid());return;}
}

2.解析

在设备驱动文件中,实现了一个platform子系统的设备驱动,通过指定的compatible来匹配,并实现了设备的probe、remove、ioctl操作等接口,并且在创建内核设备节点时,为设备申请了spi设备中断和gpio中断,并初始化了一个netlink通信端口。当设备发生中断时,会触发回调函数中的netlink接口,向指定的用户端口发送中断号以及中断类型,这样就可以在用户程序中进行后续操作。
测试小程序中主要是测试netlink的接收,在while(1)循环中一直监听等待内核驱动的信息。

注:此文中仅为大致的实现框架,仅供参考,具体设备的详细实现流程需根据实际情况进行修改。

相关文章:

记录一种在内核空间向用户空间通知中断的方法

记录一种在内核空间向用户空间通知中断的方法 0.前言1.代码实现1)内核设备驱动实现2)消息通知实现3)测试程序 2.解析 参考文章&#xff1a;Linux驱动实践&#xff1a;中断处理函数如何【发送信号】给应用层&#xff1f; 0.前言 最近在项目中遇到一个需求&#xff0c;需要将一个…...

.NetCore 过滤器和拦截器 的区别

Asp.NET Core 中的过滤器&#xff08;Filter&#xff09;和拦截器&#xff08;Interceptor&#xff09;是两个不同的概念&#xff0c;但它们在某些方面有相似之处&#xff0c;也有明显的区别。 &#x1f511;过滤器&#xff08;Filter&#xff09; 过滤器是Asp.NET Core中用于…...

【笔记】自动驾驶预测与决策规划_Part7_数据驱动的预测方法

文章目录 0. 前言1. 多模态传感器的编码方式1.1 栅格化表示1.2 向量化表示 Vectornet1.3 基于点云或者多模态输入的预测1.4 基于Transformer的方法 2. 网络输出的表达形式2.1 多模态轨迹回归2.2 轨迹分类2.3 轨迹回归轨迹分类2.4 目标点预测 3.场景级别的预测和决策3.1 论文&am…...

React渲染相关内容——渲染流程API、Fragment、渲染相关底层API

React渲染过程依次遇到的函数 在React的渲染流程中&#xff0c;从组件的创建到其UI最终呈现到屏幕上&#xff0c;会经历一系列的生命周期方法和函数。这些方法和函数对于类组件&#xff08;Class Components&#xff09;和函数组件&#xff08;Function Components&#xff09…...

Python中dict支持多个key的方法

在Python中&#xff0c;字典&#xff08;dict&#xff09;是一种非常强大的数据结构&#xff0c;它允许我们通过键&#xff08;key&#xff09;来存储和检索值&#xff08;value&#xff09;。有时候&#xff0c;我们可能想要根据多个键来检索或操作字典中的数据。虽然Python的…...

丹摩 | 基于PyTorch的CIFAR-10图像分类实现

从创建实例开始的新项目流程 第一步&#xff1a;创建实例 登录 DAMODEL 平台。创建一个 GPU 实例&#xff1a; GPU 配置&#xff1a;选择 NVIDIA H800 或其他可用高性能 GPU。 系统配置&#xff1a;推荐使用 Ubuntu 20.04&#xff0c;内存 16GB&#xff0c;硬盘 50GB。 启…...

C#变量和函数如何和unity组件绑定

1.Button On_click (1)GameObject通过Add component添加上Script (2)Button选GameObject组件而不是直接选Script,直接选Script出现不了Script中的函数 2.RawImage 上面是错的 3.Text 上面是错的&#xff0c;应该是直接在GameObject里面填上对应的值 总结&#xff1a; …...

AI模型---安装cuda与cuDNN

1.安装cuda 先打开cmd 输入nvidia-smi 查看显卡支持cuda对应的版本&#xff1a; 然后去英伟达官网下载cuda&#xff08;外网多刷几次&#xff09; https://developer.nvidia.com/cuda-toolkit-archive 注意对应版本 安装过程中如果显示如下图&#xff1a; 请安装visual Stu…...

【大数据学习 | Spark-Core】Spark提交及运行流程

spark的集群运行结构 我们要选择第一种使用方式 命令组成结构 spark-submit [选项] jar包 参数 standalone集群能够使用的选项。 --master MASTER_URL #集群地址 --class class_name #jar包中的类 --executor-memory MEM #executor的内存 --executor-cores NUM # executor的…...

内网渗透横向移动1

1.信息收集 &#xff08;1&#xff09;判断域控 shell net time /domain shell ping OWA2010CN-God.god.org &#xff08;2&#xff09;主机探测 浏览探测->网络探测 主机列表显示&#xff1a; &#xff08;3&#xff09;域用户收集&#xff1a; shell net user /domain…...

现代密码学

概论 计算机安全的最核心三个关键目标&#xff08;指标&#xff09;/为&#xff1a;保密性 Confidentiality、完整性 Integrity、可用性 Availability &#xff0c;三者称为 CIA三元组 数据保密性&#xff1a;确保隐私或是秘密信息不向非授权者泄漏&#xff0c;也不被非授权者使…...

Pod 动态分配存储空间实现持久化存储

配置 Pod 以使用 PersistentVolume 作为存储 ​ 关于持久卷的介绍&#xff0c;可以看官方文档 https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/ ​ 持久卷根据存储位置&#xff0c;可以使用本地存储和云存储&#xff0c;如果有云服务平台&#xff0c…...

Jackson、Gson、FastJSON三款JSON利器比拼

在Java领域&#xff0c;有多种JSON工具包&#xff0c;比如Jackson、Gson、FastJSON&#xff0c;每家都各有所长&#xff0c;下面我们从性能、特性、生态、易用 性等几个方面来展开下&#xff1a; 一、Jackson 性能 Jackson是一款高性能的JSON处理库。它在序列化和反序列化操作…...

php:nginx如何配置WebSocket代理?

在nginx配置中加入以下配置即可&#xff1a; server {listen 80;server_name test.com;# 配置 WebSocket 代理location /ws {proxy_pass http://127.0.0.1:8083;proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade&qu…...

3349、检测相邻递增子数组 Ⅰ

3349、[简单] 检测相邻递增子数组 Ⅰ 1、题目描述 给你一个由 n 个整数组成的数组 nums 和一个整数 k&#xff0c;请你确定是否存在 两个 相邻 且长度为 k 的 严格递增 子数组。具体来说&#xff0c;需要检查是否存在从下标 a 和 b (a < b) 开始的 两个 子数组&#xff0c…...

C++笔记之函数入参传递std::unique_ptr 时使用 std::move的场景

C++笔记之函数入参传递std::unique_ptr 时使用 std::move的场景 code review! 参考笔记 C++笔记之unique_ptr转移堆内空间的所有权 文章目录 C++笔记之函数入参传递std::unique_ptr 时使用 std::move的场景一.使用 std::unique_ptr 作为函数参数时的主要场景二.一个完整示例一…...

怎么只提取视频中的声音?从视频中提取纯音频技巧

在数字媒体的广泛应用中&#xff0c;提取视频中的声音已成为一项常见且重要的操作。无论是为了学习、娱乐、创作还是法律用途&#xff0c;提取声音都能为我们带来诸多便利。怎么只提取视频中的声音&#xff1f;本文将详细介绍提取声音的原因、工具、方法以及注意事项。 一、为什…...

数仓工具—Hive语法之窗口函数中的 case when

窗口函数中的 case when 今天我们看一下窗口函数和case when 的各种花活,最近的需求各种窗口,一个需求中十几个窗口,加上各种条件边界,所以写了大量的窗口函数和case when的组合,今天我们来看一下。 我们的数据如下 %spark.pyspark df2 = spark.createDataFrame([(&quo…...

基于微信小程序的酒店客房管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、员工、普通用户功能模块&#xff1a;员工管理、用户管理、客房管理、预订管理、商品管理、评价管理、续订管理、订单管理等技术选型&#xff1a;SSM&#xff0c;vue&#xff0c;uniapp等测试环境&#xff1a;idea2024&#xff0c;jdk1…...

Elasticsearch客户端在和集群连接时,如何选择特定的节点执行请求的?

大家好&#xff0c;我是锋哥。今天分享关于【Elasticsearch客户端在和集群连接时&#xff0c;如何选择特定的节点执行请求的&#xff1f;】面试题。希望对大家有帮助&#xff1b; Elasticsearch客户端在和集群连接时&#xff0c;如何选择特定的节点执行请求的&#xff1f; 100…...

【AI最前线】DP双像素sensor相关的AI算法全集:深度估计、图像去模糊去雨去雾恢复、图像重建、自动对焦

Dual Pixel 简介 双像素是成像系统的感光元器件中单帧同时生成的图像&#xff1a;通过双像素可以实现&#xff1a;深度估计、图像去模糊去雨去雾恢复、图像重建 成像原理来源如上&#xff0c;也有遮罩等方式的pd生成&#xff0c;如图双像素视图可以看到光圈的不同一半&#x…...

CTF之密码学(Polybius密码)

棋盘密码&#xff0c;也称为Polybius密码或方格密码&#xff0c;是一种基于替换的加密方法。以下是对棋盘密码的详细解析&#xff1a; 一、加密原理 棋盘密码使用一个5x5的方格棋盘&#xff0c;其中填充了26个英文字母&#xff08;通常i和j被视为同一个字母并放在同一个格子中…...

【C++篇】从售票窗口到算法核心:C++队列模拟全解析

文章目录 须知 &#x1f4ac; 欢迎讨论&#xff1a;如果你在学习过程中有任何问题或想法&#xff0c;欢迎在评论区留言&#xff0c;我们一起交流学习。你的支持是我继续创作的动力&#xff01; &#x1f44d; 点赞、收藏与分享&#xff1a;觉得这篇文章对你有帮助吗&#xff1…...

clipboard

clipboard 现代复制到剪贴板。无闪光。只有 3kb 的 gzip 压缩。 安装 npm install clipboard --save第三方cdn提供商 <script src"https://cdn.jsdelivr.net/npm/clipboard2.0.11/dist/clipboard.min.js"></script>使用 data-clipboard-target"…...

【Mac】VMware Fusion Pro 安装 CentOS 7

1、下载镜像 CentOS 官网阿里云镜像网易镜像搜狐镜像 Mac M1芯片无法直接使用上述地址下载的最新镜像&#xff08;7.9、9&#xff09;&#xff0c;会一直卡在安装界面&#xff08;在 install 界面按 enter 回车无效&#xff09;&#xff0c;想要使用需要经过一系列操作&#…...

游戏引擎学习第22天

移除 DllMain() 并成功重新编译 以下是对内容的详细复述与总结&#xff1a; 问题和解决方案&#xff1a; 在编译过程中遇到了一些问题&#xff0c;特别是如何告知编译器不要退出程序&#xff0c;而是继续处理。问题的根源在于编译过程中传递给链接器的参数设置不正确。原本尝试…...

洛谷 B2038:奇偶 ASCII 值判断

【题目来源】https://www.luogu.com.cn/problem/B2038http://shnoip.openjudge.cn/level1/39/【题目描述】 任意输入一个字符&#xff0c;判断其 ASCII 是否是奇数&#xff0c;若是&#xff0c;输出 YES&#xff0c;否则&#xff0c;输出 NO。 例如&#xff0c;字符 A 的 ASCII…...

APIRouter

当然可以&#xff01;理解 FastAPI 中直接在 FastAPI 实例上定义路由与使用 APIRouter 作为路由器的区别&#xff0c;对于编写结构良好、可维护性高的应用程序至关重要。下面&#xff0c;我将详细解释这两种方法的区别、各自的优缺点以及何时使用它们。 1. 直接在 FastAPI 实例…...

算法模板2:位运算+离散化+区间合并

文章目录 1.6 位运算**位运算的常见应用**1.7 离散化**经典离散化题目例子****1. 区间合并和覆盖长度问题****2. 区间查询与修改****3. 动态求第 K 小值****4. 区间最大重叠次数****5. 动态逆序对计数****6. 二维区间问题****7. 模拟车流/时间段事件****8. 区间众数统计** **具…...

钉钉授权登录

一.找开钉钉开发平台【钉钉开放平台 (dingtalk.com)】 二。点击菜单【应用开发】->左边【钉钉应用】->【创建应用】 三。创建应用-》保存成功后&#xff0c;点击自己【新建的应用】&#xff0c;进入详细页面 四。进入应用详细页面。左边【分享设置】 注意&#xff1a;进…...