Linux Container 研究报告

linux中container_of详解 linux中container_of详解作用详解typeof(((type *)0)->member)const typeof(((type )0)->member)__mptr = (ptr);offsetof(type, member))(type *)((char *)__mptr - offsetof(type, member))举例 作用 根据一个结构体变量中的一个成员变量的指针来获取指向整个结构体变量的指针 详解 container_of出现在linux/kernel.h中,定义如下 阅读详情

1. 综述

lxc是Linux Container的用户态工具包。其代码由三部分组成:

  1. shell脚本,部分lxc命令是用shell脚本写就的。
  2. c语言代码,最终编译成可执行文件。这部分代码也用来提供最终的lxc命令。但是这些代码以处理命令行参数,读取配置文件等为主。
  3. c语言代码,最终编译为动态链接库liblxc.so。该动态库提供了lxc项目的大部分功能,如配置文件分析、日志记录、容器的创建、通信等。lxc命令的各项功能基本都是通过调用liblxc.so中的函数来完成的。

在命名习惯上, 生成lxc命令的c源文件都有lxc_的前缀。而生成liblxc.so的c源文件则没有该前缀。

2. lxc-start

lxc-start的执行过程大致就是两步:

  1. 解析命令行和配置文件
  2. 创建新的进程运行container

2.1 解析命令行和配置文件

lxc-start的main函数在lxc_start.c中。从main的流程中能大致窥探出lxc-start的执行过程。首先调用lxc_arguments_parse来分析命令行,再调用lxc_config_read来解析配置文件,等获取好足够的信息后,调用lxc_start开始了container。

lxc_arguments_parse

函数的实现位于arguments.c中。通过该函数的执行,命令行参数中的信息被存放到了类型为lxc_arguments的变量my_args中。命令行参数中有几个我们可以注意一下:

  • "-n" 指定了container的名字
  • "-c" 指定了某个文件作为container的console
  • "-s" 在命令行中指定key=value的config选项
  • "-o" 指定输出的log文件
  • "-l" log的打印级别。用"-l DEBUG"命令行参数,log打印的信息最详细

lxc_arguments中有一个字段lxcpath指定了lxc container的存放路径。可以在命令参数-P选项中设置。如果不设置,会启用默认参数。该默认参数是在编译lxc代码的时候指定的,一般情况下为"/usr/local/var/lib/lxc"或"/var/lib/lxc"。在本文中,我们一律用LXCPATH来表示该路径。

另外,我们约定用CT-NAME表示-n参数指定的container的名称。

lxc_config_read

它的实现在confile.c中。逐行读取配置文件。并调用confile.c下的parse_line来每行做解析。因为配置文件每行都是key=value的形式的,所以parse_line的主要内容是找到"=",分析出(key, value)对并做处理。

配置文件的路径由-f参数指定。不指定则从LXCPATH/CT-NAME/config中读取。

confile.c的真正核心内容在与95行定义的一个结构体数组

static struct lxc_config_t config[] = {
    { "lxc.arch",                 config_personality          },
    { "lxc.pts",                  config_pts                  },
    { "lxc.tty",                  config_tty                  },
    { "lxc.devttydir",            config_ttydir               },
    .....
};

其中lxc_config_t结构体的定义如下:

typedef int (*config_cb)(const char *key, const char *value, struct lxc_conf *lxc_conf);
struct lxc_config_t {
    char* name;
    config_cb cb;
};

lxc_config_t结构体的name字段给定了key的值,回调函数cb给出了对应key的处理方法。整个config结构体数组就是键值与对应动作的一个查找表。

现在我们来考虑一个场景。我们在配置文件中写入了lxc.tty = 4。parse_line会解析出(lxc.tty, 4)的序对。到config中查询得出其对应的处理函数是config_tty,于是就开始调用config_tty。

函数指针config_cb一共有三个参数,key指的是如lxc.tty之类的键,而value指的是如4之类的值。lxc_conf用来存放config文件的分析结果。

lxc_config_read读取好的配置文件放在类型为lxc_conf的结构体指针conf。lxc_conf的定义在conf.h中。

2.2 调用lxc_start

让我们再次回到main函数。前面我们通过分析命令行参数和配置文件,收集了container的一系列信息,接下来就该启动container了。

main函数255行的lxc_start打响了了启动container的第一枪。lxc_start的实现在start.c中,函数原型如下:

int lxc_start(const char* name, char *const argv[], struct lxc_conf *conf, const char *lxcpath)

四个参数的含义如下:

  • name CT-NAME
  • argv container要执行的第一个命令。可以通过命令行参数指定, 如“lxc-start -n android4.2 /init”,这里的argv就会是{"/init", NULL}。如果没有指定,默认是{"/sbin/init", NULL}
  • conf 前面解析好的container配置文件中指定的配置信息。
  • lxcpath LXCPATH

lxc_start首先调用lxc_check_inherited来关闭所有打开的文件句柄。0(stdin), 1(stdout), 2(stder)和日志文件除外。紧接着就调__lxc_start。

__lxc_start

其原型如下:

int __lxc_start(const char* name, struct lxc_conf *conf, struct lxc_operators *op, void *data, const char *lxcpath)

lxc_operators结构体定义如下:

struct lxc_operations {
    int (*start)(struct lxc_handler *, void *);
    int (*post_start)(struct lxc_handler *, void *);
};

各个参数含义如下:

  • name CT-NAME
  • conf container配置信息
  • op 用lxc_operator结构体来存放了两个函数指针start和post_start。这两个指针分别指向start.c的start函数和post_start函数。
  • data start_args类型的结构体,唯一的成员变量argv指向了lxc_start的实参argv,也就是container要执行的init。
  • lxcpath LXCPATH

__lxc_start代码不复杂。我们将比较重要的几个函数调用抽出来看。

lxc_init

__lxc_start调用的第一个函数,用来初始化lxc_handler结构体。传入的三个参数依次为:

  • name CT-NAME
  • conf container的配置信息
  • lxcpath LXCPATH

函数先新分配一个lxc_handler的结构体handler,设置其conf、lxcpath和name字段。然后调用了lxc_command_init新创建了一个socket并listen之,新建socket的句柄放置在handler->maincmd_fd中。该socket的作用应为接受外部命令。lxc_command_init的实现在commands.c中。其分析可以详见模块commands.c部分。

接着是lxc_set_state。它将STARTING的状态消息写入到另一个socket中。lxc_set_state的实现调用了monitor.c的lxc_moitor_send_state。对其分析可以参见monitor.c模块。

接着是部分环境变量的设置:LXC_NAME, LXC_CONFIG_FILE, LXC_ROOTFS_MOUNT, LXC_ROOTFS_PATH, LXC_CONSOLE, LXC_CONSOLE_LOGPATH。

接下来的四件事情:

  1. 调用run_lxc_hooks运行pre-start的脚本。
  2. 调用lxc_create_tty创建tty
  3. 调用lxc_create_console创建console
  4. 调用setup_signal_fd处理进程的信号响应

我们来重点分析第二步和第三步

终端设备的创建

1. tty

lxc_create_tty通过调用openpty的命令来为container分配tty设备。conf->tty参数指定了要分配的tty的个数。conf->tty_info结构体用来存放分配好的tty的相关信息。

如果conf->tty的值是4,那么lxc_create_tty执行完之后的结果是:

conf->tty_info->nb_tty: 4
conf->tty_info->pty_info: 大小为4的类型为lxc_pty_info的数组的头指针

lxc_pty_info的定义如下:

struct lxc_pty_info {
    char name[MAXPATHLEN];
    int master;
    int slave;
    int busy;
};

conf->tty_info->pty_info的每一项都记录了一个新创建pty的信息,master表示pty master的句柄,slave表示slave的句柄,name表示pty slave的文件路径,即"/dev/pts/N"。

2. console

lxc_create_console同样调用openpty用来创建console设备。创建好的console设备信息存放在类型为lxc_cosnole的结构体变量conf->console中。

lxc_console的结构体定义如下:

struct lxc_console {
    int slave;
    int master;
    int peer;
    char *path;
    char *log_path;
    int log_fd;
    char name[MAXPATHLEN];
    struct termios *tios;
};

各个参数的含义如下:

  • slave 新创建pty的slave
  • master 新创建pty的master
  • path console文件路径,可以通过配置文件"lxc.console.path"或者命令行参数-c指定。默认为"/dev/tty"
  • log_path console的日志路径
  • peer 打开path, 返回句柄放入peer中。
  • log_fd 打开log_path, 返回句柄放入log_fd中。
  • name slave的路径。
  • tios 存放tty旧的控制参数。

lxc_spawn

让我们继续回到__lxc_start的主流程。前面通过调用lxc_init初始化了一个lxc_handler的结构体handler,然后在主流程里,又将传入的ops参数和data参数赋值给了handler的ops字段和data字段。接着就以handler为参数,调用了lxc_spawn。

lxc_spawn是启动新的容器的核心。进程通过Linux系统调用clone创建了拥有自己的PID、IPC、文件系统等独立的命名空间的新进程。然后在新的进程中执行/sbin/init。接下来我们来看具体过程。

  1. 首先调用lxc_sync_init来为将来父子进程同步做初始化。
  2. 准备clone调用需要的flag。各个flags如下:
    • CLONE_NEWUTS 子进程指定了新的utsname,即新的“计算机名”
    • CLONE_NEWPID 子进程拥有了新的PID空间,clone出的子进程会变成1号进程
    • CLONE_NEWIPC 子进程位于新的IPC命名空间中。这样SYSTEM V的IPC对象和POSIX的消息队列看上去会独立于原系统。
    • CLONE_NEWNS 子进程会有新的挂载空间。
    • CLONE_NEWNET 如果配置文件中有关于网络的配置,则会增加该flag。它使得子进程有了新的网络设备的命名空间
  3. 调用pin_rootfs。如果container的根文件系统是一个目录(而非独立的块设备),则在container的根文件系统之外以可写权限打开一个文件。这样可以防止container在执行过程中将整个文件系统变成只读(原因很简单,因为已经有其他进程以读写模式打开一个文件了,所以设备是“可写忙”的。所以其他进程不能将文件系统重新挂载成只读)。
  4. 调用lxc_clone,在新的命名空间中创建新的进程。
  5. 父子进程协同工作,完成container的相关配置。

我们先来看一下lxc_clone是如何创建新的进程的。

lxc_clone

该函数的原型如下:

pid_t lxc_clone(int (*fn)(void *), void *arg, int flags)

三个参数的含义如下:

fn: 子进程要执行的函数入口
arg:fn的输入参数
flags: clone的flags

lxc_clone为clone api做了一个简单的封装,最后结果就是子进程会执行fn(arg)。在lxc_spawn处,lxc_clone是这样调用的:

handler->pid = lxc_clone(do_start, handler, handler->clone_flags)

所以lxc_clone执行完后,handler的pid字段会保留子进程的pid(注意不是“1”,是子进程调用getpid()会变成1)。父进程继续,子进程执行do_start。

父子进程同步

同步机制

进程间同步的函数实现在sync.c中,其实现机制的分析可以见sync.c模块。这里只列举用于同步的函数:

  • lxc_sync_barrier_parent/child(struct lxc_handler* handler, int sequence) 发送sequence给parent/child,同时等待parent/child发送sequence+1的消息过来。
  • lxc_sync_wait_parent/child(struct lxc_handler* handler, int sequence) 等待parent/child发送sequence的消息过来。

同步完成配置的过程

  1. 父进程lxc_clone结束后,开始等待子进程发送LXC_SYNC_CONFIGURE的消息过来。此时,执行do_start的子进程完成了四件事情:
    1. 将信号处理表置为正常。
    2. 通过prctl api,将子进程设置为“如果父进程退出,则子进程收到SIGKILL的消息”。
    3. 关闭不需要的file handler
    4. 发送LXC_SYNC_CONFIGURE给父进程,通知父进程可以开始配置。同时等待父进程发送配置完成的消息LXC_SYNC_POST_CONFIGURE
  2. 受到子进程发送的LXC_SYNC_CONFIGURE的消息后,父进程继续执行。父进程执行的动作如下:
    1. 调用lxc_cgroup_path_create创建新的cgroup
    2. 调用lxc_cgroup_enter将子进程加入到新的cgroup中。
    3. 如果有新的网络命名空间,则调用lxc_assign_network为之分配设备
    4. 如果有新的用户空间,如果配置了用户ids(包括uid,gid)映射,则做用户ids映射。该映射将container的id映射到了真正系统中一个不存在的id上,使得container可以在一个虚拟的id空间中做诸如“切换到root”之类的事情。详细讨论可参见模块相关配置。
    5. 发送LXC_SYNC_POST_CONFIGURE给子进程,并等待子进程发送LXC_SYNC_CGROUP的消息
  3. 子进程收到LXC_SYNC_POST_CONFIGURE的消息被唤醒。完成如下动作:
    1. 如果id已被映射,则切换到root
    2. 开始container的设置,调用lxc_setup。主要有utsname、ip、根文件系统、设备挂载、console和tty等终端设备的各个方面的配置。
    3. 发送LXC_SYNC_CGROUP给父进程。并等待父进程发送LXC_SYNC_CGROUP_POST消息。
  4. 父进程被唤醒。根据配置文件中对CGROUP的相关配置,调用setup_cgroup进行cgroup的设置。然后发送LXC_SYNC_CGROUP_POST给子进程。等待子进程发送LXC_SYNC_CGROUP_POST+1。
  5. 子进程被唤醒。调用handler->ops->start函数。实际上是完成了对start.c中start函数的调用。该函数功能简单,基本就是通过exec执行了container的init程序,默认情况下为/sbin/init.
  6. 子进程并没有给父进程返回LXC_SYNC_CGROUP_POST+1的消息,而是关掉了父子进程间的通信信道。这导致父进程被唤醒。被唤醒后,父进程完成了以下动作:
    1. 调用detect_shared_rootfs, 检测是否共享根文件系统,是的话卸载。
    2. 修改子进程tty文件的用户ids
    3. 执行handler->ops->post_start, 打印"XXX is started with pid XXX"字样。

相关配置

在这一部分中,我们针对前面讲的父子进程的同步配置过程来对部分重要的函数做分析。

lxc_cgroup_path_create和lxc_cgroup_enter

函数定义在cgroup.c中。原型如下:

char* lxc_cgroup_path_create(const char* lxcgroup, const char* name)
int lxc_cgroup_enter(const char* cgpath, pid_t pid)

lxc_cgroup_path_create函数的作用是在cgroup各个已挂载使用的子系统的挂载点上为新创建的container新建一个文件夹。lxc_cgroup_enter的作用是把新创建的container加入到group cgpath中。

下面我们来举例说明: 比如挂载的子系统有blkio和cpuset,他们的挂载点分别是/cgroup/blkio和/cgroup/cpuset。

lxc_cgroup_path_create函数运行结束后,则会多出两个目录/cgroup/blkio/lxcgroup/name和/cgroup/cpuset/lxcgroup/name。如果传入参数lxcgroup为空,则会使用“lxc”。函数的返回值是新创建目录的相对路径。即“lxcgroup/name”。

lxc_cgroup_enter函数结束后,进程号"pid"会被追加到文件/cgroup/blkio/lxcgroup/name/tasks和/cgrop/cpuset/lxcgroup/name/tasks中。在lxc_spawn中,pid的实参用的是handler->pid,即clone出的子进程的id。

通过查看/proc/mounts查看cgroup的挂载点。通过查看/proc/cgroups查看正挂载使用的子系统。

id映射

查看confile.c下的config_idmap函数,可知在container配置文件中可以通过lxc.id_map来设置id映射。格式如下:

lxc.id_map = u/g id_inside_ns id_outside_ns range

其中,u/g指定了是uid还是gid。后三个选项表示container中的[id_inside_ns, id_inside_ns+range)会被映射到真实系统中的 [id_outside_ns, id_outside_ns+range)。

在config_idmap执行后,配置文件中的配置条目被作为链表存放到conf->id_map字段下。在lxc_spawn中,通过调用lxc_map_ids函数来完成配置。

lxc_map_ids的实现在conf.c中,原型如下:

int lxc_map_ids(struct lxc_list *idmap, pid_t pid)

第一个参数idmap为配置信息的链表,pid为新clone出的子进程的pid。lxc_map_ids的基本过程比较简单,就是将以u开头的配置项写入到文件/proc/pid/uid_map中,将以g开头的配置项写入到文件/proc/pid/gid_map中。

id映射是clone在flag CLONE_NEWUSER时指定的一个namespace特性。有关id映射可以参见此处。

lxc_setup

子进程do_start中调用的lxc_setup是一个非常重要的函数。container里面的很多配置都是在lxc_setup中完成的。这里重点分析setup_console和setup_tty两个函数,来查看比较困扰的终端字符设备是如何虚拟的。

setup_console的实现在conf.c中,函数原型如下:

int setup_console(const struct lxc_rootfs *rootfs, const struct lxc_console *console, 
        char *ttydir)

rootf变量描述了container根文件系统的路径和挂载点。console变量描述了container的console设备的相关信息。在do_start的调用中,传来的实参是lxc_conf->console,这个字段是我们在lxc_init时初始化的。回顾当时的初始化过程:

  • console->slave和console->master分别存储了新分配的pty的slave和master的句柄。
  • console->peer存储了打开原系统"/dev/tty"的句柄。
  • console->name指向了新分配pty的文件路径

setup_console根据ttydir的值,分支调用了setup_dev_console或者setup_ttydir_console。我们只看setup_dev_console来了解原理。

在setup_dev_console中,主要动作就是将console->name指向的pty通过BIND的方式挂载到rootfs/dev/console文件中。可以看出,我们对container /dev/console的访问,实质上是对新分配pty的访问。

setup_tty的过程与此类似,在rootfs/dev/目录下创建tty1, tty2等常规文件,然后用BIND的方式将新创建的pty挂载到其上。

setup_cgroup

显然,container无法访问原来的cgroup根文件系统,所以这个任务只能由父进程在lxc_spawn中调用。该函数实现比较简单,根据config文件中的配置条目,将对应的value值写入到对应的cgroup文件中。

剩下的事情

主进程陷入等待。子进程开始运行。

从ViT到Swin Transformer:一文搞懂Transformer在CV中的进化史(附实战代码) 本文系统梳理了Transformer在计算机视觉领域的演进历程,从开创性的Vision Transformer(ViT)引入全局注意力机制,到DETR实现端到端目标检测,再到里程碑式的Swin Transformer通过滑动窗口和层次化设计高效桥接CNN与ViT。文章深入剖析了各模型的核心思想、技术突破与实战应用,并提供了可运行的代码示例,帮助读者从理论到实践全面掌握这一关键技术脉络。 阅读详情

相关推荐

Jetpack Compose Navigation实战:从基础到高级导航模式

本文全面解析Jetpack Compose Navigation在Android开发中的应用,从基础导航实现到高级模式(如单任务/单顶模式),涵盖参数传递、嵌套导航、深层链接等核心功能。通过实战代码示例展示如何优化导航性能,并与ViewModel、Hilt等架构组件整合,为开发者提供高效的Compose导航解决方案。

pz890123456的博客 372

linux 容器(LXC) 第10章 之C API 使用

转:https://blog.youkuaiyun.com/tq08g2z/article/details/78741017 参考:https://www.ibm.com/developerworks/cn/linux/1312_caojh_linuxlxc/index.html Linux Namespace (ns) [1]http://blog.dotcloud.com/under-the-hoo...

caofengtao1314的专栏 1477

偷懒必备:3种方法快速移植MFC界面资源(含.rc文件打不开解决方案)

本文针对MFC桌面应用开发,详细介绍了三种快速移植界面资源的实战方法:直接编辑.rc文件、利用Visual Studio“添加现有项”进行可视化挂载,以及双实例拖拽应急方案。文章重点剖析了.rc文件无法打开的常见问题,提供了通过修复rc.exe等关键文件来根治此问题的解决方案,帮助开发者高效复用资源,规避ID冲突等陷阱。

weixin_28358083的博客 271

Linux Container(LXC)初探

为什么80%的码农都做不了架构师?>>> ...

weixin_33711641的博客 598

从厘米级到公里级:北斗网格10级精度在ArcPro中的完整应用指南

本文提供了北斗网格十级精度体系在ArcGIS Pro中的完整应用指南。详细解析了从660公里到1.5厘米的十级网格尺度及其编码逻辑,并重点演示了如何在ArcPro中生成网格、计算编码,以及根据项目需求(如滑坡监测)选择合适精度层级的实战策略。指南旨在帮助GIS专业人士利用这套统一的网格框架,高效管理多尺度空间数据并优化分析工作流。

Black的专栏 470

零外围电路!用CH340X实现ESP32一键下载的完整教程

本文详细介绍了如何利用CH340X系列USB转串口芯片实现ESP32的一键自动下载功能,无需任何外围逻辑控制电路。通过解析CH340X的增强型DTR/RTS功能,提供核心电路设计、电压匹配方案,并指导在Arduino IDE和PlatformIO中进行软件配置,帮助开发者构建简洁、可靠且低成本的ESP32下载方案。

gpu4optimizer的博客 768

LXC之.conf配置文件详解

作者: UBUNTU manpages 来源: http://manpages.ubuntu.com/manpages/disco/en/man5/lxc.container.conf.5.html DESCRIPTION LXC is the well-known and heavily tested low-level Linux container runtime. It is in...

暧暧远人村,依依墟里烟 ... 5757

IEC61850实战:从ICD文件解析到模型构建

本文深入解析IEC61850标准中的ICD文件结构,从Header、IED到DataTypeTemplates部分,详细介绍了如何构建电力自动化设备的数据模型。通过实战案例展示ICD文件的创建过程,并分享常见问题的调试技巧,帮助工程师快速掌握IEC61850建模方法,提升电力系统自动化项目的实施效率。

weixin_26841743的博客 496

LXC使用指南

[b]目录 目录 1 1 lxc简介 1 2 lxc安装 1 2.1 系统及内核版本 1 2.2 安装lxc 1 3 lxc工具集 2 3.1 创建和销毁容器 2 3.1.1 lxc-create 2 3.1.2 lxc-destroy 2 3.2 在容器中运行与结束应用 2 3.2.1 lxc-execute和lxc-start 2 3.2.2 lxc-stop 3...

coolphxnuaa的博客 2982

从VLM到VLA概论

智驾视觉大模型

xiaomu_347的博客 1706

MATLAB代码实现了船舶航线优化的功能,使用混合遗传算法(结合模拟退火算法)来寻找从大连港到格拉斯通港的最优航线,同时考虑了船舶的参数、气象数据(风速、风向、有效波高、波浪阻力系数等)对航行的影响

这段MATLAB代码主要实现了船舶航线优化的功能,使用混合遗传算法(结合模拟退火算法)来寻找从大连港到格拉斯通港的最优航线,同时考虑了船舶的参数、气象数据(风速、风向、有效波高、波浪阻力系数等)对航行的影响。通过以上步骤,该代码能够找到一条在考虑船舶性能和气象条件下,从大连港到格拉斯通港的较优航线,最小化燃油消耗和航行时间的加权和。

AI的内部世界的博客 512

LXC常用操作

lxc语法 lxc-checkconfig //检查系统环境是否满足容器使用要求; lxc-create //创建lxc容器; 格式:lxc-create -n NAME -t TEMPLATE_NAME lxc-start //启动容器; 格式:lxc-start -n NAME -d lxc-info //查看容器相关的信息; 格式:lxc-info -n NAME lxc-console //附加至指定容器的控制台; 格式:lxc-console -n NAME -t NUMBER lxc.

qq_57006788的博客 1697

自私兽群优化器(SHO)详解:从生物本能到智能优化

自私兽群优化器(SHO)是一种受动物群体自私行为启发的智能优化算法。该算法模拟动物在捕食威胁下的两种行为:聚集行为(全局搜索)和自私行为(局部搜索),将优化问题的解空间映射为生存环境,候选解视为猎物个体。SHO通过安全性评估将猎物分为安全、危险和高危三类,分别采用不同的位置更新策略,并引入捕食者角色增加选择压力。相比传统优化算法,SHO具有无需梯度信息、自适应平衡探索与开发、参数简单等优势,特别适合高维复杂和多模态优化问题。算法通过马尔可夫链理论保证收敛性,已在工程设计和数据挖掘等领域展现出良好性能。

qq_42212808的博客 193

Linux 内核 container_of 宏详解

Linux 内核 container_of 宏实现原理分析

m0_37383484的博客 6212

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Kylin Linux Advanced Server V10 上成功安装 NVIDIA Container Toolkit

在Kylin Linux Advanced Server V10上安装NVIDIA Container Toolkit的指南。首先需确保已安装NVIDIA GPU驱动和容器运行时(Docker等)。通过添加NVIDIA官方RPM仓库并安装nvidia-container-toolkit包,然后配置容器运行时(Docker/containerd/Podman)。最后通过运行nvidia-smi测试验证安装。文中还提供了常见问题排查方法,如SELinux配置、仓库添加失败等问题的解决方案。适用于需要在国产Kyl

专注于AI领域前沿技术学习与分享:目标检测、图像修复、超分重建、AI工程化 2590

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

Linux 中的 container_of 原理

这个宏函数在Linux 内核中使用的频率还是很多的。网上关于 container_of 使用的优秀文章也很多,之所以笔者也写一篇,一是想更新下最新代码中的使用,二是融入些自己的鄙见,方便自己回头查看,也希望能有助于后来读者。

私房菜 1755

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

linux驱动开发中常用函数--container_of的用法及分析

container_of的用法及分析

xi_xix_i的博客 4200

Linux 宏定义container_of详解

再写Linux驱动的过程中经常是一个结构体套一层结构体,而在某些函数中传入的参数是子结构体指针,但是我们又需要获取的其外层结构体的数据,Linux为我们提供了container_of宏定义来为我们解决这个问题。 container_of宏定义就是用来通过内层结构体的指针获取外层结构体指针,宏定义很巧妙,我等凡人想不出来。下面就详细分析其实现原理吧。 container_of宏定义需要用到offse...

zhaoyun_zzz的专栏 1931

Linux内核中container_of的原理及其使用详解

介绍了container_of的原理以及用法;

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 1万+

Linux container_of() 函数详解

container_of(ptr, type, member) 是一个宏函数,其作用是通过结构体成员的地址找到结构体的地址。该宏函数常在 linux 内核链表遍历之后使用,以此来获取虚节点所寄生的宿主结构体,详情可以参考这篇文章。参数简介:container_of(ptr, type, member) 中,ptr 为结构体成员地址,type 为结构体的类型,member 为结构体成员在结构体里的名字。

BigElt的博客 2707

Linux内核源码中container_of详解

本文出自:http://blog.youkuaiyun.com/hongchangfirst 关于container_of的用法,可参考http://blog.youkuaiyun.com/hongchangfirst/article/details/7076225。其实就是解决了”如何通过结构中的某个变量的地址获取结构本身的指针“这样的问题。container_of实现了根据一个结构体变量中的一个成员变量的指针来

hongchangfirst 7969

Linux内核中的container_of

container_of 是 Linux 内核里非常常用的宏,作用是:已知某个结构体成员的地址,通过偏移量反推结构体的起始地址。核心公式就是:结构体地址 = 成员地址 − offsetof(type, member)。常用于内核链表,因为链表遍历时拿到的是 list_head,需要通过 container_of 还原成外层结构体,比如 struct student。本质就是指针算术,完全零开销,非常高效。

God_Cluodi的博客 1028

Linux内核中的container_of浅析

本文的主要内容: 一、container_of的作用 二、container_of的定义 三、container_of的简单实现 一、container_of的作用 一般的我们通过结构体变量的地址可以找到其成员的地址,但是反过来一般是行不通的。在linux内核中就有这样的一个宏:container_of,它可以实现根据结构体成员的地址,找到这个结构体变量的地址,从而对结构体中的其

TECH_PRO的博客 923

YARN 的 Linux Container Executor 详解

是 Apache Hadoop YARN 框架中一种关键的实现。核心职责:Container Executor 是 YARN NodeManager 的一个组件,它负责在物理机或虚拟机上安全地启动和清理YARN 容器进程。它是 YARN 与底层操作系统之间的“桥梁”。LCE 的独特之处:与最简单的 DefaultContainerExecutor(几乎无隔离)不同,LCE 利用Linux 内核的原生特性来为每个 YARN 容器提供资源隔离和一定的运行隔离。

学亮编程手记 1058

Linux container_of 分析

container_of 简述 container_of  是 Linux 中最常用的宏之一,不仅仅在上一章的链表数据结构中,在很多的地方都有使用到,他的作用是: 根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针,以便对结构体的其他成员进行操作 是不是超有用?来,先贴代码为敬: /** * container_of - cast a member of a st...

StephenZhou 542

【Linux】container_of宏

container_of宏的介绍

pannlz的博客 1109
上一篇: Cgroup 研究报告
下一篇: Android 启动分析 1
Omni-Space
博客等级 码龄11年 2158粉丝 23原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值