-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsearch.xml
115 lines (115 loc) · 40.8 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[install-ripgrep]]></title>
<url>%2Fblog%2F2017-08-25-install-ripgrep.html</url>
<content type="text"><![CDATA[听闻ripgrep有着grep的速度以及ag的功能,这里简单 记录下rg的安装过程。 install proxychains-ng 12345git clone https://github.com/rofl0r/proxychains-ng.gitcd proxychains-ng./configure --prefix=/usr --sysconfdir=/etc/makesudo make install add proxy in the /etc/proxychains.conf or /usr/etc/proxychains.conf 配置完成之后即可使用proxychains4完成后续的安装。 install Rust 官方安装: curl https://sh.rustup.rs -Ssf | sh 这里要使用代理安装,所以先将安装脚本下载到本地,再通过proxychans4安装。 12curl https://sh.rustup.rs -sSf > x.shproxychains4 ~/x.sh 安装完成后,所有的命令位于 /.cargo/bin 目录下,且相关的PATH已添加至~/.profile中。 install ripgrep proxychains4 cargo install ripgrep ,安装成功后,rg位于~/.cargo/bin目录中。 Last Updated 2017-09-06 Wed 07:40 with Emacs 25.1.1 (Org mode 9.0.10)]]></content>
<tags>
<tag>Linux</tag>
<tag>rg</tag>
</tags>
</entry>
<entry>
<title><![CDATA[随笔]]></title>
<url>%2Fblog%2F2017-08-09-suibi.html</url>
<content type="text"><![CDATA[不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之。 很喜欢上面的这句话,毕业一年多了,在社会这个大环境下或多或少被烙上了它独有的印记。似乎还在怀念在 以前的时光,可以把一切慢下来,没有那么急躁,静静地学习和生活。不一定要多精彩,但足够你慢慢回味,依然 会在某天突然想起一些人,一些事,那些一起玩过,疯过和笑过的日子。 下面是美国首席大法官在儿子的毕业的典礼上发表的演讲,说的很有道理: 通常毕业致辞会祝你们好运,还会祝你们心想事成,但我不会这么做。我会告诉你们原因。 在接下来数年的时间里,我希望你们被不公平对待,如此你们才知道公平正义的重要。我希望你们遭遇背叛,如此 才知道忠诚的重要性。很抱歉这么说,但我希望你们有时候感到孤单,这样才不会把朋友当作理所当然。我希望你 们时不时遭遇不幸,如此才能意识到几率和运气在人生中扮演的角色,了解成功不是完全你所应得的,而他人的失 败也不是他们所应得的结果。 人生一定时常会有失败,当你们失败时,我希望你的对手会对你的失败幸灾乐祸,让你们理解运动家精神的重要性。 我希望你们遭遇忽视,如此才会知道聆听他人的n重要性,我还希望你们遭遇足够的痛苦来学习同情心。不管是否来 自我的希望,这些事终究会发生。至于你们是否能从中获利,则取决于你们从不幸中获得讯息的能力。 毕业致辞者通常会给学生一些建议。他们会给一些广泛的建议和有用的忠告。最常给的建议就是:做自己。给所有穿 着一样的人如此建议实在有点怪,但你们确实应该做自己。只是你们得了解做自己的意义何在。除非你很完美,否则做 自己不代表不能接受改变。在某些状况来说,你不应该做自己,而是应该变成更好的人。大家说“做自己”是因为他们希望你们能阻挡外界要求你们做的事,但除非你们了解 自己是谁,或思考过自己是谁,否则无法“做自己”。 Last Updated 2017-09-06 Wed 07:40 with Emacs 25.1.1 (Org mode 9.0.10)]]></content>
</entry>
<entry>
<title><![CDATA[linux poll分析]]></title>
<url>%2Fblog%2F2017-03-02-2017-03-02-linux-poll.html</url>
<content type="text"><![CDATA[在上层应用中使用系统调用,最终都会调用到内核中提供的接口,对于 poll ,与之相对应的即为 sys_poll 函数。 sys_poll sys_poll函数的实现在内核中的 fs/select.c 文件中: 12345678910SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs){ ... /* 在这里调用do_sys_poll */ ret = do_sys_poll(ufds, nfds, to); ...} 可以看看 SYSCALL_DEFINE3 是如何展开得到 sys_poll 函数的定义的 123456789101112131415#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)#define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ __attribute__((alias(__stringify(SyS##name)))); \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \ long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ __MAP(x,__SC_TEST,__VA_ARGS__); \ __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ return ret; \ } \ static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs) 通过宏展开后: /* 给sys_poll起的别名为Sys_poll */asmlinkage long sys_poll(__MAP(3, __SC_DECL, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs)) __attribute__((alias(__stringify(SyS_poll))));static inline long SYSC_poll(__MAP(3, __SC_DECL, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs));/* Sys_poll函数将参数类型强转为long类型 */asmlinkage SyS_poll(__MAP(3, __SC_LONG, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs));asmlinkage SyS_poll(__MAP(3, __SC_LONG, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs)){ /* 将参数类型强转为对应的实际类型,并调用下面实现的SYSC_poll函数 */ long ret = SYSC_poll(__MAP(3, __SC_CAST, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs)); __MAP(3, __SC_TEST, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs); __PROTECT(3, ret, __MAP(3, __SC_ARGS, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs)); return ret;}static inline long SYSC_poll(__MAP(3, __SC_DECL, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs)) 那么__MAP __SC_CAST __SC_DECL 以及 __SC_LONG 这些宏又是如何实现的: 123456789101112131415#define __MAP(n,...) __MAP##n(__VA_ARGS__)#define __MAP1(m,t,a) m(t,a)#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)#define __SC_DECL(t, a) t a/********************************************************************************************************************//* 对于__MAP(3, __SC_DECL, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs) *//* 展开后即为 __SC_DECL(struct pollfd __user *, ufds), __MAP2(__SC_DECL, unsigned int, nfds, int, timeout_msecs) *//* 进一步展开 __SC_DECL(struct pollfd __user *, ufds), __SC_DECL(unsigned int, nfds), __SC_DECL(int, timeout_msecs) *//* 最终即为 struct pollfd __user * ufds, unsigned int nfds, int timeout_msecs *//********************************************************************************************************************/ 可见__MAP和__SC_DECL宏的主要作用是进行参数类型和参数的配对,而当和__SC_LONG配对使用时就是将所有的参数类型强转为long类型进行接受, 这样转来转去为了啥?原因就是64位linux系统下有个名为CVE-2009-2009的漏洞,ABI规定在64位平台的在系统调用时,必须确保用户空间将系统 调用中32位的参数存放在64位的寄存器中并保证正确的符合扩展,但是用户空间程序并不能保证做到这点,这就有可能向有漏洞的系统调用传送特制 参数导致系统崩溃或者权限提升。 ABI: Application Binary Interface, 定义了的内容大概有: 数据类型的大小,布局和对齐方式。 控制函数的参数如何进行传递以及如何接受返回值,例如,通过栈还是部分通过寄存器等。 应用如何使用系统调用。 目标文件的二进制格式,程序库等。 do_sys_poll 讲了这么多,才刚分析完sys_poll是如何定义的,sys_poll会调用do_sys_poll,接下来看do_sys_poll函数做了哪些事情: 将用户传入的pollfd数组拷贝到内核空间。 遍历查询传入的pollfd数组中文件描述符对应设备的状态,如果所有设备都没有关心的事件发生,这时则需要挂起当前进程,直到有事件到来或者超时将其唤醒。如果有事件到来,则再次遍历所有设备,定位事件。 将获得的事件返回到用户空间,并释放分配的内存以及移除等待队列。 123456789101112131415int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, struct timespec *end_time){ /* 1.执行拷贝动作 */ ... /*2. 遍历查询 */ poll_initwait(&table); fdcount = do_poll(nfds, head, &table, end_time); /*3. 移除等待队列,释放内存,将事件拷贝回用户空间 */ poll_freewait(&table); ...} 拷贝 在进行拷贝时,先申请一段栈空间,转换为poll_list类型,剩余的空间则被用来存放pollfd数组,在查询的文件描述符较少时,由于变量是存放在栈空间, 这样速度可以更快,而且可以节省memory。在文件描述符超过所申请的栈空间时,再额外的分配所需空间,完成剩下的拷贝工作。 12345678910111213141516171819202122232425262728293031long stack_pps[POLL_STACK_ALLOC/sizeof(long)];struct poll_list *const head = (struct poll_list *)stack_pps;struct poll_list *walk = head;unsigned long todo = nfds;for (;;) { walk->next = NULL; walk->len = len; if (!len) break; /* 拷贝pollfd数组到poll_list中的entries成员中 */ if (copy_from_user(walk->entries, ufds + nfds-todo, sizeof(struct pollfd) * walk->len)) goto out_fds; /* todo初始值为要拷贝的文件描述符个数 */ todo -= walk->len; if (!todo) break; len = min(todo, POLLFD_PER_PAGE); /* 当要查询的文件描述符大于预先在栈中申请的空间时,申请分配内存 */ size = sizeof(struct poll_list) + sizeof(struct pollfd) * len; walk = walk->next = kmalloc(size, GFP_KERNEL); if (!walk) { err = -ENOMEM; goto out_fds; }} 查询事件 poll_initwait 初始化poll_wqueues变量table。 12345678910poll_initwait(struct poll_wqueues *pwq){ /* 将poll_table中的_qproc函数变量初始化为__pollwait,_key设置为(~0UL) */ init_poll_funcptr(&pwq->pt, __pollwait); pwq->polling_task = current; pwq->triggered = 0; pwq->error = 0; pwq->table = NULL; pwq->inline_index = 0;} __pollwait函数在驱动中的poll实现中通过poll_wait函数调用,这里先看下它的实现: 123456789101112131415161718/* Add a new entry */static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p){ struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); struct poll_table_entry *entry = poll_get_entry(pwq); if (!entry) return; entry->filp = get_file(filp); //保存设备文件 entry->wait_address = wait_address; //保存来自设备驱动的等待队列头 entry->key = p->_key; //保存设备所关心的events /* 初始化等待队列项,并将唤醒该等待队列项的函数注册为pollwake */ init_waitqueue_func_entry(&entry->wait, pollwake); entry->wait.private = pwq; /* 添加等待队列项到等待队列头 */ add_wait_queue(wait_address, &entry->wait);} do_poll 先上源码: 123456789101112131415161718192021222324252627282930313233static int do_poll(unsigned int nfds, struct poll_list *list, struct poll_wqueues *wait, struct timespec *end_time){ for (;;) { struct poll_list *walk; bool can_busy_loop = false; /* 遍历所有的pollfd */ for (walk = list; walk != NULL; walk = walk->next) { struct pollfd * pfd, * pfd_end; pfd = walk->entries; pfd_end = pfd + walk->len; for (; pfd != pfd_end; pfd++) { if (do_pollfd(pfd, pt, &can_busy_loop, busy_flag)) { count++; pt->_qproc = NULL; /* found something, stop busy polling */ busy_flag = 0; can_busy_loop = false; } } } pt->_qproc = NULL; ... if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)) timed_out = 1; }} do_pollfd会调用到文件描述符所对应设备驱动程序中的poll函数指针,该函数相信很多人都知道怎么去写,但是为什么这样写,而且 它具体做了哪些事情,这里在内核目录下找了ucma的poll实现: 12345678910111213static unsigned int ucma_poll(struct file *filp, struct poll_table_struct *wait){ struct ucma_file *file = filp->private_data; unsigned int mask = 0; poll_wait(filp, &file->poll_wait, wait); if (!list_empty(&file->event_list)) mask = POLLIN | POLLRDNORM; return mask;} poll_wait()虽然具有wait字样,但是并不会阻塞在这里,不然如果应用程序同时监控多个设备文件,每个poll函数都阻塞的话,也不会 称为IO复用了。所以do_pollfd的真正作用有两个: 利用poll_wait()将后续等待设备就绪的进程对应的等待队列项添加到驱动程序提供的等待队列头中。(仅在第一次轮循中使用,第一次轮循环结束后poll_table的_qproc被置为NULL) 查询当前是否有关心的事件到来。 12345678static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p){ /* 在poll_initwait中_qproc指向__pollwait()函数 */ if (p && p->_qproc && wait_address) p->_qproc(filp, wait_address, p);} __pollwait()的实现详见上一小节,对于不同的进程当调用poll监测同一个设备文件描述符时都会有分配一个poll_table_entry项,并将等待队列项加入到相同的等待队列头中,都为 驱动程序中所初始化的等待队列头。因此当设备就绪时,就会唤醒所有在该等待队列头中的所有等待队列项。 若无事件发生,do_poll中的poll_schedule_timeout()会挂起当前进程,直到有事件(比如说POLLIN)到来时,可以通过wake_up_interruptible()"唤醒"处于设备驱动程序等待队列头的 等待队列项,这时会调用之前__pollwait注册的回调函数pollwake函数,它通过container_of找到等待队列项对应的poll_table_entry项,最后调用__pollwake真正唤醒当前挂起的进程。 123456789static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key){ struct poll_table_entry *entry; entry = container_of(wait, struct poll_table_entry, wait); if (key && !((unsigned long)key & entry->key)) return 0; return __pollwake(wait, mode, sync, key);} 清理并返回用户空间 123456789101112131415161718192021poll_freewait(&table);for (walk = head; walk; walk = walk->next) { struct pollfd *fds = walk->entries; int j; for (j = 0; j < walk->len; j++, ufds++) /* 拷贝回用户空间 */ if (__put_user(fds[j].revents, &ufds->revents)) goto out_fds;}err = fdcount;out_fds:walk = head->next;while (walk) { struct poll_list *pos = walk; walk = walk->next; kfree(pos);} Last Updated 2017-09-06 Wed 07:40 with Emacs 25.1.1 (Org mode 9.0.10)]]></content>
<categories>
<category>Linux</category>
</categories>
<tags>
<tag>Kernel Driver</tag>
</tags>
</entry>
<entry>
<title><![CDATA[从markdow到org的迁移]]></title>
<url>%2Fblog%2F2017-02-16-2017-02-16-org-blog.html</url>
<content type="text"><![CDATA[这是一篇来自org+hexo的测试文章,依然采用travis进行持续集成,部署到github和coding.net。 作为vim党,依然还是中了emacs的毒,org mode确实很好用有没有 ~~! 行内代码 sudo apt-get install ruby 代码块 123456#include <stdio.h>int main(char argc, char **argv){ printf("www.freereaper.com\n"); return 1;} 表格 1 one 2 two 3 Three 4 four 引用 www.freereaper.com 列表 vim emacs 文字处理 stroke line Last Updated 2017-09-06 Wed 07:40 with Emacs 25.1.1 (Org mode 9.0.10)]]></content>
<categories>
<category>org</category>
</categories>
</entry>
<entry>
<title><![CDATA[python元类浅析(第二季)]]></title>
<url>%2Fblog%2F2016-11-20-python-metaclassII.html</url>
<content type="text"><![CDATA[上一篇文章中已经讲述了什么是metaclass,metaclass类似创建类的模板,继承自type类, 通过重写__new__方法控制类的创建行为。 metacalss原理12345678910111213141516171819202122232425262728293031class MetaClass(type): def __new__(cls, name, bases, attrs): print "Allocating memory for class", name print cls print bases print attrs return super(MetaClass, cls).__new__(cls, name, bases, attrs) def __init__(cls, name, bases, attrs): print "initializing class", name print cls print bases print attrs return super(MetaClass, cls).__init__(name, bases, attrs) class MyClass(object): __metaclass__ = MetaClass def fun(self, param): print param'''Allocating memory for class MyClass<class '__main__.MetaClass'>(<type 'object'>,){'fun': <function fun at 0x02E19BB0>, '__module__': '__main__', '__metaclass__': <class '__main__.MetaClass'>}initializing class MyClass<class '__main__.MyClass'>(<type 'object'>,){'fun': <function fun at 0x02E19BB0>, '__module__': '__main__', '__metaclass__': <class '__main__.MetaClass'>}''' cls: 将要创建的类。 name: 类的名字,也就是通常使用name获取的属性。 bases: 基类。 attrs: 属性字典,可以是类变量,也可以是类函数。 在MyClass定义中通过指定__metaclass__ = MetaClass来告诉python解释器,在创建MyClass类时, 要通过MetaClass来创建,而不再使用内置的type。这样在MetaClass.__new__()方法中即可对类的定义进行修改,比如加上新的方法或者 属性。 metaclass使用在采用__metaclass__创建类的时候,默认的查找顺序如下(摘自官方文档): If dict[‘metaclass‘] exists, it is used. Otherwise, if there is at least one base class, its metaclass is used (this looks for a class attribute first and if not found, uses its type). Otherwise, if a global variable named metaclass exists, it is used. Otherwise, the old-style, classic metaclass (types.ClassType) is used. 委托委托(delegate)是设计模式中常用的一种方法,通常利用委托类为需要委托的方法 去定义一个方法,以下是摘自网上的例子: 123456789101112131415class ImmutableList(object): def __init__(self, delegate): self.delegate = delegate def __getitem__(self, i): return self.delegate.__getitem__(i) def __getslice__(self, i, j): return self.delegate.__getslice__(i, j) def __len__(self): return self.delegate.__len(self) def index(self, v): return self.delegate.index(v) 以上是比较常规的做法,而使用元类的实现就显得格外简单和优雅: 12345678910111213141516171819202122232425class DelegateMetaClass(type): def __new__(cls, name, bases, attrs): methods = attrs.pop('delegated_methods', ()) for m in methods: def make_func(m): def func(self, *args, **kwargs): return getattr(self.delegate, m)(*args, **kwargs) return func attrs[m] = make_func(m) return super(DelegateMetaClass, cls).__new__(cls, name, bases, attrs) class Delegate(object): __metaclass__ = DelegateMetaClass def __init__(self, delegate): self.delegate = delegate class ImmutableList(Delegate): delegated_methods = ( '__contains__', '__eq__', '__getitem__', '__getslice__', '__str__', '__len__', 'index', 'count') class ImmutableDict(Delegate): delegated_methods = ('__contains__', '__getitem__', '__eq__', '__len__', '__str__', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'values') 接口1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071#!/usr/bin/env python# -*- coding: utf-8 -*-class Field(object): def __init__(self, fname, ftype): self.fname = fname self.ftype = ftype def __str__(self): return '{%s: (%s, %s)}' % (self.__class__.__name__, self.fname, self.ftype) class StringField(Field): def __init__(self, fname): super(StringField, self).__init__(fname, 'varchar(100)')class IntegerField(Field): def __init__(self, fname): super(IntegerField, self).__init__(fname, 'bigint') class ModelMetaclass(type): def __new__(cls, name, bases, attrs): print cls print "creating for:", name if name == "Model": attrs['author'] = "reaper" return super(ModelMetaclass, cls).__new__(cls, name, bases, attrs) else: mapping = {} print "Create Model for:", name for k, v in attrs.items(): if isinstance(v, Field): print "mapping %s with %s" %(k, v) mapping[k] = v attrs['_table'] = name attrs['_mapping'] = mapping return type.__new__(cls, name, bases, attrs) class Model(dict): __metaclass__ = ModelMetaclass def __init__(self, **kwargs): for key in kwargs.keys(): if key not in self.__class__._mapping.keys(): print "Key '%s' is not defined for %s" %(key, self.__class__.__name__) return super(Model, self).__init__(**kwargs) def save(self): fields = [] params = [] args = [] for k, v in self.__class__._mapping.items(): fields.append(k) params.append("'{0}'".format(self[k])) sql = 'insert into %s (%s) values (%s)' % (self.__class__._table, ','.join(fields), ','.join(params)) print 'SQL: %s' %sql class Student(Model): id = IntegerField('id_c') name = StringField('username_c') email = StringField('email_c')print Student.authorprint "-------------------------------------------------"print Student._tableprint Student._mappingprint "-------------------------------------------------"s1 = Student(id = 1, name = "Wilber", email = "[email protected]")print s1.ids1.save()]]></content>
<tags>
<tag>python</tag>
<tag>metaclass</tag>
</tags>
</entry>
<entry>
<title><![CDATA[YouCompleteMe笔记]]></title>
<url>%2Fblog%2F2016-11-11-YCM.html</url>
<content type="text"><![CDATA[Build Vim8 From Source 卸载旧版本的vim 12sudo apt-get remove vim vim-runtime gvimsudo apt-get remove vim-tiny vim-common vim-gui-common vim-nox 安装依赖包 12345sudo apt-get install libncurses5-dev libgnome2-dev libgnomeui-dev \ libgtk2.0-dev libatk1.0-dev libbonoboui2-dev \ libcairo2-dev libx11-dev libxpm-dev libxt-dev python-dev \ python3-dev ruby-dev lua5.1 lua5.1-dev luajit libluajit-5.1-dev \ libperl-dev git 编译vim8.0 123456789101112131415161718192021git config --global http.proxy "socks5://127.0.0.1:1080"git config --global https.proxy "socks5://127.0.0.1:1080"cd ~/downloadgit clone https://github.com/vim/vim.git vimcd vim./configure --with-compiledby="freereaper" \ --with-features=huge \ --enable-multibyte \ --enable-perlinterp=yes \ --enable-rubyinterp=yes \ --enable-pythoninterp=yes \ --with-python-config-dir=/usr/lib/python2.7/config-x86_64-linux-gnu \ --enable-python3interp=yes \ --with-python3-config-dir=/usr/lib/python3.4/config-3.4m-x86_64-linux-gnu \ --with-luajit --enable-luainterp=yes \ --with-lua-prefix=/usr/include/lua5.1 \ --enable-gui=gnome2 --enable-gnome-check --enable-cscope \ --prefix=/usr --enable-fail-if-missingmake VIMRUNTIMEDIR=/usr/share/vim/vim80sudo make install 其中python-config dir可以通过pytho-config –configdir查看 编译YCM 通过plug工具安装YouCompleteMe插件,建议走代理。 12git config --global http.proxy "socks5://127.0.0.1:1080"git config --global https.proxy "socks5://127.0.0.1:1080" 下载Pre_Buillt Clang Binaries,按照以下步骤编译ycm_core.so 1234567wget http://llvm.org/releases/3.9.0/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-14.04.tar.xz -O clang+llvm.tar.xzxz -d clang+llvm.tar.xztar -xvf clang+llvm.tar -C ~/ycm_temp/mkdir -p ~/ycm_buildcd ~/ycm_buildcmake -G "Unix Makefiles" -DPATH_TO_LLVM_ROOT=~/ycm_temp/clang+llvm-3.9.0-x86_64-linux-gnu-ubuntu-14.04 . ~/.vim/bundle/YouCompleteMe/third_party/ycmd/cppcmake --build . --target ycm_core]]></content>
<tags>
<tag>python</tag>
<tag>metaclass</tag>
</tags>
</entry>
<entry>
<title><![CDATA[python元类浅析(第一季)]]></title>
<url>%2Fblog%2F2016-11-11-python-metaclass.html</url>
<content type="text"><![CDATA[类也是对象在介绍元类之前,先来了解python中的类是什么。python中的类和大多数编程语言一样, 就是用来描述如何生成一个对象的代码片段。 12345678class ObjectCreator(object): passmyObj = ObjectCreator()print myObj#-----------console output-------------<__main__.ObjectCreator object at 0x02BE1810> 在python中,一切皆对象,类同样也是一种对象。ObjectCreator就是内存中的一个对象,这个对象(类)自身 拥有创建对象(类实例)的能力,而这就是为什么它是一个类的原因。但是,因为它本质依然是一个对象,因此也 就具有对象的行为特性: 可以被变量引用 可以拷贝 可以修改属性 可以作为函数参数进行传递 e.g.: 123456789101112131415161718192021222324252627# you can print a class because it's an objectprint(ObjectCreator) <class '__main__.ObjectCreator'> # you can pass a class as a parameterdef echo(o): print(o)echo(ObjectCreator) <class '__main__.ObjectCreator'># you can add attributes to a classprint(hasattr(ObjectCreator, 'new_attribute'))FalseObjectCreator.new_attribute = 'foo' print(hasattr(ObjectCreator, 'new_attribute'))Trueprint(ObjectCreator.new_attribute)foo# you can assign a class to a variableObjectCreatorMirror = ObjectCreator print(ObjectCreatorMirror.new_attribute)fooprint(ObjectCreatorMirror())<__main__.ObjectCreator object at 0x8997b4c> 动态创建类当使用class关键字时,python能够自动的创建类。但就像python中其它大部分设计一样, 它也提供了能够手动创建类的方法。 在python中type 除了能够返回对象的类型,它还具有动态创建类的能力。type可以接受一 个类的描述作为参数,然后返回一个类。 (我知道,根据传入参数的不同,同一个函数拥有两种完全不同的用法是一件很傻的事情, 但这在Python中是为了保持向后兼容性。) type创建类的用法如下: 1type(类名, 父类元祖(可以为空),属性字典) 以下两种方式都可以等价地创建出MyClass类: 使用class关键字 12345678910111213class MyClass(object): author = "reaper" def say_author(self): print self.author my_class = MyClass()print my_class.authormy_class.say_author() --------------------console output------------------reaperreaper` 使用type 12345678910def say_author(self): print self.authorMyClass = type("MyClass", (), {'author': 'reaper', 'say_author': say_author}my_class = MyClass()print my_class.authormy_class.say_author() --------------------console output------------------reaperreaper 你可以看到,在Python中,类也是对象,你可以动态的创建类。这就是当你使用关键字class时Python在 幕后做的事情,而这就是通过元类来实现的。 什么是元类 什么是元类?元类就是用来创建类的“东西“,元类就是类的类,直观来说就是,元类的实例就是类。 12345#元类的instance就是类MyClass = MetaClass() #类的instance就是类实例,好吧,有点绕~~!MyObject = MyClass() 在上一节中,已经讲述了type可以动态地创建类。然而,type其实就是一个元类。type元类是python 幕后用来创造所有类的元类。 在python中,str是用来创造字符串对象的类,int是用来创造整形对象的类,type就是用来创造类对象的 类。正如之前所说,python中的一切都是对象,包括整形,字符串,函数和类,它们最终都是通过元类创造出 来的。 12345678910111213age = 32age.__class__age.__class__.__class__name = "reaper"name.__class__name.__class__.__class__class MyClass(object): passmy_class = MyClass()my_class.__class__my_class.__class__.__class__ 可以看出,最后的__class__属性都是<type 'type'>,python中使用type作为内置的元类。下一季将讲述 如何定制元类,以及如何使用元类。 Refs: stackoverflow]]></content>
<tags>
<tag>python</tag>
<tag>metaclass</tag>
</tags>
</entry>
<entry>
<title><![CDATA[使用pyenv和virtualenv定制python环境]]></title>
<url>%2Fblog%2F2016-11-07-pyenv.html</url>
<content type="text"><![CDATA[pyenv提供管理和切换不同python版本的功能。 pyenv-virtualenv属于pyenv的插件,可以定制相互隔离的python开发环境。 两者可以实现多版本,多环境的控制,可以为每个项目定制完全隔离的python运行环境。 安装pyenv和pyenv-virtualenv1234567function bootstrap-pyenv { __clone 'https://github.com/yyuu/pyenv.git' '.pyenv' if [ ! -d "$HOME/.pyenv/plugins/pyenv-virtualenv" ]; then mkdir -p "$HOME/.pyenv/plugins" git clone https://github.com/yyuu/pyenv-virtualenv.git $HOME/.pyenv/plugins/pyenv-virtualenv fi} 其中__clone具体实现在init.zsh。 添加pyenv init和pyenv virtualenv-init到.zshrc中: 1234567891011121314# file : .zshrc# pyenv cfgexport PYENV_ROOT="${HOME}/.pyenv"if [ -d "${PYENV_ROOT}" ]; then export PATH="${PYENV_ROOT}/bin:${PATH}" eval "$(pyenv init -)" if [ -d "${PYENV_ROOT}/plugins/pyenv-virtualenv" ]; then eval "$(pyenv virtualenv-init -)" fifiexport PYENV_VIRTUALENV_DISABLE_PROMPT=1 pyenv的使用安装和卸载python1234567891011121314151617#查看可以安装的python版本pyenv install --list#安装版本3.5.1,系统会从python官网下载安装对应的python版本。#这里下载会比较慢,可以从后面介绍的两种方法安装。pyenv install 3.5.1#更新,为所有安装的可执行文件(~/.pyenv/versions/*/bin/*)c创建shims,#因此,每当你增删python版本或带有可执行文件的包(如pip)以后,都应该执行#一次本命令pyenv rehash#查看系统已经安装的python版本pyenv versions#卸载某个版本的pythonpyenv uninstall 3.5.1 可选安装方法: 直接下载对应的版本压缩包,例如Python-3.5.1.tgz,拷贝至~/.pyenv/cache/中, 如果没有cache目录,则手动创建,并修改文件名为Python-3.5.1.tar.gz。 12mv Python-3.5.1.tgz Python-3.5.1.tar.gzpyenv install 3.5.1 -v 使用国内镜像的pyenv源安装。 12export PYTHON_BUILD_MIRROR_URL="http://pyenv.qiniudn.com/pythons/"pyenv install 3.5.1 -v pyenv与virtualenvpyenv global 3.5.1切换当前python版本为3.5.1,pyenv global system切换回系统版本。 当系统安装了多个python版本,为了保持系统环境足够干净,可以使用pyenv virtualenv来创建虚拟python环境。 创建一个以python3.5.1为解释器的虚拟环境可以通过以下命令实现: 1pyenv virtualenv 3.5.1 env351 此时会在~/.pyenv/versions/目录下创建一个env351的目录,通过pyenv versions即可看到当前创建的虚拟环境。 为项目单独配置一个虚拟的python运行环境: 12345678910#创建名为project的虚拟环境pyenv virtualenv 3.5.1 project#设置进入project目录自动切换为project环境。#会生成.python_versions文件cd project_rootpyenv local project#安装对应的lib,所有的lib都会被安装到虚拟环境中,不会破坏系统本身的环境。pip install ... 卸载创建成功的虚拟环境: 1pyenv uninstall env351]]></content>
<tags>
<tag>python</tag>
<tag>shell</tag>
<tag>pyenv</tag>
</tags>
</entry>
<entry>
<title><![CDATA[热爱微小的改变]]></title>
<url>%2Fblog%2F2016-11-02-love_change.html</url>
<content type="text"><![CDATA[当你有着强烈的情绪时,可能是因为你要明哲保身。你不愿冒险因为你害怕被拒绝、害怕失败、害怕自己hold不住。真的,试想下如果你彻底的失败了, 甚至在完全陌生的人面前流泪你会怎么做?也许你不相信你会采取合理的风险。也许你曾经打破常规去挑战自我的极限,但是结果却并不令你满意。 但卖掉你所有的财产,搬去墨西哥并非我今天所谈论的改变类型。 也许你会害怕改变,虽然你也不知道其中的原因。一想到沉溺于同样的地方遇见同样的人,遵循例行的生活是一种最不愉快的体验。 的确如此,你每天在同一时间起床之后重复同样的行为。你吃着一成不变的食物去同一家电影院。你约会同样的朋友甚至在每周同一时间。 很多情况下常规和结构化的模式有助于情绪管理。虽然可预测性是你行为方式的一部分,但如果这部分所占比例太高,则会挤压你生活中的乐趣。 探索新体验是增加幸福感的方式之一。新体验并不需要太大的改变。或许你可以探索下你所在城市的自己不熟悉的地方,品尝些新食物,做一道新菜, 阅读一些你平时并非爱好的杂志,或者去参加一些你从未体验过的活动。你也可以走进一家专卖亚洲食品的商店,或者到公园里参加一些游戏活动。 新体验能够培养兴趣或者参与甚至取代你之前熟知的意识。当在熟知的范围内发生适当的改变,会刺激你的活力和幸福感。你看孩子们始终拥有对 世界的好奇心和迷恋感,因为对于他们来说什么都是新的。所以当你寻求新体验的时候你也能保持一份好奇感。 当你想做一些全新的不同的事情时候,通常会面临已有的惯性思维。你给自己各种借口待在房子里,重复自己昨天甚至前天同样的事情。你告诉自己 学习新东西太麻烦了,或者你根本就不喜欢轮滑,那么还为什么要熬夜到很晚,甚至失去自己呼呼大睡的机会呢?这种消极的心理暗示总是非常具有 说服力,你会认为你年纪太大没必要再去学习骑骆驼,或者如果你已经在博物馆工作那么你可能接下来的一辈子都会留在这里。 从事新活动是你可以学习的行为。给自己创造一些新体验。如果有朋友愿意和你一起,这将是非常有帮助的。刚开始你可能会觉得不舒服但是一定 要坚持下去。直到在这个水平内你感到习惯然后再继续往下走。把你想做的事情列一个清单,保证一周一次并坚持四个月。有时你会厌烦这很正常, 所以一定要坚持下去。培养兴趣和保持活力是非常值得做的事情。 译者:小太阳123作者:KARYN HALL,PHD]]></content>
<tags>
<tag>life</tag>
</tags>
</entry>
<entry>
<title><![CDATA[compress and downscaler]]></title>
<url>%2Fblog%2F2016-10-26-compress.html</url>
<content type="text"><![CDATA[Compress 有损压缩(lossy) 压缩的时候如果不能压到fail boundary以内,则强制压缩,保证burst length在fail boundary以内。 无损压缩(lossless) 压缩的时候如果能压到fail boundary以内,则压缩,否则仍然以2048的burst length输出。 只有ARGB888和NV12才会支持lossy,其余的format即使lossy打开,也是输出lossless的,即除了ARGB888和 NV12外,其余的format,lossy和lossless是相同的。 data format compress type uyvyd.bin YCRYCB422_16BIT 11 yuyvd.bin CRYCBY422_16BIT 10 compress test: 1cmode -m -x 640 480 -nd -ps 41 21 -st 190 50 -ws 200 200 -a 8000 -pse 300 300 -ste 2510 100 -wse 200 150 -ae 8000 -f 2 -fe 2 -cp 2048 -t 2 compress scaler test: 1cmode -scl 0 -p 42 22 -o 190 50 -s 100 100 -w 191 200 -pe 300 300 -oe 250 100 -se 101 91 -we 200 150 -t 2 DownScalerDIU downscaler register group: mm327c: Bit[21] — DST_FORMAT(output data format), control the output of downscaler csc. mm3280: Bit[7-8] — SCALING_MODE(downscaler work mode) mm3278: Bit[5-31] — BASE_ADDR mm8264: down scaling write back control register Bit[1-3] — csc data in format Bit[4-6] — csc data output format]]></content>
<tags>
<tag>zx</tag>
</tags>
</entry>
<entry>
<title><![CDATA[跑步|伊始]]></title>
<url>%2Fblog%2F2016-10-16-running.html</url>
<content type="text"><![CDATA[对于跑步,一开始内心是拒绝的,至于为什么最后又坚持跑下来了,甚至有点喜欢上 跑步这项“枯燥”的运动,与其说是坚持,不如归之于某种不服输的心理。 起初是冲着减肥被逼无奈才去跑步的,从跑1km就各种天昏地暗到慢慢的可以跑个3km ,渐渐发现自己也可以跑上个10km,变成自己曾经认为只能膜拜的一类人,这实在是一 种很奇妙的感受。其实吧觉得跑步很锻炼一个人,倒不是说跑步有多难,难得是坚持, 不断的突破自我,一步一个脚印,最终实现属于个人的小目标。 当想跑步了,那么就痛痛快快地穿上跑鞋,放下包袱,放空自己,无关于时间, 无关于心情,无关于整个世界,在奔跑中与自己来一次直接对话。]]></content>
<tags>
<tag>随笔</tag>
</tags>
</entry>
<entry>
<title><![CDATA[cool git]]></title>
<url>%2Fblog%2F2015-08-10-cool-git.html</url>
<content type="text"><![CDATA[很早之前就开始使用并接触Git,这种分布式的SCM给我的coding带来了不少便捷. Git学习可以在线学习ProGit对Git有比较深入的了解。 Git Tricks如何将只有两个commit历史的库合并为一个commit12git reset --soft HEAD^1git commit --amend -sv git reset –soft HEAD^1 可以将HEAD指向第一个commit,且 工作区和暂存区的文件都保持不变。 git commit –amend -v –amend 新提交覆盖上一次提交 -v verbose,列出跟上一提交之间的改变 git diff git diff 工作区和暂存区进行比较 git diff –cached 暂存区和HEAD比较 git diff HEAD 工作区和HEAD比较 git diff master origin/branch 本地master分支和远程branch分支进行比较 git add git add -A #Stage All(new, modified, deleted)files git add . #Stage New and Modified files only git add -u #Stage Modified and Deleted files only]]></content>
<tags>
<tag>git</tag>
<tag>shell</tag>
</tags>
</entry>
<entry>
<title><![CDATA[C++ Singleton Design Pattern]]></title>
<url>%2Fblog%2F2015-08-02-c%2B%2B%20singleton.html</url>
<content type="text"><![CDATA[单例模式一个类仅允许创建一个实例,这通常使用在类似于日志或者其他只有单一资源可供使用的情况。单例设计模式保证类本身提供单一实例创建的方法。 使用c++实现单例模式的方法如下: 构造函数声明为私有; 将拷贝构造函数与等号运算符声明为私有,并不提供他们的实现; 在类中声明一个静态的全局访问接口; 通过懒汉模式实现123456789101112131415class Singleton {public: static Singleton& Instance() { static Singleton theSingleton; return theSingleton; } /* more (non-static) functions here */private: Singleton(); // ctor hidden Singleton(Singleton const&); // copy ctor hidden Singleton& operator=(Singleton const&); // assign op. hidden ~Singleton(); // dtor hidden}; 懒汉模式(第一次调用创建该类实例的时候才产生一个该类的实例)通过静态局部变量创建实例,并在之后都只返回此实例。这样做的好处是,程序会在退出时自动析构该实例。 通过饿汉模式实现1234567891011121314class SingletonStatic { private: static const SingletonStatic* m_instance; SingletonStatic(){} public: static SingletonStatic* getInstance() { return m_instance; } }; //外部初始化 before invoke main const SingletonStatic* SingletonStatic::m_instance = new SingletonStatic; 饿汉模式(程序一开始就产生一个该类的实例),通过这种方式实现的单例模式保证了线程安全性,但是无法自动执行析构函数,比如有关闭文件,释放外部资源等。这可以通过在程序结束时通过delete getInstance()来实现,这种方式显得过于笨重,并且容易遗忘。利用系统在程序结束后会自动析构所有的全局变量和类的静态成员变量,我们可以在单例类中定义一个这样的静态成员变量,而它的唯一目的就是在程序结束后能够析构单例类中的实例。代码如下: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051#include <iostream>> using namespace std; class Singleton { public: static Singleton *GetInstance(); private: Singleton() { cout << "Singleton ctor" << endl; } ~Singleton() { cout << "Singleton dtor" << endl; } static Singleton *m_pInstance; class Garbo { public: ~Garbo() { if (Singleton::m_pInstance) { cout << "Garbo dtor" << endl; delete Singleton::m_pInstance; } } }; static Garbo garbo; }; Singleton::Garbo Singleton::garbo; // 一定要初始化,不然程序结束时不会析构garbo Singleton *Singleton::m_pInstance = NULL; Singleton *Singleton::GetInstance() { if (m_pInstance == NULL) m_pInstance = new Singleton; return m_pInstance; } 程序运行结束后会调用CSingleton的静态成员Garbo的析构函数,该析构函数会删除单例的唯一实例。这种方式的特点如下: 在单例类内部定义专有的嵌套类; 在单例类内定义私有的专门用于释放的静态成员; 利用程序在结束时析构全局变量的特性,选择最终的释放时机; 使用单例的代码不需要任何操作,不必关心对象的释放 Ref: C++ Singleton design pattern]]></content>
<tags>
<tag>c++</tag>
<tag>design pattern</tag>
</tags>
</entry>
</search>