<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2475333239846385273</id><updated>2012-02-16T11:06:26.979-08:00</updated><category term='linux'/><category term='mq'/><category term='xml'/><category term='js'/><category term='erlang'/><category term='python'/><category term='nodejs'/><category term='openssl'/><category term='network'/><category term='vim'/><category term='c++'/><category term='thread'/><category term='c'/><title type='text'>Command Not Found</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-3454428839178552024</id><published>2012-01-28T04:42:00.001-08:00</published><updated>2012-01-28T04:44:15.632-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='thread'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>[PThread] condition variable usage pattern</title><content type='html'>&lt;p&gt;producer/consumer model. The return value for each pthread function call need to be checked too.&lt;/p&gt;&lt;p&gt;Producer:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;while(/* condition for producer to contintue */)&lt;br /&gt;{&lt;br /&gt;  pthread_mutex_lock(&amp;mutex);&lt;br /&gt;&lt;br /&gt;  // do something for producer&lt;br /&gt;&lt;br /&gt;  // the order of the two following call is not important&lt;br /&gt;  // unlock before signal may more efficient than signal before unlock&lt;br /&gt;  pthread_mutex_unlock(&amp;mutex);&lt;br /&gt;  pthread_cond_signal(&amp;cond);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Consumer:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;while(/* condition for consumer to continue */)&lt;br /&gt;{&lt;br /&gt;  // must  contain lock before calling condition wait&lt;br /&gt;  pthread_mutex_lock(&amp;mutex);&lt;br /&gt;&lt;br /&gt;  // the condition wait need to be recheck for&lt;br /&gt;  // 1. spurious wakeup&lt;br /&gt;  // 2. other thread can be waken early&lt;br /&gt;  while(/* condition to check for state not valid */)&lt;br /&gt;  {&lt;br /&gt;    s = pthread_cond_wait(&amp;cond, &amp;mutex);&lt;br /&gt;  }&lt;br /&gt;  // do consumer work, now under mutex protection&lt;br /&gt;  pthread_mutex_unlock(&amp;mutex);&lt;br /&gt;  // some other work which don't need mutex&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Spurious wakeup:&lt;br /&gt;Some condition wait implementation can cause the thread to be waken up when no signal to the condition variable.&lt;br /&gt;man pthread&lt;em&gt;conid&lt;/em&gt;signal for further detail.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-3454428839178552024?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/3454428839178552024/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2012/01/pthread-condition-variable-usage.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3454428839178552024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3454428839178552024'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2012/01/pthread-condition-variable-usage.html' title='[PThread] condition variable usage pattern'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-1529732683182197297</id><published>2012-01-15T05:01:00.001-08:00</published><updated>2012-01-15T05:01:53.739-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='network'/><title type='text'>[TCP] some tuning options</title><content type='html'>&lt;p style="font-family: arial, sans-serif; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; text-align: left; background-color: #ffffff; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;The&amp;nbsp;&lt;code style="font-size: small !important;"&gt;IPTOS_LOWDELAY&lt;/code&gt;&amp;nbsp;keyword is most appropriate for low-delay networks such as LANs, while&amp;nbsp;&lt;code style="font-size: small !important;"&gt;IPTOS_THROUGHPUT&lt;/code&gt;&amp;nbsp;is for higher-latency WAN links. Your network may be configured differently, so it's possible that using the options might have the opposite effect.&lt;/span&gt;&lt;/p&gt;&lt;p style="font-family: arial, sans-serif; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; text-align: left; background-color: #ffffff; margin: 0px;"&gt;&lt;span style="font-size: small;"&gt;The&amp;nbsp;&lt;code style="font-size: small !important;"&gt;TCP_NODELAY&lt;/code&gt;&amp;nbsp;option disables the Nagle algorithm.&lt;/span&gt;&lt;/p&gt;&lt;p style="font-family: arial, sans-serif; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; text-align: left; background-color: #ffffff; margin: 0px;"&gt;&lt;span style="font-size: 13px;"&gt;If you have firewalls or other devices that keep state in your network, you may be interested in the&amp;nbsp;&lt;/span&gt;&lt;code style="font-size: small !important;"&gt;SO_KEEPALIVE&lt;/code&gt;&lt;span style="font-size: 13px;"&gt;&amp;nbsp;option, which turns on TCP keepalives.&lt;/span&gt;&lt;/p&gt;&lt;p style="font-family: arial, sans-serif; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; text-align: left; background-color: #ffffff; margin: 0px;"&gt;&lt;span style="font-size: 13px;"&gt;$ netstat -d -i 2&lt;/span&gt;&lt;/p&gt;&lt;p style="font-family: arial, sans-serif; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; text-align: left; background-color: #ffffff; margin: 0px;"&gt;&lt;span style="font-size: 13px;"&gt;Every 2 seconds, the status of the available interfaces is shown. In the example above, the&amp;nbsp;&lt;/span&gt;&lt;code style="font-size: small !important;"&gt;RX-OK&lt;/code&gt;&lt;span style="font-size: 13px;"&gt;&amp;nbsp;and&amp;nbsp;&lt;/span&gt;&lt;code style="font-size: small !important;"&gt;TX-OK&lt;/code&gt;&lt;span style="font-size: 13px;"&gt;columns show that packets are flowing in and out. The errors, drops, and overruns are all 0 in both directions, showing that there has been no packet loss.&lt;/span&gt;&lt;/p&gt;&lt;p style="font-family: arial, sans-serif; padding-top: 0.3em; padding-right: 5px; padding-bottom: 0.7em; padding-left: 5px; font-size: 0.76em; text-align: left; background-color: #ffffff; margin: 0px;"&gt;&lt;pre class="displaycode" style="width: 694px; margin-top: 0px; margin-bottom: 0px; font-family: 'Andale Mono', 'Lucida Console', Monaco, Liberation, fixed, monospace; overflow-x: auto; overflow-y: auto; background-image: initial !important; background-attachment: initial !important; background-origin: initial !important; background-clip: initial !important; background-color: #f7f7f7;"&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-1529732683182197297?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/1529732683182197297/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2012/01/tcp-some-tuning-options.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/1529732683182197297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/1529732683182197297'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2012/01/tcp-some-tuning-options.html' title='[TCP] some tuning options'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-6564846572745448189</id><published>2012-01-09T06:48:00.000-08:00</published><updated>2012-01-09T06:51:08.762-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] Exception-safe code</title><content type='html'>&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;b&gt;Some guide&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Exception-safe definition:&lt;br /&gt;- Basic&lt;br /&gt;&amp;nbsp; &amp;nbsp; invariants and no resource are leaked&lt;br /&gt;- Strong&lt;br /&gt;&amp;nbsp; &amp;nbsp; operations has either completed successfully or throw exception leaving program&lt;br /&gt;&amp;nbsp; &amp;nbsp; state exactlyly as it was before the operation started&lt;br /&gt;- No-throw&lt;br /&gt;&amp;nbsp; &amp;nbsp; operation will not emit an exception&lt;br /&gt;&lt;br /&gt;Exception guide line:&lt;br /&gt;- Throw by value&lt;br /&gt;- Catch by reference&lt;br /&gt;- no exception specification&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;br /&gt;* function can not template partial specialization&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Some code example:&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;     &lt;br /&gt;void foo() throw ()&lt;br /&gt;{                  &lt;br /&gt;    // it will cause abort &lt;br /&gt;    // because it throw when the exception specification said NO&lt;br /&gt;    throw(1);      &lt;br /&gt;}                  &lt;br /&gt;                   &lt;br /&gt;void goo()         &lt;br /&gt;{                  &lt;br /&gt;    try {          &lt;br /&gt;        int a = 1; &lt;br /&gt;        throw(1);  &lt;br /&gt;    } catch(...) { &lt;br /&gt;        // this will cause abort too &lt;br /&gt;        // because you can not rethrow in catch statement&lt;br /&gt;        throw;     &lt;br /&gt;    }              &lt;br /&gt;}                  &lt;br /&gt;                   &lt;br /&gt;/*                 &lt;br /&gt; * The following is the C API for C++ library pattern to handle exception&lt;br /&gt; */                &lt;br /&gt;                   &lt;br /&gt;int getReturnCodeFromException()&lt;br /&gt;{                  &lt;br /&gt;    try {          &lt;br /&gt;        // rethrow &lt;br /&gt;        throw;     &lt;br /&gt;    } catch(int a) &lt;br /&gt;    {              &lt;br /&gt;        return -1; &lt;br /&gt;    } catch(double b)&lt;br /&gt;    {              &lt;br /&gt;        return -2; &lt;br /&gt;    }              &lt;br /&gt;    // for each type of exception, you can create different return code&lt;br /&gt;    // ...         &lt;br /&gt;}                  &lt;br /&gt;void cppAPI1()&lt;br /&gt;{           &lt;br /&gt;    throw (1);&lt;br /&gt;}           &lt;br /&gt;            &lt;br /&gt;            &lt;br /&gt;void cppAPI2()&lt;br /&gt;{           &lt;br /&gt;    throw (1.12);&lt;br /&gt;}           &lt;br /&gt;            &lt;br /&gt;int cAPI1() &lt;br /&gt;{           &lt;br /&gt;    try {   &lt;br /&gt;        cppAPI1();&lt;br /&gt;    } catch(...) {                           &lt;br /&gt;        int rc = getReturnCodeFromException();&lt;br /&gt;        return rc;&lt;br /&gt;    }       &lt;br /&gt;}           &lt;br /&gt;            &lt;br /&gt;int cAPI2() &lt;br /&gt;{           &lt;br /&gt;    try {   &lt;br /&gt;        cppAPI2();&lt;br /&gt;    } catch(...) {                           &lt;br /&gt;        int rc = getReturnCodeFromException();&lt;br /&gt;        return rc;&lt;br /&gt;    }       &lt;br /&gt;}           &lt;br /&gt;            &lt;br /&gt;int main()  &lt;br /&gt;{           &lt;br /&gt;//    foo();&lt;br /&gt;//    goo();&lt;br /&gt;    std::cout &amp;lt;&amp;lt; "cAPI1 rc = " &amp;lt;&amp;lt; cAPI1() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;    std::cout &amp;lt;&amp;lt; "cAPI2 rc = " &amp;lt;&amp;lt; cAPI2() &amp;lt;&amp;lt; std::endl;&lt;br /&gt;    return 0;&lt;br /&gt;}                                &lt;br /&gt;&lt;/pre&gt;&lt;i&gt;Referencehttp://exceptionsafecode.com/&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-6564846572745448189?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/6564846572745448189/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2012/01/c-exception-safe-code.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6564846572745448189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6564846572745448189'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2012/01/c-exception-safe-code.html' title='[C++] Exception-safe code'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-4319910377232424041</id><published>2012-01-06T05:08:00.001-08:00</published><updated>2012-01-06T05:12:10.488-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] dynamic_cast</title><content type='html'>You can use dynamic_cast to identify the type. Then you can do something different according to Derived class with the same Base class pointer.&lt;br /&gt;Just a reminder, when you call destructor of derived class. The vtable pointer and RTTI is no longer exist.&lt;br /&gt;As a result, you will get NULL at second dynamic_cast.&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;#include &amp;lt;cstdio&amp;gt;&lt;br /&gt;#include &amp;lt;cstdlib&amp;gt;&lt;br /&gt;&lt;br /&gt;class Base&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    Base():a(1){};&lt;br /&gt;    ~Base(){};&lt;br /&gt;    virtual void foo() {};&lt;br /&gt;    int a;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;class Derived : public Base&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    Derived(){};&lt;br /&gt;    ~Derived(){};&lt;br /&gt;    virtual void foo() {};&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    void *p = malloc(sizeof(Derived));&lt;br /&gt;&lt;br /&gt;    Base *base = new (p) Derived();&lt;br /&gt;    Derived *d = dynamic_cast(base);&lt;br /&gt;    if(d)&lt;br /&gt;        std::cout &amp;lt;&amp;lt; "cast ok!\n";     d-&amp;gt;~Derived();&lt;br /&gt;    Derived *dd = dynamic_cast(base);&lt;br /&gt;    if(dd)&lt;br /&gt;        std::cout &amp;lt;&amp;lt; "cast ok!\n";&lt;br /&gt;    else std::cout &amp;lt;&amp;lt; "cast fail!\n";&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-4319910377232424041?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/4319910377232424041/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2012/01/c-dynamiccast.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/4319910377232424041'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/4319910377232424041'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2012/01/c-dynamiccast.html' title='[C++] dynamic_cast'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-2158273774641740025</id><published>2011-12-27T23:49:00.001-08:00</published><updated>2011-12-27T23:51:13.558-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] template class instantiation</title><content type='html'>&lt;p&gt;驗證一下, 在template class當中, 如果有method不依靠template class type T, 這樣還是會產生出兩份不一樣的code, 因為template本身在instantiation的時候就會被當作兩個不同的class.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &amp;lt;iostream&amp;gt;&lt;br /&gt;template&lt;class T&gt;&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    T goo(T a) { return a + a; };&lt;br /&gt;    int foo(int a) { return a;};&lt;br /&gt;};   &lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    Foo&lt;int&gt; a;&lt;br /&gt;    Foo&lt;double&gt; b;&lt;br /&gt;&lt;br /&gt;    a.goo(12);&lt;br /&gt;    b.goo(1.2);&lt;br /&gt;    a.foo(1);&lt;br /&gt;    b.foo(1);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;可以看到main裡面, _ZN3FooIiE3fooEi, _ZN3FooIdE3fooEi 是被call到兩個不同的function, 就算裡面code是完全一樣的&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;    .file   "template_gen.cpp"&lt;br /&gt;    .local  _ZStL8__ioinit&lt;br /&gt;    .comm   _ZStL8__ioinit,1,1&lt;br /&gt;    .text&lt;br /&gt;.globl main&lt;br /&gt;    .type   main, @function&lt;br /&gt;main:&lt;br /&gt;.LFB959:&lt;br /&gt;    .cfi_startproc&lt;br /&gt;    .cfi_personality 0x3,__gxx_personality_v0&lt;br /&gt;    pushq   %rbp&lt;br /&gt;    .cfi_def_cfa_offset 16&lt;br /&gt;    movq    %rsp, %rbp&lt;br /&gt;    .cfi_offset 6, -16&lt;br /&gt;    .cfi_def_cfa_register 6&lt;br /&gt;    subq    $16, %rsp&lt;br /&gt;    leaq    -1(%rbp), %rax&lt;br /&gt;    movl    $12, %esi&lt;br /&gt;    movq    %rax, %rdi&lt;br /&gt;    call    _ZN3FooIiE3gooEi&lt;br /&gt;    movsd   .LC0(%rip), %xmm0&lt;br /&gt;    leaq    -2(%rbp), %rax&lt;br /&gt;    movq    %rax, %rdi&lt;br /&gt;    call    _ZN3FooIdE3gooEd&lt;br /&gt;    leaq    -1(%rbp), %rax&lt;br /&gt;    movl    $1, %esi&lt;br /&gt;    movq    %rax, %rdi&lt;br /&gt;    call    _ZN3FooIiE3fooEi&lt;br /&gt;    leaq    -2(%rbp), %rax&lt;br /&gt;    movl    $1, %esi&lt;br /&gt;    movq    %rax, %rdi&lt;br /&gt;    call    _ZN3FooIdE3fooEi&lt;br /&gt;    movl    $0, %eax&lt;br /&gt;    leave&lt;br /&gt;    ret&lt;br /&gt;    .cfi_endproc&lt;br /&gt;&lt;br /&gt;...略&lt;br /&gt;&lt;br /&gt;_ZN3FooIiE3fooEi:&lt;br /&gt;.LFB962:&lt;br /&gt;    .cfi_startproc&lt;br /&gt;    .cfi_personality 0x3,__gxx_personality_v0&lt;br /&gt;    pushq   %rbp&lt;br /&gt;    .cfi_def_cfa_offset 16&lt;br /&gt;    movq    %rsp, %rbp&lt;br /&gt;    .cfi_offset 6, -16&lt;br /&gt;    .cfi_def_cfa_register 6&lt;br /&gt;    movq    %rdi, -8(%rbp)&lt;br /&gt;    movl    %esi, -12(%rbp)&lt;br /&gt;    movl    -12(%rbp), %eax&lt;br /&gt;    leave&lt;br /&gt;    ret&lt;br /&gt;    .cfi_endproc&lt;br /&gt;.LFE962:&lt;br /&gt;    .size   _ZN3FooIiE3fooEi, .-_ZN3FooIiE3fooEi&lt;br /&gt;    .section    .text._ZN3FooIdE3fooEi,"axG",@progbits,_ZN3FooIdE3fooEi,comdat&lt;br /&gt;    .align 2&lt;br /&gt;    .weak   _ZN3FooIdE3fooEi&lt;br /&gt;    .type   _ZN3FooIdE3fooEi, @function&lt;br /&gt;_ZN3FooIdE3fooEi:&lt;br /&gt;.LFB963:&lt;br /&gt;    .cfi_startproc&lt;br /&gt;    .cfi_personality 0x3,__gxx_personality_v0&lt;br /&gt;    pushq   %rbp&lt;br /&gt;    .cfi_def_cfa_offset 16&lt;br /&gt;    movq    %rsp, %rbp&lt;br /&gt;    .cfi_offset 6, -16&lt;br /&gt;    .cfi_def_cfa_register 6&lt;br /&gt;    movq    %rdi, -8(%rbp)&lt;br /&gt;    movl    %esi, -12(%rbp)&lt;br /&gt;    movl    -12(%rbp), %eax&lt;br /&gt;    leave&lt;br /&gt;    ret&lt;br /&gt;    .cfi_endproc &lt;br /&gt;&lt;br /&gt;...略&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-2158273774641740025?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/2158273774641740025/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/12/c-template-class-instantiation.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2158273774641740025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2158273774641740025'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/12/c-template-class-instantiation.html' title='[C++] template class instantiation'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-709028475419274837</id><published>2011-12-15T07:09:00.000-08:00</published><updated>2011-12-15T07:10:54.887-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>[Linux] process use multi-core CPU</title><content type='html'>&lt;pre class="prettyprint"&gt;&lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * The following code use sched_setaffinity to set CPU mask&lt;br /&gt; * it will fork process and each process will run on only one core&lt;br /&gt; *&lt;br /&gt; * you can read from /proc/cpuinfo to get the number of processor&lt;br /&gt; */&lt;br /&gt;int setup_multicore(int n)&lt;br /&gt;{&lt;br /&gt;    cpu_set_t *cpuset = CPU_ALLOC(n);&lt;br /&gt;    size_t size = CPU_ALLOC_SIZE(n);&lt;br /&gt;    CPU_ZERO_S(size, cpuset);&lt;br /&gt;    CPU_SET_S(0, size, cpuset);&lt;br /&gt;    if (sched_setaffinity(getpid(), size, cpuset) &amp;lt; 0) {&lt;br /&gt;        CPU_FREE(cpuset);&lt;br /&gt;        return -1;&lt;br /&gt;    }&lt;br /&gt;    pid_t pid = 0;&lt;br /&gt;    // fork a child for each core&lt;br /&gt;    for (int i = 1; i &amp;lt; n; ++i) {&lt;br /&gt;        pid = fork();&lt;br /&gt;        if (pid  0)&lt;br /&gt;            continue;&lt;br /&gt;        CPU_ZERO_S(size, cpuset);&lt;br /&gt;        CPU_SET_S(i, size, cpuset);&lt;br /&gt;        if (sched_setaffinity(getpid(), size, cpuset) &amp;lt; 0) {&lt;br /&gt;            CPU_FREE(cpuset);&lt;br /&gt;            return -1;&lt;br /&gt;        }&lt;br /&gt;        break;&lt;br /&gt;    }&lt;br /&gt;    CPU_FREE(cpuset);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-709028475419274837?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/709028475419274837/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/12/linux-process-use-multi-core-cpu.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/709028475419274837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/709028475419274837'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/12/linux-process-use-multi-core-cpu.html' title='[Linux] process use multi-core CPU'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-6653386217943898353</id><published>2011-12-07T22:52:00.001-08:00</published><updated>2011-12-07T22:52:44.510-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>[Linux] Signal should not be block</title><content type='html'>&lt;p&gt;The following signal should be deliverd on the thread that generated the original error. Blocking them interferes with proper recovery&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;   sigdelset(sig_mask, SIGABRT);&lt;br /&gt;   sigdelset(sig_mask, SIGBUS);&lt;br /&gt;   sigdelset(sig_mask, SIGEMT);&lt;br /&gt;   sigdelset(sig_mask, SIGFPE);&lt;br /&gt;   sigdelset(sig_mask, SIGILL);&lt;br /&gt;   sigdelset(sig_mask, SIGIOT);&lt;br /&gt;   sigdelset(sig_mask, SIGPIPE);&lt;br /&gt;   sigdelset(sig_mask, SIGSEGV);&lt;br /&gt;   sigdelset(sig_mask, SIGSYS);&lt;br /&gt;   sigdelset(sig_mask, SIGTRAP);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;待續...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-6653386217943898353?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/6653386217943898353/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/12/linux-signal-should-not-be-block.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6653386217943898353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6653386217943898353'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/12/linux-signal-should-not-be-block.html' title='[Linux] Signal should not be block'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8749875099965818289</id><published>2011-12-01T01:47:00.001-08:00</published><updated>2011-12-01T04:21:32.474-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>[Pthread] signal handler on other thread</title><content type='html'>&lt;p&gt;在multithread程式裡面, 不管你是由child thread還是main thread 註冊signal handler, 在signal handler都是在main thread處理.&lt;br /&gt;可以從下面的範例看出&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include &lt;br /&gt;&lt;br /&gt;static void hdl (int sig, siginfo_t *siginfo, void *context)&lt;br /&gt;{&lt;br /&gt;    pthread_t ret = pthread_self();&lt;br /&gt;    sleep(2);&lt;br /&gt;    printf ("Sending PID: %ld, UID: %ld, self=%u\n",&lt;br /&gt;            (long)siginfo-&amp;gt;si_pid, (long)siginfo-&amp;gt;si_uid, pthread_self());&lt;br /&gt;}           &lt;br /&gt;&lt;br /&gt;void *child1_fun(void *data)&lt;br /&gt;{&lt;br /&gt;    struct sigaction act;&lt;br /&gt;&lt;br /&gt;    memset (&amp;amp;act, '\0', sizeof(act));&lt;br /&gt;    printf("child1 pid=%u\n", pthread_self());&lt;br /&gt;    /* Use the sa_sigaction field because the handles has two additional parameters */&lt;br /&gt;    act.sa_sigaction = &amp;amp;hdl;&lt;br /&gt;    /* The SA_SIGINFO flag tells sigaction() to use the sa_sigaction field, not sa_handler. */&lt;br /&gt;    act.sa_flags = SA_SIGINFO;&lt;br /&gt;    if (sigaction(SIGALRM, &amp;amp;act, NULL) &amp;lt; 0) {&lt;br /&gt;        perror ("sigaction");&lt;br /&gt;        return 1;&lt;br /&gt;    }&lt;br /&gt;    pause();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void *child2_fun(void *data)&lt;br /&gt;{&lt;br /&gt;    pthread_t *child1 = (pthread_t *) data;&lt;br /&gt;    printf("child2 pid=%u\n", pthread_self());&lt;br /&gt;    //alarm(2);&lt;br /&gt;    struct itimerval timer;&lt;br /&gt;&lt;br /&gt;    timer.it_value.tv_sec = 5 ;&lt;br /&gt;    timer.it_value.tv_usec = 0;&lt;br /&gt;    timer.it_interval.tv_sec = 5;&lt;br /&gt;    timer.it_interval.tv_usec = 0;&lt;br /&gt;    setitimer(ITIMER_REAL, &amp;amp;timer, NULL);&lt;br /&gt;//    pthread_kill(*child1, SIGALRM);&lt;br /&gt;}&lt;br /&gt;int main (int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;    pthread_t child1, child2;&lt;br /&gt;    sigset_t  newSet;&lt;br /&gt;    sigset_t    oset;&lt;br /&gt;    sigemptyset(&amp;amp;newSet);&lt;br /&gt;    sigaddset(&amp;amp;newSet, SIGALRM);&lt;br /&gt;    pthread_sigmask(SIG_BLOCK, &amp;amp;newSet, NULL);&lt;br /&gt;&lt;br /&gt;    printf("main pid=%u\n", pthread_self());&lt;br /&gt;    pthread_create(&amp;amp;child1, NULL, child1_fun, NULL);&lt;br /&gt;    pthread_create(&amp;amp;child2, NULL, child2_fun, &amp;amp;child1);&lt;br /&gt;    pthread_join(child1, NULL);&lt;br /&gt;&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;可以看到都是main thread在處理signal.&lt;br /&gt;Output:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;ytshen@ytshen-ThinkCentre-A58:~/temp$ ./a.out&lt;br /&gt;main pid=256317184&lt;br /&gt;child1 pid=248338176&lt;br /&gt;child2 pid=239945472&lt;br /&gt;Sending PID: 0, UID: 0, self=256317184&lt;br /&gt;Sending PID: 0, UID: 0, self=256317184&lt;br /&gt;^C&lt;br /&gt;ytshen@ytshen-ThinkCentre-A58:~/temp$&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;當我們希望是尤其他的child thread來處理signal, 我們就必須要改成這樣, 要先在main thread用sigmask 把不想接得signal設成SIG_BLOCK (非常重要! 不然當signal發生他會當你沒有註冊任何signal handler, 造成program stop), 在child thread 呼叫sigwait的時候, 他就會wait你想要wait的signal&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include &lt;br /&gt;&lt;br /&gt;void *child1_fun(void *data)&lt;br /&gt;{&lt;br /&gt;    sigset_t  newSet;&lt;br /&gt;    sigemptyset(&amp;amp;newSet);&lt;br /&gt;    sigaddset(&amp;amp;newSet, SIGALRM);&lt;br /&gt;    int signum;&lt;br /&gt;    while(1) {&lt;br /&gt;        printf("child1 pid=%u start to wait\n", pthread_self());&lt;br /&gt;        sigwait(&amp;amp;newSet, &amp;amp;signum);&lt;br /&gt;        printf("child1 pid=%u get signal = %d!\n", pthread_self(), signum);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void *child2_fun(void *data)&lt;br /&gt;{&lt;br /&gt;    pthread_t *child1 = (pthread_t *) data;&lt;br /&gt;    printf("child2 pid=%u\n", pthread_self());&lt;br /&gt;    //alarm(2);&lt;br /&gt;    struct itimerval timer;&lt;br /&gt;&lt;br /&gt;    timer.it_value.tv_sec = 5 ;&lt;br /&gt;    timer.it_value.tv_usec = 0;&lt;br /&gt;    timer.it_interval.tv_sec = 5;&lt;br /&gt;    timer.it_interval.tv_usec = 0;&lt;br /&gt;    setitimer(ITIMER_REAL, &amp;amp;timer, NULL);&lt;br /&gt;//    pthread_kill(*child1, SIGALRM);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main (int argc, char *argv[])&lt;br /&gt;{&lt;br /&gt;    pthread_t child1, child2;&lt;br /&gt;    sigset_t  newSet;&lt;br /&gt;    sigset_t    oset;&lt;br /&gt;    sigemptyset(&amp;amp;newSet);&lt;br /&gt;    sigaddset(&amp;amp;newSet, SIGALRM);&lt;br /&gt;    pthread_sigmask(SIG_BLOCK, &amp;amp;newSet, NULL);&lt;br /&gt;&lt;br /&gt;    printf("main pid=%u\n", pthread_self());&lt;br /&gt;    pthread_create(&amp;amp;child1, NULL, child1_fun, NULL);&lt;br /&gt;    pthread_create(&amp;amp;child2, NULL, child2_fun, &amp;amp;child1);&lt;br /&gt;    pthread_join(child1, NULL);&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Output:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;ytshen@ytshen-ThinkCentre-A58:~/temp$ ./a.out&lt;br /&gt;main pid=1378113280&lt;br /&gt;child1 pid=1370134272 start to wait&lt;br /&gt;child2 pid=1361741568&lt;br /&gt;child1 pid=1370134272 get signal = 14!&lt;br /&gt;child1 pid=1370134272 start to wait&lt;br /&gt;child1 pid=1370134272 get signal = 14!&lt;br /&gt;child1 pid=1370134272 start to wait&lt;br /&gt;^C&lt;br /&gt;ytshen@ytshen-ThinkCentre-A58:~/temp$&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Updated!!&lt;br /&gt;保險作法是在main thread create其他所有thread之前, sigprocmask 把該signal block住, 在create child thread(這樣所有child thread也會繼承main thread signal mask), 然後在要處理signal的child thread去sigwait, 這樣就不會有其他沒有block該signal的child thread因為沒有處理而被terminate!&lt;/p&gt;&lt;p&gt;Reference:&lt;br /&gt;http://www.cognitus.net/html/howto/pthreadSemiFAQ_8.html&lt;br /&gt;http://stackoverflow.com/questions/5282099/signal-handling-in-pthreads&lt;br /&gt;http://blog.csdn.net/wozaiwogu/article/details/4361456&lt;br /&gt;http://blog.csdn.net/fytzzh/article/details/660457&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8749875099965818289?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8749875099965818289/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/12/pthread-signal-handler-on-other-thread.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8749875099965818289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8749875099965818289'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/12/pthread-signal-handler-on-other-thread.html' title='[Pthread] signal handler on other thread'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-5744593180853068972</id><published>2011-11-09T19:44:00.003-08:00</published><updated>2011-11-09T19:44:58.768-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>[Python] property decorator</title><content type='html'>&lt;p&gt;正常用法是http://docs.python.org/library/functions.html#property&lt;/p&gt;&lt;p&gt;以下是鬼打牆用法...&lt;/p&gt;&lt;p&gt;應該把Dgram裡面的started改名字才對~&lt;/p&gt;&lt;p&gt;似乎在舊得python可以work&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;class Base(object):&lt;br /&gt;    a = 1&lt;br /&gt;    def __init__(self, listener, handle=None, backlog=None, spawn='default'):&lt;br /&gt;        self._xxx = 'xxx'&lt;br /&gt;        # the faulure is because of started name is used by derived object Dram&lt;br /&gt;        self.started = None                                                    &lt;br /&gt;&lt;br /&gt;class Dgram(Base):&lt;br /&gt;    b = 2&lt;br /&gt;    def __init__(self, listener, handle=None, backlog=None, spawn='default', **args):&lt;br /&gt;        Base.__init__(self, listener, handle=handle, backlog=backlog, spawn=spawn)&lt;br /&gt;        self.delay = 123                                                       &lt;br /&gt;&lt;br /&gt;    @property&lt;br /&gt;    def started(self):&lt;br /&gt;        return self._recv_event is not None or self._start_receving_timer is not None&lt;br /&gt;&lt;br /&gt;def echo(msg, addr):&lt;br /&gt;    print 'echo ' + msg                                                        &lt;br /&gt;&lt;br /&gt;if __name__ == '__main__':&lt;br /&gt;    s = Dgram('123', echo)&lt;br /&gt;&lt;/pre&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;ytshen@ytshen-ThinkCentre-A58:~/temp$ python test_obj.py&lt;br /&gt;Traceback (most recent call last):&lt;br /&gt;  File "test_obj.py", line 23, in &lt;module&gt;&lt;br /&gt;    s = Dgram('123', echo)&lt;br /&gt;  File "test_obj.py", line 12, in __init__&lt;br /&gt;    Base.__init__(self, listener, handle=handle, backlog=backlog, spawn=spawn)&lt;br /&gt;  File "test_obj.py", line 6, in __init__&lt;br /&gt;    self.started = None&lt;br /&gt;AttributeError: can't set attribute&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-5744593180853068972?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/5744593180853068972/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/11/python-property-decorator.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5744593180853068972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5744593180853068972'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/11/python-property-decorator.html' title='[Python] property decorator'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-1452840539967397556</id><published>2011-11-02T06:57:00.001-07:00</published><updated>2011-11-02T07:06:12.454-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mq'/><title type='text'>[RabbitMQ] priority queue</title><content type='html'>&lt;p&gt;目前RabbitMQ沒有直接支援priority queue的功能, 所以目前只能work around, 可以在client動點手腳&lt;/p&gt;&lt;p&gt;建立logical queue, 並根據priority的數量, 來建立physical queue (ex: 如果只有high &amp;amp; low priority, 那就建立兩個queue)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;方法一&lt;/strong&gt;&lt;br /&gt;client polling, 按照priority從相對應的physical queue取出message&lt;/p&gt;&lt;p&gt;&lt;strong&gt;方法二&lt;/strong&gt;&lt;br /&gt;client subsribe queue, 並且限制channel prefetch counts, 防止subscription flood, 並且在local建立in memory priority queue, 直到message被處理, 在送ack給RabbitMQ server&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;strong&gt;&lt;span style="font-size: large;"&gt;Reference&lt;/span&gt;&lt;/strong&gt;&lt;/em&gt;&lt;br /&gt;&lt;em&gt;&lt;a href="http://dougbarth.github.com/2011/07/01/approximating-priority-with-rabbitmq.html"&gt;http://dougbarth.github.com/2011/07/01/approximating-priority-with-rabbitmq.html&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;/em&gt;&lt;a href="http://dougbarth.github.com/2011/06/10/keeping-the-rabbit-on-a-leash.html"&gt;http://dougbarth.github.com/2011/06/10/keeping-the-rabbit-on-a-leash.html&lt;/a&gt;&lt;em&gt;&amp;nbsp;&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-1452840539967397556?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/1452840539967397556/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/11/rabbitmq-priority-queue.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/1452840539967397556'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/1452840539967397556'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/11/rabbitmq-priority-queue.html' title='[RabbitMQ] priority queue'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8037244192714210379</id><published>2011-10-31T07:56:00.001-07:00</published><updated>2011-10-31T07:56:37.073-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] wrapper C++ method in C (inline)</title><content type='html'>&lt;p&gt;先說結論, 這應該是不可行的, 等於你想要直接把C++ embed在C裡面. 通常inline是要寫在header file, 讓使用者直接include.&lt;/p&gt;&lt;p&gt;在這情形就等於你要讓C program直接include C++ library, 所以無法達成.&lt;/p&gt;&lt;p&gt;那如果寫在.cpp裡面, 編成.o, 再跟C program 一起compile.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// this is foo.cpp&lt;br /&gt;#ifdef __cplusplus&lt;br /&gt;extern "C" {&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#include "foo.h"&lt;br /&gt;&lt;br /&gt;int foo()&lt;br /&gt;{&lt;br /&gt;    int i = 0;&lt;br /&gt;&lt;br /&gt;    return i++;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;#ifdef __cplusplus&lt;br /&gt;}&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// this is foo.h&lt;br /&gt;inline int foo();&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;接下來main.c&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;#include "foo.h"&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    int t = foo();&lt;br /&gt;&lt;br /&gt;    printf("%d\n", t);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;但是在compile main.o foo.o會找不到foo這個symbol, 利用strings也找不到, 這是因為inline寫在foo.cpp, compile展開完之後, foo因為被宣告程inline, 所以就沒有出現在foo.o裡面了.&lt;/p&gt;&lt;p&gt;因此, 在C裡面要wrap C++ library並且inline 應該是不可行的, 不過可以使用wrapper function回傳function pointer的方式作到~&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8037244192714210379?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8037244192714210379/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/10/c-wrapper-c-method-in-c-inline.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8037244192714210379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8037244192714210379'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/10/c-wrapper-c-method-in-c-inline.html' title='[C++] wrapper C++ method in C (inline)'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-2437573787498981053</id><published>2011-10-24T00:25:00.001-07:00</published><updated>2011-10-25T02:18:59.776-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] pthread_cancel issue</title><content type='html'>&lt;p&gt;今天遇到一個很神奇的情況, 發現program在call pthread_cancel的時候居然abort, 下面是簡化過後的code, create一個thread, 並且在之後把他cancel.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include&lt;br /&gt;&lt;pthread.h&gt;&lt;br /&gt;#include &lt;iostream&gt;&lt;br /&gt;&lt;br /&gt;#include &lt;stdlib.h&gt;&lt;br /&gt;#include &lt;stdio.h&gt;&lt;br /&gt;using namespace std;   &lt;br /&gt;&lt;br /&gt;void* sleepyThread(void*)&lt;br /&gt;{&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;      cerr &amp;lt;&amp;lt; "enter sleep" &amp;lt;&amp;lt; endl;&lt;br /&gt;      sleep(20);&lt;br /&gt;  }&lt;br /&gt;  catch(...)&lt;br /&gt;  {&lt;br /&gt;     cerr &amp;lt;&amp;lt;"catch all";&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  pthread_t thread;&lt;br /&gt;  int id=pthread_create(&amp;amp;thread, NULL, &amp;amp;sleepyThread, NULL);&lt;br /&gt;&lt;br /&gt;  cerr&amp;lt;&amp;lt;"lets try to cancel it..."&amp;lt;&amp;lt; id &amp;lt;&amp;lt; endl;&lt;br /&gt;  sleep(1);&lt;br /&gt;  pthread_cancel(thread);&lt;br /&gt;  pthread_join(thread, NULL);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;經過實驗, 發現sleepyThread不catch all exception或是不呼叫pthread&lt;em&gt;&lt;em&gt;join就可以正常運作, 不然一旦child thread有catch all就會產生abort,&lt;br /&gt;從http://stackoverflow.com/questions/4766768/unhandled-forced-unwind-causes-abort 得知,&lt;br /&gt;在呼叫pthread&lt;em&gt;&amp;nbsp;&lt;/em&gt;&lt;/em&gt;cancel的時候會產生unwind exception, 這時一定要re-throw, 不然會有問題.&lt;br /&gt;基本上在call pthread&lt;/em&gt;&lt;em&gt;cancel他是async的方式, 只是把thread state設成cancel, 之後就會等待. 所以之前實驗把pthread&lt;/em&gt;join拿掉不會abort, 只是因為他還沒走到cancellation point.&lt;/p&gt;&lt;p&gt;來看一下當發生abort時的backtrace, 從gdb上面看到他最後呼叫了unwind_cleanup&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;(gdb) r&lt;br /&gt;Starting program: /home/ytshen/a.out&lt;br /&gt;[Thread debugging using libthread_db enabled]&lt;br /&gt;[New Thread 0x7ffff709c700 (LWP 17360)]&lt;br /&gt;lets try to cancel it...0&lt;br /&gt;enter sleep&lt;br /&gt;helloFATAL: exception not rethrown&lt;br /&gt;&lt;br /&gt;Program received signal SIGABRT, Aborted.&lt;br /&gt;[Switching to Thread 0x7ffff709c700 (LWP 17360)]&lt;br /&gt;0x00007ffff70d0ba5 in raise () from /lib/libc.so.6&lt;br /&gt;(gdb) bt&lt;br /&gt;#0  0x00007ffff70d0ba5 in raise () from /lib/libc.so.6&lt;br /&gt;#1  0x00007ffff70d46b0 in abort () from /lib/libc.so.6&lt;br /&gt;#2  0x00007ffff7bcd311 in unwind_cleanup () from /lib/libpthread.so.0&lt;br /&gt;#3  0x0000000000400b81 in sleepyThread(void*) ()&lt;br /&gt;#4  0x00007ffff7bc6971 in start_thread () from /lib/libpthread.so.0&lt;br /&gt;#5  0x00007ffff718392d in clone () from /lib/libc.so.6&lt;br /&gt;#6  0x0000000000000000 in ?? ()&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;所以接下來就直接去看pthread code, 他有註冊unwind&lt;em&gt;&lt;em&gt;&lt;em&gt;cleanup, 當exception被catch的話會被call,&lt;br /&gt;如果看pthread&lt;/em&gt;&lt;/em&gt;&lt;/em&gt;cancel這個function可以知道底層他其實找出thread id並且送給他signal. (From http://sourceware.org/git/?p=glibc.git;a=blobplain;f=nptl/pthread_cancel.c;hb=HEAD)&lt;/p&gt;&lt;p&gt;(pthread是pure C, 但是如果是用C++, 底層會用signal handler並且在裡面throw exception, 這應該是為了C++必須符合離開scope要把local variable都給destroy, 所以採用exception方式, 可以從下面的pthread_create function得知, 他把parent signal mask reset)&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;/* If the parent was running cancellation handlers while creating&lt;br /&gt;264      the thread the new thread inherited the signal mask.  Reset the&lt;br /&gt;265      cancellation signal mask.  */&lt;br /&gt; if (__builtin_expect (pd-&amp;gt;parent_cancelhandling &amp;amp; CANCELING_BITMASK, 0))&lt;br /&gt;...&lt;br /&gt;__sigemptyset (&amp;amp;mask);&lt;br /&gt;__sigaddset (&amp;amp;mask, SIGCANCEL);&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Ans:&amp;nbsp;&lt;/p&gt;&lt;p&gt;http://kolpackov.net/projects/glibc/cxx-unwind/&lt;/p&gt;&lt;p&gt;http://groups.google.com/group/comp.programming.threads/browse_thread/thread/652bcf186fbbf697/f63757846514e5e5?pli=1&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;從以下code, 可以發現當exception被抓住, 就會呼叫abort,&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;// From http://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/unwind.c&lt;br /&gt; 103 unwind_cleanup (_Unwind_Reason_Code reason, struct _Unwind_Exception *exc)&lt;br /&gt; 104 {&lt;br /&gt; 105   /* When we get here a C++ catch block didn't rethrow the object.  We&lt;br /&gt; 106      cannot handle this case and therefore abort.  */&lt;br /&gt; 107 # define STR_N_LEN(str) str, strlen (str)&lt;br /&gt; 108   INTERNAL_SYSCALL_DECL (err);&lt;br /&gt; 109   INTERNAL_SYSCALL (write, err, 3, STDERR_FILENO,&lt;br /&gt; 110                     STR_N_LEN ("FATAL: exception not rethrown\n"));&lt;br /&gt; 111   abort ();&lt;br /&gt; 112 }&lt;br /&gt;...&lt;br /&gt; 117 void&lt;br /&gt; 118 __cleanup_fct_attribute __attribute ((noreturn))&lt;br /&gt; 119 __pthread_unwind (__pthread_unwind_buf_t *buf)&lt;br /&gt; 120 {&lt;br /&gt; 121   struct pthread_unwind_buf *ibuf = (struct pthread_unwind_buf *) buf;&lt;br /&gt; 122   struct pthread *self = THREAD_SELF;&lt;br /&gt; 123&lt;br /&gt; 124 #ifdef HAVE_FORCED_UNWIND&lt;br /&gt; 125   /* This is not a catchable exception, so don't provide any details about&lt;br /&gt; 126      the exception type.  We do need to initialize the field though.  */&lt;br /&gt; 127   THREAD_SETMEM (self, exc.exception_class, 0);&lt;br /&gt; 128   THREAD_SETMEM (self, exc.exception_cleanup, unwind_cleanup);&lt;br /&gt; 129&lt;br /&gt; 130   _Unwind_ForcedUnwind (&amp;amp;self-&amp;gt;exc, unwind_stop, ibuf);&lt;br /&gt; 131 #else&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;結論:&lt;br /&gt;寫C++ code的時候, 如果有catch all exception, 最後還是要re-throw 或是根本不要在C++裡面cancel thread, 不然在multi-thread的情況下, 有可能有未預期的情況出現!!&lt;/p&gt;&lt;p&gt;問題:&lt;br /&gt;為什饃是在pthread&lt;em&gt;&lt;em&gt;join才會造成abort, 從code來看, 應該在pthread&lt;/em&gt;cancel就會trigger catch all exception, 怎麼會在pthread&lt;/em&gt;&lt;em&gt;join才發生...&amp;nbsp;&lt;br /&gt;我在pthread_&lt;/em&gt;join上面沒有看到類似的code, 不過大家都不推薦在C++裡面cancel thread!&lt;/p&gt;&lt;p&gt;Reference:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;http://stackoverflow.com/questions/4766768/unhandled-forced-unwind-causes-abort&lt;/li&gt;&lt;li&gt;http://stackoverflow.com/questions/4760687/cancelling-a-thread-using-pthread-cancel-good-practice-or-bad&lt;/li&gt;&lt;li&gt;http://udrepper.livejournal.com/21541.html&lt;/li&gt;&lt;li&gt;http://sourceware.org/git/?p=glibc.git;a=blob;f=nptl/pthread_cancel.c;h=55bb0da922ba1ed1c4bd33478075e1b41f2baaff;hb=3a33e487eeb65e2f1f633581c56bee2c60d0ca43&lt;/li&gt;&lt;li&gt;http://skaark.wordpress.com/2010/08/26/pthread_cancel-considered-harmful/&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-2437573787498981053?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/2437573787498981053/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/10/c-pthreadcancel-issue.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2437573787498981053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2437573787498981053'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/10/c-pthreadcancel-issue.html' title='[C++] pthread_cancel issue'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-2089618504005815701</id><published>2011-10-16T06:55:00.001-07:00</published><updated>2011-10-16T06:55:27.676-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mq'/><title type='text'>[RabbitMQ] rabbit_mnesia module</title><content type='html'>&lt;p&gt;RabbitMQ所有的meta data (ex: exchange, user, virtual host)也就是server state 都是存在erlang內建的mnesia distribute database, 並且會存在cluster內部每個node, 這個module主要就是node啟動的時候, 初始化mnesia 這個 database的動作, 包含如果是已經存在其他cluster node, 那就會去跟其他node 同步, 不然就會自己建立新的table.&amp;nbsp;&lt;/p&gt;&lt;p&gt;並且他會檢查erlang version, 是不是一樣, 還有當node reset, 在ram mode and disc mode之間轉換要做的事情.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-2089618504005815701?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/2089618504005815701/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/10/rabbitmq-rabbitmnesia-module.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2089618504005815701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2089618504005815701'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/10/rabbitmq-rabbitmnesia-module.html' title='[RabbitMQ] rabbit_mnesia module'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-1592059867963035341</id><published>2011-10-15T09:22:00.001-07:00</published><updated>2011-10-15T09:23:41.348-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mq'/><title type='text'>[RabbitMQ] HA on cluster</title><content type='html'>&lt;p&gt;原來RabbitMQ在使用cluster的時候, 所有的meta都會在所有node各存一份, 除了queue以外, 所以當其中某個node掛掉的時候, 在這個node當中queue裡面的message會全部遺失,&lt;/p&gt;&lt;p&gt;自RabbitMQ 從2.6之後開始support active-active HA, 使用的方法也很簡單, 只需要在declare queue的時候多加"x-ha-policy" 這個argument就可以了.&lt;/p&gt;&lt;p&gt;他是用mirror queue的方式來達到HA的目的, 也就是說, 你可以選擇要把某個queue mirror到哪些其他的nodes.&lt;/p&gt;&lt;p&gt;另外他mirror的方式, 是把master node mirror到其他slave node, 而且要從slave node加進來之後, 他才會開始sync, 之前已經存在master的msg並不會sync.&lt;/p&gt;&lt;p&gt;如果master 掛掉, 他會選擇存在最久的slave node來當作下一個master node.&lt;/p&gt;&lt;p&gt;以目前的2.6.1, "x-ha-policy" 支援兩種方式:&lt;br /&gt;&lt;br /&gt;1. all&lt;/p&gt;&lt;p&gt;&amp;nbsp; 把目前的queue之後的message都mirror到cluster裡面其他的所有nodes!&lt;br /&gt;&lt;br /&gt;2. nodes&lt;/p&gt;&lt;p&gt;&amp;nbsp; 可以自己選擇要mirror到哪些node, 就算是目前不存在cluster的node也行, mirror會等到那個node加進cluster之後才開始mirror,&lt;br /&gt; &amp;nbsp; 這個需要多加一個參數"x-ha-policy-params", 並把node list 當成value&lt;br /&gt; &amp;nbsp; &lt;strong&gt;!!這個目前有問題, 需要等到下一個release才會修正!!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;以下是用pika這個python amqp client API的例子:&lt;/p&gt;&lt;pre class="prettyprint"&gt;    channel.exchange_declare(exchange='test.topic', type='topic')&lt;br /&gt;    channel.queue_declare(queue="test_topic", durable=True,&lt;br /&gt;                          exclusive=False, auto_delete=False,&lt;br /&gt;                          arguments={'x-ha-policy': 'all'},&lt;br /&gt;                          callback=on_queue_declared)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt;&lt;br /&gt; &lt;em&gt;http://www.rabbitmq.com/ha.html&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-1592059867963035341?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/1592059867963035341/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/10/rabbitmq-ha-on-cluster.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/1592059867963035341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/1592059867963035341'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/10/rabbitmq-ha-on-cluster.html' title='[RabbitMQ] HA on cluster'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-3613968691428218200</id><published>2011-09-28T02:24:00.001-07:00</published><updated>2011-09-28T02:42:09.696-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>[Linux] Fork &amp; exec</title><content type='html'>&lt;p&gt;Fork 會把除了process id 之外, 整個program 都複製一份給child process (先不管copy on write), 在child process 執行exec之後, 原本program的資料就會lost, 全部取代成新的program, 但是fd不會自動close, 除非你有設定close-on-exec, 不然要不你需要手動close, 或是用來當作跟parent process溝通的管道.&lt;/p&gt;&lt;p&gt;p.s 當child process在處理NFS之類的fd, 要關掉fd,&amp;nbsp;有時會需要很長得時間才關得掉 (NFS server unreachable or 你改了ethernet address), 似乎這時候process會在D (uninterruptable) 這個state 停留非常久的時間...簡單來說, 在處理NFS這種網路的fd, 需要注意以免被watchdog&lt;/p&gt;&lt;p&gt;Reference&lt;br /&gt;&lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Fork-exec"&gt;http://en.wikipedia.org/wiki/Fork-exec&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href="http://stackoverflow.com/questions/1643304/how-to-set-close-on-exec-by-default"&gt;http://stackoverflow.com/questions/1643304/how-to-set-close-on-exec-by-default&lt;/a&gt;&amp;nbsp;&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-3613968691428218200?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/3613968691428218200/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/09/linux-fork-exec.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3613968691428218200'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3613968691428218200'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/09/linux-fork-exec.html' title='[Linux] Fork &amp;amp; exec'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-9120403216157240914</id><published>2011-09-27T22:52:00.001-07:00</published><updated>2011-09-27T22:59:59.904-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>[XML] The difference between value-of and copy-of</title><content type='html'>&lt;p&gt;差別:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;xsl:value-of returns all the TEXT within the selected tag(s).&lt;/li&gt;&lt;li&gt;xsl:copy-of returns all the ELEMENTS (both tags and text) of the selected tag(s).&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;一言以蔽之, value-of 只會回傳你選擇node裡面的text, 但是copy-of 卻是會把整個node structure都回傳回來.&lt;/p&gt;&lt;p&gt;例子:&lt;/p&gt;&lt;p&gt;&lt;p&gt;&lt;span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #f6f6f6;"&gt;&amp;lt;Name&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;lt;Family&amp;gt;Smith&amp;lt;/Family&amp;gt;&lt;br /&gt;&amp;nbsp;&amp;lt;Given&amp;gt;John&amp;lt;/Given&amp;gt;&lt;br /&gt;&amp;lt;/Name&amp;gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #f6f6f6;"&gt;&lt;strong&gt;XSLT:&lt;/strong&gt;&lt;br /&gt;&amp;lt;xsl:value-of select="Name"/&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;lt;!-- 輸出element Name下面的所有text --&amp;gt;&lt;/p&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;Output:&lt;/span&gt;&lt;br /&gt;Smith&lt;br /&gt;John&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;XSLT:&lt;/strong&gt;&lt;br /&gt;&lt;p&gt;&lt;span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #f6f6f6;"&gt;&amp;lt;xsl:value-of select="Name"/&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;/p&gt;&lt;p&gt;輸出Name底下的所有element (包含tag)&lt;/p&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;Output:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;lt;Name&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;lt;Family&amp;gt;Smith&amp;lt;/Family&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;lt;Given&amp;gt;John&amp;lt;/Given&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;lt;/Name&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;XSLT:&lt;/strong&gt;&lt;br /&gt;&lt;span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #f6f6f6;"&gt;&amp;lt;xsl:value-of select="Name/node()"/&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;輸出Name底下子節點的所有element (包含tag), 不包含自己&lt;/p&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;Output:&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;lt;Family&amp;gt;Smith&amp;lt;/Family&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&amp;lt;Given&amp;gt;John&amp;lt;/Given&amp;gt;&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;XSLT:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; font-size: 13px; background-color: #f6f6f6;"&gt;&amp;lt;xsl:value-of select="Name/text()"/&amp;gt;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;輸出Name底下的text, 但是這邊沒有, 所以沒有輸出&lt;/p&gt;&lt;p&gt;&lt;span style="text-decoration: underline;"&gt;Output:&lt;/span&gt;&lt;/p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Reference:&lt;/strong&gt;&lt;br /&gt; &lt;em&gt;http://dev.ektron.com/blogs.aspx?id=10472&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-9120403216157240914?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/9120403216157240914/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/09/xml-difference-between-value-of-and.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/9120403216157240914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/9120403216157240914'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/09/xml-difference-between-value-of-and.html' title='[XML] The difference between value-of and copy-of'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-5515454025285756558</id><published>2011-09-26T03:00:00.001-07:00</published><updated>2011-09-26T03:01:55.387-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] Constructor call other constructor</title><content type='html'>&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &lt;iostream&gt;   &lt;br /&gt;&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    Foo() { Foo(1); };&lt;br /&gt;    Foo(int a) { m = a; std::cout &lt;&lt;"Foo " &lt;&lt; a &lt;&lt; std::endl; }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;    int m;&lt;br /&gt;};                    &lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    Foo a, b(2);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;It is ok to call other constructor on method body, but calling other constructor on Initialize list is not allowed!&lt;br /&gt;The following example is not allowed.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &lt;iostream&gt;   &lt;br /&gt;&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    // this will cause compile error!!&lt;br /&gt;    Foo() : this(1) { };&lt;br /&gt;    Foo(int a) { m = a; std::cout &lt;&lt;"Foo " &lt;&lt; a &lt;&lt; std::endl; }&lt;br /&gt;&lt;br /&gt;private:&lt;br /&gt;    int m;&lt;br /&gt;};                    &lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    Foo a, b(2);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Reference:&lt;br /&gt;http://stackoverflow.com/questions/308276/c-call-constructor-from-constructor&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-5515454025285756558?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/5515454025285756558/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/09/c-constructor-call-other-constructor.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5515454025285756558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5515454025285756558'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/09/c-constructor-call-other-constructor.html' title='[C++] Constructor call other constructor'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-6272249873201906906</id><published>2011-09-16T21:18:00.001-07:00</published><updated>2011-09-17T09:05:45.457-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>[RabbitMQ] cluster setting</title><content type='html'>&lt;p&gt;在Ubuntu機器上面安裝很方便, 先安裝完erlang,另外要在裝erlang-nox, 接著直接把抓下來的rabbitmq-server deb安裝就行&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;$ sudo apt-get install erlang&lt;br /&gt;$ sudo apt-get install erlang-nox&lt;br /&gt;$ dpkg -i rabbitmq-server_2.6.1-1_all.deb&lt;br /&gt;$&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;另外rabbitmq有提供使用plugin, 如果你是用deb安裝, 那你只需要把所有plugin (.ez)放到 /usr/lib/rabbitmq/lib/rabbitmq&lt;em&gt;server-2.6.1/plugins下就行了.&lt;br /&gt;我是安裝rabbitmq-management plugin, 在cluster裡面, 只需要有一台安裝完整management plugin, 其他台都指需要裝management&lt;/em&gt;agent就行~&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;$ ls /usr/lib/rabbitmq/lib/rabbitmq_server-2.6.1/plugins/&lt;br /&gt;amqp_client-2.6.1.ez&lt;br /&gt;rabbitmq_mochiweb-2.6.1.ez&lt;br /&gt;mochiweb-1.3-rmq2.6.1-git9a53dbd.ez&lt;br /&gt;README&lt;br /&gt;rabbitmq_management-2.6.1.ez&lt;br /&gt;webmachine-1.7.0-rmq2.6.1-hg0c4b60a.ez&lt;br /&gt;rabbitmq_management_agent-2.6.1.ez&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;在erlang的世界裡面, 需要設定同樣的cookie,不同的node彼此之間才可以溝通, 所以假設我們有lab1, lab2, lab3三台機器, 只要把lab1 上面的/var/lib/rabbitmq/.erlang.cookie copy到其他兩台機器上面, 就可以溝通了, 之後就可以透過rabbitmqctl來建立cluster, 有幾點要特別注意&lt;/p&gt;&lt;ul&gt;&lt;li&gt;更換.erlang.cookie完之後, 要記得rm -rf /var/lib/rabbitmq/mnesia&lt;/li&gt;&lt;li&gt;要記得更改/etc/hosts裡面關於cluster ip host mapping, 這樣erlang才可以查到domain name的ip&lt;/li&gt;&lt;li&gt;之後要自動設定, 可以寫檔案在/etc/rabbitmq 下面&lt;/li&gt;&lt;/ul&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;$ rm -rf /var/lib/rabbitmq/mnesia&lt;br /&gt;$ rabbitmqctl cluster_status&lt;br /&gt;...&lt;br /&gt;$ rabbitmqctl stop_app&lt;br /&gt;...&lt;br /&gt;$ rabbitmqctl reset&lt;br /&gt;...&lt;br /&gt;$ rabbitmqctl cluster rabbit@lab001 # add lab002 as mem mode&lt;br /&gt;...&lt;br /&gt;$ rabbitmqctl cluster rabbit@lab001 rabbit@lab003 # add lab003 as disk mode&lt;br /&gt;...&lt;br /&gt;$ rabbitmqctl cluster_status&lt;br /&gt;...&lt;br /&gt;$ cat /etc/rabbitmq/rabbitmq-env.conf&lt;br /&gt;RABBITMQ_CONFIG_FILE=/etc/rabbitmq/rabbitmq.conf&lt;br /&gt;$ cat /etc/rabbitmq/rabbitmq.conf&lt;br /&gt;[ {rabbit, [ {cluster_nodes, ['rabbit@lab001', 'rabbit@lab003']} ]} ].&lt;br /&gt;$&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;另外提到一點, erlang的shell可以拿來幫助debug, 當你選定某組cookie來跑rabbitmq server, 假設跑在lab001, 可以利用erlang shell確認連線有沒有錯誤,&lt;br /&gt;假如回傳的是pang, 那代表連線有問題~ 另外也要確定epmd 這個erlang內建的daemon有沒有跑起來~&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;lab002 $ erl -sname ooo -setcookie&lt;br /&gt;Erlang R13B03 (erts-5.7.4) [source] [64-bit] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]&lt;br /&gt;&lt;br /&gt;Eshell V5.7.4  (abort with ^G)&lt;br /&gt;(oo@lab002)1&amp;gt; net_adm:ping('rabbit@lab001').&lt;br /&gt;pong&lt;br /&gt;(oo@lab002)2&amp;gt;&lt;br /&gt;&lt;br /&gt;$ epmd -names&lt;br /&gt;epmd: up and running on port 4369 with data:&lt;br /&gt;name rabbit at port 58909&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Reference&lt;br /&gt;http://www.rabbitmq.com/clustering.html&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-6272249873201906906?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/6272249873201906906/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/09/rabbitmq-cluster-setting.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6272249873201906906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6272249873201906906'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/09/rabbitmq-cluster-setting.html' title='[RabbitMQ] cluster setting'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-155557563537193890</id><published>2011-09-16T08:40:00.001-07:00</published><updated>2011-09-16T08:57:55.136-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='network'/><title type='text'>[Network] TCP hole punching under NAT</title><content type='html'>&lt;p&gt;NAT (network address translation) box, 目前可以分為四種address mapping方式&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Full Cone mapping&lt;/li&gt;&lt;li&gt;Restricted Cone mapping&lt;/li&gt;&lt;li&gt;Port Restricted Cone mapping&lt;/li&gt;&lt;li&gt;Symmetric mapping&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;當我們要從Addr1: Port1 經過NAT1: Port 0出去到Addr2: Port 2的時候&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Full Cone mapping:&lt;/strong&gt;&lt;br /&gt;NAT1: Port 0會處理任何跟Addr1:Port 1的連線, 就算是Addr3:Port3, 只要能猜到NAT1:Port 0, 都可以跟Addr1: Port 1溝通&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Restricted Cone mapping:&lt;/strong&gt;&lt;br /&gt;只有當Addr1: Port 1之前有連線到Addr 3, Addr 3 才可以透過NAT1: Port 0連進來 Addr1: Port 1&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Port Restricted Cone mapping:&lt;/strong&gt;&lt;br /&gt;只有當Addr1: Port 1之前有連線到Addr 3: Port 3, Addr 3:Port 3 才可以透過NAT1: Port 0連進來 Addr1: Port 1&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Symmetric mapping:&lt;/strong&gt;&lt;br /&gt;NAT會自動為每一組Addr1: Port 1所連出去的IP Port都準備獨立的Port mapping, 例如&lt;br /&gt;Addr1: Port 1 -&amp;gt; NAT: Port 0 -&amp;gt; Addr2: Port 2&amp;nbsp;&lt;br /&gt;Addr1: Port 1 -&amp;gt; NAT: Port 4 -&amp;gt; Addr2: Port 3&lt;/p&gt;&lt;p&gt;這四種mapping的方式會影響到, 你如何利用TCP 來對NAT 打洞 (TCP hole punching), 前三種都算好解, 畢竟妳只要有辦法知道Addr 1:Port 1連出去的 NAT: Port 0, 你就可以跟他溝通, 第四種可能只能靠port predict的方式來做&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-155557563537193890?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/155557563537193890/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/09/network-tcp-hole-punching-under-nat.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/155557563537193890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/155557563537193890'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/09/network-tcp-hole-punching-under-nat.html' title='[Network] TCP hole punching under NAT'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8675057409480637694</id><published>2011-09-06T00:26:00.001-07:00</published><updated>2011-09-06T00:26:20.603-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] Derived class no need to write virtual when base class already has</title><content type='html'>&lt;p&gt;From&lt;br /&gt;&lt;em&gt;http://stackoverflow.com/questions/4895294/c-virtual-keyword-for-functions-in-derived-classes-is-it-necessary&lt;/em&gt;&lt;/p&gt;&lt;p&gt;But I think it's more readable and clear to write on virtual...&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8675057409480637694?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8675057409480637694/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/09/c-derived-class-no-need-to-write.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8675057409480637694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8675057409480637694'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/09/c-derived-class-no-need-to-write.html' title='[C++] Derived class no need to write virtual when base class already has'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-7064561726314476759</id><published>2011-08-30T05:39:00.000-07:00</published><updated>2011-08-30T05:39:44.187-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] Effective C++ Item 42: Understand the two meanings of typename</title><content type='html'>今天剛好遇到一個小問題, 之前剛好在翻Effective C++, 翻一下書剛好就找到了, 順便在加深一下印象~&lt;br /&gt;&lt;br /&gt;typename除了直接使用在template裡面當然宣告template parameter的地方, 如以下情形之外&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;template&lt;typename T&gt;&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    void foo(T a);&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;當在程式內部的name跟template parameter有相依關係的時候, 這個就叫做dependent name, 在C++當中, 他預設不會幫你假設這樣的name是type, 除非你有明確的告訴parser.&lt;br /&gt;&lt;br /&gt;所以像以下的情形, 你就必須在前面加上typename, 這樣compiler才會認為宣告的T::iterator 也是一個type, 才不會有compiler error.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;template&lt;typename T&gt;&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;public:&lt;br /&gt;    void foo(T a);&lt;br /&gt;    void goo(typename T::iterator i);&lt;br /&gt;private:&lt;br /&gt;    typename std::vector&lt;T&gt;::iterator a;&lt;br /&gt;};&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-7064561726314476759?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/7064561726314476759/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/c-effective-c-item-42-understand-two.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/7064561726314476759'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/7064561726314476759'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/c-effective-c-item-42-understand-two.html' title='[C++] Effective C++ Item 42: Understand the two meanings of typename'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-3378300372928250847</id><published>2011-08-28T00:45:00.000-07:00</published><updated>2011-08-28T00:46:21.707-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mq'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>[Erlang] RabbitMQ rabbit_alarm module</title><content type='html'>在Erlang裡面, 我們可以很簡單的實做一個alarm handler, 他可以接收各種alarm event, 並根據event &amp;nbsp;message來做出回應, 同時Erlang不限制你只能有一個alarm handler, 你可以根據不同功能來實做相對應的alarm handler, 只要註冊不同的名字, 在你觸發事件的時候, 可以選擇要給哪些alarm handler處理.&lt;br /&gt;&lt;br /&gt;當要觸發事件的時候, 只需要呼叫gen_event:notify, 並且在handle_event處理相對應的event即可.&lt;br /&gt;&lt;br /&gt;在rabbitmq內部他有實做一套memory monitor的機制, 這個機制是可以運作在cluster node內部或是單一node的情況. 而這個memory monitr有兩個部份, 關於內部所有用到的queue, channel所使用的memory monitor下次在介紹, 這次的memory monitor 只監控整體的使用量, 當到達高水位的時候, 便會block新進來的connection, 並且通知cluster其他node也要開始節省使用.&lt;br /&gt;&lt;br /&gt;所在檔案rabbit_alarm.erl &amp;amp; vm_memory_monitor.erl&lt;br /&gt;&lt;br /&gt;rabbitmq 在啟動的時候, boot的階段會去spawn一個alarm process.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;rabbit.erl&lt;br /&gt;&lt;br /&gt; 88 -rabbit_boot_step({rabbit_alarm,           &lt;br /&gt; 89          [{description, "alarm handler"},&lt;br /&gt; 90           {mfa,         {rabbit_alarm, start, []}},&lt;br /&gt; 91           {requires,    kernel_ready},&lt;br /&gt; 92           {enables,     core_initialized}]}).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;在rabbit_alarm 這個process啟動的時候做了以下的事情, 他會從ebin/rabbit.app 裡面你所設定的memory條件來設定並啟動另外一個monitor process 來monitor memory, 當memory到達那個條件後的時候給你alarm.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;rabbit_alarm.erl&lt;br /&gt;&lt;br /&gt; 45 start() -&amp;gt;&lt;br /&gt;        % 新增一個新的alarm handler, 名字是rabbit_alarm&lt;br /&gt; 46     ok = alarm_handler:add_alarm_handler(?MODULE, []),&lt;br /&gt; 47     {ok, MemoryWatermark} = application:get_env(vm_memory_high_watermark),&lt;br /&gt; 48     ok = case MemoryWatermark == 0 of&lt;br /&gt;            % 如果沒設定就不監控&lt;br /&gt; 49          true  -&amp;gt; ok;&lt;br /&gt;            % 啟動另外一個monitor process&lt;br /&gt; 50          false -&amp;gt; rabbit_sup:start_restartable_child(vm_memory_monitor,&lt;br /&gt; 51                [MemoryWatermark])&lt;br /&gt; 52     end,&lt;br /&gt; 53     ok.&lt;br /&gt;&lt;br /&gt;    % rabbit_alarm本身有maintain兩個table&lt;br /&gt;    % alertees 代表發生alarm他要通知的其他node&lt;br /&gt;    % alarmed_nodes 代表已經發生過alarm的node&lt;br /&gt; 78 init([]) -&amp;gt;&lt;br /&gt; 79     {ok, #alarms{alertees      = dict:new(),&lt;br /&gt; 80                  alarmed_nodes = sets:new()}}.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;接下來先來看他監控的方式.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;vm_memory_monitor.erl&lt;br /&gt;&lt;br /&gt;105 start_link(Args) -&amp;gt;&lt;br /&gt;106     gen_server:start_link({local, ?SERVER}, ?MODULE, [Args], []).&lt;br /&gt;107  &lt;br /&gt;108 init([MemFraction]) -&amp;gt;&lt;br /&gt;109     TotalMemory =&lt;br /&gt;        % get_total_memory 可以查看該檔案內部&lt;br /&gt;        % 針對不同OS的處理&lt;br /&gt;110         case get_total_memory() of&lt;br /&gt;111             unknown -&amp;gt;&lt;br /&gt;112                 error_logger:warning_msg(&lt;br /&gt;113                   "Unknown total memory size for your OS ~p. "&lt;br /&gt;114                   "Assuming memory size is ~pMB.~n",&lt;br /&gt;115                   [os:type(), trunc(?MEMORY_SIZE_FOR_UNKNOWN_OS/1048576)]),&lt;br /&gt;116                 ?MEMORY_SIZE_FOR_UNKNOWN_OS;&lt;br /&gt;117             M -&amp;gt; M&lt;br /&gt;118         end,&lt;br /&gt;119     MemLimit = get_mem_limit(MemFraction, TotalMemory),&lt;br /&gt;120     error_logger:info_msg("Memory limit set to ~pMB.~n",&lt;br /&gt;121                           [trunc(MemLimit/1048576)]),&lt;br /&gt;        % 啟動timer, 固定時間檢查memory usage&lt;br /&gt;122     TRef = start_timer(?DEFAULT_MEMORY_CHECK_INTERVAL),&lt;br /&gt;123     State = #state { total_memory = TotalMemory,&lt;br /&gt;124                      memory_limit = MemLimit,&lt;br /&gt;125                      timeout = ?DEFAULT_MEMORY_CHECK_INTERVAL,&lt;br /&gt;126                      timer = TRef,&lt;br /&gt;127                      alarmed = false},&lt;br /&gt;128     {ok, internal_update(State)}.&lt;br /&gt;&lt;br /&gt;171 internal_update(State = #state { memory_limit = MemLimit,&lt;br /&gt;172                                  alarmed = Alarmed}) -&amp;gt;&lt;br /&gt;        % erlang VM內部目前使用的&lt;br /&gt;173     MemUsed = erlang:memory(total),&lt;br /&gt;174     NewAlarmed = MemUsed &amp;gt; MemLimit,&lt;br /&gt;175     case {Alarmed, NewAlarmed} of&lt;br /&gt;176         {false, true} -&amp;gt;&lt;br /&gt;            % 如果之前還沒發出過alarm&lt;br /&gt;            % 就會發出alarm, 給alarm_handler&lt;br /&gt;177             emit_update_info(set, MemUsed, MemLimit),&lt;br /&gt;178             alarm_handler:set_alarm({{vm_memory_high_watermark, node()}, []});&lt;br /&gt;179         {true, false} -&amp;gt;&lt;br /&gt;            % 反之則清理掉alarm&lt;br /&gt;180             emit_update_info(clear, MemUsed, MemLimit),&lt;br /&gt;181             alarm_handler:clear_alarm({vm_memory_high_watermark, node()});&lt;br /&gt;182         _ -&amp;gt;&lt;br /&gt;183             ok&lt;br /&gt;184     end,&lt;br /&gt;185     State #state {alarmed = NewAlarmed}.&lt;br /&gt;186  &lt;br /&gt;    % 印出log&lt;br /&gt;187 emit_update_info(State, MemUsed, MemLimit) -&amp;gt;&lt;br /&gt;188     error_logger:info_msg(&lt;br /&gt;189       "vm_memory_high_watermark ~p. Memory used:~p allowed:~p~n",&lt;br /&gt;190       [State, MemUsed, MemLimit]).&lt;br /&gt;191  &lt;br /&gt;    % 定時update memory usage state&lt;br /&gt;192 start_timer(Timeout) -&amp;gt;&lt;br /&gt;193     {ok, TRef} = timer:apply_interval(Timeout, ?MODULE, update, []),&lt;br /&gt;194     TRef.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;現在回到rabbitm_alarm.erl 看他怎麼處理當收到high memory watermark的alarm.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;rabbit_alarm.erl&lt;br /&gt;&lt;br /&gt; 89 handle_event({set_alarm, {{vm_memory_high_watermark, Node}, []}}, State) -&amp;gt;&lt;br /&gt; 90     {ok, maybe_alert(fun sets:add_element/2, Node, State)};&lt;br /&gt; 91  &lt;br /&gt; 92 handle_event({clear_alarm, {vm_memory_high_watermark, Node}}, State) -&amp;gt;&lt;br /&gt; 93     {ok, maybe_alert(fun sets:del_element/2, Node, State)};&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;126 maybe_alert(SetFun, Node, State = #alarms{alarmed_nodes = AN,&lt;br /&gt;127                      alertees      = Alertees}) -&amp;gt;&lt;br /&gt;128     AN1 = SetFun(Node, AN),&lt;br /&gt;129     BeforeSz = sets:size(AN),&lt;br /&gt;130     AfterSz  = sets:size(AN1),&lt;br /&gt;131     %% If we have changed our alarm state, inform the remotes.&lt;br /&gt;132     IsLocal = Node =:= node(),&lt;br /&gt;        % 如果是local alarm&lt;br /&gt;        % 就會通知其他的remote node&lt;br /&gt;133     if IsLocal andalso BeforeSz &amp;lt; AfterSz -&amp;gt; ok = alert_remote(true,  Alertees);&lt;br /&gt;134        IsLocal andalso BeforeSz &amp;gt; AfterSz -&amp;gt; ok = alert_remote(false, Alertees);&lt;br /&gt;135        true                               -&amp;gt; ok&lt;br /&gt;136     end,&lt;br /&gt;137     %% If the overall alarm state has changed, inform the locals.&lt;br /&gt;138     case {BeforeSz, AfterSz} of&lt;br /&gt;139         {0, 1} -&amp;gt; ok = alert_local(true,  Alertees);&lt;br /&gt;140         {1, 0} -&amp;gt; ok = alert_local(false, Alertees);&lt;br /&gt;141         {_, _} -&amp;gt; ok&lt;br /&gt;142     end,&lt;br /&gt;        % 更新alarmed_node&lt;br /&gt;143     State#alarms{alarmed_nodes = AN1}.&lt;br /&gt;&lt;br /&gt;145 alert_local(Alert, Alertees)  -&amp;gt; alert(Alert, Alertees, fun erlang:'=:='/2).&lt;br /&gt;146      &lt;br /&gt;147 alert_remote(Alert, Alertees) -&amp;gt; alert(Alert, Alertees, fun erlang:'=/='/2).&lt;br /&gt;148      &lt;br /&gt;    % 找出所有需要通知的node, 並且執行Node之前register的callback&lt;br /&gt;149 alert(Alert, Alertees, NodeComparator) -&amp;gt;&lt;br /&gt;150     Node = node(),                                                                                                                                                     &lt;br /&gt;151     dict:fold(fun (Pid, {M, F, A}, ok) -&amp;gt;&lt;br /&gt;152                       case NodeComparator(Node, node(Pid)) of&lt;br /&gt;153                           true  -&amp;gt; apply(M, F, A ++ [Pid, Alert]);&lt;br /&gt;154                           false -&amp;gt; ok&lt;br /&gt;155                       end&lt;br /&gt;156               end, ok, Alertees).&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;所以之後其他的module, 只需要register callback, 當memory用量過高, 要怎麼處理就行, 這部份的code 是放在rabbit_reader.erl, 也就是當connection coming的時候.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;rabbit_reader.erl&lt;br /&gt;&lt;br /&gt;691     State1 = internal_conserve_memory(&lt;br /&gt;           % register callback&lt;br /&gt;           % 當記憶體使用過量&lt;br /&gt;           % 便會呼叫&lt;br /&gt;692        rabbit_alarm:register(self(), {?MODULE, conserve_memory, []}),&lt;br /&gt;693        State#v1{connection_state = running,&lt;br /&gt;694                connection = NewConnection}),&lt;br /&gt;&lt;br /&gt;    % 當使用過量, state改為blocking&lt;br /&gt;    % 不在接收新的connection&lt;br /&gt;348 internal_conserve_memory(true,  State = #v1{connection_state = running}) -&amp;gt;&lt;br /&gt;349     State#v1{connection_state = blocking};&lt;br /&gt;350 internal_conserve_memory(false, State = #v1{connection_state = blocking}) -&amp;gt;                                                                                           &lt;br /&gt;351     State#v1{connection_state = running};&lt;br /&gt;352 internal_conserve_memory(false, State = #v1{connection_state = blocked,&lt;br /&gt;353                                             heartbeater      = Heartbeater}) -&amp;gt;&lt;br /&gt;354     ok = rabbit_heartbeat:resume_monitor(Heartbeater),&lt;br /&gt;355     State#v1{connection_state = running};&lt;br /&gt;356 internal_conserve_memory(_Conserve, State) -&amp;gt;&lt;br /&gt;357     State&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;另外當新的cluster node 啟動的時候, 假設現在Node A收到Node B up的event, Node A會跟Node B註冊一個remote_conserve_memory callback, 當Node B 記憶體過大, 他就會呼叫Node A 開始節省memory, 直到原本的alarm被clear.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;rabbit_alarm.erl&lt;br /&gt;&lt;br /&gt; 95 handle_event({node_up, Node}, State) -&amp;gt;         &lt;br /&gt; 96     %% Must do this via notify and not call to avoid possible deadlock.&lt;br /&gt; 97     ok = gen_event:notify(                      &lt;br /&gt; 98            {alarm_handler, Node},               &lt;br /&gt; 99            {register, self(), {?MODULE, remote_conserve_memory, []}}),&lt;br /&gt;100     {ok, State};&lt;br /&gt;&lt;br /&gt; 69 remote_conserve_memory(Pid, true) -&amp;gt;&lt;br /&gt;        % 叫自己開始節省記憶體&lt;br /&gt; 70     gen_event:notify({alarm_handler, node(Pid)},&lt;br /&gt; 71                      {set_alarm, {{vm_memory_high_watermark, node()}, []}});&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-3378300372928250847?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/3378300372928250847/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/erlang-rabbitmq-rabbitalarm-module.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3378300372928250847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3378300372928250847'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/erlang-rabbitmq-rabbitalarm-module.html' title='[Erlang] RabbitMQ rabbit_alarm module'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8186312377498306373</id><published>2011-08-26T20:48:00.001-07:00</published><updated>2011-08-26T23:54:05.782-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mq'/><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>[Erlang] RabbitMQ cluster node monitor module</title><content type='html'>&lt;p&gt;在RabbitMQ啟動的時候, 會預先執行一些boot steps, 其中有一步就是會啟動rabbit&lt;em&gt;node&lt;/em&gt;monitor.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit.erl (program entry point)&lt;br /&gt;&lt;br /&gt;% 先啟動node_monitor這個process&lt;br /&gt;114 -rabbit_boot_step({rabbit_node_monitor,&lt;br /&gt;115            [{description, "node monitor"},&lt;br /&gt;116             {mfa,         {rabbit_sup, start_restartable_child,&lt;br /&gt;117             [rabbit_node_monitor]}},&lt;br /&gt;118             {requires,    kernel_ready},&lt;br /&gt;119             {enables,     core_initialized}]}).&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;所以實際在monitor cluster node的module是在rabbit&lt;em&gt;node&lt;/em&gt;monitor.erl檔案裡面.&lt;/p&gt;&lt;p&gt;在erlang的世界當中, 其實要組成cluster是相當容易的, 每一個node只要在啟動的時候, 設定node的名字(cluster內部不重複), 並且搭配同樣的cookie, 彼此之間就可以互相溝通.&lt;/p&gt;&lt;p&gt;所以在node&lt;em&gt;monitor 這個process起來的時候他會呼叫init function, 而net&lt;/em&gt;kernel:monitor_nodes, 代表他會接收所有他監控node的status message.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit&lt;em&gt;node&lt;/em&gt;monitor.erl&lt;br /&gt;&lt;br /&gt;init([]) -&amp;gt;&lt;br /&gt;    ok = net_kernel:monitor_nodes(true),&lt;br /&gt;    {ok, no_state}.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;到這時候, node_monitor就做好了初始化的動作, 接下來就要開始cluster內部node資料傳遞, 所以boot steps後面的動作就是notify cluster&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit.erl (program entry point)&lt;br /&gt;&lt;br /&gt;155 -rabbit_boot_step({notify_cluster,&lt;br /&gt;156          [{description, "notify cluster nodes"},&lt;br /&gt;157           {mfa,         {rabbit_node_monitor, notify_cluster, []}},&lt;br /&gt;158           {requires,    networking}]}).&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;在51行, 可以看到把自己的資訊multicast出去&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit&lt;em&gt;node&lt;/em&gt;monitor.erl&lt;br /&gt;&lt;br /&gt; % 接下來在收集整個cluster的information, 並且把自己的資料傳出去, 讓cluster的其他node知道&lt;br /&gt; 47 notify_cluster() -&amp;gt;&lt;br /&gt; 48     Node = node(), % 這是代表自己的node&lt;br /&gt;        % 這邊因為每個rabbitmq 起來, 都會有自己的mnesia, 所以可以藉由這個來收集已經起來的rabbitmq node&lt;br /&gt; 49     Nodes = rabbit_mnesia:running_clustered_nodes() -- [Node],&lt;br /&gt; 50     %% notify other rabbits of this rabbit&lt;br /&gt; 51     case rpc:multicall(Nodes, rabbit_node_monitor, rabbit_running_on,&lt;br /&gt; 52                        [Node], ?RABBIT_UP_RPC_TIMEOUT) of&lt;br /&gt; 53         {_, [] } -&amp;gt; ok;&lt;br /&gt; 54         {_, Bad} -&amp;gt; rabbit_log:info("failed to contact nodes ~p~n", [Bad])&lt;br /&gt; 55     end,&lt;br /&gt; 56     %% register other active rabbits with this rabbit&lt;br /&gt; 57     [ rabbit_node_monitor:rabbit_running_on(N) || N &amp;lt;- Nodes ],&lt;br /&gt; 58     ok.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;而接下來的程式就是當monitor_node這個process根據收到各種status message所做的處理&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit&lt;em&gt;node&lt;/em&gt;monitor.erl&lt;br /&gt;&lt;br /&gt; 66 handle_call(_Request, _From, State) -&amp;gt;&lt;br /&gt; 67     {noreply, State}.&lt;br /&gt; 68&lt;br /&gt; 69 handle_cast({rabbit_running_on, Node}, State) -&amp;gt;&lt;br /&gt; 70     rabbit_log:info("node ~p up~n", [Node]),&lt;br /&gt;        % 收到新的node, 所以納入監控&lt;br /&gt; 71     erlang:monitor(process, {rabbit, Node}),&lt;br /&gt;        % 呼叫自己的event handler 處理新啟動的node&lt;br /&gt; 72     ok = rabbit_alarm:on_node_up(Node),&lt;br /&gt; 73     {noreply, State};&lt;br /&gt; 74 handle_cast(_Msg, State) -&amp;gt;&lt;br /&gt; 75     {noreply, State}.&lt;br /&gt; 76&lt;br /&gt; 77 handle_info({nodedown, Node}, State) -&amp;gt;&lt;br /&gt;        % 收到有監控的node 正常掛掉了&lt;br /&gt; 78     rabbit_log:info("node ~p down~n", [Node]),&lt;br /&gt; 79     ok = handle_dead_rabbit(Node),&lt;br /&gt; 80     {noreply, State};&lt;br /&gt; 81 handle_info({'DOWN', _MRef, process, {rabbit, Node}, _Reason}, State) -&amp;gt;&lt;br /&gt;        % 收到突然掛掉的node&lt;br /&gt; 82     rabbit_log:info("node ~p lost 'rabbit'~n", [Node]),&lt;br /&gt; 83     ok = handle_dead_rabbit(Node),&lt;br /&gt; 84     {noreply, State};&lt;br /&gt;&lt;br /&gt; 96 %% TODO: This may turn out to be a performance hog when there are lots&lt;br /&gt; 97 %% of nodes.  We really only need to execute some of these statements&lt;br /&gt; 98 %% on *one* node, rather than all of them.&lt;br /&gt; 99 handle_dead_rabbit(Node) -&amp;gt;&lt;br /&gt;100     ok = rabbit_networking:on_node_down(Node),&lt;br /&gt;101     ok = rabbit_amqqueue:on_node_down(Node),&lt;br /&gt;102     ok = rabbit_alarm:on_node_down(Node).&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;接下來針對有新node啟動的情形來看一下他怎麼處理, 他會呼叫 rabbit&lt;em&gt;alarm 這個module來處理, 在這裡的flow有點不太一樣, 要分成兩個部份來看, 現在的情形是Node A跟Node B, Node A收到Node B node&lt;/em&gt;up 的message, 所以Node A呼叫自己的 rabbit_alarm module 來處理, 進入這邊之後, Node A沒作甚饃特別的事情(反正Node A已經有monitor Node B了), 但是他會送一個{register, self(), ...} event給Node B去處理.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit_alarm.erl on Node A&lt;br /&gt;&lt;br /&gt; 95 handle_event({node_up, Node}, State) -&amp;gt;&lt;br /&gt; 96     %% Must do this via notify and not call to avoid possible deadlock.&lt;br /&gt; 97     ok = gen_event:notify(&lt;br /&gt; 98            {alarm_handler, Node},&lt;br /&gt; 99            {register, self(), {?MODULE, remote_conserve_memory, []}}),&lt;br /&gt;100     {ok, State};&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;接著我們來看Node B這邊做了甚饃事情~ 他接著也會monitor Node A, 並且看Node A是不是有在他的alarmed&lt;em&gt;nodes裡面, 如果有的話, 就會執行傳進來的Module, Function, Arguments, 就是rabbit&lt;/em&gt;alarm.erl 69-71行做的事情, 接著再把Node A加進alertees裡面(之後有alert發生要通知的對象之一), 這樣子就完成加入新Node的動作.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;rabbit_alarm.erl on Node B&lt;br /&gt;&lt;br /&gt; 67 %% Can't use alarm_handler:{set,clear}_alarm because that doesn't&lt;br /&gt; 68 %% permit notifying a remote node.&lt;br /&gt;    % 在送set_alarm event 回給 Node A&lt;br /&gt; 69 remote_conserve_memory(Pid, true) -&amp;gt;&lt;br /&gt; 70     gen_event:notify({alarm_handler, node(Pid)},&lt;br /&gt; 71                      {set_alarm, {{vm_memory_high_watermark, node()}, []}});&lt;br /&gt; 72 remote_conserve_memory(Pid, false) -&amp;gt;&lt;br /&gt; 73     gen_event:notify({alarm_handler, node(Pid)},&lt;br /&gt; 74                      {clear_alarm, {vm_memory_high_watermark, node()}}).&lt;br /&gt;&lt;br /&gt;    % 收到Node A的 event&lt;br /&gt; 82 handle_call({register, Pid, HighMemMFA}, State) -&amp;gt;&lt;br /&gt; 83     {ok, 0 &amp;lt; sets:size(State#alarms.alarmed_nodes),&lt;br /&gt; 84      internal_register(Pid, HighMemMFA, State)};     &lt;br /&gt;&lt;br /&gt;    % 首先M, F, A 分別是 ?MODULE, remote_conserve_memory, []&lt;br /&gt;158 internal_register(Pid, {M, F, A} = HighMemMFA,&lt;br /&gt;159                   State = #alarms{alertees = Alertees}) -&amp;gt;&lt;br /&gt;160     _MRef = erlang:monitor(process, Pid),&lt;br /&gt;161     case sets:is_element(node(), State#alarms.alarmed_nodes) of&lt;br /&gt;162         true  -&amp;gt; ok = apply(M, F, A ++ [Pid, true]);&lt;br /&gt;163         false -&amp;gt; ok&lt;br /&gt;164     end,&lt;br /&gt;165     NewAlertees = dict:store(Pid, HighMemMFA, Alertees),&lt;br /&gt;166     State#alarms{alertees = NewAlertees}.&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;所以其實monitor cluster node的部份在erlang的實做是相當的簡單~&lt;/p&gt;&lt;p&gt;至於關於rabbit_alarm.erl的部份, 裡面有關於monitor memory部份, 留到下次再說~&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8186312377498306373?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8186312377498306373/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/erlang-rabbitmq-cluster-node-monitor.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8186312377498306373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8186312377498306373'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/erlang-rabbitmq-cluster-node-monitor.html' title='[Erlang] RabbitMQ cluster node monitor module'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-525425577656979874</id><published>2011-08-26T00:11:00.001-07:00</published><updated>2011-08-26T19:46:34.056-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>[Linux] system info</title><content type='html'>Use sudo dmidecode -t memory to see how much memory capacity in your machine. There are some more information about hardware information can be found by using this command.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-525425577656979874?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/525425577656979874/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/linux-system-info.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/525425577656979874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/525425577656979874'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/linux-system-info.html' title='[Linux] system info'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8554312336451443968</id><published>2011-08-23T08:48:00.001-07:00</published><updated>2011-08-23T08:50:17.832-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='erlang'/><title type='text'>[Erlang] Prime generator</title><content type='html'>&lt;p&gt;好久沒寫erlang, 有點生疏了~ 剛好看到有人在講prime generator, 就寫了一個~:P&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;-module(prime).                     &lt;br /&gt;&lt;br /&gt;-export([generate_prime/1]).        &lt;br /&gt;&lt;br /&gt;filter_number(Pid, P) -&gt;&lt;br /&gt;    receive&lt;br /&gt;        N when N rem P /= 0 -&gt;&lt;br /&gt;            % In this case, the N can not be divided by P,&lt;br /&gt;            % so pass it to next prime process&lt;br /&gt;            Pid ! N;&lt;br /&gt;        _N -&gt; ok&lt;br /&gt;    end,&lt;br /&gt;    filter_number(Pid, P).          &lt;br /&gt;&lt;br /&gt;prime() -&gt;&lt;br /&gt;    Prime = receive P -&gt; P end,&lt;br /&gt;    io:format("Prime ~p~n", [Prime]),&lt;br /&gt;    Pid = spawn(fun prime/0),&lt;br /&gt;    filter_number(Pid, P).          &lt;br /&gt;&lt;br /&gt;generate_prime(N) -&gt;&lt;br /&gt;    % create the first prime process&lt;br /&gt;    Pid = spawn(fun prime/0),&lt;br /&gt;    lists:map(fun(X) -&gt; Pid ! X end, lists:seq(2, N)),&lt;br /&gt;    ok.                             &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8554312336451443968?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8554312336451443968/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/erlang-prime-generator.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8554312336451443968'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8554312336451443968'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/erlang-prime-generator.html' title='[Erlang] Prime generator'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-6793288443933370216</id><published>2011-08-18T07:40:00.001-07:00</published><updated>2011-08-18T08:03:41.814-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>[GDB] Reverse step for GDB</title><content type='html'>&lt;p&gt;從GDB 7.0之後就support Process record 也就是所謂的"reverse debugging", 一般而言我們在gdb上面可以執行step, continue, next這些指令, 但是一旦走到下一步之後, 就無法回到下一步~ "reverse debugging" 就是可以還原到上一步, 或是還原上一次的breakpoint. 目前這個功能有平台上的限制, 只能支援以下平台&lt;/p&gt;&lt;ul&gt;&lt;li&gt;i386-linux&lt;/li&gt;&lt;li&gt;amd64-linux&lt;/li&gt;&lt;li&gt;moxie-elf / moxie-linux&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;他底層其實就是gdb 會把你每一步執行的指令logging起來,搭配memory跟register的狀態, 所以才能成功還原上一步.&amp;nbsp;&lt;/p&gt;&lt;p&gt;假設我有下面的程式&lt;/p&gt;&lt;pre class="prettyprint"&gt;#include&lt;br /&gt;#include &lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    int i;       &lt;br /&gt;&lt;br /&gt;    for(i=0;i&amp;lt;100;i++) {&lt;br /&gt;        int t =&lt;br /&gt;        printf("i = %d, t = %d\n", i, t);&lt;br /&gt;    }&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;現在開始進行gdb debug&lt;/p&gt;&lt;pre class="prettyprint"&gt;$ gcc -g tests.c # compile code&lt;br /&gt;$ gdb a.out # start to debug&lt;br /&gt;(gdb) r&lt;br /&gt;The program being debugged has been started already.&lt;br /&gt;Start it from the beginning? (y or n) y&lt;br /&gt;Starting program: /home/ytshen/a.out &lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 0&lt;br /&gt;1: i = 0&lt;br /&gt;(gdb) record # 代表我們開始紀錄, 之後才能使用 reverse-step或是相關指令&lt;br /&gt;(gdb) c&lt;br /&gt;Continuing.&lt;br /&gt;ci = 0, t = 1804289383&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 1804289383&lt;br /&gt;1: i = 1&lt;br /&gt;(gdb) c&lt;br /&gt;Continuing.&lt;br /&gt;i = 1, t = 846930886&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 846930886&lt;br /&gt;1: i = 2&lt;br /&gt;(gdb) c&lt;br /&gt;Continuing.&lt;br /&gt;i = 2, t = 1681692777&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 1681692777&lt;br /&gt;1: i = 3&lt;br /&gt;(gdb) c&lt;br /&gt;Continuing.&lt;br /&gt;i = 3, t = 1714636915&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 1714636915&lt;br /&gt;1: i = 4&lt;br /&gt;# 接下來開始進行reverse&lt;br /&gt;(gdb) reverse-continue&lt;br /&gt;Continuing.&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 1681692777&lt;br /&gt;1: i = 3&lt;br /&gt;# 可以看到所有的state都被保留下來&lt;br /&gt;(gdb) reverse-continue&lt;br /&gt;Continuing.&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 846930886&lt;br /&gt;1: i = 2&lt;br /&gt;(gdb) reverse-continue&lt;br /&gt;Continuing.&lt;br /&gt;&lt;br /&gt;Breakpoint 1, main () at tests.c:9&lt;br /&gt;9            int t = random();&lt;br /&gt;2: t = 1804289383&lt;br /&gt;1: i = 1&lt;br /&gt;(gdb)&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;上面就是一個簡單的例子, 利用gdb來進行reverse debugging, 他還有一些簡單的指令&lt;br /&gt; ex:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;"record stop":&amp;nbsp;停止紀錄指令&lt;/li&gt;&lt;li&gt;"record delete": 刪除之前的紀錄&lt;/li&gt;&lt;li&gt;"info record":&amp;nbsp;&lt;/li&gt;&lt;li&gt;"set record stop-at-limit": 設定logging buffer滿之後的行為, 如果是on, 在buffer滿了就會停下來, off則會蓋掉舊得logging指令&lt;/li&gt;&lt;li&gt;"set record insn-number-max":&amp;nbsp;設定紀錄指令的大小, 預設是3292&lt;/li&gt;&lt;li&gt;"reverse-step": 上一步, 如果是function call則會進入function開頭&lt;/li&gt;&lt;li&gt;"reverse-continue": 還原到上一個break point&lt;/li&gt;&lt;li&gt;"reverse-next": 上一步, 但是如果是function call會直接執行完到return&lt;/li&gt;&lt;li&gt;"set exec-direction [forward | reverse]: 設定好方向之後, 可以直接使用continue, next, step&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;span style="font-size: medium;"&gt;Reference&lt;/span&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;em&gt;&amp;nbsp;&lt;a href="http://sourceware.org/gdb/wiki/ReverseDebug"&gt;http://sourceware.org/gdb/wiki/ReverseDebug&lt;/a&gt;&lt;/em&gt;&lt;/li&gt;&lt;li&gt;&lt;em&gt;&lt;a href="http://sourceware.org/gdb/wiki/ReverseDebug"&gt;&lt;/a&gt;&lt;a href="http://sourceware.org/gdb/wiki/ProcessRecord/Tutorial"&gt;http://sourceware.org/gdb/wiki/ProcessRecord/Tutorial&lt;/a&gt;&amp;nbsp;&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-6793288443933370216?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/6793288443933370216/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/gdb-reverse-step-for-gdb.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6793288443933370216'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/6793288443933370216'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/gdb-reverse-step-for-gdb.html' title='[GDB] Reverse step for GDB'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-5807620583629924039</id><published>2011-08-02T01:56:00.001-07:00</published><updated>2011-08-02T01:56:47.068-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>[C] Low level IO primitives</title><content type='html'>&lt;p&gt;Low level IO like open/write/close should call fdatasync() when you want to make sure data is write to disk, because this still keep some data buffered in file descriptor.&lt;/p&gt;&lt;p&gt;And about stdio library like fopen/fwrite/fclose should call fflush() before fdatasync(), because stdio library keep some data buffered in the FILE structure.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-5807620583629924039?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/5807620583629924039/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/08/c-low-level-io-primitives.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5807620583629924039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5807620583629924039'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/08/c-low-level-io-primitives.html' title='[C] Low level IO primitives'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-2525592244415404524</id><published>2011-07-28T20:34:00.001-07:00</published><updated>2011-08-18T07:52:59.868-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>[C++] NULL reference and NULL pointer deference</title><content type='html'>&lt;p&gt;通常如果function是在接受reference的參數, 不像是pointer 需要去檢查是不是NULL,但是下面這種情況卻會造成segmentation fault.&lt;br /&gt;原因是因為deference NULL pointer (ex: *p) 本身就是未定義行為, 而NULL reference只可能出現在未定義行為的地方.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &amp;lt; stdio.h &amp;gt;&lt;br /&gt;struct obj&lt;br /&gt;{&lt;br /&gt;  int t;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void foo(obj &amp;amp;a)&lt;br /&gt;{&lt;br /&gt;  std::cout &amp;lt;&amp;lt; a.t;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  obj *p = NULL;&lt;br /&gt;&lt;br /&gt;  foo(*p);&lt;br /&gt;  return 0;&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;以下的程式就算我把foo裡面的std::cout comment掉, 並且用-O0, 他就不會造成crash, 造理來說*p應該就要crash,&lt;br /&gt;這邊可以看一下輸出的assembly, 就可以理解其實底層實做reference 也是用到pointer, 所以只要沒有真的access NULL pointer, 是不會造成crash&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;                                                                                                         &lt;br /&gt;&lt;br /&gt;struct obj&lt;br /&gt;{&lt;br /&gt;    int t;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void foo(obj &amp;amp;a)&lt;br /&gt;{&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    obj *p = NULL;&lt;br /&gt;&lt;br /&gt;    foo(*p);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;可以看到main裡面assembly, 他其實也只是把pointer當參數傳進去~&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;    movq    $0, -8(%rbp)&lt;br /&gt;    movq    -8(%rbp), %rax&lt;br /&gt;    movq    %rax, %rdi&lt;br /&gt;    call    _Z3fooR3obj&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;雖然可以透過下面的方式去檢查, 但是我覺得這樣寫很奇怪, 畢竟問題不是在foo function.&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;                                                                                                       &lt;br /&gt;&lt;br /&gt;struct obj&lt;br /&gt;{&lt;br /&gt;    int t;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;void foo(obj &amp;amp;a)&lt;br /&gt;{&lt;br /&gt;    if( &amp;amp;a == NULL) {&lt;br /&gt;        std::cout &amp;lt;&amp;lt; "null\n";&lt;br /&gt;        return;&lt;br /&gt;    }&lt;br /&gt;    std::cout &amp;lt;&amp;lt; a.t;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;    obj *p = NULL;&lt;br /&gt;&lt;br /&gt;    foo(*p);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;所以只有caller需要自己去檢查傳進去的pointer是不是NULL&lt;/p&gt;&lt;p&gt;&lt;em&gt;Reference:&amp;nbsp;&lt;br /&gt;&lt;/em&gt;&lt;em&gt;&lt;a href="http://stackoverflow.com/questions/4364536/c-null-reference"&gt;http://stackoverflow.com/questions/4364536/c-null-reference&lt;br /&gt;&lt;/a&gt;&lt;/em&gt;&lt;em&gt;&lt;a href="http://www.nicollet.net/2009/11/can-references-be-null/"&gt;http://www.nicollet.net/2009/11/can-references-be-null/&lt;br /&gt;&lt;/a&gt;&lt;a href="http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&amp;amp;ixPost=17154"&gt;http://discuss.fogcreek.com/joelonsoftware/default.asp?cmd=show&amp;amp;ixPost=17154&lt;/a&gt;&amp;nbsp;&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-2525592244415404524?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/2525592244415404524/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/07/c-null-pointer-deference.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2525592244415404524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2525592244415404524'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/07/c-null-pointer-deference.html' title='[C++] NULL reference and NULL pointer deference'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-5245323713604068434</id><published>2011-07-27T21:40:00.001-07:00</published><updated>2011-07-27T23:07:53.020-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='openssl'/><title type='text'>[C++] Diffie-Hellman Key Exchange (Client API)</title><content type='html'>&lt;p&gt;DHKeyCrypt.h&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#if !defined(dhkeycrypt_include)&lt;br /&gt;&lt;br /&gt;#define dhkeycrypt_include&lt;br /&gt;&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include &lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * Example:&lt;br /&gt; *&lt;br /&gt; * // initial steps&lt;br /&gt; * const char *p, *g, *public_key;&lt;br /&gt; * char *buf;&lt;br /&gt; * int buf_size;&lt;br /&gt; * DHKeyCrypt *key = new DHKeyCrypt(256); // mean generate 256 bits prime&lt;br /&gt; *&lt;br /&gt; * // p, g, public_key will point to the hex representation string&lt;br /&gt; * key-&amp;gt;GenerateKey(&amp;amp;p, &amp;amp;g, &amp;amp;public_key);&lt;br /&gt; *&lt;br /&gt; * // use the 3rd party public key to compute session key&lt;br /&gt; * key-&amp;gt;ComputeKey(other_pubkey);&lt;br /&gt; *&lt;br /&gt; * // usage&lt;br /&gt; * key-&amp;gt;Encode(buf, buf_size); // encode buf&lt;br /&gt; *&lt;br /&gt; */&lt;br /&gt;class DHKeyCrypt&lt;br /&gt;{&lt;br /&gt;private:&lt;br /&gt;    char *m_g[2];&lt;br /&gt;    DH *m_dh;&lt;br /&gt;    char *m_p;&lt;br /&gt;    char *m_pubkey;&lt;br /&gt;    unsigned char *m_session_key;&lt;br /&gt;&lt;br /&gt;    int m_key_len;&lt;br /&gt;    int m_gindex;&lt;br /&gt;&lt;br /&gt;public:&lt;br /&gt;    DHKeyCrypt(int size);&lt;br /&gt;    void GenerateKey(const char **p, const char **g, const char **public_key);&lt;br /&gt;    int ComputeKey(const char *pubkey_3rd);&lt;br /&gt;    void Encode(char *buf, int buf_len);&lt;br /&gt;    ~DHKeyCrypt();&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;#endif&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;DHKeyCrypt.cpp&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;#include "DHKeyCrypt.h"&lt;br /&gt;#include&lt;br /&gt;#include &lt;br /&gt;&lt;br /&gt;/*&lt;br /&gt; * generate size bits prime&lt;br /&gt; */&lt;br /&gt;DHKeyCrypt::DHKeyCrypt(int size) : m_session_key(NULL)&lt;br /&gt;{&lt;br /&gt;    m_g[0] = strdup("2");&lt;br /&gt;    m_g[1] = strdup("5");&lt;br /&gt;    m_gindex = time(NULL) &amp;amp; 1;&lt;br /&gt;    m_dh = DH_generate_parameters(size, m_g[m_gindex][0] - '0', NULL, NULL);&lt;br /&gt;    DH_generate_key(m_dh);&lt;br /&gt;    m_p = BN_bn2hex(m_dh-&amp;gt;p);&lt;br /&gt;    m_pubkey = BN_bn2hex(m_dh-&amp;gt;pub_key);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void DHKeyCrypt::GenerateKey(const char **p, const char **g, const char **public_key)&lt;br /&gt;{&lt;br /&gt;    *p = m_p;&lt;br /&gt;    *g = m_g[m_gindex];&lt;br /&gt;    *public_key = m_pubkey;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int DHKeyCrypt::ComputeKey(const char *pubkey_3rd)&lt;br /&gt;{&lt;br /&gt;    BIGNUM *bn = NULL;&lt;br /&gt;&lt;br /&gt;    if(!BN_hex2bn(&amp;amp;bn, pubkey_3rd))&lt;br /&gt;        return -1;&lt;br /&gt;    m_session_key = new (std::nothrow) unsigned char [DH_size(m_dh)];&lt;br /&gt;    if(!m_session_key) return -1;&lt;br /&gt;    m_key_len = DH_compute_key(m_session_key, bn, m_dh);&lt;br /&gt;    if(m_key_len == -1) return -1;&lt;br /&gt;    /*&lt;br /&gt;    printf("SessionKey: ");&lt;br /&gt;    for(int i=0;  i &lt; m_key_len; i++)&lt;br /&gt;       printf("%02X", m_session_key[i]);&lt;br /&gt;    printf("\n");&lt;br /&gt;    */&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void DHKeyCrypt::Encode(char *buf, int buf_len)&lt;br /&gt;{&lt;br /&gt;    for(int i=0; i &lt; buf_len; i++)&lt;br /&gt;        buf[i] = buf[i] ^ m_session_key[i % m_key_len];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;DHKeyCrypt::~DHKeyCrypt()&lt;br /&gt;{&lt;br /&gt;    OPENSSL_free(m_p);&lt;br /&gt;    OPENSSL_free(m_pubkey);&lt;br /&gt;    free(m_g[0]);&lt;br /&gt;    free(m_g[1]);&lt;br /&gt;    delete [] m_session_key;&lt;br /&gt;    DH_free(m_dh);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-5245323713604068434?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/5245323713604068434/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/07/c-diffie-hellman-key-exchange-client.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5245323713604068434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/5245323713604068434'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/07/c-diffie-hellman-key-exchange-client.html' title='[C++] Diffie-Hellman Key Exchange (Client API)'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-7081957394571822287</id><published>2011-06-29T02:53:00.001-07:00</published><updated>2011-08-18T08:02:58.612-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>[Linux] driver's log</title><content type='html'>&lt;p&gt;dmesg 如果有開syslogd &amp;amp; klogd的話, 會把printk印出的message 寫到/var/log/kern.log之下&lt;br /&gt;關機的方式有好幾種&lt;br /&gt;如果是shutdown -h的話 那會照順序執行/etc/rc0.d/ 下面的script, 簡單而言如果要找關機時發生的錯誤, 應該是可以到 /var/log/kern.loug去找&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-7081957394571822287?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/7081957394571822287/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/06/linux-driver-log.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/7081957394571822287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/7081957394571822287'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/06/linux-driver-log.html' title='[Linux] driver&amp;#39;s log'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-7854881778991265468</id><published>2011-06-10T00:46:00.000-07:00</published><updated>2011-06-10T01:01:24.718-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='c'/><title type='text'>[Linux] vfork &amp; waitpid</title><content type='html'>在Linux底下有vfork &amp;amp; fork 兩種方式可以讓你create child process去作事情, &amp;nbsp;vfork &amp;amp; fork的差別請參照&amp;nbsp;&lt;a href="http://csie-tw.blogspot.com/2009/04/vforkuclinux.html"&gt;http://csie-tw.blogspot.com/2009/04/vforkuclinux.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://csie-tw.blogspot.com/2009/04/vforkuclinux.html"&gt;&lt;/a&gt;最近遇到很奇怪的情形, 就是通常parent process fork child process之後, 要不parent process必須waitpid 去等待child process結束, 不然就是你必須在parent process上面註冊SIGCHLD 的signal handler (這個SIGCHLD會在child process terminated的時候發送給parent process), 結果我在parent process當中居然waitpid return -1, 訊息是no child process! &amp;nbsp;所以猜測parent process在還沒有執行到waitpid的時候, child process就結束了&lt;br /&gt;&lt;br /&gt;所以稍微寫了小程式測試&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;version1: vfork + execv with no signal handler (parent process 在執行waitpid前先sleep)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;waitpid return 0,&amp;nbsp;WEXITSTATUS(status)可以正常拿到child process exit code&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;version1: vfork&amp;nbsp;+ execv&amp;nbsp;with SIGCHLD signal handler&amp;nbsp;(parent process 在執行waitpid前先sleep)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;waitpid return -1, no child process,&amp;nbsp;WEXITSTATUS(status)拿不到child process exit code&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;version1: vfork&amp;nbsp;+ execv&amp;nbsp;with ignore SIGCHLD signal(parent process 在執行waitpid前先sleep)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;waitpid return -1, no child process,&amp;nbsp;WEXITSTATUS(status)拿不到child process exit code&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;所以最後問題在於只要你有註冊SIGCHILD相關處理, 就無法拿到child process exit code!&lt;br /&gt;&lt;br /&gt;另外還有一種情形, 在linux system call的時候, 有甚饃會被系統interrupt, 這時候通常的解法就是retry~&lt;br /&gt;&lt;a href="http://book.chinaunix.net/special/ebook/addisonWesley/APUE2/0201433079/ch10lev1sec5.html"&gt;http://book.chinaunix.net/special/ebook/addisonWesley/APUE2/0201433079/ch10lev1sec5.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-7854881778991265468?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/7854881778991265468/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/06/linux-vfork-waitpid.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/7854881778991265468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/7854881778991265468'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/06/linux-vfork-waitpid.html' title='[Linux] vfork &amp; waitpid'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8421955178164669604</id><published>2011-05-20T21:27:00.000-07:00</published><updated>2011-06-05T05:34:51.029-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='js'/><category scheme='http://www.blogger.com/atom/ns#' term='nodejs'/><title type='text'>[Javascript] Node.js CPU bound action</title><content type='html'>Node.js 是一個base在 V8 javascript engine 上的event-driven server framework, 因為目前V8的限制, 所以他目前只有single thread 在處理所有event.&lt;br /&gt;&lt;br /&gt;所以如果我寫出以下的code, 就會造成單一request block後面的request, 這是一個echo server, 當有資料進來的時候, 會呼叫function(data), 如果我在這個function裡面作一些time consuming的動作, 就會造成其他的request delay.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;var net = require("net");          &lt;br /&gt;// echo server example             &lt;br /&gt;var TCPServer = net.createServer(function (socket){&lt;br /&gt;    // on "data" event             &lt;br /&gt;    socket.on("data", function(data){&lt;br /&gt;        request = data.toString('utf8');&lt;br /&gt;        now = new Date().getTime();&lt;br /&gt;        // it will wait for 5 seconds to block following request                                            &lt;br /&gt;        while(new Date().getTime() &amp;lt; now + 5000) {&lt;br /&gt;           // do nothing           &lt;br /&gt;        }                          &lt;br /&gt;        socket.write(request);     &lt;br /&gt;    });                            &lt;br /&gt;});                                &lt;br /&gt;                                   &lt;br /&gt;TCPServer.listen(7777, "127.0.0.1");&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;所以針對一些cpu bound的運算, 目前我查到的解法有兩種, 第一種就是普通的fork,&lt;br /&gt;fork出child process去執行你要得command, 等到執行結束, 在利用callback繼續下去, 這樣就可以讓CPU bound的運算不至於影響到其他的request.&lt;br /&gt;&lt;pre class="prettyprint"&gt;var net = require("net");         &lt;br /&gt;var sys = require('sys');         &lt;br /&gt;var exec = require('child_process').exec;&lt;br /&gt;                                  &lt;br /&gt;                                  &lt;br /&gt;// echo server example            &lt;br /&gt;var TCPServer = net.createServer(function (socket){              &lt;br /&gt;    sys.debug('new socket coming!');&lt;br /&gt;    socket.on('data', function(d) {&lt;br /&gt;        sys.debug('new data coming ' + d);&lt;br /&gt;        var sleep = exec('sleep 5', function(error, stdout, stderr) {                                                                                                     &lt;br /&gt;            socket.write('finish job: ' + d);&lt;br /&gt;        });                       &lt;br /&gt;    });                           &lt;br /&gt;});                               &lt;br /&gt;                                  &lt;br /&gt;TCPServer.listen(7777, "127.0.0.1");&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Webworker, 這是node.js的某一個ext module, 他是利用unix domain socket來達到IPC (inter process communication), 他提供比較抽象的API, 透過postMessage, onmessage這種API,我下面的實做只提供message傳遞, 當worker事情做完就把結果回傳給server. postMessage 的參數需要以JSON的格式傳過去, 在postMessage的時候可以把file descriptor當第二個參數傳給worker process, 但是這部份我一直無法成功實驗出來...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Server.js&lt;/b&gt;&lt;br /&gt;=================&lt;br /&gt;&lt;pre class="prettyprint"&gt;var net = require("net");                                                                                                                                                 &lt;br /&gt;var sys = require('sys');&lt;br /&gt;var Worker = require('webworker').Worker;&lt;br /&gt;var index = 0;&lt;br /&gt;var workers = [];&lt;br /&gt;var socks = {};&lt;br /&gt;var sock_num = 0;&lt;br /&gt; &lt;br /&gt;for(var i = 0; i &amp;lt; 8; i++) {&lt;br /&gt;    workers.push(new Worker('&lt;absolute path="" to="" worker.js=""&gt;'));&lt;br /&gt;    // when some result message return from worker process&lt;br /&gt;    workers[i].onmessage = function(msg) {&lt;br /&gt;        var sock_index = msg.data.index;&lt;br /&gt;        var result = msg.data.result;&lt;br /&gt;        sys.debug('master: ' + sock_index);&lt;br /&gt;        socks[parseInt(sock_index)].write(result);&lt;br /&gt;    };&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;// echo server example&lt;br /&gt;var TCPServer = net.createServer(function (socket){&lt;br /&gt;    var l = sock_num;&lt;br /&gt; &lt;br /&gt;    sock_num++;&lt;br /&gt;    socks[l] = socket;&lt;br /&gt;    // when client send data&lt;br /&gt;    socket.on('data', function(d) {&lt;br /&gt;        var data = d.toString('utf8').trim();&lt;br /&gt; &lt;br /&gt;        sys.debug(index + ' worker data: ' + data);&lt;br /&gt;        sys.debug('socks: ' + l);&lt;br /&gt;        workers[index].postMessage({'text': data, 'index': index, sock_index: l});&lt;br /&gt;        index++;&lt;br /&gt;    });&lt;br /&gt;    // when client close connection&lt;br /&gt;    socket.on('close', function() {&lt;br /&gt;        sys.debug('delete socks: ' + l);&lt;br /&gt;        delete socks[l];&lt;br /&gt;    });&lt;br /&gt;});&lt;br /&gt; &lt;br /&gt;TCPServer.listen(7777, "127.0.0.1");&lt;br /&gt;&lt;br /&gt;&lt;/absolute&gt;&lt;/pre&gt;&lt;br /&gt;&lt;b&gt;Worker.js&lt;/b&gt;&lt;br /&gt;=================&lt;br /&gt;&lt;pre class="prettyprint"&gt;var http = require('http');    &lt;br /&gt;var net = require('net');      &lt;br /&gt;var sys = require('sys');      &lt;br /&gt;    &lt;br /&gt;function sleep() {&lt;br /&gt;    var now = new Date().getTime();&lt;br /&gt;    // it will wait for 5 seconds to block following request&lt;br /&gt;    while(new Date().getTime() &amp;lt; now + 5000) {&lt;br /&gt;        ;&lt;br /&gt;    }&lt;br /&gt;};  &lt;br /&gt;    &lt;br /&gt;onmessage = function(msg) {    &lt;br /&gt;    sys.debug('worker index: ' + msg.data.index);&lt;br /&gt;    sys.debug('worker sock_index: ' + msg.data.sock_index);&lt;br /&gt;    sys.debug('worker text: ' + msg.data.text);&lt;br /&gt;    &lt;br /&gt;    var result_text = msg.data.text + ' processed\n';&lt;br /&gt;                                                                                                                                                                          &lt;br /&gt;    // time consuming operation&lt;br /&gt;    sleep();&lt;br /&gt;    sys.debug('worker after sleep');&lt;br /&gt;    postMessage({index: msg.data.sock_index, result: result_text});&lt;br /&gt;};  &lt;br /&gt;    &lt;br /&gt;onclose = function() {&lt;br /&gt;    sys.debug('Worker shuttting down.');&lt;br /&gt;};  &lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;下面這是後來gibson試出來的用法~&lt;br /&gt;&lt;b&gt;master.js&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;=====================&lt;br /&gt;&lt;pre class="prettyprint"&gt;var http = require('http');    &lt;br /&gt;var sys = require('sys');                                                                                                                                                  &lt;br /&gt;var path = require('path');&lt;br /&gt;var net = require('net');&lt;br /&gt;var Worker = require('webworker').Worker;&lt;br /&gt;var workers = [];&lt;br /&gt;var wid=0;&lt;br /&gt; &lt;br /&gt;for (var i = 0; i &amp;lt; 8; i++) {&lt;br /&gt;    workers[i] = new Worker(path.join(__dirname, 'worker.js'));&lt;br /&gt;}&lt;br /&gt; &lt;br /&gt;net.createServer(function(socket){      &lt;br /&gt;    socket.pause();&lt;br /&gt;    wid = (++wid) % 8;&lt;br /&gt;    sys.debug('pass to worker '+ wid + ' fd:' + socket.fd);&lt;br /&gt;    workers[wid].postMessage({'wid':wid}, socket.fd);&lt;br /&gt;}).listen(8080);&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;worker.js&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;  =====================  &lt;br /&gt;&lt;pre class="prettyprint"&gt;var http = require('http');    &lt;br /&gt;var sys = require('sys');                                                                                                                                                  &lt;br /&gt;var net = require('net');&lt;br /&gt; &lt;br /&gt;var srv = net.createServer(function(socket){&lt;br /&gt;    socket.on('data', function(data){&lt;br /&gt;        buf = data.toString('utf8');&lt;br /&gt;        socket.write('['+process.pid+'] received: ' + buf); &lt;br /&gt;    });&lt;br /&gt;});&lt;br /&gt; &lt;br /&gt;onmessage = function(msg) {&lt;br /&gt;    sys.debug('worker received msg.data.wid: ' + msg.data.wid);&lt;br /&gt;    sys.debug('worker received msg.fd: ' + msg.fd);&lt;br /&gt;    var socket = net.Stream(msg.fd);&lt;br /&gt;    socket.type = srv.type;&lt;br /&gt;    socket.server = srv;&lt;br /&gt;    socket.resume();&lt;br /&gt;    srv.emit('connection', socket);&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;b&gt;Reference:&lt;/b&gt; &lt;i&gt;http://blog.mixu.net/2011/02/01/understanding-the-node-js-event-loop/&lt;/i&gt; &lt;i&gt;http://blog.std.in/2010/07/08/nodejs-webworker-design/&lt;/i&gt; &lt;i&gt;http://developer.yahoo.com/blogs/ydn/posts/2010/07/multicore_http_server_with_nodejs/&lt;/i&gt; &lt;i&gt;http://nodejs.org/docs/v0.4.7/api/child_processes.html&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8421955178164669604?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8421955178164669604/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/05/javascript-nodejs-cpu-bound-action.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8421955178164669604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8421955178164669604'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/05/javascript-nodejs-cpu-bound-action.html' title='[Javascript] Node.js CPU bound action'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-2714059820101823231</id><published>2011-05-05T08:22:00.000-07:00</published><updated>2011-05-05T08:22:52.443-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><title type='text'>[vim] Display Ansi in vim</title><content type='html'>Download from http://www.vim.org/scripts/script.php?script_id=302&lt;br /&gt;&lt;br /&gt;After download and extract.&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;$ vim AnsiEsc.vba&lt;br /&gt;:so %&lt;br /&gt;:q&lt;br /&gt;&lt;/pre&gt;Then you can use :AnsiEsc to toggles ansi escape sequence highlighting!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;:h ansiesc &lt;/b&gt;for more information.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-2714059820101823231?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/2714059820101823231/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/05/vim-display-ansi-in-vim.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2714059820101823231'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/2714059820101823231'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/05/vim-display-ansi-in-vim.html' title='[vim] Display Ansi in vim'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-3893856270621257256</id><published>2011-05-04T02:41:00.001-07:00</published><updated>2011-05-04T02:44:43.200-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>[Linux] setuid</title><content type='html'>When you want to execute a program which has root privilege. Here is what you can do.&lt;br /&gt;First program.c&lt;br /&gt;&lt;pre class="prettyprint"&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include&lt;br /&gt;#include                                                            &lt;br /&gt;&lt;br /&gt;int main()&lt;br /&gt;{&lt;br /&gt;  setuid( 0 );&lt;br /&gt;  system( "&amp;lt;program&amp;gt;" );&lt;br /&gt;&lt;br /&gt;  return 0;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Then in the shell enter the following commands:&lt;br /&gt;&lt;pre class="prettyprint"&gt;$ gcc -o program program.c&lt;br /&gt;$ sudo chown root program&lt;br /&gt;$ sudo u+s program&lt;br /&gt;&lt;/pre&gt;Then you can execute program to execute your program under root privilege!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-3893856270621257256?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/3893856270621257256/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/05/linux-setuid.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3893856270621257256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/3893856270621257256'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/05/linux-setuid.html' title='[Linux] setuid'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2475333239846385273.post-8040989142251036840</id><published>2011-04-23T01:09:00.001-07:00</published><updated>2011-04-23T01:23:23.239-07:00</updated><title type='text'>[book] Beautiful Code - population count</title><content type='html'>&lt;p&gt;面試的時候 有時會問到, 給你一個數字, 求出他二進位表示當中 有多少個1&lt;/p&gt;&lt;p&gt;ex:&lt;/p&gt;&lt;p&gt;5&lt;sub&gt;10&lt;/sub&gt; = 101&lt;sub&gt;2&lt;/sub&gt; 所以答案就是2 (因為有兩個1)&lt;/p&gt;&lt;p&gt;跳過最直接的解法 (就是一位一位去數), 下面這個方式應該是有看過這題目會提出的解法&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;int pop(unsigned int n)&lt;br /&gt;{&lt;br /&gt;    int count = 0;&lt;br /&gt;    while(n) {&lt;br /&gt;        n = n &amp; (n - 1);&lt;br /&gt;        count++;&lt;br /&gt;    }&lt;br /&gt;    return count;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;建表的方法&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;int pop(unsigned int n)&lt;br /&gt;{&lt;br /&gt;  char table[256] = {0, 1, 1, ...};&lt;br /&gt;  return table[n &amp;amp; 0xff] + table[(n&amp;gt;&amp;gt;8)&amp;amp;0xff] + table[(n&amp;gt;&amp;gt;16)&amp;amp;0xff] + table[n&amp;gt;&amp;gt;24];&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;但是其實還有其他也蠻有趣的解法~ 就是常常會聽到的divide &amp;amp; conquere&lt;/p&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;int pop2(unsigned int n)&lt;br /&gt;{&lt;br /&gt;    n = (n &amp; 0x55555555) + ((n &gt;&gt; 1) &amp; 0x55555555);&lt;br /&gt;    n = (n &amp; 0x33333333) + ((n &gt;&gt; 2) &amp; 0x33333333);&lt;br /&gt;    n = (n &amp; 0x0f0f0f0f) + ((n &gt;&gt; 4) &amp; 0x0f0f0f0f);&lt;br /&gt;    n = (n &amp; 0x00ff00ff) + ((n &gt;&gt; 8) &amp; 0x00ff00ff);&lt;br /&gt;    n = (n &amp; 0x0000ffff) + ((n &gt;&gt; 16) &amp; 0x0000ffff);&lt;br /&gt;    return n;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;int pop3(unsigned int n)&lt;br /&gt;{&lt;br /&gt;    n = (n &amp; 0x55555555) + ((n &gt;&gt; 1) &amp; 0x55555555);&lt;br /&gt;    n = (n &amp; 0x33333333) + ((n &gt;&gt; 2) &amp; 0x33333333);&lt;br /&gt;    // 因為 4bit 互加, 不會干擾到前面的欄位, 也就是不會進位前一個4 bites&lt;br /&gt;    // 順便清除 結果8 bits的前4個bits&lt;br /&gt;    n = (n + (n &gt;&gt; 4)) &amp; 0x0f0f0f0f;&lt;br /&gt;    n = (n + (n &gt;&gt; 8));&lt;br /&gt;    n = (n + (n &gt;&gt; 16));&lt;br /&gt;    // 因為最高只會是32, 所以最後只要取出我們要得bits(6個bits)&lt;br /&gt;    return (n &amp; 0x3f);&lt;br /&gt;}&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;有了這些, 接下來如果我們要比較x, y誰的1比較多, 當然可以先算出個別的數字在比較&lt;br /&gt;如果要求出兩個數字總共有幾個1, 也可以利用上面4 bits相加部會溢位, 在第三步就先加起來~&lt;br /&gt;相減的話, 可以利用pop(x) - pop(y) = pop(x) - (32 - pop(y')) = pop(x) + pop(y') - 32&lt;br /&gt;y' 是y 的1補數&lt;/p&gt;&lt;p&gt;不過書上提供另一種作法, 就是先把雙方重複的1先刪掉, 在一起數&lt;/p&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;int pop_comp(unsigned int x, unsigned int y)&lt;br /&gt;{&lt;br /&gt;    unsigned int x1 = x &amp; (~y);&lt;br /&gt;    unsigned int y1 = y &amp; (~x);&lt;br /&gt;&lt;br /&gt;    while(1) {&lt;br /&gt;        if(x1 == 0) return y1?-1:0;&lt;br /&gt;        if(y1 == 0) return 1;&lt;br /&gt;        x1 = x1 &amp; (x1 - 1);&lt;br /&gt;        y1 = y1 &amp; (y1 - 1);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;而且接下來要求出Hamming distance (兩個數字的二進位當中有幾位元不一樣)也很容易&lt;br /&gt;先求出兩個數字的xor, 在找出他二進位有幾個1&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2475333239846385273-8040989142251036840?l=shenyute.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://shenyute.blogspot.com/feeds/8040989142251036840/comments/default' title='張貼意見'/><link rel='replies' type='text/html' href='http://shenyute.blogspot.com/2011/04/book-beautiful-code-population-count.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8040989142251036840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2475333239846385273/posts/default/8040989142251036840'/><link rel='alternate' type='text/html' href='http://shenyute.blogspot.com/2011/04/book-beautiful-code-population-count.html' title='[book] Beautiful Code - population count'/><author><name>Yu-Teh Shen</name><uri>https://profiles.google.com/102249536116095884743</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-w864sSdusEw/AAAAAAAAAAI/AAAAAAAAJ2o/-n9VNwrDIuo/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry></feed>
