XSHelper :: XenStore API c++ 渣疯装

12 篇文章 0 订阅
7 篇文章 0 订阅

我把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)

string       map_path_n(vector<string> vec)
{
	string ret;
	for (int i=0; i<vec.size()-1; i++)
		ret+=vec[i]+'/';
	ret+=vec[vec.size()-1];
	return ret;
}
调用:
map_path_n({pwd, ls[j], "cancel"});           
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"})这样子。结果编译提示:

could not convert ‘。。。’ from ‘<花括号里的初始化列表>’ to ‘std::vector<std::basic_string<char> >

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

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

期待更好的办法。

2 模板推断,重载的问题

template <typename T> static bool write_key(xs_handle *xh, int xt, string path, T value)
{...}
template <typename T> static T read_key(xs_handle *xh, int xt, string path)
{...}

template <typename T> static bool write_key(string path, T value)
{	return write_key(xh_shared, xt_shared, path, value);	}
template <typename T> static T read_key(string path)
{	return read_key<T>(xh_shared, xt_shared, path);		}
后两个函数是前两个的简单封装。其中

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

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

xsutil.hpp:144:48: 错误:对‘xsutil::XSHelper::read_key(xs_handle*&, int&, std::string&)’的调用没有匹配的函数
xsutil.hpp:144:48: 附注:备选是:
xsutil.hpp:117:35: 附注:template<class T> static T xsutil::XSHelper::read_key(xs_handle*, int, std::string)
xsutil.hpp:117:35: 附注:  template argument deduction/substitution failed:
xsutil.hpp:144:48: 附注:  couldn't deduce template parameter ‘T’
xsutil.hpp:143:35: 附注:template<class T> static T xsutil::XSHelper::read_key(std::string)
xsutil.hpp:143:35: 附注:  template argument deduction/substitution failed:
xsutil.hpp:144:48: 附注:  cannot convert ‘xsutil::XSHelper::xh_shared’ (type ‘xs_handle*’) to type ‘std::string {aka std::basic_string<char>}’

不解。


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

inline bool is_on_watch()
{
	return (th && pthread_kill(th, 0)==0);	//send empty signal to check existence
}
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;后半部分主要是多线程监视的部分。




#ifndef _XSUTIL_HPP
#define _XSUTIL_HPP

#include "string"
#include "sstream"
#include "iostream"
#include "vector"
#include "assert.h"
#include "pthread.h"
#include "semaphore.h"
#include "errno.h"
#include "unistd.h"
#include "signal.h"
#include "stdarg.h"
extern "C"
{
//#define USE_PTHREAD
#include "xs.h"		//libxenstore
#include "xs_lib.h"
}
using namespace std;

namespace xsutil
{
	//string process func
	template <typename T> const string to_s(T x)
	{
		stringstream ss; ss.clear();
		ss << x;
		return ss.str();
	}
	template <typename T> T from_s(string s)
	{
		T ret;
		stringstream ss; ss.clear();
		ss << s; ss >> ret;
		return ret;
	}
	const char*  from_s(string s){return s.c_str();}
	
	string       map_path_n(vector<string> vec)
	{
		string ret;
		for (int i=0; i<vec.size()-1; i++)
			ret+=vec[i]+'/';
		ret+=vec[vec.size()-1];
		return ret;
	}
	
	string       map_path(string dir, string key) 
	{
		string ret= dir + '/' + key;
		//cout << "map_path -> " << ret << endl;
		return ret;
	}
	const string map_guest(int domid, string path) 
	{
		stringstream ss; ss.clear();
		ss << "/local/domain/" << domid << "/" << path;
		//cout << "map_guest -> " << ss.str() << endl;
		return ss.str();
	}
	template <typename T>
	size_t get_feature(T x)
	{
		const int p=113, size=sizeof(T);
		size_t ret=0, i;
		uint8_t *ptr=(void *)&x;
		for (i=0; i<size; i++)
			ret+=(size_t)ptr[i]*p;
		return ret;
	}
	
	//used to extract (>_<) xs_handle internal members.
	typedef struct list_head {
         struct list_head *next, *prev;
	}list_head_struct;
	typedef struct
	{
		int fd;
		pthread_t read_thr;
		int read_thr_exists;
		struct list_head watch_list;
		pthread_mutex_t watch_mutex;
		pthread_cond_t watch_condvar;
		int watch_pipe[2];
		struct list_head reply_list;
		pthread_mutex_t reply_mutex;
		pthread_cond_t reply_condvar;
		pthread_mutex_t request_mutex;
	}my_xs_handle;

	#if __GNUC__ > 3
	#define offsetof(a,b) __builtin_offsetof(a,b)
	#else
	#define offsetof(a,b) ((unsigned long)&(((a *)0)->b))
	#endif

	class XSHelper
	{
		//static (shared) functions and members
		protected:
			static xs_handle *xh_shared;
			static int xt_shared;
		public:
			static bool is_open;
			static void open_shared(){	assert(xh_shared=xs_open(0)); is_open=true;	}
			static void close_shared(){	xs_close(xh_shared); is_open=false;			}
			static void start_shared(){	xt_shared=xs_transaction_start(xh_shared);		}
			static void end_shared(){	xs_transaction_end(xh_shared, xt_shared, 0);	}
			
			//read/write key, recursive rm
			template <typename T> static bool write_key(xs_handle *xh, int xt, string path, T value)
			{	//note: use sstream "<<" to process type T.
				return xs_write(xh, xt, path.c_str(), to_s(value).c_str(), to_s(value).length());
			}
			template <typename T> static T read_key(xs_handle *xh, int xt, string path)
			{
				T ret;
				stringstream ss; ss.clear();
				int len=0;
				
				char *buf = xs_read(xh, xt, path.c_str(), &len);
				ss << buf; ss >> ret;
				free(buf);
				return ret;
			}
			static void rmdir(xs_handle *xh, int xt, string dir)
			{
				int n;
				char **ls = xs_directory(xh, xt, dir.c_str(), &n);
				if (ls)
				{
					for (int i=0; i<n; i++)
						rmdir(map_path(dir, ls[i]));
					xs_rm(xh, xt, dir.c_str());
					free(ls);
				}
			}
			//simpler overrided version, use xh_shared and xt_shared
			template <typename T> static bool write_key(string path, T value)
			{	return write_key(xh_shared, xt_shared, path, value);	}
			template <typename T> static T read_key(string path)
			{	return read_key<T>(xh_shared, xt_shared, path);		}
			static void rmdir(string dir)
			{	return rmdir(xh_shared, xt_shared, dir);	}
			static int mkdir(string dir)
			{	return xs_mkdir(xh_shared, xt_shared, dir.c_str());	}
			
			
			//extra functions
			static vector<string> directory(string dir)
			{
				vector<string> ret; ret.clear();
				int num=0, i;
				//cout << "list-directory -> " << dir << endl;
				char **ls=xs_directory(xh_shared, xt_shared, dir.c_str(), &num);
				for (i=0; i<num; i++)
					ret.push_back(ls[i]);
				free(ls);
				return ret;
			}
			static bool permission(int domid, string path, bool b_read, bool b_write)
			{
				int value=b_read | ((int)b_write) << 1;
				xs_permissions xp={domid, value};
				return xs_set_permissions(xh_shared, xt_shared, path.c_str(), &xp, 1);
			}
			
		//local members and functions
		protected:
			pthread_t th;
			void (*callback)(XSHelper *pthis, const char *path);		//arg = the char* path which xs returns
			bool flag;
		public:
			xs_handle *xh;								//used by threads
			int xt;										//unused, but callback func may use this
			string path;
		public:
			XSHelper(): xh(0), xt(-1), th(0), flag(false){}
			~XSHelper()
			{
				if (is_on_watch())
				{
					cout << "dtor -> ";
					unwatch();
				}
			}
			inline bool is_on_watch()
			{
				return (th && pthread_kill(th, 0)==0);	//send empty signal to check existence
			}
			inline pthread_t get_thread(){	return th;	}		//used when join
			void watch(string path_str, void (*watch_callback)(XSHelper *, const char *))
			{	
				cout << "watch -> add watch on path " << path_str << " callback func " << hex << (void *)watch_callback << endl;
				path=path_str;
				callback=watch_callback;
				
				xh=xs_open(0);
				assert(xs_watch(xh, path.c_str(), map_path("watch", path).c_str()));
				pthread_create(&th, 0, XSHelper::thread_func, (void *)this);	//thread does xs_read_watch only.
			}
			void finish() {flag=true;}		//used by callback func to make working thread exit normally
			void unwatch()					//cancel working thread. cleanup done by main thread
			{
				cout << "unwatch -> ";
				if (is_on_watch())
				{
					pthread_cancel(th);
					cout << "**stopping work thread. waiting here...";
					pthread_join(th, 0);
					cout << "work thread already stopped." << endl;
					
					thread_cleanup(this);
				}
				else cout << "--work thread already stopped." << endl;
			}
			static void *thread_func(void *arg_this)	//work thread functions
			{
				XSHelper *pthis = (XSHelper *)arg_this;
				int num, i;
				sigset_t mask;
				//set up environment
				cout << "thread_func -> begin watch thread path= " << pthis->path << endl;
				sigemptyset(&mask);
				sigaddset(&mask, SIGINT);
				assert(0 == pthread_sigmask(SIG_BLOCK, &mask, 0));					//mask SIGINT
				pthis->flag=false;
				
				while (!pthis->flag)
				{
					char **result = 0;
					result = xs_read_watch(pthis->xh, &num);	//has cancellation point (read) inside.
					if (result)
					{
						for (i=0; i<num; i+=2)
						{
							cout << "thread_func -> watch event path= " << result[i] << " token= " << result[i+1] << endl;
							if (map_path("watch", pthis->path) == string(result[i+1]))
							{
								//cout << "thread_func -> call callback func -> ";
								pthis->callback(pthis, result[i]);
							}
						}
						//cout << "thread_func -> free result" << endl;
						free(result);
					}
				}
				thread_cleanup(arg_this);
				cout << "thread_func -> work thread exit normally." << endl;
				pthread_exit(0);
			}

#define check_xh_lock(x) do {\
				pthread_mutex_t *pm = (pthread_mutex_t *)(((void *)pthis->xh) + offsetof(my_xs_handle, x));	\
				if (pthread_mutex_trylock(pm) == EBUSY){			\
					cout << "thread_cleanup -> " #x " is already locked!" << endl;	\
					if (0 != pthread_mutex_unlock(pm))				\
						cout << "thread_cleanup -> error unlocking!" << endl;			\
					else cout << "thread_cleanup -> unlocking " #x << endl;			\
				} else assert(pthread_mutex_unlock(pm)==0); 			\
			} while (0)

			static void thread_cleanup(void *arg_this)
			{
				XSHelper *pthis=(XSHelper *)arg_this;
				cout << "thread_cleanup -> path= " << pthis->path << " thread=" << hex << pthis->th << endl;
					
				/* The thread is stopped by pthread_cancel
				 * however, the xs_read_watch API does not release the mutex lock xh->watch_mutex when cancelled (**possibly a bug?**)
				 * but following APIs still try to get the lock -> deadlock here
				 * so we extract the watch_mutex from xs_handle struct to unlock it here.
				 */
				if (pthis->xh)
				{
					check_xh_lock(watch_mutex);
					check_xh_lock(request_mutex);
					check_xh_lock(reply_mutex);
					cout << "----- unwatch -----" << endl;
					xs_unwatch(pthis->xh, pthis->path.c_str(), map_path("watch", pthis->path).c_str());
					
					check_xh_lock(watch_mutex);
					check_xh_lock(request_mutex);
					check_xh_lock(reply_mutex);
					
					cout << "-----  close  -----" << endl;
					xs_close(pthis->xh);
					pthis->xh=0;
				}
				cout.flush();
				pthis->flag=true;
			}
			
	};
	//static member declaration
	xs_handle *XSHelper::xh_shared;
	int XSHelper::xt_shared;
	bool XSHelper::is_open;

}; //namespace
#endif


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值