GlusterFS源码学习——函数指针数组的妙用
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源码学习——函数指针数组的妙用相关推荐
- 函数指针和指针函数以及函数指针数组
2019独角兽企业重金招聘Python工程师标准>>> 问题:一个整型a,根据a的值执行相应的代码 我的回答是使用switch case 面试官说可以这样做,但是还有速度更快的办法, ...
- 【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 ...
- postgresql源码学习(51)—— 提交日志CLOG 原理 用途 管理函数
一. CLOG是什么 CLOG(commit log)记录事务的最终状态. 物理上,是$PGDATA/pg_xact目录下的一些文件 逻辑上,是一个数组,下标为事务id,值为事务最终状态 1. 事务最 ...
- postgresql源码学习(27)—— 事务日志⑦-日志落盘上层函数 XLogFlush
一. 预备知识 1. XLOG什么时候需要落盘 事务commit之前 log buffer被覆盖之前 后台进程定期落盘 2. 两个核心结构体 这两个结构体定义代码在xlog.c,它们在日志落盘过程中非 ...
- 【C++学习】指针数组,数组指针,以及函数指针,以及堆中的分配规则--有是一篇好文章,收到自己门下 慢慢学习
一 :关于指针和堆的内存分配 先来介绍一下指针 : 指针一种类型,理论上来说它包含其他变量的地址,因此有的书上也叫它:地址变量.既然指针是一个类型,是类型就有大小,在达内的服务器上或者普通的PC机上, ...
- STL源码学习之空间配置
STL的空间配置器主要用于内存的分配.填充.释放等操作,在学习它之前,需要深入一点理解new和delete.由于new和delete分两段操作:内存配置和对象构建(析构),本文亦将按此进行分类,其中第 ...
- JDK11源码学习05 | HashMap类
JDK11源码学习05 | HashMap类 JDK11源码学习01 | Map接口 JDK11源码学习02 | AbstractMap抽象类 JDK11源码学习03 | Serializable接口 ...
- Kubernetes调度器源码学习(三):Preempt抢占机制、调度失败与重试处理
本文基于Kubernetes v1.22.4版本进行源码学习 5.Preempt抢占机制 当高优先级的Pod没有找到合适的节点时,调度器会尝试抢占低优先级的Pod的节点.抢占过程是将低优先级的Pod从 ...
- 基于Qt5.14.2和mingw的Qt源码学习(三) — 元对象系统简介及moc工具是如何保存类属性和方法的
基于Qt5.14.2和mingw的Qt源码学习(三) - 元对象系统简介及moc工具是如何保存类属性和方法的 一.什么是元对象系统 1.元对象系统目的 2.实现元对象系统的关键 3.元对象系统的其他一 ...
最新文章
- vue v-model 简单使用
- tcp长连接java_JAVA TCP长连接
- 傲梅分区助手 linux,傲梅分区助手专业版
- Django菜鸟教程学习记录(一)
- 简单说明什么是网络的DMZ区域
- C语言入门:查找子串
- 倪光南建议禁用Win10政府版 微软合作方回应
- 热门智力题 过桥问题和倒水问题
- Javascript 中文按拼音顺序
- 手机微信中对方正在输入...,不显示有4种原因,还能永不显示
- 2020nyist第三场个人赛
- 字符串题目:重新排列字符串
- 注意力机制基本原理详解及应用
- BioPython读取FASTA文件保留header中空格的方法
- sin90度=1的证明
- 12自由度六足机器人实现蓝牙遥控
- 2的幂,3的幂,4的幂
- 声明式UI(Declarative)和命令式(Imperative)UI的差异?
- DVWA系列(一)——DVWA简介
- 发明专利实质审查需要多久?