xenbus

来源:互联网 发布:淘宝钱夫人和王总 编辑:程序博客网 时间:2024/05/22 16:19

【转】XenBus的结构

ref: http://blog.csdn.net/majieyue/article/details/6686729
http://blog.csdn.net/xjtuse_mal/article/details/5473366

Xenbus是Xenstore的一个接口, 它也是在Xenstore之上写的设备驱动的连接协议. Xenbus是一个虚拟设备的mgmt bus. Xen PV "backend" 设备出现在xenbus上, 而且能被DomU使用PV "fronted"设备驱动访问到. 这些虚拟后端设备的状态由xenbus管理. 这些状态被存储到xenstore, 并且一直被Dom0和DomU的xenbus驱动程序监测.XenStore 指供了一个domain如何将前端设备与后端提供的服务联系起来的方法, (实际这部分是由XenBus承载的, 一种建立在XenStore顶层的协议).

xenbus <--> xenstore

xenbus和xenstore通信的代码主要在pvops/drivers/xen/xenbus/目录下的xenbus_xs.c xenbus_comms.c

 

xenbus驱动在初始化时,会调用xs_init函数,xs_init调用xs_init_comms先初始化xenbus和xenstore通信的两个ring。最后通过kthread_run调用xenwatch_thread,xenbus_thread两个内核线程。通过ps可以看到[xenwatch] [xenbus]。

 

 

[xenwatch]线程会调用wait_event_interruptible来监控watches_events链表,所有需要watch的xenstore node都在这个watches_events里面。对应的wait_queue是watch_events_waitq。OK, 下面遍历开始,对watch_events里每一个list_head的结构,通过list_entry找到包含他的xs_stored_msg,调用xs_stored_msg.u.watch.handle->callback函数。

 

[xenbus]线程循环调用process_msg,前面我们知道,xenbus和xenstore通过两个ring通信,如果ring上有xenstore返回给xenbus的rsp,这时break出循环开始处理rsp。首先kmalloc一块xs_stored_msg的内存,先读取msg的head,然后msg的body。如何msg是一个watch event,把event挂到watch_events中,然后wake_upwatch_events_waitq(这玩意儿像个sem),如果是xenstore的reply,就挂到xs_state.reply_list中,并wake_upreply_waitq。

 

xenbus_xs.c中,xs_talkv是xenbus和xenstore通信的核心函数,xs_talkv调用xb_write把请求发到xenstore,调用read_reply接受xenstore的rsp。

 

xenbus_directory, xenbus_read,xenbus_write, xenbus_exists, xenbus_rm, xenbus_mkdir等一系列xenbus_xxxx函数都是基于上述方法

 

xenbus_comms.c中,主要都是底层的通信实现

 

 

xenbus <--> frontend, backend

xenbus与前后端设备打交道也是其重要功能之一。无论前端还是后端设备,在xenbus看来都是一个xenbus_device结构。

 

 

xenbus_client.c

xenbus_grant_ring:前(后)端给后(前)端设备某个ring的access

 

__xenbus_switch_state:改变前(后)端设备的state

 

xenbus_alloc_evtchn:为前(后)端和后(前)端设备通信建立event channel。其中本地domain是DOMID_SELF,remote_domain是dev->otherend_id,最后调HYPERVISOR_event_channel_op

 

xenbus_bind_evtchn:为本地event channel绑定一个remote port。我们知道event channel一般有两个port,传进来bind_interdomain.remote_dom = dev->otherend_id,和bind_interdomain.remote_port。通过调用HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain),得到本地的port为bind_interdomain.local_port

 

xenbus_map_ring_valloc:授权dev->otherend_id的domain来访问一个page。该page是通过xen_alloc_vm_area(PAGE_SIZE)生成出来的。

xenbus_map_ring:授权dev->otherend_id的domain来访问vaddr所在的内存

 

 

xenbus_probe.c

 

xenbus_read_otherend_details:前(后)端调用xenbus_gather收集后(前)端信息。xenbus_gather最终调用xenbus_read,通过xenstore读出。

 

xenbus_otherend_changed:调用xenbus_read_driver_state,读取另一端设备状态

 

xenbus_dev_probe:传入的struct device结构__dev为本地端设备,通过to_xenbus_device,to_xenbus_driver得到struct xenbus_device *dev, struct xenbus_driver *drv结构。接着调用talk_to_otherend得到另一端设备信息,最后调用drv->probe。其实核心还是drv->probe,用来发现dev设备是不是在xenbus上(??这个我不太确定)

 

xenbus_dev_remove:核心也是调用drv->remove函数,其中drv是传入的_dev对应的xenbus_driver。之后把dev对应的xenbus state置为XenbusStateClosed

 

xenbus_dev_shutdown:调用xenbus_switch_state,修改dev的xenbus状态

 

get_device, put_device:dev对应的引用计数

 

xenbus_probe_node:基于nodename,new一片内存并生成一个xenbus_device结构体。最后调用device_register注册该设备。

 

xenbus_probe_device_type:探测bus下设备的类型

 

xenbus_init

xenbus_init是xenbus的初始化函数(废话,看名字就知道啦)。首先判断下是不是xen_initial_domain,如果在dom0里执行,要做一系列初始化的工作,包括

 

申请一个page的空间,用于和xenstore通信,并且把地址写到start_info那个共享page中

 

调用HYPERVISOR_event_channel_op,创建一个event channel,并把event channel其中一个port写到start_info里面。这样xenstore就可以去bind这个port

 

如果在domU里执行,继续判断是否是hvm,无论是否hvm,最终都为了获取到xenbus和xenstore通信的三个数据结构:共享ring的页空间,event channel的port,并基于该空间生成xenstore_domain_interface结构。

 

最后调用xs_init,初始化和xenstore通信的工作


我把xenstore的API简单的封装了一下,方便用户空间的C++使用。主要功能:

1. 把char换成了string,让c++去处理那什么gc。xenstore源代码里面的各种"call free() after use!!!"注释看得我很无语。

2. 提供一个共享的xs_handle对象,一般的读写操作不需要自己定义xs_handle和xs_transaction,方便使用。

3. 简单的全局工具函数,拼合路径名、读写键值更加方便,不需要自己去维护buffer

4. 多线程处理监视事件。


下面是几个比较困惑的地方。


1 想让map_path一次能够读入多个参数,实现map_path("a","b", "c")="a/b/c"这样的效果,最好输入参数还能泛型。现在的做法:(-std=c++0x)

[cpp] view plaincopyprint?
  1. string       map_path_n(vector<string> vec)  
  2. {  
  3.     string ret;  
  4.     for (int i=0; i<vec.size()-1; i++)  
  5.         ret+=vec[i]+'/';  
  6.     ret+=vec[vec.size()-1];  
  7.     return ret;  
  8. }  
调用:
[cpp] view plaincopyprint?
  1. map_path_n({pwd, ls[j], "cancel"});             
[cpp] view plaincopyprint?
  1. map_path_n({to_s(1), to_s(2.65), string(char_str)});           //  结果:1/2.65/char_str  
这样还是比较纠结:调用有2层括号({});而且,不能泛型,毕竟c++没有一个Object类似雾能够表示所有的基本类型和类。所以想处理数字还是得首先转成字符串。

至于其他的做法,我首先尝试了一下C语言的stdarg.h的那种声明里用"..."的方式。结果发现这样根本没法知道传入了几个参数。如果参数都是已知大小的倒还好说,但是字符串……

然后尝试使用vector,在调用的时候使用map_path({"a", "b", "c"})这样子。结果编译提示:

[plain] view plaincopyprint?
  1. could not convert ‘。。。’ from ‘<花括号里的初始化列表>’ to ‘std::vector<std::basic_string<char> >  

然后试了一下map_path((const vector<string>){"a", "b", "c"}); 结果编译通过了。但是这样也太麻烦了吧!

最后在编译选项里面加上了-std=c++0x,然后这样的代码就可以编译通过了。

[cpp] view plaincopyprint?
  1.   

期待更好的办法。

2 模板推断,重载的问题

[cpp] view plaincopyprint?
  1. template <typename T> static bool write_key(xs_handle *xh, int xt, string path, T value)  
[cpp] view plaincopyprint?
  1. {...}  
[cpp] view plaincopyprint?
  1. template <typename T> static T read_key(xs_handle *xh, int xt, string path)  
[cpp] view plaincopyprint?
  1. {...}  
[cpp] view plaincopyprint?
  1.   
[cpp] view plaincopyprint?
  1. template <typename T> static bool write_key(string path, T value)  
  2. {   return write_key(xh_shared, xt_shared, path, value);    }  
  3. template <typename T> static T read_key(string path)  
  4. {   return read_key<T>(xh_shared, xt_shared, path);       }  
后两个函数是前两个的简单封装。其中

第一个函数write_key,参数表里有模板,在调用4个参数的write_key时,不需要告诉模板类型,编译器可以自己推断。

第二个函数read_key,返回值类型是模板,调用3个参数的read_key时必须加上<T>,否则出错:

[plain] view plaincopyprint?
  1. xsutil.hpp:144:48: 错误:对‘xsutil::XSHelper::read_key(xs_handle*&, int&, std::string&)’的调用没有匹配的函数  
  2. xsutil.hpp:144:48: 附注:备选是:  
  3. <em><span style="color:#ff0000;">xsutil.hpp:117:35: 附注:template<class T> static T xsutil::XSHelper::read_key(xs_handle*, int, std::string)  
  4. xsutil.hpp:117:35: 附注:  template argument deduction/substitution failed:  
  5. xsutil.hpp:144:48: 附注:  couldn't deduce template parameter ‘T’</span></em>  
  6. xsutil.hpp:143:35: 附注:template<class T> static T xsutil::XSHelper::read_key(std::string)  
  7. xsutil.hpp:143:35: 附注:  template argument deduction/substitution failed:  
  8. xsutil.hpp:144:48: 附注:  cannot convert ‘xsutil::XSHelper::xh_shared’ (type ‘xs_handle*’) to type ‘std::string {aka std::basic_string<char>}’  

不解。


3 小技巧:判断线程是否存在(linux)

[cpp] view plaincopyprint?
  1. inline bool is_on_watch()  
  2. {  
  3.     return (th && pthread_kill(th, 0)==0);  //send empty signal to check existence  
  4. }  
th是pthread_t类型,是线程的handle。判断方法是用pthread_kill给线程发0号(空)消息,如果返回0(成功)就表示线程存在了。

4 如何控制线程的退出。


5

6

7

代码结构:

前面是全局的字符串处理函数:to|from_s, map_path[_n], map_guest, get_feature。后面是一个类Class XSHelper,前半部分静态函数,可以方便地使用共享的连接(xh_shared, xt_shared)操作xenstore;后半部分主要是多线程监视的部分。




[cpp] view plaincopyprint?
  1. #ifndef _XSUTIL_HPP  
  2. #define _XSUTIL_HPP  
  3.   
  4. #include "string"  
  5. #include "sstream"  
  6. #include "iostream"  
  7. #include "vector"  
  8. #include "assert.h"  
  9. #include "pthread.h"  
  10. #include "semaphore.h"  
  11. #include "errno.h"  
  12. #include "unistd.h"  
  13. #include "signal.h"  
  14. #include "stdarg.h"  
  15. extern "C"  
  16. {  
  17. //#define USE_PTHREAD  
  18. #include "xs.h"     //libxenstore  
  19. #include "xs_lib.h"  
  20. }  
  21. using namespace std;  
  22.   
  23. namespace xsutil  
  24. {  
  25.     //string process func  
  26.     template <typename T> const string to_s(T x)  
  27.     {  
  28.         stringstream ss; ss.clear();  
  29.         ss << x;  
  30.         return ss.str();  
  31.     }  
  32.     template <typename T> T from_s(string s)  
  33.     {  
  34.         T ret;  
  35.         stringstream ss; ss.clear();  
  36.         ss << s; ss >> ret;  
  37.         return ret;  
  38.     }  
  39.     const char*  from_s(string s){return s.c_str();}  
  40.       
  41.     string       map_path_n(vector<string> vec)  
  42.     {  
  43.         string ret;  
  44.         for (int i=0; i<vec.size()-1; i++)  
  45.             ret+=vec[i]+'/';  
  46.         ret+=vec[vec.size()-1];  
  47.         return ret;  
  48.     }  
  49.       
  50.     string       map_path(string dir, string key)   
  51.     {  
  52.         string ret= dir + '/' + key;  
  53.         //cout << "map_path -> " << ret << endl;  
  54.         return ret;  
  55.     }  
  56.     const string map_guest(int domid, string path)   
  57.     {  
  58.         stringstream ss; ss.clear();  
  59.         ss << "/local/domain/" << domid << "/" << path;  
  60.         //cout << "map_guest -> " << ss.str() << endl;  
  61.         return ss.str();  
  62.     }  
  63.     template <typename T>  
  64.     size_t get_feature(T x)  
  65.     {  
  66.         const int p=113, size=sizeof(T);  
  67.         size_t ret=0, i;  
  68.         uint8_t *ptr=(void *)&x;  
  69.         for (i=0; i<size; i++)  
  70.             ret+=(size_t)ptr[i]*p;  
  71.         return ret;  
  72.     }  
  73.       
  74.     //used to extract (>_<) xs_handle internal members.  
  75.     typedef struct list_head {  
  76.          struct list_head *next, *prev;  
  77.     }list_head_struct;  
  78.     typedef struct  
  79.     {  
  80.         int fd;  
  81.         pthread_t read_thr;  
  82.         int read_thr_exists;  
  83.         struct list_head watch_list;  
  84.         pthread_mutex_t watch_mutex;  
  85.         pthread_cond_t watch_condvar;  
  86.         int watch_pipe[2];  
  87.         struct list_head reply_list;  
  88.         pthread_mutex_t reply_mutex;  
  89.         pthread_cond_t reply_condvar;  
  90.         pthread_mutex_t request_mutex;  
  91.     }my_xs_handle;  
  92.   
  93.     #if __GNUC__ > 3  
  94.     #define offsetof(a,b) __builtin_offsetof(a,b)  
  95.     #else  
  96.     #define offsetof(a,b) ((unsigned long)&(((a *)0)->b))  
  97.     #endif  
  98.   
  99.     class XSHelper  
  100.     {  
  101.         //static (shared) functions and members  
  102.         protected:  
  103.             static xs_handle *xh_shared;  
  104.             static int xt_shared;  
  105.         public:  
  106.             static bool is_open;  
  107.             static void open_shared(){  assert(xh_shared=xs_open(0)); is_open=true; }  
  108.             static void close_shared(){ xs_close(xh_shared); is_open=false;         }  
  109.             static void start_shared(){ xt_shared=xs_transaction_start(xh_shared);      }  
  110.             static void end_shared(){   xs_transaction_end(xh_shared, xt_shared, 0);    }  
  111.               
  112.             //read/write key, recursive rm  
  113.             template <typename T> static bool write_key(xs_handle *xh, int xt, string path, T value)  
  114.             {   //note: use sstream "<<" to process type T.  
  115.                 return xs_write(xh, xt, path.c_str(), to_s(value).c_str(), to_s(value).length());  
  116.             }  
  117.             template <typename T> static T read_key(xs_handle *xh, int xt, string path)  
  118.             {  
  119.                 T ret;  
  120.                 stringstream ss; ss.clear();  
  121.                 int len=0;  
  122.                   
  123.                 char *buf = xs_read(xh, xt, path.c_str(), &len);  
  124.                 ss << buf; ss >> ret;  
  125.                 free(buf);  
  126.                 return ret;  
  127.             }  
  128.             static void rmdir(xs_handle *xh, int xt, string dir)  
  129.             {  
  130.                 int n;  
  131.                 char **ls = xs_directory(xh, xt, dir.c_str(), &n);  
  132.                 if (ls)  
  133.                 {  
  134.                     for (int i=0; i<n; i++)  
  135.                         rmdir(map_path(dir, ls[i]));  
  136.                     xs_rm(xh, xt, dir.c_str());  
  137.                     free(ls);  
  138.                 }  
  139.             }  
  140.             //simpler overrided version, use xh_shared and xt_shared  
  141.             template <typename T> static bool write_key(string path, T value)  
  142.             {   return write_key(xh_shared, xt_shared, path, value);    }  
  143.             template <typename T> static T read_key(string path)  
  144.             {   return read_key<T>(xh_shared, xt_shared, path);       }  
  145.             static void rmdir(string dir)  
  146.             {   return rmdir(xh_shared, xt_shared, dir);    }  
  147.             static int mkdir(string dir)  
  148.             {   return xs_mkdir(xh_shared, xt_shared, dir.c_str()); }  
  149.               
  150.               
  151.             //extra functions  
  152.             static vector<string> directory(string dir)  
  153.             {  
  154.                 vector<string> ret; ret.clear();  
  155.                 int num=0, i;  
  156.                 //cout << "list-directory -> " << dir << endl;  
  157.                 char **ls=xs_directory(xh_shared, xt_shared, dir.c_str(), &num);  
  158.                 for (i=0; i<num; i++)  
  159.                     ret.push_back(ls[i]);  
  160.                 free(ls);  
  161.                 return ret;  
  162.             }  
  163.             static bool permission(int domid, string path, bool b_read, bool b_write)  
  164.             {  
  165.                 int value=b_read | ((int)b_write) << 1;  
  166.                 xs_permissions xp={domid, value};  
  167.                 return xs_set_permissions(xh_shared, xt_shared, path.c_str(), &xp, 1);  
  168.             }  
  169.               
  170.         //local members and functions  
  171.         protected:  
  172.             pthread_t th;  
  173.             void (*callback)(XSHelper *pthis, const char *path);        //arg = the char* path which xs returns  
  174.             bool flag;  
  175.         public:  
  176.             xs_handle *xh;                              //used by threads  
  177.             int xt;                                     //unused, but callback func may use this  
  178.             string path;  
  179.         public:  
  180.             XSHelper(): xh(0), xt(-1), th(0), flag(false){}  
  181.             ~XSHelper()  
  182.             {  
  183.                 if (is_on_watch())  
  184.                 {  
  185.                     cout << "dtor -> ";  
  186.                     unwatch();  
  187.                 }  
  188.             }  
  189.             inline bool is_on_watch()  
  190.             {  
  191.                 return (th && pthread_kill(th, 0)==0);  //send empty signal to check existence  
  192.             }  
  193.             inline pthread_t get_thread(){  return th;  }       //used when join  
  194.             void watch(string path_str, void (*watch_callback)(XSHelper *, const char *))  
  195.             {     
  196.                 cout << "watch -> add watch on path " << path_str << " callback func " << hex << (void *)watch_callback << endl;  
  197.                 path=path_str;  
  198.                 callback=watch_callback;  
  199.                   
  200.                 xh=xs_open(0);  
  201.                 assert(xs_watch(xh, path.c_str(), map_path("watch", path).c_str()));  
  202.                 pthread_create(&th, 0, XSHelper::thread_func, (void *)this);    //thread does xs_read_watch only.  
  203.             }  
  204.             void finish() {flag=true;}      //used by callback func to make working thread exit normally  
  205.             void unwatch()                  //cancel working thread. cleanup done by main thread  
  206.             {  
  207.                 cout << "unwatch -> ";  
  208.                 if (is_on_watch())  
  209.                 {  
  210.                     pthread_cancel(th);  
  211.                     cout << "**stopping work thread. waiting here...";  
  212.                     pthread_join(th, 0);  
  213.                     cout << "work thread already stopped." << endl;  
  214.                       
  215.                     thread_cleanup(this);  
  216.                 }  
  217.                 else cout << "--work thread already stopped." << endl;  
  218.             }  
  219.             static void *thread_func(void *arg_this)    //work thread functions  
  220.             {  
  221.                 XSHelper *pthis = (XSHelper *)arg_this;  
  222.                 int num, i;  
  223.                 sigset_t mask;  
  224.                 //set up environment  
  225.                 cout << "thread_func -> begin watch thread path= " << pthis->path << endl;  
  226.                 sigemptyset(&mask);  
  227.                 sigaddset(&mask, SIGINT);  
  228.                 assert(0 == pthread_sigmask(SIG_BLOCK, &mask, 0));                  //mask SIGINT  
  229.                 pthis->flag=false;  
  230.                   
  231.                 while (!pthis->flag)  
  232.                 {  
  233.                     char **result = 0;  
  234.                     result = xs_read_watch(pthis->xh, &num); //has cancellation point (read) inside.  
  235.                     if (result)  
  236.                     {  
  237.                         for (i=0; i<num; i+=2)  
  238.                         {  
  239.                             cout << "thread_func -> watch event path= " << result[i] << " token= " << result[i+1] << endl;  
  240.                             if (map_path("watch", pthis->path) == string(result[i+1]))  
  241.                             {  
  242.                                 //cout << "thread_func -> call callback func -> ";  
  243.                                 pthis->callback(pthis, result[i]);  
  244.                             }  
  245.                         }  
  246.                         //cout << "thread_func -> free result" << endl;  
  247.                         free(result);  
  248.                     }  
  249.                 }  
  250.                 thread_cleanup(arg_this);  
  251.                 cout << "thread_func -> work thread exit normally." << endl;  
  252.                 pthread_exit(0);  
  253.             }  
  254.   
  255. #define check_xh_lock(x) do {\  
  256.                 pthread_mutex_t *pm = (pthread_mutex_t *)(((void *)pthis->xh) + offsetof(my_xs_handle, x));  \  
  257.                 if (pthread_mutex_trylock(pm) == EBUSY){            \  
  258.                     cout << "thread_cleanup -> " #x " is already locked!" << endl;   \  
  259.                     if (0 != pthread_mutex_unlock(pm))              \  
  260.                         cout << "thread_cleanup -> error unlocking!" << endl;            \  
  261.                     else cout << "thread_cleanup -> unlocking " #x << endl;          \  
  262.                 } else assert(pthread_mutex_unlock(pm)==0);             \  
  263.             } while (0)  
  264.   
  265.             static void thread_cleanup(void *arg_this)  
  266.             {  
  267.                 XSHelper *pthis=(XSHelper *)arg_this;  
  268.                 cout << "thread_cleanup -> path= " << pthis->path << " thread=" << hex << pthis->th << endl;  
  269.                       
  270.                 /* The thread is stopped by pthread_cancel 
  271.                  * however, the xs_read_watch API does not release the mutex lock xh->watch_mutex when cancelled (**possibly a bug?**) 
  272.                  * but following APIs still try to get the lock -> deadlock here 
  273.                  * so we extract the watch_mutex from xs_handle struct to unlock it here. 
  274.                  */  
  275.                 if (pthis->xh)  
  276.                 {  
  277.                     check_xh_lock(watch_mutex);  
  278.                     check_xh_lock(request_mutex);  
  279.                     check_xh_lock(reply_mutex);  
  280.                     cout << "----- unwatch -----" << endl;  
  281.                     xs_unwatch(pthis->xh, pthis->path.c_str(), map_path("watch", pthis->path).c_str());  
  282.                       
  283.                     check_xh_lock(watch_mutex);  
  284.                     check_xh_lock(request_mutex);  
  285.                     check_xh_lock(reply_mutex);  
  286.                       
  287.                     cout << "-----  close  -----" << endl;  
  288.                     xs_close(pthis->xh);  
  289.                     pthis->xh=0;  
  290.                 }  
  291.                 cout.flush();  
  292.                 pthis->flag=true;  
  293.             }  
  294.               
  295.     };  
  296.     //static member declaration  
  297.     xs_handle *XSHelper::xh_shared;  
  298.     int XSHelper::xt_shared;  
  299.     bool XSHelper::is_open;  
  300.   
  301. }; //namespace  
  302. #endif  

0 0
原创粉丝点击