Nouveau源码分析(二):Nouveau结构体的基本框架

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-1 23:35   11   0

Nouveau源码分析(二)

在讨论Nouveau对Nvidia设备的初始化前,我准备先说一下Nouveau结构体的基本框架

Nouveau的很多结构体都可以看作是C++中的类,之间有很多相似的东西,比如继承关系,virtual成员函数等.

模拟继承

先尝试阅读一下这个代码:

#include <stdlib.h>

struct abc
{
   int a;
   int b;
   int c;
};

struct def
{
   struct abc base;
   int d;
   int e;
   int f;
};

#define abc_create(a,b,c,pabc) \
   abc_create_(a,b,c,sizeof(**pabc),(void **)pabc)

int abc_create_(int a,int b,int c,
                 size_t size,void **pabc)
{
   struct abc *abc_ = (struct abc *)malloc(size); //按传入的size分配空间

   abc_->a = a;
   abc_->b = b;
   abc_->c = c; //初始化自身

   *pabc = abc_;
   return 0;
}

#define def_create(a,b,c,d,e,f,pdef) \
   def_create_(a,b,c,d,e,f,sizeof(**pdef),(void **)pdef) //获得实际应分配空间大小

int def_create_(int a,int b,int c,int d,int e,int f,
                 size_t size,void **pdef)
{
   struct def *def_;
   abc_create_(a,b,c,size,pdef); //先初始化基类
   def_ = (struct def *)*pdef;

   def_->d = d;
   def_->e = e; //然后初始化自身
   def_->f = f;
   return 0;
}

int main(void)
{
    struct def *d;
    def_create(1,2,3,4,5,6,&d);
    return 0;
}
Nouveau中大部分的结构体都是这种模式的,模拟C++的继承关系

当然一般还会有配套使用的宏,比如这个例子中可以有:

#define nv_abc(a) ((struct abc *)a)

//使用方法:

struct def *b;
//初始化b,做一些事情
nv_abc(b)->a = 7;


[注意:实际在nouveau代码中,还有一种关系是parent关系,这和此处讨论的继承关系无关]

模拟virtual函数

改造一下上面写的程序,改成这样:

#include <stdlib.h>
#include <stdio.h>

struct oclass
{
    int (*test)(int); //类的test函数
};

/****************abc****************/
struct abc
{
   struct oclass *oclass;
   int a;
   int b;
   int c;
};

int abc_test(int a)
{
    return a * a;
}

struct oclass abc_oclass = {abc_test}; //abc的test函数

#define nv_abc(a) ((struct abc *)a)

#define abc_create(a,b,c,pabc) \
   abc_create_(&abc_oclass, \
       a,b,c,sizeof(**pabc),(void **)pabc)

int abc_create_(struct oclass *oclass,int a,int b,int c,
                 size_t size,void **pabc)
{
   struct abc *abc_ = (struct abc *)malloc(size);

   abc_->a = a;
   abc_->b = b;
   abc_->c = c;
   abc_->oclass = oclass;

   *pabc = abc_;
   return 0;
}

/****************def****************/
struct def
{
   struct abc base;
   int d;
   int e;
   int f;
};


int def_test(int a)
{
    return a;
}

struct oclass def_oclass = {def_test}; //def的test函数

#define nv_def(a) ((struct def *)a)

#define def_create(a,b,c,d,e,f,pdef) \
   def_create_(a,b,c,d,e,f,sizeof(**pdef),(void **)pdef)

int def_create_(int a,int b,int c,int d,int e,int f,
                 size_t size,void **pdef)
{
   struct def *def_;
   abc_create_(&def_oclass,a,b,c,size,pdef);
   def_ = (struct def *)*pdef;

   def_->d = d;
   def_->e = e;
   def_->f = f;
   return 0;
}

int main(void)
{
    struct def *d;
    struct abc *a;
    def_create(1,2,3,4,5,6,&d);
    abc_create(1,2,3,&a);

    printf("%d %d\n",nv_abc(d)->oclass->test(3),
                     nv_abc(a)->oclass->test(3)); //尝试执行
    return 0;
}

利用这个,就可以用同一个接口nouveau_object,实现对很多不同设备模块的访问

使用标识符获得oclass

还有一种情况,传递参数时传递的是"u32 oclass",而不是"struct nouveau_oclass *oclass",这种情况就要依照parent向上搜索,得到具体的oclass

此处不展开讨论,等看到那部分代码再详细说明

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP