首页 > 其他分享 >container_of宏

container_of宏

时间:2024-02-18 16:33:26浏览次数:21  
标签:container struct list dev device i2c type

玩转内核链表list_head


container_of 是 Linux 内核中一个常用的宏,用于从结构体的成员指针获取包含该成员的整个结构体的指针。

/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({              \
    void *__mptr = (void *)(ptr);                   \
    BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&   \
             !__same_type(*(ptr), void),            \
             "pointer type mismatch in container_of()");    \
    ((type *)(__mptr - offsetof(type, member))); })

ptr:指向结构体中某个成员的指针。
type:结构体的类型。
member:结构体中的成员名。
offsetof: 计算结构体成员member在type这个结构体中的偏移

#define offsetof(type, member) ((size_t)(&((type *)0)->member))

例子:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kmod.h>

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/list.h>

#define MAX_NAME_LEN 32
#define MAX_ID_LEN 10

struct list_head device_list;

#define I2C_TYPE 1
#define SPI_TYPE 2

char *dev_name[]={
  "none",
  "I2C",
  "SPI"
};

struct device
{
  int type;
  char name[MAX_NAME_LEN];
  struct list_head list;
};

struct i2c_node
{
  int data;
  unsigned int reg;
  struct device dev;
};

struct spi_node
{  
  unsigned int reg;
  struct device dev;
};

void display_i2c_device(struct device *device)
{
  struct i2c_node *i2c_device = container_of(device, struct i2c_node, dev);

  pr_info("\t  i2c_device->data: %d\n", i2c_device->data);
  pr_info("\t  i2c_device->reg: %#x\n", i2c_device->reg);
}

void display_spi_device(struct device *device)
{
  struct spi_node *spi_device = container_of(device, struct spi_node, dev);
  pr_info("\t  spi_device->reg: %#x\n", spi_device->reg);
}

void display_device(struct device *device)
{
    pr_info("\t  dev.type: %d\n", device->type);
    pr_info("\t  dev.type: %s\n", dev_name[device->type]);
    pr_info("\t  dev.name: %s\n", device->name);
}

void display_list(struct list_head *list_head)
{
  int i=0;
  struct list_head *p;
  struct device *entry;

  pr_info("-------list---------\n");
  list_for_each(p, list_head)
  {
    pr_info("node[%d]\n",i++);
    entry=list_entry(p, struct device, list);

    switch(entry->type)
    {
      case I2C_TYPE:
        display_i2c_device(entry);
        break;
      case SPI_TYPE:
        display_spi_device(entry);
        break;
      default:
        pr_info("unknown device type!\n");
        break;
    }
    display_device(entry);
  }
  pr_info("-------end----------\n");
}

void i2c_register_device(struct device *device)
{
  struct i2c_node *i2c_device = container_of(device, struct i2c_node, dev);

  i2c_device->dev.type = I2C_TYPE;
  strcpy(i2c_device->dev.name,"yikoulinux");

  list_add(&device->list, &device_list);  
}

void spi_register_device(struct device *device)
{
  struct spi_node *spi_device = container_of(device, struct spi_node, dev);

  spi_device->dev.type = SPI_TYPE;
  strcpy(spi_device->dev.name,"yikoupeng");

  list_add(&device->list, &device_list);  
}

void i2c_unregister_device(struct device *device)
{
  struct i2c_node *i2c_device = container_of(device, struct i2c_node, dev);

  list_del(&device->list);
}

void spi_unregister_device(struct device *device)
{
  struct spi_node *spi_device = container_of(device, struct spi_node, dev);

  list_del(&device->list);
}


static int hello_init(void)                                                                                                                                                                
{

  struct i2c_node dev1;
  struct spi_node dev2;

  INIT_LIST_HEAD(&device_list);
  dev1.data = 1;
  dev1.reg = 0x40009000;
  i2c_register_device(&dev1.dev);
  dev2.reg  = 0x40008000;
  spi_register_device(&dev2.dev);  
  display_list(&device_list);
  i2c_unregister_device(&dev1.dev);
  display_list(&device_list);  
  return 0;
}

static void hello_exit(void)
{
    printk(KERN_ALERT "Goodbye, kernel\n");
}           
            
module_init(hello_init);
module_exit(hello_exit);
            
MODULE_LICENSE("GPL");
MODULE_AUTHOR("xxx");

标签:container,struct,list,dev,device,i2c,type
From: https://www.cnblogs.com/tangshunhui/p/18019515

相关文章

  • 在k8S中,初始化容器(init container)概念原理是什么?
    在Kubernetes(k8S)中,初始化容器(InitContainer)是一个特殊类型的容器,它会在应用程序容器启动之前运行。它的主要目的是执行一些必要的先决条件任务,这些任务必须在主应用容器开始服务前完成。初始化容器的概念原理如下:顺序执行:Pod中可以定义多个初始化容器,它们按照配置文件......
  • 轻量级容器管理工具Containerd的两种安装方式
    1.yum安装1.1.获取阿里云YUM源[root@centos]#wget-O/etc/yum.repos.d/docker-ce.repohttps://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo1.2.查看YUM源中Containerd软件[root@centos]#yumlist|grepcontainerdcontainerd.io.x86_641.4.12-3.......
  • containerd 镜像层分析
    meta.db找到d842e8e2623636b8fb0d070a2dd9592c1eb0ebfa975c6a283960bc1f710feab4mediatype:application/vnd.docker.distribution.manifest.v2+json多种类型application/vnd.docker.distribution.manifest.list.v2+json===================================================......
  • nerdctl build -- command to build container image from docker file
    1.Prerequisiteofusingnerdctlbuildbuildctlneedstobeinstalledandbuildkitdneedstoberunning.2.checkifbuildctlinstalled$nerdctlversionClient:Version: v1.7.2OS/Arch: linux/amd64Gitcommit: e32c4b023bf41e5c8325cfb893a53cefb5fc68edb......
  • 在写布局样式的时候,什么时候命名为area,什么时候为container,什么时候为wrapper,什么时
    在编写布局样式时,对于类名的选择如area、container、wrapper和box等具有语义的名称是非常重要的,它们可以帮助开发者和维护者更好地理解HTML结构与功能。以下是一些最佳实践以及何时使用这些类名的理由:container:通常用于包裹整个页面或特定区块的主要内容容器。理由:这......
  • containerd 像Docker一样丝滑操作镜像【转】
    containerd像Docker一样丝滑操作镜像• 我们知道DockerCLI工具提供了需要增强用户体验的功能,containerd同样也提供一个对应的CLI工具:ctr,不过ctr的功能没有docker完善,但是关于镜像和容器的基本功能都是有的。接下来我们就先简单介绍下ctr的使用。➜  ~ ctrN......
  • Go语言核心36讲 08 | container包中的那些容器
    我们在上次讨论了数组和切片,当我们提到数组的时候,往往会想起链表。那么Go语言的链表是什么样的呢?Go语言的链表实现在标准库的container/list代码包中。这个代码包中有两个公开的程序实体——List和Element,List实现了一个双向链表(以下简称链表),而Element则代表了链表中元素的结构......
  • 容器管理工具Containerd
    一、Containerd介绍1.前言早在2016年3月,Docker1.11的DockerEngine里就包含了containerd,而现在则是把containerd从DockerEngine里彻底剥离出来,作为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础设施。和原先包含在DockerEngine里containerd相比,独......
  • podman和vscode dev container的一些问题
    1.MacArm芯片上podmanmachine启动时卡在CurrentStarting起不来。参考这个链接的回答,更新Qemu的文件https://github.com/containers/podman/issues/21096#issuecomment-1872551224Ihavethesameissue,andalsotriedsomemethodsdiscussedin#21088(comment),none......
  • 删除Azure Container Registry中tag为null的容器镜像
    删除AzureContainerRegistry中tag为null的容器镜像近几年容器技术的蓬勃发展,越来越多的客户开始在Azure中使用AKS,ACR等容器相关的Azure服务,来满足其不断发展的业务使用需求。但随着时间的推移和业务复杂性的增长,很多客户都会发现,ACR中的某些Repo内,显示的清单计数和实际的清单数量......