GlusterFS使用C编写,源码中使用了大量的函数指针来实现模块化编程(是我自己以前没有接触过的编写方式),这样的方式可以很方便的实现功能扩展以及调用。

今天学习的是函数指针数组,也就是把相同系列的函数的函数指针存放到一个数组中,通过这个数组和对应于函数操作的编号来进行调用。源码中代码很多,而且跳来跳去的很麻烦,所以自己照葫芦画瓢写了一个小的demo来加深印象,用来学习和记忆该方法。

本文前面部分是自己的小demo,后面是GlusterFS的部分源码。

demo

/* 用来练习函数指针数组的的小demo */#include <stdio.h>
#include <math.h>#define MATH_OP_HIGH 6// 用来存放要进行操作的数据
typedef struct Operand {double num1;double num2;
}Operand_t;// 回调函数的
typedef void(op_handler_t)(Operand_t *operand, double *ret);// 操作的编号
enum op_id {OP_ADD = 1,OP_SUB,OP_MUL,OP_DIV,OP_POWER,
};// 操作的声明
static void op_add(Operand_t *operand, double *ret);
static void op_sub(Operand_t *operand, double *ret);
static void op_mul(Operand_t *operand, double *ret);
static void op_div(Operand_t *operand, double *ret);
static void op_power(Operand_t *operand, double *ret);// 把相应的操作的函数指针存放到函数指针数组中,方便功能的拓展和调用
static op_handler_t *math_ops[MATH_OP_HIGH] = {[OP_ADD] = op_add,[OP_SUB] = op_sub,[OP_MUL] = op_mul,[OP_DIV] = op_div,[OP_POWER] = op_power,
};int main()
{Operand_t operand;double ans;unsigned opid;printf("+ : 1\n- : 2\n* : 3\n/ : 4\npow : 5\n");printf("=============\n");while(1) {printf("\n");printf("please input two numbers:\n");scanf("%lf", &operand.num1);scanf("%lf", &operand.num2);printf("please input opration id:\n");scanf("%d", &opid);if(opid > 5) {printf("illegal operation");continue;}math_ops[opid](&operand, &ans);printf("ans is : %.3lf\n", ans);}return 0;
}// 操作的实现
static void op_add(Operand_t *operand, double *ret) {*ret = operand->num1 + operand->num2;
}static void op_sub(Operand_t *operand, double *ret) {*ret = operand->num1 - operand->num2;
}static void op_mul(Operand_t *operand, double *ret) {*ret = operand->num1 * operand->num2;
}static void op_div(Operand_t *operand, double *ret) {*ret = operand->num1 / operand->num2;
}static void op_power(Operand_t *operand, double *ret) {*ret = pow(operand->num1, operand->num2);
}

运行结果:

+ : 1
- : 2
* : 3
/ : 4
pow : 5
=============please input two numbers:
3.14 4.77
please input opration id:
1
ans is : 7.910please input two numbers:
5.6 6.9
please input opration id:
5
ans is : 145377.564please input two numbers:
18.7 2.64
please input opration id:
2
ans is : 16.060please input two numbers:
3.14 2.33
please input opration id:
4
ans is : 1.348

GlusterFS部分源码

实现该功能的源码在./xlators/mount/fuse/src/fuse-bridge.c可以找到

fuse操作对应的编号:

enum fuse_opcode {FUSE_LOOKUP = 1,FUSE_FORGET = 2, /* no reply */FUSE_GETATTR = 3,FUSE_SETATTR = 4,FUSE_READLINK = 5,FUSE_SYMLINK = 6,FUSE_MKNOD = 8,FUSE_MKDIR = 9,FUSE_UNLINK = 10,FUSE_RMDIR = 11,FUSE_RENAME = 12,FUSE_LINK = 13,FUSE_OPEN = 14,FUSE_READ = 15,FUSE_WRITE = 16,FUSE_STATFS = 17,FUSE_RELEASE = 18,FUSE_FSYNC = 20,FUSE_SETXATTR = 21,FUSE_GETXATTR = 22,FUSE_LISTXATTR = 23,FUSE_REMOVEXATTR = 24,FUSE_FLUSH = 25,FUSE_INIT = 26,FUSE_OPENDIR = 27,FUSE_READDIR = 28,FUSE_RELEASEDIR = 29,FUSE_FSYNCDIR = 30,FUSE_GETLK = 31,FUSE_SETLK = 32,FUSE_SETLKW = 33,FUSE_ACCESS = 34,FUSE_CREATE = 35,FUSE_INTERRUPT = 36,FUSE_BMAP = 37,FUSE_DESTROY = 38,FUSE_IOCTL = 39,FUSE_POLL = 40,FUSE_NOTIFY_REPLY = 41,FUSE_BATCH_FORGET = 42,FUSE_FALLOCATE = 43,FUSE_READDIRPLUS = 44,/* CUSE specific operations */CUSE_INIT = 4096,
};

函数指针数组的定义,作为fuse的接口,这是客户端各种操作的入口,是文件系统的“桥节点”

typedef void(fuse_handler_t)(xlator_t *this, fuse_in_header_t *finh, void *msg); static fuse_handler_t *fuse_std_ops[FUSE_OP_HIGH] = {[FUSE_LOOKUP] = fuse_lookup,[FUSE_FORGET] = fuse_forget,[FUSE_GETATTR] = fuse_getattr,[FUSE_SETATTR] = fuse_setattr,[FUSE_READLINK] = fuse_readlink,[FUSE_SYMLINK] = fuse_symlink,[FUSE_MKNOD] = fuse_mknod,[FUSE_MKDIR] = fuse_mkdir,[FUSE_UNLINK] = fuse_unlink,[FUSE_RMDIR] = fuse_rmdir,[FUSE_RENAME] = fuse_rename,[FUSE_LINK] = fuse_link,[FUSE_OPEN] = fuse_open,[FUSE_READ] = fuse_readv,[FUSE_WRITE] = fuse_write,[FUSE_STATFS] = fuse_statfs,[FUSE_RELEASE] = fuse_release,[FUSE_FSYNC] = fuse_fsync,[FUSE_SETXATTR] = fuse_setxattr,[FUSE_GETXATTR] = fuse_getxattr,[FUSE_LISTXATTR] = fuse_listxattr,[FUSE_REMOVEXATTR] = fuse_removexattr,[FUSE_FLUSH] = fuse_flush,[FUSE_INIT] = fuse_init,[FUSE_OPENDIR] = fuse_opendir,[FUSE_READDIR] = fuse_readdir,[FUSE_RELEASEDIR] = fuse_releasedir,[FUSE_FSYNCDIR] = fuse_fsyncdir,[FUSE_GETLK] = fuse_getlk,[FUSE_SETLK] = fuse_setlk,[FUSE_SETLKW] = fuse_setlk,[FUSE_ACCESS] = fuse_access,[FUSE_CREATE] = fuse_create,/* [FUSE_INTERRUPT] *//* [FUSE_BMAP] */[FUSE_DESTROY] = fuse_destroy,
/* [FUSE_IOCTL] */
/* [FUSE_POLL] */
/* [FUSE_NOTIFY_REPLY] */#if FUSE_KERNEL_MINOR_VERSION >= 16[FUSE_BATCH_FORGET] = fuse_batch_forget,
#endif#if FUSE_KERNEL_MINOR_VERSION >= 19
#ifdef FALLOC_FL_KEEP_SIZE[FUSE_FALLOCATE] = fuse_fallocate,
#endif /* FALLOC_FL_KEEP_SIZE */
#endif#if FUSE_KERNEL_MINOR_VERSION >= 21[FUSE_READDIRPLUS] = fuse_readdirp,
#endif
};

操作的具体实现(部分):

static void
fuse_lookup(xlator_t *this, fuse_in_header_t *finh, void *msg)
{char *name = msg;fuse_state_t *state = NULL;GET_STATE(this, finh, state);(void)fuse_resolve_entry_init(state, &state->resolve, finh->nodeid, name);fuse_resolve_and_resume(state, fuse_lookup_resume);return;
}// 客户端fuse实际要执行的写函数
static void
fuse_write(xlator_t *this, fuse_in_header_t *finh, void *msg)
{// 这个操作是特殊的,操作的元数据附加在in_header上// msg是有效负载/* WRITE is special, metadata is attached to in_header,* and msg is the payload as-is.*/struct fuse_write_in *fwi = (struct fuse_write_in *)(finh + 1);// 记录fuse的状态fuse_state_t *state = NULL;fd_t *fd = NULL;
#if FUSE_KERNEL_MINOR_VERSION >= 9fuse_private_t *priv = NULL;priv = this->private;
#endifGET_STATE(this, finh, state);fd = FH_TO_FD(fwi->fh);state->fd = fd;state->size = fwi->size;state->off = fwi->offset;/* lets ignore 'fwi->write_flags', but just consider 'fwi->flags' */
#if FUSE_KERNEL_MINOR_VERSION >= 9state->io_flags = fwi->flags;
#elsestate->io_flags = fwi->write_flags;
#endif/* TODO: may need to handle below flag(fwi->write_flags & FUSE_WRITE_CACHE);*/// 解析传进来的文件描述符fuse_resolve_fd_init(state, &state->resolve, fd);/* See comment by similar code in fuse_settatr */
#if FUSE_KERNEL_MINOR_VERSION >= 9priv = this->private;if (priv->proto_minor >= 9 && fwi->write_flags & FUSE_WRITE_LOCKOWNER)state->lk_owner = fwi->lock_owner;
#endifstate->vector.iov_base = msg;       // msg作为起点,去读取数据state->vector.iov_len = fwi->size;  // 要操作的数据的长度fuse_sem_set(state, this->private);// 把信息传进函数里,并把回调函数的指针传进去,表示会进入到fuse_write_resume中// 主要是解析一些文件的元数据,并且返回到 fuse_writev_resume 中fuse_resolve_and_resume(state, fuse_write_resume);return;
}

GlusterFS源码学习——函数指针数组的妙用相关推荐

  1. 函数指针和指针函数以及函数指针数组

    2019独角兽企业重金招聘Python工程师标准>>> 问题:一个整型a,根据a的值执行相应的代码 我的回答是使用switch case 面试官说可以这样做,但是还有速度更快的办法, ...

  2. 【Qt】通过QtCreator源码学习Qt(十二):Q_D和Q_Q指针(简称“d指针”)详解

    1.Q_D和Q_Q指针(简称"d指针")简介 参考博客: https://www.devbean.net/2016/11/qt-creator-source-study-07/ h ...

  3. postgresql源码学习(51)—— 提交日志CLOG 原理 用途 管理函数

    一. CLOG是什么 CLOG(commit log)记录事务的最终状态. 物理上,是$PGDATA/pg_xact目录下的一些文件 逻辑上,是一个数组,下标为事务id,值为事务最终状态 1. 事务最 ...

  4. postgresql源码学习(27)—— 事务日志⑦-日志落盘上层函数 XLogFlush

    一. 预备知识 1. XLOG什么时候需要落盘 事务commit之前 log buffer被覆盖之前 后台进程定期落盘 2. 两个核心结构体 这两个结构体定义代码在xlog.c,它们在日志落盘过程中非 ...

  5. 【C++学习】指针数组,数组指针,以及函数指针,以及堆中的分配规则--有是一篇好文章,收到自己门下 慢慢学习

    一 :关于指针和堆的内存分配 先来介绍一下指针 : 指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量.既然指针是一个类型,是类型就有大小,在达内的服务器上或者普通的PC机上, ...

  6. STL源码学习之空间配置

    STL的空间配置器主要用于内存的分配.填充.释放等操作,在学习它之前,需要深入一点理解new和delete.由于new和delete分两段操作:内存配置和对象构建(析构),本文亦将按此进行分类,其中第 ...

  7. JDK11源码学习05 | HashMap类

    JDK11源码学习05 | HashMap类 JDK11源码学习01 | Map接口 JDK11源码学习02 | AbstractMap抽象类 JDK11源码学习03 | Serializable接口 ...

  8. Kubernetes调度器源码学习(三):Preempt抢占机制、调度失败与重试处理

    本文基于Kubernetes v1.22.4版本进行源码学习 5.Preempt抢占机制 当高优先级的Pod没有找到合适的节点时,调度器会尝试抢占低优先级的Pod的节点.抢占过程是将低优先级的Pod从 ...

  9. 基于Qt5.14.2和mingw的Qt源码学习(三) — 元对象系统简介及moc工具是如何保存类属性和方法的

    基于Qt5.14.2和mingw的Qt源码学习(三) - 元对象系统简介及moc工具是如何保存类属性和方法的 一.什么是元对象系统 1.元对象系统目的 2.实现元对象系统的关键 3.元对象系统的其他一 ...

最新文章

  1. vue v-model 简单使用
  2. tcp长连接java_JAVA TCP长连接
  3. 傲梅分区助手 linux,傲梅分区助手专业版
  4. Django菜鸟教程学习记录(一)
  5. 简单说明什么是网络的DMZ区域
  6. C语言入门:查找子串
  7. 倪光南建议禁用Win10政府版 微软合作方回应
  8. 热门智力题 过桥问题和倒水问题
  9. Javascript 中文按拼音顺序
  10. 手机微信中对方正在输入...,不显示有4种原因,还能永不显示
  11. 2020nyist第三场个人赛
  12. 字符串题目:重新排列字符串
  13. 注意力机制基本原理详解及应用
  14. BioPython读取FASTA文件保留header中空格的方法
  15. sin90度=1的证明
  16. 12自由度六足机器人实现蓝牙遥控
  17. 2的幂,3的幂,4的幂
  18. 声明式UI(Declarative)和命令式(Imperative)UI的差异?
  19. DVWA系列(一)——DVWA简介
  20. 发明专利实质审查需要多久?

热门文章

  1. 美光股票现在真的便宜吗?
  2. 中国航空货运行业投资战略分析与发展动向展望报告2021-2027年
  3. 强化学习在计算机视觉领域的应用
  4. 无忧行-出国必备神器
  5. tesseract-ocr引擎学习笔记
  6. Windows高手必备之十大免费系统工具
  7. 盲人程序员是怎样炼成的
  8. 高新技术企业认定有什么好处
  9. boost multi_index_container 多索引容器的使用
  10. oracle10漏洞补丁下载,Oracle漏洞修复工具