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.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;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值