RTC

news2024/11/25 17:21:13

文章目录

    • 前言
    • 驱动
    • 应用程序
    • 运行

前言

RTC(Real Time Clock,实时时钟)是个常用的外设,通过 RTC 我们可以知道日期和时间信息,因此在需要记录时间的场合就需要实时时钟。
可以使用专用的实时时钟芯片来完成此功能,如 DS1302,不过有些 SOC 内部就已经自带了 RTC 外设,比如 IMX6U。
RTC 本质上就是一个定时器,只要给它提供时钟,它就会一直运行。寄存器保存着秒数,直接读取寄存器值就知道过了多长时间了,一般以 1970 年 1 月 1 日为起点。
RTC 也是带有闹钟功能的,往相应寄存器写入值,当时钟值和闹钟值匹配时就会产生时钟中断。

驱动

step1:
内核启动打印

...
snvs_rtc 20cc000.snvs:snvs-rtc-lp: rtc core: registered 20cc000.snvs:snvs-r as rtc0
...
snvs_rtc 20cc000.snvs:snvs-rtc-lp: setting system clock to 2021-07-28 10:40:23 UTC (1627468823)
...

得知 rtc 的驱动为 20cc000.snvs

step2:
查看设备树

snvs: snvs@020cc000 {
     compatible = "fsl,sec-v4.0-mon", "syscon", "simple-mfd";
     reg = <0x020cc000 0x4000>;


     snvs_rtc: snvs-rtc-lp {
         compatible = "fsl,sec-v4.0-mon-rtc-lp";
         regmap = <&snvs>;
         offset = <0x34>;
         interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
     };


     snvs_poweroff: snvs-poweroff {
         compatible = "syscon-poweroff";
         regmap = <&snvs>;
         offset = <0x38>;
         mask = <0x61>;
     };


     snvs_pwrkey: snvs-powerkey {
         compatible = "fsl,sec-v4.0-pwrkey";
         regmap = <&snvs>;
         interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
         linux,keycode = <KEY_POWER>;
         wakeup;
     };
 };

可知:rtc 是 snvs(Secure Non-Volatile Storage)的一个子功能,和其并列的还有 poweroff、pwrkey
目前我们只关注 snvs_rtc

snvs_rtc: snvs-rtc-lp {
    compatible = "fsl,sec-v4.0-mon-rtc-lp";
    regmap = <&snvs>;
    offset = <0x34>;
    interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
};

step3:
在 C 文件中搜索 "fsl,sec-v4.0-mon-rtc-lp",用来找到驱动

// drivers/rtc/rtc-snvs.c

static const struct of_device_id snvs_dt_ids[] = {
    { .compatible = "fsl,sec-v4.0-mon-rtc-lp", },
    { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, snvs_dt_ids);

进而找到对应的 probe() 函数

static struct platform_driver snvs_rtc_driver = {
    .driver = {
        .name    = "snvs_rtc",
        .pm    = SNVS_RTC_PM_OPS,
        .of_match_table = snvs_dt_ids,
    },
    .probe        = snvs_rtc_probe,
};
module_platform_driver(snvs_rtc_driver);    // 疑问:为什么是平台总线?

step4:
分析驱动注册(初始化)流程

static int snvs_rtc_probe(struct platform_device *pdev)
{
    struct snvs_rtc_data *data;
    struct resource *res;
    int ret;
    void __iomem *mmio;

    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;

    data->regmap = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "regmap");

    if (IS_ERR(data->regmap)) {
        dev_warn(&pdev->dev, "snvs rtc: you use old dts file, please update it\n");
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

        mmio = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(mmio))
            return PTR_ERR(mmio);

        data->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, &snvs_rtc_config);
    } else {
        data->offset = SNVS_LPREGISTER_OFFSET;
        of_property_read_u32(pdev->dev.of_node, "offset", &data->offset);
    }

    if (!data->regmap) {
        dev_err(&pdev->dev, "Can't find snvs syscon\n");
        return -ENODEV;
    }


    data->irq = platform_get_irq(pdev, 0);
    if (data->irq < 0)
        return data->irq;

    data->clk = devm_clk_get(&pdev->dev, "snvs-rtc");
    if (IS_ERR(data->clk)) {
        data->clk = NULL;
    } else {
        ret = clk_prepare_enable(data->clk);
        if (ret) {
            dev_err(&pdev->dev,
                "Could not prepare or enable the snvs clock\n");
            return ret;
        }
    }

    platform_set_drvdata(pdev, data);

    /* Initialize glitch detect */
    regmap_write(data->regmap, data->offset + SNVS_LPPGDR, SNVS_LPPGDR_INIT);

    /* Clear interrupt status */
    regmap_write(data->regmap, data->offset + SNVS_LPSR, 0xffffffff);

    /* Enable RTC */
    snvs_rtc_enable(data, true);

    device_init_wakeup(&pdev->dev, true);

    ret = devm_request_irq(&pdev->dev, data->irq, snvs_rtc_irq_handler,
                   IRQF_SHARED, "rtc alarm", &pdev->dev);
    if (ret) {
        dev_err(&pdev->dev, "failed to request irq %d: %d\n",
            data->irq, ret);
        goto error_rtc_device_register;
    }

    data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                    &snvs_rtc_ops, THIS_MODULE); // 设备注册
    if (IS_ERR(data->rtc)) {
        ret = PTR_ERR(data->rtc);
        dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
        goto error_rtc_device_register;
    }

    return 0;

error_rtc_device_register:
    if (data->clk)
        clk_disable_unprepare(data->clk);

    return ret;
}

step5:
先分析结构体

struct snvs_rtc_data {
    struct rtc_device *rtc;
    struct regmap *regmap;
    int offset;
    int irq;    // 中断号,初始化过程中,register_irq()
    struct clk *clk;
};
struct rtc_device
{
    struct device dev;
    struct module *owner;


    int id;
    char name[RTC_DEVICE_NAME_SIZE];   // 初始化过程中,肯定有个函数来对其进行赋值,猜测赋值 “rtc0”


    const struct rtc_class_ops *ops;    // file operations,行为核心
    struct mutex ops_lock;


    struct cdev char_dev;
    unsigned long flags;


    unsigned long irq_data;
    spinlock_t irq_lock;
    wait_queue_head_t irq_queue;
    struct fasync_struct *async_queue;


    struct rtc_task *irq_task;
    spinlock_t irq_task_lock;
    int irq_freq;
    int max_user_freq;


    struct timerqueue_head timerqueue;
    struct rtc_timer aie_timer;
    struct rtc_timer uie_rtctimer;
    struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
    int pie_enabled;
    struct work_struct irqwork;
    /* Some hardware can't support UIE mode */
    int uie_unsupported;


#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
    struct work_struct uie_task;
    struct timer_list uie_timer;
    /* Those fields are protected by rtc->irq_lock */
    unsigned int oldsecs;
    unsigned int uie_irq_active:1;
    unsigned int stop_uie_polling:1;
    unsigned int uie_task_active:1;
    unsigned int uie_timer_active:1;
#endif
};
struct rtc_class_ops {
    int (*open)(struct device *);    // 打开
    void (*release)(struct device *);    // 关闭
    int (*ioctl)(struct device *, unsigned int, unsigned long);    // ioctl
    int (*read_time)(struct device *, struct rtc_time *);    // 读时间
    int (*set_time)(struct device *, struct rtc_time *);    // 设置时间
    int (*read_alarm)(struct device *, struct rtc_wkalrm *);    // 读闹钟时间
    int (*set_alarm)(struct device *, struct rtc_wkalrm *);    // 设置闹钟时间
    int (*proc)(struct device *, struct seq_file *);
    int (*set_mmss64)(struct device *, time64_t secs);
    int (*set_mmss)(struct device *, unsigned long secs);
    int (*read_callback)(struct device *, int data);
    int (*alarm_irq_enable)(struct device *, unsigned int enabled);
};
static const struct file_operations rtc_dev_fops = {
    .owner        = THIS_MODULE,
    .llseek        = no_llseek,
    .read        = rtc_dev_read,
    .poll        = rtc_dev_poll,
    .unlocked_ioctl    = rtc_dev_ioctl, // case RTC_RD_TIME: rtc->ops->read_time(rtc->dev.parent, tm);
    .open        = rtc_dev_open,        // rtc->ops->open()
    .release    = rtc_dev_release,      // rtc->ops->release()
    .fasync        = rtc_dev_fasync,
};

关键函数

data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                    &snvs_rtc_ops, THIS_MODULE); // 设备注册

devm_rtc_device_register(,&snvs_rtc_ops,) // 设备注册
        rtc_device_register()
                rtc_dev_prepare()
                        cdev_init(&rtc->char_dev, &rtc_dev_fops);

驱动初始化的核心是上面这个函数 devm_rtc_device_register(),这个函数的核心是挂载 snvs_rtc_opsrtc_dev_fops 这两个 operations。
其中 rtc_dev_fops 为 /dev/rtc0 对应的 operations,即在应用层对 /dev/rtc0 执行 open() 系统调用,则最终会执行 rtc_dev_open(),其它函数类似。
snvs_rtc_ops 是作为 RTC 功能实现的函数,作为 rtc_dev_fops 的 RTC 功能支撑。比如,应用层调用 open() 系统调用后,会调 file_operations 的 rtc_dev_open() 函数,而在这个函数里面又会去调用 RTC 功能的 snvs_rtc_ops 函数。
总结就是,file_operations 看名字带个 file 就知道,操作 /dev/rtc 文件,就会最终调用其 hook 函数。
而在 file_operations 的各个 hook 函数中,我们想要实现的是 RTC 功能,所以就要借助 RTC 相关的功能函数来完成任务,这些 RTC 的功能函数就是 snvs_rtc_ops

open() --> rtc_dev_open() --> rtc->ops->open()
read() --> rtc_dev_read()
ioctl(fd, RTC_RD_TIME,) --> rtc_dev_ioctl: case RTC_RD_TIME: rtc->ops->read_time(); --> read_time()
close() --> rtc_dev_release() --> rtc->ops->release()

应用程序

rtc_test.c

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <linux/rtc.h>

static const char default_rtc[] = "/dev/rtc0";

int main(int argc, char **argv)
{
	int i, fd, retval, irqcount = 0;
	unsigned long tmp, data;
	struct rtc_time rtc_tm;
	const char *rtc = default_rtc;

	switch (argc) {
	case 2:
		rtc = argv[1];
		/* FALLTHROUGH */
	case 1:
		break;
	default:
		fprintf(stderr, "usage:  rtctest [rtcdev]\n");
		return 1;
	}

	fd = open(rtc, O_RDONLY);

	if (fd == -1) {
		perror(rtc);
		exit(errno);
	}

	fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n");

	/* Turn on update interrupts (one per second) */
	retval = ioctl(fd, RTC_UIE_ON, 0);
	if (retval == -1) {
		if (errno == ENOTTY) {
			fprintf(stderr, "\n...Update IRQs not supported.\n");
			goto test_READ;
		}
		perror("RTC_UIE_ON ioctl");
		exit(errno);
	}

	fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:\n", rtc);
	fflush(stderr);
	for (i = 1; i < 6; i++) {
		/* This read will block */
		retval = read(fd, &data, sizeof(unsigned long));
		if (retval == -1) {
			perror("read");
			exit(errno);
		}
		fprintf(stderr, "%d ", i);
		fflush(stderr);
		irqcount++;
	}

	fprintf(stderr, "\nAgain, from using select(2) on %s:\n", rtc);
	fflush(stderr);
	for (i = 1; i < 6; i++) {
		struct timeval tv = {5, 0}; /* 5 second timeout on select */
		fd_set readfds;

		FD_ZERO(&readfds);
		FD_SET(fd, &readfds);
		/* The select will wait until an RTC interrupt happens. */
		retval = select(fd + 1, &readfds, NULL, NULL, &tv);
		if (retval == -1) {
			perror("select");
			exit(errno);
		}
		/* This read won't block unlike the select-less case above. */
		retval = read(fd, &data, sizeof(unsigned long));
		if (retval == -1) {
			perror("read");
			exit(errno);
		}
		fprintf(stderr, "%d ", i);
		fflush(stderr);
		irqcount++;
	}

	/* Turn off update interrupts */
	retval = ioctl(fd, RTC_UIE_OFF, 0);
	if (retval == -1) {
		perror("RTC_UIE_OFF ioctl");
		exit(errno);
	}

test_READ:
	/* Read the RTC time/date */
	retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
	if (retval == -1) {
		perror("RTC_RD_TIME ioctl");
		exit(errno);
	}

	fprintf(stderr, "\n\nCurrent RTC date/time is :\n%d-%d-%d, %02d:%02d:%02d\n", rtc_tm.tm_mday,
			rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);

	/* Set the alarm to 5 sec in the future, and check for rollover */
	rtc_tm.tm_sec += 5;
	if (rtc_tm.tm_sec >= 60) {
		rtc_tm.tm_sec %= 60;
		rtc_tm.tm_min++;
	}
	if (rtc_tm.tm_min == 60) {
		rtc_tm.tm_min = 0;
		rtc_tm.tm_hour++;
	}
	if (rtc_tm.tm_hour == 24)
		rtc_tm.tm_hour = 0;

	retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
	if (retval == -1) {
		if (errno == ENOTTY) {
			fprintf(stderr, "\n...Alarm IRQs not supported.\n");
			goto test_PIE;
		}
		perror("RTC_ALM_SET ioctl");
		exit(errno);
	}

	/* Read the current alarm settings */
	retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
	if (retval == -1) {
		perror("RTC_ALM_READ ioctl");
		exit(errno);
	}

	fprintf(stderr, "Alarm time now set to :\n%02d:%02d:%02d\n", rtc_tm.tm_hour, rtc_tm.tm_min,
			rtc_tm.tm_sec);

	/* Enable alarm interrupts */
	retval = ioctl(fd, RTC_AIE_ON, 0);
	if (retval == -1) {
		perror("RTC_AIE_ON ioctl");
		exit(errno);
	}

	fprintf(stderr, "Waiting 5 seconds for alarm...\n");
	fflush(stderr);
	/* This blocks until the alarm ring causes an interrupt */
	retval = read(fd, &data, sizeof(unsigned long));
	if (retval == -1) {
		perror("read");
		exit(errno);
	}
	irqcount++;
	fprintf(stderr, "okay. Alarm rang.\n");

	/* Disable alarm interrupts */
	retval = ioctl(fd, RTC_AIE_OFF, 0);
	if (retval == -1) {
		perror("RTC_AIE_OFF ioctl");
		exit(errno);
	}

test_PIE:
	/* Read periodic IRQ rate */
	retval = ioctl(fd, RTC_IRQP_READ, &tmp);
	if (retval == -1) {
		/* not all RTCs support periodic IRQs */
		if (errno == ENOTTY) {
			fprintf(stderr, "\nNo periodic IRQ support\n");
			goto done;
		}
		perror("RTC_IRQP_READ ioctl");
		exit(errno);
	}
	fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp);

	fprintf(stderr, "Counting 20 interrupts at:");
	fflush(stderr);

	/* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
	for (tmp = 2; tmp <= 64; tmp *= 2) {

		retval = ioctl(fd, RTC_IRQP_SET, tmp);
		if (retval == -1) {
			/* not all RTCs can change their periodic IRQ rate */
			if (errno == ENOTTY) {
				fprintf(stderr, "\n...Periodic IRQ rate is fixed\n");
				goto done;
			}
			perror("RTC_IRQP_SET ioctl");
			exit(errno);
		}

		fprintf(stderr, "\n%ldHz:\t", tmp);
		fflush(stderr);

		/* Enable periodic interrupts */
		retval = ioctl(fd, RTC_PIE_ON, 0);
		if (retval == -1) {
			perror("RTC_PIE_ON ioctl");
			exit(errno);
		}

		for (i = 1; i < 21; i++) {
			/* This blocks */
			retval = read(fd, &data, sizeof(unsigned long));
			if (retval == -1) {
				perror("read");
				exit(errno);
			}
			fprintf(stderr, " %d", i);
			fflush(stderr);
			irqcount++;
		}

		/* Disable periodic interrupts */
		retval = ioctl(fd, RTC_PIE_OFF, 0);
		if (retval == -1) {
			perror("RTC_PIE_OFF ioctl");
			exit(errno);
		}
	}

done:
	fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");

	close(fd);

	return 0;
}

Makefile

all:
	arm-linux-gnueabihf-gcc rtc_test.c -o rtc_test.out

install:
	# cp rtc_test.out ~/tftp/
	cp rtc_test.out ~/project/board/IMX6ULL/rootfs/home/root/

clean:
	rm *.out

主要讲下 ioctl(fd, RTC_UIE_ON, 0),在应用程序调用 ioctl() 最终会执行驱动程序中的 rtc_dev_ioctl()。
内核中那么多 ioctl,怎么知道是要执行 rtc_dev_ioctl() 这个 ioctl 的呢,是根据 fd 匹配的。
在 rtc_dev_ioctl() 中解析 cmd,根据不同命令,执行不同操作,如读取时间、设置时间、中断使能和关闭等。

static long rtc_dev_ioctl(struct file *file,
		unsigned int cmd, unsigned long arg)
{
	int err = 0;
	struct rtc_device *rtc = file->private_data;
	const struct rtc_class_ops *ops = rtc->ops;
	struct rtc_time tm;
	struct rtc_wkalrm alarm;
	void __user *uarg = (void __user *) arg;

	err = mutex_lock_interruptible(&rtc->ops_lock);
	if (err)
		return err;

	switch (cmd) {
	case RTC_RD_TIME:
		mutex_unlock(&rtc->ops_lock);

		err = rtc_read_time(rtc, &tm);
		if (err < 0)
			return err;

		if (copy_to_user(uarg, &tm, sizeof(tm)))
			err = -EFAULT;
		return err;

	case RTC_SET_TIME:
		mutex_unlock(&rtc->ops_lock);

		if (copy_from_user(&tm, uarg, sizeof(tm)))
			return -EFAULT;

		return rtc_set_time(rtc, &tm);

	case RTC_UIE_ON:
		mutex_unlock(&rtc->ops_lock);
		return rtc_update_irq_enable(rtc, 1);

	case RTC_UIE_OFF:
		mutex_unlock(&rtc->ops_lock);
		return rtc_update_irq_enable(rtc, 0);

	default:
		/* Finally try the driver's ioctl interface */
		if (ops->ioctl) {
			err = ops->ioctl(rtc->dev.parent, cmd, arg);
			if (err == -ENOIOCTLCMD)
				err = -ENOTTY;
		} else
			err = -ENOTTY;
		break;
	}

done:
	mutex_unlock(&rtc->ops_lock);
	return err;
}

运行

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/651799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PostgreSQL如何创建临时表?

分类 PostgreSQL支持两种临时表&#xff1a; 会话级临时表&#xff1a;数据可以一直保存在整个会话的生命周期中事务级临时表&#xff1a;数据只存在于这个事务的生命周期中 在PostgreSQL中&#xff0c;不管是事务级的临时表还是会话级的临时表&#xff0c;当会话结束时都会…

家庭版Windows10/Windows11不支持远程桌面的解决办法

家庭版Windows10或11是不支持远程桌面的。我们可以在电脑的“设置”-> “远程桌面设置”中查看系统是否支持远程桌面&#xff1a;我们可以通过RDPWrap这个项目让家庭版也支持远程桌面。 百度网盘下载 首先在下面网址下载该项目&#xff0c;下载zip&#xff1a;https://gith…

【wifi使用指导】wifi模块怎么用?无线路由wifi模块SKW92A/SKW77网页配置说明

据悉&#xff0c;在全球范围内&#xff0c;WiFi承载了超过一半的数据流量&#xff0c;并且65%-90%的智能手机流量来自WiFi。无线覆盖的实现依赖于WiFi模块提供的WiFi信号&#xff0c;支持AP/Client&#xff0c;Bridge&#xff0c;Gateway&#xff0c;Router&#xff0c;3G/4G R…

U-Mail企业邮件服务器搭建方案

数字化办公的日渐推行&#xff0c;使企业对邮箱的依赖与日俱增&#xff0c;正式工作报告&#xff0c;部门之间的事物往来、通知等等都需要使用到企业邮箱。随着企业对数字化建设的不断深入&#xff0c;企业对企业邮箱的要求也越来越高&#xff0c;比如对第三方应用集成及协同办…

【C++】STL之string类(1)

个人主页&#xff1a;平行线也会相交&#x1f4aa; 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C之路】&#x1f48c; 本专栏旨在记录C的学习路线&#xff0c;望对大家有所帮助&#x1f647;‍ 希望我们一起努力、成长&…

19项网络与数据安全新国标全文公开免费下载

根据2023年5月23日国家市场监督管理总局、国家标准化管理委员会发布的中华人民共和国国家标准公告&#xff08;2023年第2号&#xff09;&#xff0c;全国信息安全标准化技术委员会归口的19项网络安全国家标准正式发布。近日&#xff0c;标准全文正式公开&#xff0c;博主第一时…

【社区图书馆】疯狂 Java 讲义:但凡种种,不一而足

虽说酒香不怕巷子深&#xff0c;但是千里之外并不一定能闻到&#xff0c;有人看到这可能会感觉这不免有些杠的味道&#xff0c;其实我想表达的是好酒也需要宣传&#xff0c;比如今天我所要讲的这本书《疯狂Java讲义》。 这不是【赠书活动】&#xff0c;这不是赠书活动… …&…

ChatGPT辅助学Qt6.2——1.Qt安装及编写登录界面

本文旨在帮助读者理解如何使用ChatGPT来辅助安装和学习Qt 6.2。我们将从Qt 6.2的基本概念开始&#xff0c;然后深入了解其安装过程&#xff0c;并探讨如何使用ChatGPT作为一个强大的辅助工具。对于那些寻求在学习和使用Qt 6.2中找到有效支持的人来说&#xff0c;这篇文章将提供…

中国电子学会2023年05月份青少年软件编程Python等级考试试卷五级真题(含答案)

2023-05 Python五级真题 分数&#xff1a;100 题数&#xff1a;38 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1. 有列表L[UK,china,lili,"张三"]&#xff0c;print(L[-2])的结果是&#xff1f;&#xff08; C&#xff09; A. UK B.…

华为防火墙基础知识

1.什么是防火墙 墙&#xff0c;始于防&#xff0c;忠于守。自古至今&#xff0c;墙予人以安全之意。防火墙&#xff0c;顾名思义&#xff0c;阻挡的是火&#xff0c;这一名词起源于建筑领域&#xff0c;其作用是隔离火灾&#xff0c;阻止火势从一个区域蔓延到另一个区域。 而…

Spring常见问题

包含内容 单例bean线程是安全的吗&#xff1f; Spring框架中的bean是单例的吗&#xff1f; 是单例的 这个默认是单例的但是可以在Bean注解类文件使用Scope注解进行配置 singleton&#xff1a;bean在每个Spring IOC容器中只有一个实例prototype&#xff1a;一个bean的定义可以…

C语言指针入门学习、知识点梳理(三)

本篇继续深入介绍C语言指针的基本概念与知识点&#xff0c;以经典指针程序--------”互换两个数字“进行阐述&#xff0c;基础不牢地动山摇&#xff0c;有关指针的基础概念&#xff0c;需要提前学习的&#xff0c;可以通过链接跳转至第一、第二篇。 C语言指针入门学习、概念梳…

Linux常见指令

Linux常见指令 引言Linux常见指令查指令——man文件管理相关指令lspwdcdtouchmkdirrmdir与rmrmdirrm cpmvfind 文件查看类catmorelesshead 与 tailheadtail使用管道显示某段内容 grep 打包压缩相关指令zip/unziptar 总结 引言 Linux与我们熟悉的Window都是操作系统&#xff0c…

C语言之指针详解(6)

目录 本章重点 1. 字符指针 2. 数组指针 3. 指针数组 4. 数组传参和指针传参 5. 函数指针 6. 函数指针数组 7. 指向函数指针数组的指针 8. 回调函数 9. 指针和数组面试题的解析 指向函数指针数组的指针 指向函数指针数组的指针是一个指针指针指向一个数组 &#xff0…

【Shiro】第三章 Shiro入门

目录 1、身份认证 2、Realm 3、编码、散列算法 4、Realm使用散列算法 1、身份认证 【1】基本流程 流程如下: 1、Shiro把用户的数据封装成标识token,token一般封装着用户名&

《C++程序设计原理与实践》笔记 第19章 向量、模板和异常

本章将完成最常见、最有用的STL容器vector的设计与实现。我们将展示如何实现元素数量可变的容器&#xff0c;如何以参数形式指定容器的元素类型&#xff0c;以及如何处理越界错误。本章使用的技术依赖模板和异常&#xff0c;因此我们将介绍如何定义模板&#xff0c;并给出资源管…

糖化学试剂:4594-52-9,1,3,5-三乙酰基-2-脱氧-D-赤式戊呋喃糖,试剂用途说明

基础产品数据&#xff08;Basic Product Data&#xff09;&#xff1a; CAS号&#xff1a;4594-52-9 中文名&#xff1a;1,3,5-三乙酰基-2-脱氧-D-赤式戊呋喃糖 英文名&#xff1a;1,3,5-Tri-O-acetyl-2-deoxy-D-erythro-pentofuranose 沸点 &#xff1a;329.342.0 C at 760 m…

vue2、vue3分别配置echarts多图表的同步缩放

文章目录 ⭐前言⭐使用dataZoom api实现echart的同步缩放&#x1f496; vue2实现echarts多图表同步缩放&#x1f496; vue3实现echarts多图表同步缩放 ⭐结束 ⭐前言 大家好&#xff01;我是yma16&#xff0c;本文分享在vue2和vue3中配置echarts的多图表同步缩放 背景&#xf…

进程描述+PCB+fork用法介绍

进程控制块PCB 进程id&#xff1a;系统中每个进程有唯一的id,在c语言中用pid_t 表示&#xff0c;其实就是非负整数进程的状态&#xff1a;就绪&#xff0c;运行&#xff0c;挂起&#xff0c;停止&#xff0c;僵尸等状态进程切换是需要保存和恢复的一些cpu寄存器描述虚拟地址空…

微调Hugging Face中图像分类模型

前言 本文主要针对Hugging Face平台中的图像分类模型&#xff0c;在自己数据集上进行微调&#xff0c;预训练模型为Google的vit-base-patch16-224模型&#xff0c;模型简介页面。代码运行于kaggle平台上&#xff0c;使用平台免费GPU&#xff0c;型号P100&#xff0c;笔记本地址…