Chinaunix首页 | 论坛 | 博客
  • 博客访问: 521651
  • 博文数量: 51
  • 博客积分: 345
  • 博客等级: 民兵
  • 技术积分: 534
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-21 12:02
个人简介

文章分类

全部博文(51)

文章存档

2023年(2)

2022年(1)

2021年(7)

2020年(10)

2019年(2)

2016年(20)

2015年(5)

2014年(1)

2011年(3)

我的朋友

分类: C/C++

2016-08-24 16:26:14

OpenWrt 启动Service流程及struct blob_buf相关代码

/sbin/ubusd的启动为例来说明服务启动流程:

./procd/state.c

procdSTATE_UBUS状态时启动ubusd

char ubus_cmd[] = "/sbin/ubusd";

 

service_init();

         service_start_early("ubus", ubus_cmd);

void service_init(void)

void service_init(void)

{

         avl_init(&services, avl_strcmp, false, NULL);

         service_validate_init();

}

void service_validate_init(void)

{

         avl_init(&validators, avl_strcmp, true, NULL);

}

这里主要是初始化两个avl数,servicesvalidators

service_start_early("ubus", ubus_cmd);

该函数处理分为两部分:1、生成blob消息;2、根据blob消息处理service内容

生成blob消息

service_start_early(char *name, char *cmdline)

{

         void *instances, *instance, *command, *respawn;

         char *t;

 

         blob_buf_init(&b, 0);

         blobmsg_add_string(&b, "name", name);

         instances = blobmsg_open_table(&b, "instances");

         instance = blobmsg_open_table(&b, "instance1");

         command = blobmsg_open_array(&b, "command");

         t = strtok(cmdline, " ");

         while (t) {

                   blobmsg_add_string(&b, NULL, t);

                   t = strtok(NULL, " ");

         }

         blobmsg_close_array(&b, command);

         respawn = blobmsg_open_array(&b, "respawn");

         blobmsg_add_string(&b, NULL, "3600");

         blobmsg_add_string(&b, NULL, "1");

         blobmsg_add_string(&b, NULL, "0");

         blobmsg_close_array(&b, respawn);

         blobmsg_close_table(&b, instance);

         blobmsg_close_table(&b, instances);

 

         return service_handle_set(NULL, NULL, NULL, "add", b.head);

}

 

blob_buf_init(&b, 0);初始化blob_buf结构;

int blob_buf_init(struct blob_buf *buf, int id)

{

         if (!buf->grow)

                   buf->grow = blob_buffer_grow;    //buf空间不够调用该函数分配空间

 

         buf->head = buf->buf;    //此时都为NULL

         if (blob_add(buf, buf->buf, id, 0) == NULL) //增加首个struct blob_attr *attr结构

                   return -ENOMEM;

 

         return 0;

}

blob_add()    添加一个新的struct blob_attr *attr并做部分初始化

static struct blob_attr * blob_add(struct blob_buf *buf, struct blob_attr *pos, int id, int payload)

{

         int offset = attr_to_offset(buf, pos);    //此时偏移量为BLOB_COOKIE值;

         int required = (offset - BLOB_COOKIE + sizeof(struct blob_attr) + payload) - buf->buflen; //需要的buf空间

         struct blob_attr *attr;

 

         if (required > 0) {

                   if (!blob_buf_grow(buf, required))    //首次使用必须申请空间,由blob_buffer_grow完成,同时将buf->head指向新申请的空间;

                            return NULL;

                   attr = offset_to_attr(buf, offset);

         } else {

                   attr = pos;

         }

 

         blob_init(attr, id, payload + sizeof(struct blob_attr)); //设置id_len字段值,包括:id和长度信息(payload + sizeof(struct blob_attr))

         blob_fill_pad(attr);  //初始化填充字段;

         return attr;    //返回申请到的attr结构指针

}

blobmsg_add_string(&b, "name", name);增加attr信息

其包裹的函数为

blobmsg_add_field(buf, BLOBMSG_TYPE_STRING, name, string, strlen(string) + 1);

int blobmsg_add_field(struct blob_buf *buf, int type, const char *name,

                  const void *data, unsigned int len)

{

         struct blob_attr *attr;

         void *data_dest;

 

         attr = blobmsg_new(buf, type, name, len, &data_dest); // data_dest返回存放数据的地址;

         if (!attr)

                   return -1;

 

         if (len > 0)

                   memcpy(data_dest, data, len);    //拷贝string(“ubus”)到数据部分

         return 0;

}

blobmsg_new(buf, type, name, len, &data_dest)

再次申请一个attr结构,用来存放name信息;在struct blob_attr *attrdata字段首先内包裹了struct blobmsg_hdr *hdr;结构,用来存放属性类别,之后才是真实数据部分;

static struct blob_attr *

blobmsg_new(struct blob_buf *buf, int type, const char *name, int payload_len, void **data)

{

         struct blob_attr *attr;

         struct blobmsg_hdr *hdr;

         int attrlen, namelen;

         char *pad_start, *pad_end;

 

         if (!name)

                   name = "";

 

         namelen = strlen(name);

         attrlen = blobmsg_hdrlen(namelen) + payload_len; //the length of  (struct blobmsg_hdr + namelen + payload_len)

         attr = blob_new(buf, type, attrlen);         //get the address of next attr

         if (!attr)

                   return NULL;

 

         attr->id_len |= be32_to_cpu(BLOB_ATTR_EXTENDED);

         hdr = blob_data(attr);

         hdr->namelen = cpu_to_be16(namelen);

         strcpy((char *) hdr->name, (const char *)name);     //fill-in the name

         pad_end = *data = blobmsg_data(attr);

         pad_start = (char *) &hdr->name[namelen];

         if (pad_start < pad_end)

                   memset(pad_start, 0, pad_end - pad_start);            //set 0 to padding

 

         return attr;

}

struct blob_attr *

blob_new(struct blob_buf *buf, int id, int payload)

{

         struct blob_attr *attr;

         attr = blob_add(buf, blob_next(buf->head), id, payload);   //computer buffer again, and get the address of next attr

         if (!attr)

                   return NULL;

 

         blob_set_raw_len(buf->head, blob_pad_len(buf->head) + blob_pad_len(attr));   //set attr->id_len again

         return attr;

}

 

instances = blobmsg_open_table(&b, "instances");

添加instances服务属性;

包裹函数为blobmsg_open_nested(buf, name, false); 从函数名看有个nested单词就可以猜测到是上一个attr的角色的子attr

void *

blobmsg_open_nested(struct blob_buf *buf, const char *name, bool array)

{

         struct blob_attr *head;

         int type = array ? BLOBMSG_TYPE_ARRAY : BLOBMSG_TYPE_TABLE;// type is BLOBMSG_TYPE_TABLE

         unsigned long offset = attr_to_offset(buf, buf->head);

         void *data;

 

         if (!name)

                   name = "";

 

         head = blobmsg_new(buf, type, name, 0, &data);    //returrn a new struct blob_attr;

         if (!head)

                   return NULL;

         blob_set_raw_len(buf->head, blob_pad_len(buf->head) - blobmsg_hdrlen(strlen(name)));   //注意这里是减号,在从blobmsg_new返回之前,buf->head就已经被更新了一次,这里又减去了一部分内容,与下面blobmsg_close_array内容一起看就知道为什么这么做了

         buf->head = head;    //这是与上一个attr的子attr,此处更换buf->head指针;

         return (void *)offset;

}

      instance = blobmsg_open_table(&b, "instance1");

与上面内容一致,又嵌套一次;

添加command属性

         command = blobmsg_open_array(&b, "command");

         t = strtok(cmdline, " ");    //此处cmdline /sbin/ubusd;

         while (t) {

                   blobmsg_add_string(&b, NULL, t);    //添加cmdline

                   t = strtok(NULL, " ");

         }

         blobmsg_close_array(&b, command);

blobmsg_open_array 嵌套函数为blobmsg_open_nested(buf, name, true);添加command属性

blobmsg_close_array的作用是结束此时的嵌套,返回上一级attr;其包裹函数为blob_nest_end

void blob_nest_end(struct blob_buf *buf, void *cookie)    //cookie表示是上一级attr的偏移信息;

{

         struct blob_attr *attr = offset_to_attr(buf, (unsigned long) cookie);

         blob_set_raw_len(attr, blob_pad_len(attr) + blob_len(buf->head)); //这里对id_len的改变,没有再次增加sizeof(struct blob_attr),因为在blobmsg_open_nested中没有修改id_len时,已经将struct blob_attr包含在内了;

         buf->head = attr;

}

static inline void *

blob_data(const struct blob_attr *attr)

{

         return (void *) attr->data;

}

 

/*

 * blob_id: returns the id of an attribute

 */

static inline unsigned int

blob_id(const struct blob_attr *attr)

{

         int id = (be32_to_cpu(attr->id_len) & BLOB_ATTR_ID_MASK) >> BLOB_ATTR_ID_SHIFT;

         return id;

}

 

static inline bool

blob_is_extended(const struct blob_attr *attr)

{

         return !!(attr->id_len & cpu_to_be32(BLOB_ATTR_EXTENDED));

}

 

/*

 * blob_len: returns the length of the attribute's payload

 */

static inline unsigned int

blob_len(const struct blob_attr *attr)

{

         return (be32_to_cpu(attr->id_len) & BLOB_ATTR_LEN_MASK) - sizeof(struct blob_attr);

}

 

/*

 * blob_raw_len: returns the complete length of an attribute (including the header)

 */

static inline unsigned int

blob_raw_len(const struct blob_attr *attr)

{

         return blob_len(attr) + sizeof(struct blob_attr);

}

 

/*

 * blob_pad_len: returns the padded length of an attribute (including the header)

 */

static inline unsigned int

blob_pad_len(const struct blob_attr *attr)

{

         unsigned int len = blob_raw_len(attr);

         len = (len + BLOB_ATTR_ALIGN - 1) & ~(BLOB_ATTR_ALIGN - 1);

         return len;

}

其它code

接下来代码就依据上面流程再次添加respawn属性,并依次返回上一层attr并修改id_len字段

 

借网上一张图,可参考这个来看代码;


 

service服务处理

service_handle_set(NULL, NULL, NULL, "add", b.head);

static int

service_handle_set(struct ubus_context *ctx, struct ubus_object *obj,

                      struct ubus_request_data *req, const char *method,

                      struct blob_attr *msg)

{

         struct blob_attr *tb[__SERVICE_SET_MAX], *cur;

         struct service *s = NULL;

         const char *name;

         bool add = !strcmp(method, "add");

         int ret;

 

         blobmsg_parse(service_set_attrs, __SERVICE_SET_MAX, tb, blob_data(msg), blob_len(msg)); //查找消息的每个attrstruct blob_attr *tb[__SERVICE_SET_MAX]每个entry指向消息内对应服务信息的地址;

         cur = tb[SERVICE_ATTR_NAME];    //cur指向name attr

         if (!cur)

                   return UBUS_STATUS_INVALID_ARGUMENT;

 

         name = blobmsg_data(cur);     //提取name信息

 

         s = avl_find_element(&services, name, s, avl);    //avl树查找是否已经存在该项;

         if (s) {

                   DEBUG(2, "Update service %s\n", name);

                   return service_update(s, tb, add);

         }

 

         DEBUG(2, "Create service %s\n", name);

         s = service_alloc(name);    //创建服务对应的struct service *s结构

         if (!s)

                   return UBUS_STATUS_UNKNOWN_ERROR;

 

         ret = service_update(s, tb, add);

         if (ret)

                   return ret;

 

         avl_insert(&services, &s->avl);      //插入avl数;

 

         service_event("service.start", s->name, NULL);    //此时ctxNULL,不发送任何消息;

 

         return 0;

}

static struct service * service_alloc(const char *name)

{

         struct service *s;

         char *new_name;

 

         s = calloc_a(sizeof(*s), &new_name, strlen(name) + 1);

         strcpy(new_name, name);

 

         vlist_init(&s->instances, avl_strcmp, service_instance_update); //最重要的是一个回调函数,service_instance_update用于服务启动/更新

         s->instances.keep_old = true;

         s->name = new_name;

         s->avl.key = s->name;

         INIT_LIST_HEAD(&s->validators);

 

         return s;

}

service_update(s, tb, add)

该函数对blob记录的各个属性做对应的处理,这里我们只关心SERVICE_SET_INSTANCES属性;

         if (tb[SERVICE_SET_INSTANCES]) {

                   if (!add)

                            vlist_update(&s->instances);

                   blobmsg_for_each_attr(cur, tb[SERVICE_SET_INSTANCES], rem) {     //get instances attribute,该attr只有一个,那么下面函数只执行一次;

                            service_instance_add(s, cur);

                   }

                   if (!add)

                            vlist_flush(&s->instances);

         }

 

         rc(s->name, "running"); //若存在/etc/init.d/ubus,则执行running动作,但这里没有该文件;

static void

service_instance_add(struct service *s, struct blob_attr *attr)

{

         struct service_instance *in;    //进程管理由该结构来完成;

 

         if (blobmsg_type(attr) != BLOBMSG_TYPE_TABLE)

                   return;

 

         in = calloc(1, sizeof(*in));

         if (!in)

                   return;

 

         instance_init(in, s, attr);  //各个字段初始化,主要的是提取此时attr的信息,记录该需要启动进程的路径,nicerespawn信息等;in->command记录“/sbin/ubusd

         vlist_add(&s->instances, &in->node, (void *) in->name);    //此函数会简介启动需要的服务;

}

void

vlist_add(struct vlist_tree *tree, struct vlist_node *node, const void *key)

{

         struct vlist_node *old_node = NULL;

         struct avl_node *anode;

     ……

         avl_insert(&tree->avl, &node->avl);    //插入avl

 

update_only:

         tree->update(tree, node, old_node);    //此处调用service_instance_update

}

 

service_instance_update

这里我们关心create操作;

static void service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new,

                            struct vlist_node *node_old)

{

         ……

         } else if (in_n) {

                   DEBUG(2, "Create instance %s::%s\n", in_n->srv->name, in_n->name);

                   instance_start(in_n);

         }

         blob_buf_init(&b, 0);

         trigger_event("instance.update", b.head);

}

void

instance_start(struct service_instance *in)

{

         ……

 

         pid = fork();

         if (pid < 0)

                   return;

 

         if (!pid) {    //子进程启动服务

                   uloop_done();     //调用uloop_done关闭由父进程继承来的epoll信息;

                   closefd(opipe[0]);

                   closefd(epipe[0]);

                   instance_run(in, opipe[1], epipe[1]);      //该函数从blob消息中提取需要执行的指令,并设置环境变量;最终调用execvp(argv[0], argv);

                   return;

         }

 

         DEBUG(2, "Started instance %s::%s\n", in->srv->name, in->name);

         in->proc.pid = pid;        //记录子进程pid

         clock_gettime(CLOCK_MONOTONIC, &in->start);     //记录启动时间

         uloop_process_add(&in->proc);    //添加到processes链表,若进程退出时会调用cb函数instance_exit

         ……

}

 


阅读(5416) | 评论(0) | 转发(0) |
0

上一篇:OpenWrt ubusd

下一篇:AVL树源码分析

给主人留下些什么吧!~~