linux watchdog 子系统
目录
- 一、watchdog 子系统
- 二、关键数据结构
- 2.1 watchdog_device
- 2.2 watchdog_ops
- 2.3 watchdog_info
- 三、重要流程
- 3.1 watchdog 初始化
- 3.2 watchdog 设备注册
- 3.3 watchdog 设备文件操作函数
- 3.4 watchdog 喂狗
- 用户空间 watchdog(busybox)
- 内核空间喂狗
- 疑问 or bug?
- 3.5 watchdog pretimeout 和 governor
- 四、softdog
- 4.1 softdog_init
- 4.2 softdog_ping
- 4.3 softdog_fire
一、watchdog 子系统
linux 中 watchdog 子系统是用于防止系统发生长时间故障、将系统从死循环或者死锁等异常状态中退出并重启的一种机制。
linux 内核支持基于 hrtimer 的 softdog 和基于硬件的硬件看门狗,创建 /dev/watchdog* 设备文件与用户空间程序进行交互。
用户空间的 watchdog 程序,会通过/dev/watchdog* 设备进行周期性喂狗。
二、关键数据结构
2.1 watchdog_device
watchdog_device 表示一个 watchdog 设备,保存了 watchdog 的各种操作参数和操作 ops。
struct watchdog_device {int id;struct device *parent;const struct attribute_group **groups; // 创建watchdog device的sysfs属性列表const struct watchdog_info *info; // 记录watchdog的特性,例如WDIOF_SETTIMEOUT WDIOF_KEEPALIVEPINGconst struct watchdog_ops *ops; // watchdog 操作接口const struct watchdog_governor *gov; // pretimeout使用的governorunsigned int bootstatus; // boot 时 watchdog 的状态unsigned int timeout;unsigned int pretimeout;unsigned int min_timeout;unsigned int max_timeout;unsigned int min_hw_heartbeat_ms;unsigned int max_hw_heartbeat_ms;struct notifier_block reboot_nb;struct notifier_block restart_nb;void *driver_data;struct watchdog_core_data *wd_data;unsigned long status; // watchdog 状态,active\running……
/* Bit numbers for status flags */
#define WDOG_ACTIVE 0 /* Is the watchdog running/active */
#define WDOG_NO_WAY_OUT 1 /* Is 'nowayout' feature set ? */
#define WDOG_STOP_ON_REBOOT 2 /* Should be stopped on reboot */
#define WDOG_HW_RUNNING 3 /* True if HW watchdog running */
#define WDOG_STOP_ON_UNREGISTER 4 /* Should be stopped on unregister */struct list_head deferred;
};
2.2 watchdog_ops
watchdog_ops 定义了 watchdog device 操作函数。
struct watchdog_ops {struct module *owner;/* mandatory operations */int (*start)(struct watchdog_device *);int (*stop)(struct watchdog_device *);/* optional operations */int (*ping)(struct watchdog_device *);unsigned int (*status)(struct watchdog_device *);int (*set_timeout)(struct watchdog_device *, unsigned int);int (*set_pretimeout)(struct watchdog_device *, unsigned int);unsigned int (*get_timeleft)(struct watchdog_device *);int (*restart)(struct watchdog_device *, unsigned long, void *);long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
};
2.3 watchdog_info
struct watchdog_info {__u32 options; /* Options the card/driver supports */__u32 firmware_version; /* Firmware version of the card */__u8 identity[32]; /* Identity of the board */
};
三、重要流程
3.1 watchdog 初始化
watchdog_init
接口对 watchdog 子系统做初始化:
watchdog_init->watchdog_dev_init->kthread_create_worker(0, "watchdogd")->sched_setscheduler // 设置watchdog_kworker的线程调度策略为SCHED_FIFO, 优先级MAX_RT_PRIO - 1->class_register->alloc_chrdev_region->watchdog_deferred_registration // 如果watchdog设备驱动早于watchdog_init则将设备加入到wtd_deferred_reg_list,此处集中进行列表上watchdog设备注册。
3.2 watchdog 设备注册
devm_watchdog_register_device
接口用于注册 watchdog 设备:
int devm_watchdog_register_device(struct device *dev, struct watchdog_device *wdd)-> watchdog_register_device(wdd);-> __watchdog_register_device-> // 参数检查-> watchdog_check_min_max_timeout-> watchdog_dev_register-> watchdog_cdev_register-> kthread_init_work // 创建pingwork任务-> hrtimer_init // 创建一个高精度定时器,定时器结束后调用的接口是 watchdog_timer_expired-> misc_register // if (wdd->id == 0),如果是注册第一个watchdog,则注册misc设备-> device_initialize-> cdev_init-> cdev_device_add // 创建并初始化watchdog设备,设备名为/dev/watchdog*-> watchdog_register_pretimeout-> watchdog_reboot_notifier // if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))-> register_restart_handler // if (wdd->ops->restart)
3.3 watchdog 设备文件操作函数
watchdog创建的misc 设备和 cdev 的文件操作函数都是 watchdog_fops
:
static const struct file_operations watchdog_fops = {.owner = THIS_MODULE,.write = watchdog_write,.unlocked_ioctl = watchdog_ioctl,.open = watchdog_open,.release = watchdog_release,
};static struct miscdevice watchdog_miscdev = {.minor = WATCHDOG_MINOR,.name = "watchdog",.fops = &watchdog_fops,
};
watchdog_open 接口中调用 watchdog_start 接口,start watchdog 和更新内核喂狗定时器。
static int watchdog_open(struct inode *inode, struct file *file)-> watchdog_start(wdd);-> wdd->ops->start(wdd)-> watchdog_update_worker // 更新喂狗定时器-> stream_open(inode, file);
watchdog_write 接口实现喂狗功能,写任意值都能喂狗; “V” 是 magic 字符,写 “V” 之后使能 watchdog 的魔法关闭功能:
static ssize_t watchdog_write(struct file *file, const char __user *data,size_t len, loff_t *ppos)->set_bit(_WDOG_ALLOW_RELEASE, &wd_data->status) // if (c == 'V')-> watchdog_ping(wdd)
watchdog_ioctl 支持一系列 watchdog 设置和信息获取操作。
static long watchdog_ioctl(struct file *file, unsigned int cmd,unsigned long arg)case WDIOC_GETSUPPORT: // 返回watchdog_info结构体case WDIOC_GETSTATUS: // 返回watchdog状态case WDIOC_GETBOOTSTATUS:case WDIOC_SETOPTIONS: // start 和stop操作case WDIOC_KEEPALIVE: // 喂狗case WDIOC_SETTIMEOUT: // 设置超时时间case WDIOC_GETTIMEOUT: // 获取超时时间case WDIOC_GETTIMELEFT: // 获取超时剩余时间case WDIOC_SETPRETIMEOUT: // 设置pretimeout case WDIOC_GETPRETIMEOUT: // 获取pretimeout
3.4 watchdog 喂狗
用户空间 watchdog(busybox)
watchdog 是 busybox 中的一个工具,通过watchdog -T 60 -t /dev/watchdog0,每 30秒喂一次狗,60秒没有喂狗则重启。
watchdog 是 busybox 中的一个工具,通过watchdog -T 60 -t /dev/watchdog0,每 30秒喂一次狗,60秒没有喂狗则重启。
Usage: watchdog [-t N[ms]] [-T N[ms]] [-F] DEVPeriodically write to watchdog device DEV-T N Reboot after N seconds if not reset (default 60)-t N Reset every N seconds (default 30)-F Run in foregroundUse 500ms to specify period in milliseconds
watchdog 内部大概实现如下:
watchdog_main->shutdown_on_signal // watchdog收到异常信号退出时调用,关闭watchdog。->shutdown_watchdog // 关闭watchdog。->watchdog_open // 打开 /dev/watchdog* 设备->WDIOC_SETOPTIONS // 启动watchdog。->WDIOC_SETTIMEOUT // 设置timeout。->while(1) // 循环写空内容,然后睡眠。
内核空间喂狗
在内核空间也有一个定时器定时喂狗,流程如下:
1、在 watchdog_dev_init 接口中,注册了一个优先级为 MAX_RT_PRIO - 1、调度策略为 SCHED_FIFO、名为 watchdogd 的内核线程;
struct sched_param param = {.sched_priority = MAX_RT_PRIO - 1,};
watchdog_kworker = kthread_create_worker(0, "watchdogd");
sched_setscheduler(watchdog_kworker->task, SCHED_FIFO, ¶m);
2、在注册 watchdog 设备时,初始化了一个 kthread_work 结构体,这个结构体表示一个内核线程工作项,用于调度和执行异步任务。kthread_init_work 函数将工作项与一个 watchdog_ping_work 关联起来,这个处理函数将在工作项被执行时调用;
kthread_init_work(&wd_data->work, watchdog_ping_work);
3、 在注册 watchdog 设备时,还会创建一个定时器,定时器超时接口是 watchdog_timer_expired,定时器在 watchdog_start 时会被开启;
hrtimer_init(&wd_data->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
wd_data->timer.function = watchdog_timer_expired;
hrtimer_start(&wd_data->timer, t, HRTIMER_MODE_REL_HARD);
4、在定时器超时接口 watchdog_timer_expired 中,使用 kthread_queue_work 接口将 kthread_work 工作项 wd_data->work 添加到了 watchdog 工作线程 watchdog_kworker 的工作队列中,使得工作线程可以异步执行该工作项。
static enum hrtimer_restart watchdog_timer_expired(struct hrtimer *timer)
{struct watchdog_core_data *wd_data;wd_data = container_of(timer, struct watchdog_core_data, timer);kthread_queue_work(watchdog_kworker, &wd_data->work);return HRTIMER_NORESTART;
}
5、 wd_data->work 调用接口为 watchdog_ping_work ,改接口中执行看门狗的 ping 或者 start 动作实现看门狗喂狗,然后在watchdog_update_worker 接口中计算合适的下次喂狗时间,并重启定时器。
static void watchdog_ping_work(struct kthread_work *work)-> __watchdog_ping // if (watchdog_worker_should_ping(wd_data))-> wdd->ops->ping(wdd); // if (wdd->ops->ping)-> wdd->ops->start(wdd); // else-> watchdog_update_worker(wdd);-> hrtimer_start
总结一下,watchdog 驱动中,通过创建一个定时器,并在定时器的超时函数中将看门狗喂狗函数添加到看门狗线程的工作队列中,实现当定时器超时时调用喂狗函数。并在喂狗函数中,计算合适的下次喂狗时间并重启定时器,由此实现了反复喂狗。
疑问 or bug?
上面提到的内核定时器喂狗需要配合用户空间喂狗时才能生效,单独内核空间定时器喂狗一段时间后定时器将不再刷新,只有在用户空间喂狗的前提下,内核空间喂狗的定时器才会刷新!!?那么内核空间定时器喂狗保留的意义是什么?这地方是个 bug 还是设计的就是如此,有大佬清楚的话可以一起讨论下。
代码分析如下:
上面提到,内核喂狗定时器任务 watchdog_ping_work 接口中,执行看门狗的 ping 或者 start 动作实现看门狗喂狗,然后在watchdog_update_worker 接口中计算合适的下次喂狗时间,并重启定时器。
static inline void watchdog_update_worker(struct watchdog_device *wdd)-> ktime_t t = watchdog_next_keepalive(wdd); // 计算下次喂狗时间t-> hrtimer_start(&wd_data->timer, t, HRTIMER_MODE_REL_HARD) // if (t > 0),更新定时器
下次喂狗时间通过 watchdog_next_keepalive
接口计算:
static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd)
{struct watchdog_core_data *wd_data = wdd->wd_data;unsigned int timeout_ms = wdd->timeout * 1000;ktime_t keepalive_interval;ktime_t last_heartbeat, latest_heartbeat;ktime_t virt_timeout;unsigned int hw_heartbeat_ms;if (watchdog_active(wdd))virt_timeout = ktime_add(wd_data->last_keepalive,ms_to_ktime(timeout_ms));elsevirt_timeout = wd_data->open_deadline;hw_heartbeat_ms = min_not_zero(timeout_ms, wdd->max_hw_heartbeat_ms);keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2);/** To ensure that the watchdog times out wdd->timeout seconds* after the most recent ping from userspace, the last* worker ping has to come in hw_heartbeat_ms before this timeout.*/last_heartbeat = ktime_sub(virt_timeout, ms_to_ktime(hw_heartbeat_ms));latest_heartbeat = ktime_sub(last_heartbeat, ktime_get());if (ktime_before(latest_heartbeat, keepalive_interval))return latest_heartbeat;return keepalive_interval;
}
分析该接口,主要有这么几个变量:
virt_timeout = ktime_add(wd_data->last_keepalive, ms_to_ktime(timeout_ms));
// 下次超时时间,是 last_keepalive 时间 + watchdog timeout 时间last_heartbeat = ktime_sub(virt_timeout, ms_to_ktime(hw_heartbeat_ms));
// 理论最近一次的喂狗时间,要根据 max_hw_heartbeat_ms 时间和 timeout 时间稍微提前一点返回值1:latest_heartbeat = ktime_sub(last_heartbeat, ktime_get());
// 理论时间减去当前时间,是还差多久需要喂狗的时间返回值2:keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2);
// keepalive_interval是根据看门狗设置的 max_hw_heartbeat_ms 计算的还差多久需要喂狗的时间
该接口返回值当前时间到下次喂狗时间的差值,有两种可能的返回值:
- 返回值 keepalive_interval 是根据watchdog驱动设置的
wdd->timeout
和wdd->max_hw_heartbeat_ms
计算出的,timeout 和 max_hw_heartbeat_ms 设置确定后,该值就不变了; - 返回值 latest_heartbeat 是先根据上次更新 wd_data->last_keepalive 值的时间计算出一个理论下次喂狗时间 last_heartbeat,该理论时间减去当前时间 ktime_sub(last_heartbeat, ktime_get()) 得到 latest_heartbeat;
- 返回值是判断 latest_heartbeat 和 keepalive_interval 的较小值,返回较小值;
问题:
但是,wd_data->last_keepalive 只在 wdg_start 和用户空间喂狗函数 watchdog_ping 接口中会更新,在内核定时器喂狗任务接口中,不会更新 wd_data->last_keepalive 值!!
static int watchdog_ping(struct watchdog_device *wdd)
{struct watchdog_core_data *wd_data = wdd->wd_data;if (!watchdog_active(wdd) && !watchdog_hw_running(wdd))return 0;set_bit(_WDOG_KEEPALIVE, &wd_data->status);wd_data->last_keepalive = ktime_get(); // 更新 wd_data->last_keepalivereturn __watchdog_ping(wdd);
}
// 内核定时器的喂狗接口,接口内不会更新 wd_data->last_keepalive
static void watchdog_ping_work(struct kthread_work *work)
{struct watchdog_core_data *wd_data;wd_data = container_of(work, struct watchdog_core_data, work);mutex_lock(&wd_data->lock);if (watchdog_worker_should_ping(wd_data))__watchdog_ping(wd_data->wdd);mutex_unlock(&wd_data->lock);
}
- 当 last_keepalive 不再更新,通过
latest_heartbeat = ktime_sub(last_heartbeat, ktime_get());
计算出的值将是个负值(linux 中 ktime_t 类型是一个有符号数); - watchdog_next_keepalive 接口返回一个负值;
hrtimer_start(&wd_data->timer, t, HRTIMER_MODE_REL_HARD);
设置的定时器超时时间入参 t 是一个负值;
对于 hrtimer_start 设置一个负值的超时时间是怎么处理的没有再细追,但是实际测试下来,的确没有再继续喂狗!
所以如果没有用户空间的喂狗情况下,只靠内核空间是无法实现定时喂狗的。
3.5 watchdog pretimeout 和 governor
- pretimeout 区别于 timeout,某些 watchdog 触发 timeout 后立即重启了,来不及做一些现场保存等动作。
- pretimeout 是指在 timeout 之前的设置的一个超时时间,此时软件还处于可控状态,可以做一些预警和提前保存的动作。
- 触发 pretimeout 调用指定的 governor 可以执行不同动作。
- 支持 pretimeout 的 watchdog options 包含 WDIOF_PRETIMEOUT。
int watchdog_register_governor(struct watchdog_governor *gov);--governor的注册和注销接口。
void watchdog_unregister_governor(struct watchdog_governor *gov);int watchdog_register_pretimeout(struct watchdog_device *wdd);--pretimeout注册和注销接口。
void watchdog_unregister_pretimeout(struct watchdog_device *wdd);
int watchdog_pretimeout_available_governors_get(char *buf);
int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf);--设置/获取pretimeout对应的governor。
int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,const char *buf);
注册governor:
int watchdog_register_governor(struct watchdog_governor *gov)-> list_add(&priv->entry, &governor_list) // 将gov添加到governor_list// 如果gov是default gov,将所有wdd的gov设置为当前govif (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,WATCHDOG_GOV_NAME_MAXLEN)) {default_gov = gov;list_for_each_entry(p, &pretimeout_list, entry)if (!p->wdd->gov)p->wdd->gov = default_gov;}
设置 watchdog 设备的 governor:
int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,const char *buf)-> find_governor_by_name(buf);-> wdd->gov = priv->gov;
调用 governor:
void watchdog_notify_pretimeout(struct watchdog_device *wdd)-> wdd->gov->pretimeout(wdd);
四、softdog
softdog 驱动通过软件模拟 watchdog 实现看门狗功能。
4.1 softdog_init
softdog_init 流程与正常硬件驱动的 watchdog 类似,只是实现了一个 softwatchdog 的定时器,该定时器在 ping 接口会被反复重启,当定时器超时也就说明软件没有及时喂狗,触发定时器超时函数,在超时函数里执行重启或者 panic 操作。
static int __init softdog_init(void)// 正常看门狗设备初始化watchdog_init_timeout(&softdog_dev, soft_margin, NULL);watchdog_set_nowayout(&softdog_dev, nowayout);watchdog_stop_on_reboot(&softdog_dev); // softdog使用的定时器hrtimer_init(&softdog_ticktock, CLOCK_MONOTONIC, HRTIMER_MODE_REL);softdog_ticktock.function = softdog_fire;// 设置pretimeout的定时器,超时接口softdog_pretimeout中调用watchdog_notify_pretimeoutif (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) {softdog_info.options |= WDIOF_PRETIMEOUT;hrtimer_init(&softdog_preticktock, CLOCK_MONOTONIC,HRTIMER_MODE_REL);softdog_preticktock.function = softdog_pretimeout;}// 看门狗设备注册ret = watchdog_register_device(&softdog_dev);if (ret)return ret;
}
module_init(softdog_init);
4.2 softdog_ping
softdog_ping 实现 softdog 喂狗,喂狗函数里是重新启动 softdog timeout 和 pretimeout 的定时器。
static int softdog_ping(struct watchdog_device *w)
{if (!hrtimer_active(&softdog_ticktock))__module_get(THIS_MODULE);hrtimer_start(&softdog_ticktock, ktime_set(w->timeout, 0),HRTIMER_MODE_REL);if (IS_ENABLED(CONFIG_SOFT_WATCHDOG_PRETIMEOUT)) {if (w->pretimeout)hrtimer_start(&softdog_preticktock,ktime_set(w->timeout - w->pretimeout, 0),HRTIMER_MODE_REL);elsehrtimer_cancel(&softdog_preticktock);}return 0;
}
4.3 softdog_fire
softdog_fire 是 softdag timeout 定时器超时函数,函数内部执行重启或者 panic 动作。
static enum hrtimer_restart softdog_fire(struct hrtimer *timer)
{module_put(THIS_MODULE);if (soft_noboot) {pr_crit("Triggered - Reboot ignored\n");} else if (soft_panic) {pr_crit("Initiating panic\n");panic("Software Watchdog Timer expired");} else {pr_crit("Initiating system reboot\n");emergency_restart();pr_crit("Reboot didn't ?????\n");}return HRTIMER_NORESTART;
}
- 参考:
- Linux watchdog子系统概述
相关文章:

linux watchdog 子系统
目录 一、watchdog 子系统二、关键数据结构2.1 watchdog_device2.2 watchdog_ops2.3 watchdog_info 三、重要流程3.1 watchdog 初始化3.2 watchdog 设备注册3.3 watchdog 设备文件操作函数3.4 watchdog 喂狗用户空间 watchdog(busybox)内核空间喂狗疑问 …...

论文引用h指数
文章目录 1、描述2、关键字3、思路4、notes5、复杂度6、code 1、描述 给你一个整数数组 citations ,其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数。 根据维基百科上 h 指数的定义:h 代表“高引用次数” &…...

四、Python日志系统之日志文件的备份和删除
import os import datetime import logging from watchdog.events import FileSystemEventHandler from watchdog.observers import Observer """实现代码中处理日志文件的备份和删除""" class UserLog:def __init__(self):self.logger logging…...

Android Camera Framework:从基础到高级
目录 基础知识1. Camera API 与 Camera2 API2. 权限 关键组件1. CameraManager2. CameraDevice3. CaptureRequest 和 CaptureSession 高级功能1. 实时滤镜2. 手动控制3. 高动态范围 (HDR) 和夜间模式 在现代移动应用开发中,相机功能已成为许多应用程序的核心组成部分…...

面向 Rust 新手的 Cargo 教程:轻松上手
面向 Rust 新手的 Cargo 教程:轻松上手 引言Cargo 简介定义与重要性与传统构建工具的对比 安装与配置 Cargo在不同操作系统上安装 Rust 和 CargoWindowsmacOSLinux 配置 Cargo 环境变量与路径第一个 Cargo 项目 主要功能概述结语 引言 在编程语言的浩瀚宇宙中&…...

MSPM0G3507——时钟配置(与32关系)
先将32端时钟配置分为1,2,3如图 1是PSC左边未经分频的时钟源(HZ) 2是经过PSC分频的时钟信号(HZ) 3是最终的输出信号(HZ) 3输出的是一个定时器周期的HZ,可以转换成时间 …...

Linux 创建新虚拟机的全过程图解
一、创建新虚拟机 1.选择自定义 2.直接下一步 3.选择稍后安装 4.设置虚拟机名和安装位置 5.配置处理器(处理器数量:4、每个处理器的内核:2) 6. 内存选择 7.网络类型 8. IO控制器类型-默认推荐 9.磁盘类型-默认推荐 10.选择虚拟磁…...

【已解决】腾讯云安装了redis,但是本地访问不到,连接不上
汇总了我踩过的所有问题。 查看配置文件redis.conf 1、把bind 127.0.0.1给注释掉(前面加个#就是)或者改成bind 0.0.0.0,因为刚下载时它是默认只让本地访问。(linux查找文档里的内容可以输入/后面加需要匹配的内容,然后…...

python批量去除图片文字水印
#!/usr/bin/env python # -*- coding:utf-8 -*- # 需要安装的库 # pip install paddlepaddle -i https://mirrors.aliyun.com/pypi/simple/ # pip install paddleocr -i https://mirrors.aliyun.com/pypi/simple/ # pip install cv2 -i https://mirrors.aliyun.com/pypi/simple…...

C++ Qt 自制开源科学计算器
C Qt 自制开源科学计算器 项目地址 软件下载地址 目录 0. 效果预览1. 数据库准备2. 按键&快捷键说明3. 颜色切换功能(初版)4. 未来开发展望5. 联系邮箱 0. 效果预览 普通计算模式效果如下: 科学计算模式效果如下: 更具体的功能演示视频见如下链接…...

相机光学(二十八)——感光度(ISO)
感光度又称为ISO,是指相机对光线的敏感程度。ISO值越大,感光度越高,拍出来的照片就会越亮,反之就会越暗。但是ISO过高会使照片噪点也随之变高。感光度,又称为ISO值,是衡量底片对于光的灵敏程度,…...

基于全国产复旦微JFM7K325T+ARM人工智能数据处理平台
复旦微可以配合的ARM平台有:RK3588/TI AM62X/ NXP IMX.8P/飞腾FT2000等。 产品概述 基于PCIE总线架构的高性能数据预处理FMC载板,板卡采用复旦微的JFM7K325T FPGA作为实时处理器,实现各个接口之间的互联。该板卡可以实现100%国产化。 板卡具…...

HarmonyOS Next应用开发之系统概述
一、鸿蒙系统概述 鸿蒙系统可以分为华为鸿蒙系统(HUAWEI HarmonyOS)和开源鸿蒙系统(OpenHarmony),华为鸿蒙系统是基于OpenHarmony基础之上开发的商业版操作系统。他们二者的关系可以用下图来表示: 1.1、…...

RedHat运维-Linux SSH基础2-基于公钥认证
1. 要想配置基于公钥认证的SSH连接,而不是基于密码认证的SSH连接,只需要将自己的公钥传送给对方即可,假如公钥是~/.ssh/id_rsa.pub,对方是centos192.168.197.128,则命令是____________________________________&#x…...

机器学习模型运用在机器人上
机器学习模型在机器人技术中的应用非常广泛,涵盖了从简单的运动控制到复杂的认知和交互功能。以下是几种机器学习模型在机器人上的典型应用: 感知与识别: 计算机视觉:使用卷积神经网络(CNNs)识别和理解视觉…...

振弦采集仪在大型工程安全监测中的作用与意义
振弦采集仪在大型工程安全监测中的作用与意义 河北稳控科技振弦采集仪是一种用于测量振动频率的仪器,常用于大型工程的安全监测中。它通过采集振弦的振动信号,可以对工程结构的振动特性进行实时监测和分析。振弦采集仪在大型工程安全监测中具有重要的作…...

CVE-2024-36991:Splunk Enterprise任意文件读取漏洞复现 [附POC]
文章目录 CVE-2024-36991:Splunk Enterprise任意文件读取漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议CVE-2024-36991:Splunk Enterprise任意文件读取漏洞复现 [附POC] 0x01 前言 免责声明:…...

Python的utils库详解
Python的utils库并不是一个官方标准库,而是指一系列提供实用功能的工具库或模块,这些库或模块通常包含了一系列帮助开发人员加速日常工作、提高开发效率的工具函数或类。由于Python社区的开放性和活跃性,存在多个不同的utils库,每…...

基于 Qt、FFmpeg 和 OpenGL 开发跨平台安卓实时投屏软件 QtScrcpy
文章目录 基于 Qt、FFmpeg 和 OpenGL 开发跨平台安卓实时投屏软件 QtScrcpy项目详细介绍1. 项目背景2. 功能特点3. 关键代码解读1. 引入必要的头文件和初始化函数2. VideoWidget 类的定义3. OpenGL 初始化和绘制函数4. 视频解码和渲染线程5. 主函数示例结语基于 Qt、FFmpeg 和 …...

LabVIEW光谱测试系统
在现代光通信系统中,光谱分析是不可或缺的工具。开发了一种基于LabVIEW的高分辨率光谱测试系统,通过对可调谐激光器、可编程光滤波器和数据采集系统的控制,实现了高效、高精度的光谱测量。 项目背景 随着光通信技术的迅速发展,对…...

SpringBoot使用@RestController处理GET和POST请求
在Spring MVC中,RestController注解的控制器类可以处理多种HTTP请求方法,包括GET和POST。这些请求方法通过特定的注解来映射,比如GetMapping用于GET请求,PostMapping用于POST请求。这些注解是RequestMapping的特定化版本ÿ…...

Kudu分区策略
Kudu表的分区策略主要有三种:范围分区(Partition By Range)、哈希分区(Partition By Hash)和高级分区(Partition By Hash And Range)。这些策略都要求分区字段必须包含在主键中。 范围分区&…...

spring的bean注册
bean注册 第三方jar包的类想添加到ioc中,加不了Component该怎么办呢。 可以使用Bean和Import引入jar包,可以使用maven安装到本地仓库。 修改bean的名字:Bean("aaa")使用ioc的已经存在的bean对象,如Country:p…...

权限控制权限控制权限控制权限控制权限控制
1.权限的分类 视频学习:https://www.bilibili.com/video/BV15Q4y1K79c/?spm_id_from333.337.search-card.all.click&vd_source386b4f5aae076490e1ad9b863a467f37 1.1 后端权限 1. 后端如何知道该请求是哪个用户发过来的 可以根据 cookie、session、token&a…...

JavaWeb系列二十一: 数据交换和异步请求(JSON, Ajax)
文章目录 官方文档JSON介绍JSON快速入门JSON对象和字符串对象转换应用案例注意事项和细节 JSON在java中使用说明JSON在Java中应用场景应用实例1.3.3 Map对象和JSON字符串转换 2. Ajax介绍2.1 Ajax应用场景2.2 传统的web应用-数据通信方式2.3 Ajax-数据通信方式2.4 Ajax文档使用…...

layui项目中的layui.define、layui.config以及layui.use的使用
第一步:创建一个layuiTest项目,结构如下 第二步:新建一个test.js,利用layui.define定义一个模块test,并向外暴露该模块,该模块里面有两个方法method1和method2. 第三步:新建一个test.html,在该页面引入layui.js&#x…...

ChatGPT对话:Scratch编程中一个单词,如balloon,每个字母行为一致,如何优化编程
【编者按】balloon 7个字母具有相同的行为,根据ChatGPT提供的方法,优化了代码,方便代码维护与复用。初学者可以使用7个字母精灵,复制代码到不同精灵,也能完成这个功能,但不是优化方法,也没有提高…...

HTML【详解】超链接 a 标签的四大功能(页面跳转、页内滚动【锚点】、页面刷新、文件下载)
超链接 a 标签主要有以下功能: 跳转到其他页面 <a href"https://www.baidu.com/" target"_blank" >百度</a>href:目标页面的 url 地址或同网站的其他页面地址,如 detail.htmltarget:打开目标页面…...

Nginx+Tomcat群集
一.实验环境 二.安装多台Tomcat服务器 1.在安装Tomcat之前必须先安装JDK。 JDK的全称是Java Development Kit,是sun公司提供的JAVA语言的软件开发工具包,其中包含Java虚拟机(JVM),编写好的Java源程序经过编译可形成Ja…...

DBA 数据库管理 部署Mysql 服务,基础查询
数据库:存储数据的仓库 数据库服务软件: 关系型数据库: 存在硬盘 ,制作表格的 数据库的参数 [rootmysql50 ~]# cat /etc/my.cnf.d/mysql-server.cnf 主配置文件 [mysqld] datadir/var/lib/mysql 存放数据库目录…...