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.910
please input two numbers:
5.6 6.9
please input opration id:
5
ans is : 145377.564
please input two numbers:
18.7 2.64
please input opration id:
2
ans is : 16.060
please 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 >= 9
fuse_private_t *priv = NULL;
priv = this->private;
#endif
GET_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 >= 9
state->io_flags = fwi->flags;
#else
state->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 >= 9
priv = this->private;
if (priv->proto_minor >= 9 && fwi->write_flags & FUSE_WRITE_LOCKOWNER)
state->lk_owner = fwi->lock_owner;
#endif
state->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;
}