メモ代わり。てきとーに。 いや、ですからてきとーですって。 2年前ぐらいにPythonあたりでメールくれた方、ごめんなさい。メール紛失してしまい無視した形になってしまいました。。。

2008年2月23日土曜日

[Apache][CodeReading] Apache2.2.8コードリーディング23日目

今日もApache2.2.8コードリーディング。

ちょっと気になったので、今どのぐらいこなしたのか大雑把に計算してみた。
Apacheには、ざっと20000シンボルあって、で読破した分は294シンボル。
23日間で約1.3%終えたことになる。

すると、ざっと4.5年かかる計算。
今のところ毎日できているが、もうじき毎日読めなくなりそうなので
4.5年以上はかかることに。

まぁ、面白いから別にいいや。

で、今日は

  • apr_pollset_add()(select)/Apache2.2.8
  • HAS_SOCKETマクロ/Apache2.2.8
  • HAS_PIPESマクロ/Apache2.2.8
  • APR_FILES_AS_SOCKETSマクロ/Apache2.2.8
  • get_event()(port)/Apache2.2.8
  • get_epoll_event()(epoll)/Apache2.2.8
  • apr_pollset_add()(poll)/Apache2.2.8
  • get_event()(poll)/Apache2.2.8
  • APR_POLLNVALマクロ/Apache2.2.8
  • APR_POLLHUPマクロ/Apache2.2.8
  • APR_POLLERRマクロ/Apache2.2.8
  • APR_POLLPRIマクロ/Apache2.2.8
らへんを読んだ。
昨日読んだapr_pollset_add()の別バージョン。
処理内容はほぼ一緒。

apr_pollset_add()のselectバージョンは、
リングを持っていない。その代わりreadset、writeset、exceptsetを持っていて、
リングに追加する代わりにそれらのビットをオン・オフする感じ。


まぁ、昨日やったところなんで、特に面白いところは無い感じ。


おしまい
.

[Python][お勉強] Python入門(53) - __class__と___bases__

__class__
インスタンス全て__class__という属性を持っている。
この__class__は、インスタンスがどのクラスのインスタンスなのかが記録されている。


>>> class C1:
... pass
...
>>> a = C1()
>>> a.__class__
<class>
>>>
 



__bases__
クラスが持っていて、どのスーパークラスにリンクされているのかを保持している。

>>> class C1:
... pass
...
>>> class C2(C1): pass
...
>>> class C3(C1,C2): pass
...
>>> C3.__bases__
(<class>, <class>)
>>> C2.__bases__
(<class>,)
>>> C1.__bases__
()
>>>
 

な感じー。



おしまい。
.

[Python][お勉強] Python入門(52) - 名前空間の実態

モジュールと同様にクラス、インスタンス属性もディクショナリで管理される。


>>> class C1:
... def aaa(self):
... self.data1 = 'aaa'
...
>>> a = C1()
>>> a.__dict__
{}
>>> a.aaa()
>>> a.__dict__
{'data1': 'aaa'}
>>> a.X = [1,2,3,4,5]
>>> a.__dict__
{'X': [1, 2, 3, 4, 5], 'data1': 'aaa'}
>>>
 

この__dict__はインスタンス毎に作られる。




ふーん。

おしまい。
.

[Python][お勉強] Python入門(51) - クラス、インスタンスにおける名前空間の注意事項

今日もPythonお勉強。

クラス、インスタンスにおける注意事項から。

特に気をつけるのは、「.」を使って指定された場合とそうでない場合。
「.」を使って指定された名前を修飾名といい、「.」を使わないで指定された名前を
非修飾名という。

修飾名と非修飾名ではスコープ決定ルールが違う。
非修飾名の場合にはLEGBルールが適用される。
修飾名の場合には特定のオブジェクトの名前空間に属する。

非修飾名のルール


X = 100
 

といったコードの場合、Xは非修飾名。
この場合、その変数がどのスコープに属するかをまずローカルスコープから順に
ネストスコープ、グローバルスコープ、ビルトインスコープで検索される。
いわゆるLEGBルール。

修飾名のルール

hogehoge.taratara = 'hogetarapii'
 

といったコードの場合にはtarataraは修飾名。
この際は属性の検索はhogehogeより上位のクラスで検索が行われることはない。


hogehoge.taratara
 

といったコードの場合、hogehogeオブジェクトのオブジェクトツリーが検索される。
最初にhogehogeオブジェクトが検索され、次にその上位のクラスが検索される。
また、hogehogeがクラスやインスタンスでなく、モジュールであった場合は当然であるが、
オブジェクトツリーで検索は行われない。


値が代入される場所
修飾名、非修飾名にはそれぞれいくつかの種類がある。
そのためどこに属する属性なのかがわかりにくくなる場合がある。
が、Pythonでは「どこで代入するか」が重要な意味があるとのこと。

その面白い例

>>> X = 11
>>>
>>> class C1:
... X = 22 # クラスの属性
... def m(self):
... X = 33 # メソッドのローカル変数
... self.X = 44 # インスタンス属性
...
>>> def f():
... X = 55 # 関数のローカル変数
...
>>> def g():
... print X # モジュールのグローバル変数
...
>>>
 

6箇所で使われているXという名の変数は、最初の1つを除いて全て別の変数。



変数の扱いについては要注意。



おしまい。
.

2008年2月22日金曜日

[Apache][CodeReading] Apache2.2.8コードリーディング22日目

今日もApache2.2.8コードリーディング。

今日やったところは、

  • apr_pollset_add()(kqueue)/Apache2.2.8
  • apr_pollset_add()(epoll)/Apache2.2.8
  • APR_EBADFマクロ/Apache2.2.8
  • apr_pollset_remove()/Apache2.2.8
  • apr_os_sock_t/Apache2.2.8
  • NETWAREマクロ/Apache2.2.8
  • __BEOS__マクロ/Apache2.2.8
  • OS2マクロ/Apache2.2.8
  • WIN32マクロ/Apache2.2.8
  • pollset_unlock_rings()/Apache2.2.8
  • APR_RING_INSERT_TAILマクロ/Apache2.2.8
  • APR_RING_SPLICE_TAILマクロ/Apache2.2.8
  • APR_RING_SPLICE_BEFOREマクロ/Apache2.2.8
あたり。

で、まだ初期化部分。
DEBUGログを出力後にIOWAITするところ。
IOWAITするためにpollするんだけど、それを実行しようとしている部分。

リングの構造はさらっと19日目ぐらいにやった。
apr_pollset_tは環境により5種類の実装のうちひとつがconfigureなりで選択される。
今日読んだapr_pollset_add()もapr_pollset_remove()も5種類。

apr_pollset_remove()
apr_pollset_removeは、指定されたポールセット(apr_pollset_t)から指定されたディスクリプタ(apr_pollfd_t)を削除する。
ringをapr_pollset_t構造体に持つパターン(epoll、kqueue、portが使える環境)の場合は、
query_ringというリングから対象ディスクリプタを削除し、dead_ringというリングに対象ディスクリプタを登録する、
ということをやっている。
もちろん、epoll、kqueue、portからも削除する。


epoll、kqueue、portのいずれも使えず、poll関数が使える場合はringを保持しない。
代わりにquery_setというapr_pollfd_t構造体へのポインタの配列を保持する。
その配列から、対象ディスクリプタを削除する。

epoll、kqueue、portのいずれも使えず、さらにpoll関数も使用不可の場合も、ringを保持しないapr_pollset_tが使用される。
またpoll関数が使える場合と同様に、query_setほ保持し、apr_pollfd_t構造体へのポインタの配列から対象ディスクリプタを削除する。



apr_pollset_add()
まだ、epoll版とkqueue版しか読んでいない。

まず最初にfree_ringから空き領域を取得する。
空きが無ければapr_palloc()で領域を確保後、その領域を初期化(APR_RING_ELEM_INIT)する。
その領域にパラメータで指定されたディスクリプタをセットし、epoll_ctlを使用してepollにイベントを追加する。
うまく追加できればquery_ringにfree_ringから取得した領域を追加し、
うまく追加できなければfree_ringに取得した領域を返す。

で、そのソースが以下。

138 APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
139 const apr_pollfd_t *descriptor)
140 {
141 struct epoll_event ev;
142 int ret = -1;
143 pfd_elem_t *elem;
144 apr_status_t rv = APR_SUCCESS;
145
146 pollset_lock_rings();
147
148 if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) {
149 elem = APR_RING_FIRST(&(pollset->free_ring));
150 APR_RING_REMOVE(elem, link);
151 }
152 else {
153 elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
154 APR_RING_ELEM_INIT(elem, link);
155 }
156 elem->pfd = *descriptor;
157
158 ev.events = get_epoll_event(descriptor->reqevents);
159 ev.data.ptr = elem;
160 if (descriptor->desc_type == APR_POLL_SOCKET) {
161 ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
162 descriptor->desc.s->socketdes, &ev);
163 }
164 else {
165 ret = epoll_ctl(pollset->epoll_fd, EPOLL_CTL_ADD,
166 descriptor->desc.f->filedes, &ev);
167 }
168
169 if (0 != ret) {
170 rv = APR_EBADF;
171 APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link);
172 }
173 else {
174 pollset->nelts++;
175 APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link);
176 }
177
178 pollset_unlock_rings();
179
180 return rv;
181 }
 

APR_RING_EMPTYで空かどうかチェックし、空でなければ先頭の領域を取得する。
空だった場合は、領域確保後、APR_RING_ELEM_INITマクロで初期化するのだが、
この、APR_RING_ELEM_INITが良くわからない。
やっていることは、elem->link->nextとelem->link->prevにelemを代入しているだけ。
その初期化自体は良いのだが、epoll_ctl後、free_ringか、query_ringにすぐに追加してしまうので
APR_RING_ELEM_INIT自体無意味に思える。
最初はAPR_RING_INSERT_TAILマクロでnextとprevに何かしらのポインタが必要なのかと思ったが、
そうでもない。

APR_RING_INSERT_TAILは、

#define APR_RING_SPLICE_BEFORE(lep, ep1, epN, link) do { \
APR_RING_NEXT((epN), link) = (lep); \
APR_RING_PREV((ep1), link) = APR_RING_PREV((lep), link); \
APR_RING_NEXT(APR_RING_PREV((lep), link), link) = (ep1); \
APR_RING_PREV((lep), link) = (epN); \
} while (0)
 

こんな感じに置き換わる。
で、

APR_RING_NEXT((epN), link) = (lep)
 

は、

elem->link = APR_SENTINEL(hp)
 

に、そして、

APR_RING_PREV((ep1), link = APR_RING_PREV((lep), link);
 

は、

elem->link->prev = APR_SENTINEL(hp)->link->prev;
 

に置き換わる。
つまり、せっかく初期化してもすぐに上書きしてしまうので、
無意味な気がする・・・・。

理由があるとすれば、RINGを構成する構造体に何かしらの変更が加わった場合に対処しやすいように
といった感じか。
といってもそれも考えにくい・・・。

うーむ。

わからん。
とりあえず、今度APR_RING_ELEM_INITをコメントアウトして動かしてみようかと思う。

いつかやるタスク。
  • APR_RING_ELEM_INITをapr_pollset_add関数から削除して動かしてみる。
あと、ついでに、
apr_palloc()関数も。
apr_palloc()は空きノードが無かった場合allocator_alloc()をつかってmallocするんだが、
このときNULLが返ってきた場合apr_palloc()はNULLを返す。
なのにもかかわらず、apr_palloc()を使用しているところのほとんどがNULLチェックをしていない。
うーむ。
Segmentation Faltですか??
ということで、
  • malloc失敗するパターンで、apr_palloc()を読んでみる。
というのもやってみようと思う。





おしまい。
.

[Python][お勉強] Python入門(50) - 演算子のオーバーロード

演算子のオーバーロードから。


演算子のオーバーロードを行うには、演算子に対応付けられたメソッドを対象クラスに実装してやる必要がある。
以下、演算子と演算子に対応付けられたメソッドの一部。

演算子・処理対応するメソッド名メソッド起動の例
+__add__A + B
-__sub__A - B
/__div__A / B
*__mul__A * B
|__or__A | B
インスタンスの作成__init__Class()
ガーベージコレクション__del__
出力・型変換__repr__,__str__print X, `X`, str(X)
インスタンスの呼び出し__call__X()
.を使用した属性へのアクセス__getattr__X.abc
属性への値の代入__setattr__X.abc = value
インデクシング__getitem__X[key]
シーケンスの特定の要素への代入__setitem__X[key] = value
シーケンスの長さ取得__len__len(X)
比較__cmp__X == Y, X < Y
小なり__lt__ X < Y(__cmp__でも対応可)
同等か__eq__ X == Y(__cmp__でも対応可)
インスタンスが右側に使われた場合の+演算子__radd__Noninstance + X
上書き加算__iadd__X += Y(__add__でも対応可)
ループ、反復__iter__forループ, X in Y


演算子が呼ばれると、対応する__XXX__といった前後にアンダースコアがつけられた関数が呼ばれる。また、そういったメソッドを他の通常のメソッドと区別して「フックメソッド」と呼ばれる。


__getitem__
__getitem__はインデクシングの処理に対応する「フックメソッド」。
対象クラスに定義されているか、対象クラスの継承ツリーに定義されていないとコールされない。

以下、__getitem__の例

>>> class C1:
... def __getitem__(self, index):
... return index * 100
...
>>> a = C1()
>>> a[0]
0
>>> a[1]
100
>>> a[2]
200
>>> a[3]
300
>>>
 


この__getitem__メソッドはループにも対応可。

>>> for b in a:
... if b > 1000: break
... print b
...
0
100
200
300
400
500
600
700
800
900
1000
>>>
 

このようにループでも__getitem__が呼ばれる。が、Pythonの中では__getitem__メソッドを実行する
前に、__iter__メソッドが実装されていないか調べている。もし、__iter__があった場合で、ループ処理
の場合には__iter__がコールされる。


__iter__
__iter__は「イテレータプロトコル」をサポートしたオブジェクト(イテレータオブジェクト)を返す。

以下、その例。

>>> class C1:
... def __init__(self, start, stop):
... self.value = start - 1
... self.stop = stop
... def __iter__(self):
... return self
... def next(self):
... if self.value == self.stop:
... raise StopIteration
... self.value += 1
... return self.value ** 2
...
>>> for aa in C1(1,10):
... print aa
...
1
4
9
16
25
36
49
64
81
100
>>>

 

上記の例では__iter__はselfを返している。
__iter__はイテレータオブジェクトを返す必要があるので、self自身にnextメソッドを持たせる必要がある。
nextメソッドでは現在保持している値に1を加算し、その加算結果を2乗している。

__iter__はループ処理自体を複数回繰り返すことには対応していない。

>>> aa = C1(1,5)
>>> for bb in aa:
... print bb
...
1
4
9
16
25
>>> for bb in aa:
... print bb
...
>>>
 

複数回実行するにはもう一度オブジェクトを作成しなければならない。


__getattr__
通常の「インスタンスの属性へのアクセス」では呼ばれないとのこと。

>>> class C1:
... def __getattr__(self, name):
... print "name=[", name , "]"
... return self.X
... X = [1,2,3,4]
...
>>> a = C1()
>>> a.X
[1, 2, 3, 4]
>>> a.Y
name=[ Y ]
[1, 2, 3, 4]
>>>
 

ほんとだ。
XはC1クラスに存在するので、__getattr__はコールされない。
オブジェクトツリーも含めて存在しない場合にのみコールされるとのこと。
上記Yはどこにも存在しないので、__getattr__が呼ばれている。



__setattr__
<オブジェクト>.属性 = 値
といった形の場合、コールされるメソッド。
実際には、

<オブジェクト>.__setattr__(属性名、値)
 

というコードが実行される。
このメソッドで注意しなければいけないところは、
__setattr__メソッド内で属性へ代入すると無限ループになってしまう、という点。
つまり、

def __setattr__(self, attr, value):
self.X = value
 

とすると、__setattr__メソッドの中でさらに__setattr__が呼ばれる。
いつまでたっても終了しない。

そこで、こういった場合、__dict__を使用するとのこと。

>>> class C1:
... def __setattr__(self, attr, value):
... if attr == 'age':
... self.__dict__[attr] = value
... else:
... raise AttributeError, attr + ' not allowed'
...
>>> a = C1()
>>> a.age = 1000
>>> a.age
1000
>>> a.ageage = 1000
Traceback (most recent call last):
File "", line 1, in ?
File "", line 6, in __setattr__
AttributeError: ageage not allowed
>>>
 

な感じ。


__repr__、__str__
str()や、repr()で別の動作をさせたいときに実装する。


__call__
インスタンスを関数のように「呼び出し」たときにコールされる。

>>> class C1:
... def __call__(self):
... return str(self)
...
>>> a = C1()
>>> a()
'<__main__.c1>'
>>>
 


コールバックハンドラなどを作成するときに使える。



__del__
インスタンスが破棄されるときに呼ばれる。
リファレンスがどこにも存在しなくなり、ガーベージコレクタによって破棄されるときにコールされる
メソッド。







おしまい。
.

[Apache][CodeReading] Apache2.2.8コードリーディング21日目

昨日もApache2.2.8コードリーディング。

昨日はメモするの忘れた。

昨日やった分は、

  • APR_RING_REMOVEマクロ/Apache2.2.8
  • APR_RING_UNSPLICEマクロ/Apache2.2.8
  • APR_RING_PREVマクロ/Apache2.2.8
  • APR_RING_EMPTYマクロ/Apache2.2.8
  • APR_NOTFOUND定数/Apache2.2.8
  • APR_POLL_SOCKET定数/Apache2.2.8
あたり。
マクロだけしかページは作ってない。

で、これはどの辺かというと、
Apacheの初期化部分・・・。
まだ初期化。
まだListenしてない。。


詳細は今日の分も合わせてメモ予定。




.

2008年2月21日木曜日

[Python][お勉強] Python入門(49) - メソッド

つづいて、メソッドをやる。

メソッド
ほぼ関数と一緒。classステートメントにネストされているかどうかと、
第一引数が特殊な引数であるということのみ違うらしい。

メソッドへのアクセス


インスタンス名.メソッド名(引数,...)
 

のようにアクセスする。
これはPythonにより、自動で、

クラス名.メソッド名(インスタンス名,引数,...)
 

に読み替えられる。
ということは、好ましいかどうかは別にして

クラス名.メソッド名(インスタンス名,引数,...)
 

と呼び出すこともできるということ。

>>> class C1:
... def method(self, x):
... self.X = x
...
>>> i1 = C1()
>>> C1.method(i1,10)
>>> i1.X
10
>>>
 

perl5までのクラスと一緒な感じか。


ふーん。

おしまい。
.

[Python][お勉強] Python入門(48) - classステートメント

今日もPythonのお勉強。

今日はclassステートメントからやる。

classステートメント
クラスオブジェクトを生成する。
書式は以下な感じ。


class <name>(superclass,...):
data = value
def method(self, ...):
localValue = value1
self.member = value2

 

1行目
クラス名(name)へのクラスオブジェクトの代入
2行目
クラス属性(data)の生成、クラス属性への代入
3行目
メソッド名(method)へのメソッドの代入
4行目
methodメソッドのローカル変数への代入
5行目
インスタンス属性(member)への代入。

となっている。
1行目の()内にスーパークラスを列挙する。無い場合には()自体書かない。


クラス属性にアクセスするには、

<クラス名>.<クラス属性名>
<クラスオブジェクト>.<クラス属性名>
 

のように指定する。
1番目の方法を実際にやってみると、

>>> class C1:
... X = [1,2,3,4]
...
>>> C1.X
[1, 2, 3, 4]
>>>
 

といった感じ。
2番目の方法を実際にやってみると、

>>> a = C1
>>> a.X
[1, 2, 3, 4]
 

な感じか。
2番目の方は、クラスオブジェクトを「呼び出し」ているわけでは無いので、
クラスオブジェクトへのリファレンスがコピーされている模様。
現に、

>>> a.X = []
>>> C1.X
[]
>>>
 

となっている。


書式の5行目はインスタンス属性となる。インスタンス属性なのでクラスオブジェクトには影響しない。
また別のインスタンスオブジェクトにも影響しない。

で、やってみる。

>>> class C1:
... def method(self, x):
... self.X = x
...
>>> i1 = C1()
>>> i2 = C1()
>>> i1.method(10)
>>> i1.X
10
>>> i2.X
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: C1 instance has no attribute 'X'
>>> i2.method(20)
>>> i2.X
20
>>> i1.X
10
>>> C1.X
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: class C1 has no attribute 'X'
>>>



ふーん。
そもそもクラスオブジェクトにインスタンス属性は持たせられないので、
「インスタンス属性なのでクラスオブジェクトには影響しない。」は確かめようが無い。



へー。

おしまい。
.

2008年2月20日水曜日

[Apache][CodeReading] Apache2.2.8コードリーディング20日目

今日もApache2.2.8コードリーディング。


今日はapr_pollset_create()周り。

作ったページは

  • apr_pollset_create()/Apache2.2.8
  • APR_NO_DESC定数/Apache2.2.8
  • APR_EINVAL定数/Apache2.2.8

らへん。

apr_pollset_createは、環境毎に定義が異なり、apr_pollset_t構造体と同じく5種類ある。
やっていることは、ほぼ一緒。apr_pollset_t用の領域を確保し、
epollが使える環境であれば、epollの初期化を、
kqueueが使える環境であれば、kqueueの初期化を、
portが使える環境であれば、portの初期化を、
上記どれでもなく、pollが使える環境であればpoll用の初期化処理を、
さらにpollも使えない場合はselect用の初期化処理を行う。


5種類のうちどれを使うかはconfigureにより静的に決定される。

apr_pollset_t構造体のリング以外は特に面白くはない。
一応それぞれ見ておく。

epollが使える環境の場合
httpd-2.2.8/srclib/apr/poll/unix/epoll.cに記述されているapr_pollset_create関数とapr_pollset_t構造体が選択される。
apr_pollset_t構造体は、

59 struct apr_pollset_t
60 {
61 apr_pool_t *pool;
62 apr_uint32_t nelts;
63 apr_uint32_t nalloc;
64 int epoll_fd;
65 struct epoll_event *pollset;
66 apr_pollfd_t *result_set;
67 apr_uint32_t flags;
70 apr_thread_mutex_t *ring_lock;
73 APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
75 APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
78 APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
79 };
 

となっていて、epoll特有の構造体epoll_eventが入っている。
まだ、初期化部分しか見ていないのでどのように使われるのか、さっぱりわからないリングももっている。

epollの時のapr_pollset_create()は以下な感じ。

88 APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
89 apr_uint32_t size,
90 apr_pool_t *p,
91 apr_uint32_t flags)
92 {
93 apr_status_t rv;
94 int fd;
95
96 fd = epoll_create(size);
97 if (fd < 0) {
98 *pollset = NULL;
99 return errno;
100 }
101
102 *pollset = apr_palloc(p, sizeof(**pollset));
104 if (flags & APR_POLLSET_THREADSAFE &&
105 ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
106 APR_THREAD_MUTEX_DEFAULT,
107 p) != APR_SUCCESS))) {
108 *pollset = NULL;
109 return rv;
110 }
117 (*pollset)->nelts = 0;
118 (*pollset)->nalloc = size;
119 (*pollset)->flags = flags;
120 (*pollset)->pool = p;
121 (*pollset)->epoll_fd = fd;
122 (*pollset)->pollset = apr_palloc(p, size * sizeof(struct epoll_event));
123 apr_pool_cleanup_register(p, *pollset, backend_cleanup, backend_cleanup);
124 (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
125
126 APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
127 APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
128 APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
129
130 return APR_SUCCESS;
131 }

やっていることは、apr_pollset_tの領域を確保し、そのメンバの領域も確保する。
apr_pollset_tの各要素の値を初期化し、apr_pool_cleanup_registerでpool破棄時の動作を登録。
epollのディスクリプタを作成し、epoll_event構造体用の領域も確保する。

apr_pool_cleanup_registerで引数として渡されているbackend_cleanup関数では、
epollのディスクリプタをクローズしているだけ。

kqueueが使える環境の場合
httpd-2.2.8/srclib/apr/poll/unix/kqueue.cのapr_pollset_create関数とapr_pollset_t構造体が
使用される。
apr_pollset_t構造体は、

37 struct apr_pollset_t
38 {
39 apr_pool_t *pool;
40 apr_uint32_t nelts;
41 apr_uint32_t nalloc;
42 int kqueue_fd;
43 struct kevent kevent;
44 struct kevent *ke_set;
45 apr_pollfd_t *result_set;
46 apr_uint32_t flags;
49 apr_thread_mutex_t *ring_lock;
52 APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
54 APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
57 APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
58 };


epollのときとほとんど一緒。違うのは、

42 int kqueue_fd;
43 struct kevent kevent;
44 struct kevent *ke_set;

だけ。

apr_pollset_createは以下な感じ。

67 APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
68 apr_uint32_t size,
69 apr_pool_t *p,
70 apr_uint32_t flags)
71 {
72 apr_status_t rv = APR_SUCCESS;
73 *pollset = apr_palloc(p, sizeof(**pollset));
75 if (flags & APR_POLLSET_THREADSAFE &&
76 ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
77 APR_THREAD_MUTEX_DEFAULT,
78 p) != APR_SUCCESS))) {
79 *pollset = NULL;
80 return rv;
81 }
88 (*pollset)->nelts = 0;
89 (*pollset)->nalloc = size;
90 (*pollset)->flags = flags;
91 (*pollset)->pool = p;
92
93 (*pollset)->ke_set =
94 (struct kevent *) apr_palloc(p, size * sizeof(struct kevent));
95
96 memset((*pollset)->ke_set, 0, size * sizeof(struct kevent));
97
98 (*pollset)->kqueue_fd = kqueue();
99
100 if ((*pollset)->kqueue_fd == -1) {
101 return APR_ENOMEM;
102 }
103
104 apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup,
105 apr_pool_cleanup_null);
106
107 (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
108
109 APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
110 APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
111 APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
112
113 return rv;
114 }


やっていることも、epollの場合とほとんど一緒。
違うのはepollの代わりにカーネルキューになっていること。
backend_cleanupではカーネルキューのfdをクローズしているだけ。


portが使える環境の場合
これはまったく知らないのだが、恐らくSolarisの場合。/dev/poll?
httpd-2.2.8/srclib/apr/poll/unix/port.cのapr_pollset_create関数とapr_pollset_t構造体が使用される。
portのときのapr_pollset_t構造体は以下のとおり。

62 struct apr_pollset_t
63 {
64 apr_pool_t *pool;
65 apr_uint32_t nelts;
66 apr_uint32_t nalloc;
67 int port_fd;
68 port_event_t *port_set;
69 apr_pollfd_t *result_set;
70 apr_uint32_t flags;
73 apr_thread_mutex_t *ring_lock;
76 APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
77 APR_RING_HEAD(pfd_add_ring_t, pfd_elem_t) add_ring;
79 APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
82 APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
83 };
 

これも、epollの場合とほとんど一緒。
違うのは、

67 int port_fd;
68 port_event_t *port_set;

のport用構造体と変数。
あと、リング要素がひとつ追加になっているところ。

apr_pollset_create関数は以下な感じ。

92 APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
93 apr_uint32_t size,
94 apr_pool_t *p,
95 apr_uint32_t flags)
96 {
97 apr_status_t rv = APR_SUCCESS;
98 *pollset = apr_palloc(p, sizeof(**pollset));
100 if (flags & APR_POLLSET_THREADSAFE &&
101 ((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
102 APR_THREAD_MUTEX_DEFAULT,
103 p) != APR_SUCCESS))) {
104 *pollset = NULL;
105 return rv;
106 }
113 (*pollset)->nelts = 0;
114 (*pollset)->nalloc = size;
115 (*pollset)->flags = flags;
116 (*pollset)->pool = p;
117
118 (*pollset)->port_set = apr_palloc(p, size * sizeof(port_event_t));
119
120 (*pollset)->port_fd = port_create();
121
122 if ((*pollset)->port_fd < 0) {
123 return APR_ENOMEM;
124 }
125
126 apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup,
127 apr_pool_cleanup_null);
128
129 (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
130
131 APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
132 APR_RING_INIT(&(*pollset)->add_ring, pfd_elem_t, link);
133 APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
134 APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
135
136 return rv;
137 }
 

これもepollとやっていることはほとんど一緒。
違うのはepollの代わりにport用の初期化処理が入ったというのと、
add_ringの初期化が入っただけ。

このadd_ringはなんとなく興味あり。
backend_cleanup関数でもport_fdをクローズしているだけ。


pollが使える環境の場合
今どきのlinuxでは使うことはないが、自分の開発環境は2.4系なのでこれが選択されてしまう。
httpd-2.2.8/srclib/apr/poll/unix/poll.cのapr_pollset_create関数とapr_pollset_t構造体が使用
される。
apr_pollset_t構造体は以下のとおり。

150 struct apr_pollset_t
151 {
152 apr_pool_t *pool;
153 apr_uint32_t nelts;
154 apr_uint32_t nalloc;
155 struct pollfd *pollset;
156 apr_pollfd_t *query_set;
157 apr_pollfd_t *result_set;
158 };


ずいぶんと単純になる。
基本的にはepollと同じだが、リングもなければmutexももっていない。
代わりにapr_pollfd_tのポインタが1つ増え、poll用の構造体が入っている。

で、apr_pollset_create関数は以下のとおり。

160 APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
161 apr_uint32_t size,
162 apr_pool_t *p,
163 apr_uint32_t flags)
164 {
165 if (flags & APR_POLLSET_THREADSAFE) {
166 *pollset = NULL;
167 return APR_ENOTIMPL;
168 }
169
170 *pollset = apr_palloc(p, sizeof(**pollset));
171 (*pollset)->nelts = 0;
172 (*pollset)->nalloc = size;
173 (*pollset)->pool = p;
174 (*pollset)->pollset = apr_palloc(p, size * sizeof(struct pollfd));
175 (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
176 (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
177 return APR_SUCCESS;
178 }
 

poll用apr_pollset_t構造体同様、より簡単になった。
backend_cleanup関数もない。


selectしか使えない環境
最後に、pollすらも使えない環境用。
監視・通知機構にselectを使用する。
httpd-2.2.8/srclib/apr/poll/unix/select.cのapr_pollset_create関数とapr_pollset_t構造体が使用
される。

apr_pollset_t構造体は以下のとおり。

struct apr_pollset_t
{
apr_pool_t *pool;

apr_uint32_t nelts;
apr_uint32_t nalloc;
fd_set readset, writeset, exceptset;
int maxfd;
apr_pollfd_t *query_set;
apr_pollfd_t *result_set;
};
 

pollの場合と同じく単純になっている。
select用に、fd_setをもつ。

apr_pollset_create関数は以下のとおり。

187 APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
188 apr_uint32_t size,
189 apr_pool_t *p,
190 apr_uint32_t flags)
191 {
192 if (flags & APR_POLLSET_THREADSAFE) {
193 *pollset = NULL;
194 return APR_ENOTIMPL;
195 }
202 *pollset = apr_palloc(p, sizeof(**pollset));
203 (*pollset)->nelts = 0;
204 (*pollset)->nalloc = size;
205 (*pollset)->pool = p;
206 FD_ZERO(&((*pollset)->readset));
207 FD_ZERO(&((*pollset)->writeset));
208 FD_ZERO(&((*pollset)->exceptset));
209 (*pollset)->maxfd = 0;
213 (*pollset)->query_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
214 (*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
215
216 return APR_SUCCESS;
217 }
 

FD_ZEROぐらいか。


この辺は、selectによる監視・通知が効率が悪いってんで、各環境でいろいろな代替手段が
開発されてしまった話の被害者部分か。。

とにかくこの辺はリングのデータ構造がどのように使われるのか、
その辺が面白そうなところ。







.

[Python][お勉強] Python入門(47) - クラスの特徴その3

クラスでは演算子のオーバーロードができる。

オーバーロード。

要点は以下のとおり。

  • 演算子のオーバーロードは__x__という前後にアンダースコアがついた名前のメソッドを使う。
  • ビルトインオブジェクトに使用される演算子のほとんど全てをオーバーロードできる
以下な感じにコーディングする。(+演算子の場合)

>>> class C1:
... def __add__(self, x):
... return self.x + x
... def __init__(self, x):
... self.x = x
...
>>> a = C1()
>>> a = C1(10)
>>> a + 2
12
>>>





おしまい。
.

[Python][お勉強] Python入門(46) - クラスの特徴その2

クラスは継承によってカスタマイズできる。

まぁ、継承できるということ。サブクラスが作成できるということ。

継承時の要点は以下のとおり。

  • サブクラス作成の際はclassステートメントの見出し行にスーパークラス名を列挙する。
  • サブクラスはスーパークラスの属性を継承する。
  • インスタンスは作成元になったクラスだけでなく、その上位にあるクラスからも全ての属性を継承する。
  • <オブジェクト>.<属性>という式があるとその度に逐一属性の検索が行われる。
  • サブクラスで属性に変更を加えてもスーパークラスには影響しない。


あとは特になし。



おしまい。
.










.

[Python][お勉強] Python入門(45) - クラスの特徴その1

インスタンスオブジェクトはひとつのクラスから複数作ることができる。

ひとつのクラスのコードを基に、クラスオブジェクトとインスタンスオブジェクトの2種類のオブジェクトが生成される。クラスオブジェクトはインスタンスオブジェクトのいわば「工場」の役割を果たす。
クラスのコードからまず作られるのはクラスオブジェクトで、そのクラスオブジェクトからインスタンスオブジェクトが作成される。
インスタンスオブジェクトを生成するためにはクラスオブジェクトの「呼び出し」操作を行う。
「呼び出し」操作を行うたびに新たなインスタンスオブジェクトが作成される。


クラスオブジェクト
1) classステートメントが実行され、クラスオブジェクトが生成される。生成結果はクラス名に代入される。
2) classステートメントの内側で値の代入が行われた変数はクラスの属性になる。
3) ステート情報を保持する変数もメソッドもクラスの属性になる。

インスタンスオブジェクト
1)クラスオブジェクトを関数のように「呼び出す」とインスタンスオブジェクトが作成される。


>>> class C1:
... X = 10
... def aaa(self, x):
... print x, self.X
...
>>> a = C1() # クラスオブジェクト「呼び出し」。aにはインスタンスオブジェクトが代入される。
 


2)インスタンスオブジェクトはクラス属性全てを継承し、独立した名前空間になる。
3)メソッドの第一引数selfを利用すればインスタンス属性を作成することができる。

>>> class C1:
... def __init__(self,x):
... self.X = x #インスタンス属性X
...
>>> a = C1(10)
>>> b = C1(20)
>>> c = C1(30)
>>> a.X # インスタンス属性にアクセス
10
>>> b.X # インスタンス属性にアクセス
20
>>> c.X # インスタンス属性にアクセス
30
>>>
 





おしまい。
.

[Python][お勉強] Python入門(44) - Pythonでのオブジェクト指向プログラミング概要

今日はPythonでのオブジェクト指向プログラミング概要から。


Pythonでのオブジェクト指向プログラミング
Pythonにおいてはあらゆるものがオブジェクト。であるが、Pythonにおけるオブジェクト指向プログラミングは、あくまでオプションである、とのこと。


クラス
Pythonにおいて「クラス」は、関数やモジュールと同じような「プログラムの構成単位」である。
他の構成単位と違う特徴は以下のとおり。

  • 1つのクラスを基に複数のオブジェクトを作ることができる
  • 継承によってカスタマイズできる。
  • 演算子のオーバーロードができる。

属性へのアクセス
他の構成単位と同じような形でアクセスできる。

<オブジェクト>.<属性>
 

といった形。
また、上記のように指定した場合、「オブジェクトツリー」の中から属性が検索される。
スーパークラスを上、サブクラスまたはインスタンスを下とし、クラス定義時に左から右へスーパークラスを指定したとすると、検索の優先順位は「下」から「上」へ、「左」から「右」への順。


インスタンスとオブジェクト
Pythonにおいてはインスタンスオブジェクト(インスタンス)とクラスオブジェクト(クラス)は
まったく型の違うオブジェクトとして扱われる。

クラスオブジェクト(クラス)はインスタンスの雛形として機能し、インスタンスはクラスオブジェクトから
属性(データ、関数など)を全て継承する。

インスタンスオブジェクト(インスタンス)は、プログラム中での現実世界の物事に対応するものとして扱われる。個々のインスタンス毎に異なるデータが保持される。

インスタンスは元になったクラスから属性を継承する。


クラスを作るには
classステートメントを使用する。

class C1:
def method1(x):
pass

class C2:
def method2(x):
pass

class C3(C1,C2):
def method3(x):
pass
 

最初のclassステートメントはC1というクラスオブジェクトを生成する。
2番目のclassステートメントはC2というクラスオブジェクトを生成する。
3番目のclassステートメントはC3というC1とC2を継承したクラスオブジェクトを生成する。

クラスオブジェクトが生成されるときの要点を以下に記す。
  • classステートメントが実行されると、クラスオブジェクトが生成される。
  • クラスが呼び出されると、インスタンスオブジェクトが生成される。
  • インスタンスは基になったクラスと自動的にリンクされる。
  • クラスはスーパークラスにリンクされる。
  • スーパークラスはclassステートメントの見出し行で括弧を使用して指定する。
  • スーパークラスの優先順位は括弧の中の並び順で決まる。

クラスの属性
  • classステートメントの中で値の代入が行われた属性は通常クラスの属性になる。
  • classステートメントの中の関数の中で、selfという特殊引数を使って値が代入された属性は、通常インスタンスの属性になる。

__init__メソッド
クラスの中に__init__メソッドが定義されている場合、クラス生成時に自動的にこの__init__メソッドが実行される。

class C1:
def __init__(self, x):
self.name = x
 

__init__の第一引数selfはPythonにより自動的にインスタンスが渡される。
第二引数以降のパラメータ(上記だとx)は、インスタンス生成時に指定したパラメータが渡される。


>>> a = C1('aaa') # インスタンスの生成
>>> a.name #インスタンスの属性にアクセス
'aaa'
>>>
 








おしまい。
.

2008年2月19日火曜日

[Apache][CodeReading] Apache2.2.8コードリーディング19日目(2)

今日もApache2.2.8コードリーディング。

今日読んだところは、

  • APR_RING_SENTINELマクロ/Apache2.2.8
  • APR_RING_LASTマクロ/Apache2.2.8
  • APR_OFFSETOFマクロ/Apache2.2.8
  • CRAY2定数/Apache2.2.8
  • LINUX定数/Apache2.2.8
  • CRAY定数/Apache2.2.8
  • APR_RING_FIRSTマクロ/Apache2.2.8
  • APR_STRINGIFY_HELPERマクロ/Apache2.2.8
  • APR_STRINGIFYマクロ/Apache2.2.8
ら辺。

apr_pollset_t構造体は環境によって定義が違う。

kqueueを使える環境用(FreeBSD、今や*BSD?)、
epoll用(Linuxカーネル2.5.44以降)、
portが使える環境用(Solarisか)、
pollが使える環境用、
selectしか使えない環境用の5種類ある。

ほとんどメンバは一緒なんだけど、poll、select用以外の環境用のapr_pollset_tは、
リングを持っている。
このリングを定義しているものが、
APR_RING_HEADマクロ、今日読んだAPR_RING_SENTINELマクロ、APR_RING_FIRSTマクロ、APR_RING_LASTマクロあたり。

このリングがなかなか素敵。

ざっと簡単に言うと
「headを持つ構造体」と「リストを構成する構造体」が別なのにもかかわらず、
「headを持つ構造体」を無理やり「リストを構成する構造体」に「キャスト」して
双方向リストを「リング」にしている
っていう感じ・・・。
うーむ・・・。

とりあえず画像を入れてみる・・・。


双方向リストは、通常右の画像のようにつながっている。







これにこのリストの先頭へのポインタと最後尾へのポインタを持つlinkと同じ構造体をheadとして入れると、右の2番目の画像のように最後尾(左側のelem)のnextの値と、先頭(右側のelem)のprevの値が決められない。
最後尾(左側のelem)のnextと先頭(右側のelem)のprevにNULLを入れておく、なんてことでも良いが、それだとhead部も含めてリングとして操作できない。

つまり、先頭(右側)→prev→prevとして最後尾(左側)を指すことができないし、最後尾(左側)→next→nextとやって先頭(右側)の指すことができない。



そこで、ファントム(幽霊、で良い?)を用意する。head用にバーチャルなelemを用意する。それが右の図。
こうしておくことでheadも含めて全ての要素をリングとして扱うことができる。



赤い矢印の指すポイントを仮にSENTINELと名づけよう。
このバーチャルなelemを用意するのにheadのアドレスからSENTINELを算出しなければならないのだが、それはAPR_RING_SENTINELというマクロでやっている。
elemのlink要素のオフセット値をheadのアドレスから差し引いた値がSENTINELになる。
こうしてSENTINELからheadまでの距離とelemの先頭アドレスからlink要素までの距離を等しくする
ことでSENTINELをあたかもelemの先頭アドレスとして扱えるようになる。

結果、最後尾→next→nextというアクセスや、先頭→prev→prevというアクセスが可能になる。

ちなみになんでSENTINELというかというと、headから算出できる値なもんで、いわゆる番兵の役割
を果たすからなのではないかと・・・・。(てきとー)

また、SENTINELを算出するときに、構造体のメンバのオフセット値を求めなくてはならないのだが、
Linuxなんかだと、offsetof関数があるんで問題ないのだが、offsetof関数が無い環境の場合はなか
なか素敵なコードが定義される。

それが下記。

((unsigned int)&(((struct xxx *)NULL)->link))


なんてことを構造体メンバのオフセット値を取得するためにやっている。(xxxは適当)
Apacheのソース以外でも見たことがあるような気がするが、それは置いといて、
ぱっと見、NULLがあって気持ちわるい。

が、Linuxでもばっちり動く。

これは、struct xxxの先頭アドレスをとりあえず0番地にして、
struct xxxのメンバのアドレスを取得してみると、あら不思議。
オフセットになっている

というテクニックだか常套手段だかなんだか良く知らない。
でこのオフセット取得をやっているのがAPR_OFFSETOFマクロ。apr_general.hに書かれている。

あとは特になしな感じ。
敢えて言うなら、

APR_STRINGIFYマクロか。

といっても、文字列化マクロなだけ。

#define APR_STRINGIFY(n) #n


な感じ。本当はもう一段階階層が深いけど。



おしまい。
.

[Python][お勉強] Python入門(43) - import、fromステートメントで文字列を指定する

import、fromステートメントではモジュール名を指定するが、
時としてimportするモジュールを動的に決定したい場合があるそうな。

その場合はざっと、

  • execステートメントを使う
  • __import__関数を使う
を使う方法があるとのこと。

execステートメントを使った例
abcという名のモジュールがあったとする。
モジュール名に文字列を指定すると、、、

>>> import "abc"
File "<stdin>", line 1
import "abc"
^
SyntaxError: invalid syntax
>>>
 

となる。
そこでexecステートメントを使用する。

>>> exec "import abc"
>>> abc.X
[1, 2, 3, 4, 5]
>>>
 

execを使えばモジュール名を文字列で指定できる。


__import__ビルトイン関数を使う例

>>> zzz = __import__("abc")
>>> zzz.X
[1, 2, 3, 4, 5]
>>>
 

な感じ。
__import__関数はモジュールオブジェクトを返すので戻り値を代入する変数が必要。

また、execステートメントでは実行する度にコードのコンパイルが必要になるので、
パフォーマンスが低いとのこと。パフォーマンスのことを考えれば__import__関数を
使った方が良いとのこと。



ふーん。


おしまい。
.

[Python][お勉強] Python入門(42) - メタプログラムのために

Pythonのお勉強。

今日はメタプログラムのために利用できる事柄から。

メタプログラムとは?
プログラムの上位にあるプログラムのこと。

ここでは他のモジュールを管理・操作するプログラム、
プログラムがプログラムを調べてそれを操作する(イントロスペクション)
ようなプログラムの作成に利用できる事柄をやる。
Cで言うところのlibbfdあたりを使ってがんばるプログラム?JavaだとMethodあたり?な感じか。

Pythonでやってみる
まず、操作対象のモジュールを作る。


$ cat abc.py

X = [1,2,3,4,5]

def func(x):
print x
 

とりあえず、こんなモジュールを用意。

で、やってみる。
最初は__dict__というビルトインディクショナリを使用して属性にアクセス。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import abc
>>> abc.__dict__['X']
[1, 2, 3, 4, 5]
>>> abc.__dict__['func'](10)
10
>>>
 


ふむふむ。
次は、sys.modulesを使用してアクセス。

>>> import sys
>>> sys.modules['abc'].X
[1, 2, 3, 4, 5]
>>> sys.modules['abc'].func(10)
10
>>>
 

なるほど。
で、次はビルトイン関数を利用する方法。

>>> getattr(abc, 'X')
[1, 2, 3, 4, 5]
>>> getattr(abc, 'func')(10)
10
>>>
 




ふーん。


おしまい。
.

[Apache][CodeReading] Apache2.2.8コードリーディング19日目(1)

昨日読んだapr_thread_mutex_createの中で、
pthread_mutexattr関連を使っているところでちょっとひっかかった。

確かpthread_mutexattr_t構造体の領域はdestroy後触っちゃいけなかった気が・・・。
manによるとLinuxThreadでは何もしないと書いてあるが。

apr_thread_mutex_create()の中で、

54     if (flags & APR_THREAD_MUTEX_NESTED) {
55 pthread_mutexattr_t mattr;
56
57 rv = pthread_mutexattr_init(&mattr);
58 if (rv) return rv;
59
60 rv = pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
61 if (rv) {
62 pthread_mutexattr_destroy(&mattr);
63 return rv;
64 }
65
66 rv = pthread_mutex_init(&new_mutex->mutex, &mattr);
67
68 pthread_mutexattr_destroy(&mattr);
69
 
なんていうふうに使われている。
mattrは自動変数。
つまりdestroyした後、スタックの積み具合によって対象の領域を触ってしまうのでは?
と思ってしまった。

で、気になったんでphtreadのソースを拝見。

int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)
{
if (!mutex) return EINVAL;
if (attr && attr->pshared == PTHREAD_PROCESS_SHARED) return ENOSYS;

mutex->lock = 0;
mutex->recursion = 0;
mutex->kind = attr ? attr->kind : PTHREAD_MUTEX_DEFAULT;
mutex->owner = NOHANDLE;
mutex->event = mkevent(0, 0);
if (mutex->event < 0) return ENOSPC;
return 0;
}
 

見てみると、なーんてことは無い。
attrが指定されていたら、そのkindをコピーして
後は用無し。

なーんだ。
つまらん。

.

2008年2月18日月曜日

[Apache][CodeReading] Apache2.2.8コードリーディング18日目(2)

今日読んだところは、

  • apr_thread_mutex_create()/Apache2.2.8
  • apr_pool_cleanup_null()/Apache2.2.8
  • thread_mutex_cleanup()/Apache2.2.8
  • apr_pcalloc()/Apache2.2.8
  • APR_POOL__FILE_LINE__マクロ/Apache2.2.8
  • apr_pcalloc_debug()/Apache2.2.8
  • APR_POOL_DEBUG_VERBOSE_ALLOC定数/Apache2.2.8
  • pool_alloc()/Apache2.2.8
  • SIZEOF_DEBUG_NODE_Tマクロ/Apache2.2.8
  • debug_node_t構造体/Apache2.2.8
  • DOXYGEN定数/Apache2.2.8
  • HAVE_PTHREAD_MUTEX_RECURSIVE定数/Apache2.2.8
  • APR_THREAD_MUTEX_UNNESTED定数/Apache2.2.8
  • APR_THREAD_MUTEX_DEFAULT定数/Apache2.2.8
  • APR_THREAD_MUTEX_NESTED定数/Apache2.2.8
  • APR_ENOTIMPL定数/Apache2.2.8
  • APR_POLLSET_THREADSAFE定数/Apache2.2.8
  • APR_RING_ENTRYマクロ/Apache2.2.8
のあたり。
まぁまぁ大きめのところは、
apr_pcallocとapr_thread_mutex_createぐらい。
といってもたいしたことをしていないが・・・。


apr_pcalloc()
apr_pcalloc関数はapr_pallocでサイズを確保後memsetで0クリアしているだけ。
APR_POOL_DEBUGが定義されていると、apr_pcallocの実態がapr_pcalloc_debug関数になる。
apr_pcalloc_debugはapr_pallocは使わずに、mallocを使用して領域を確保する。
確保する際はalloc数をカウントし、またパラメータに渡されたpoolの親子関係をチェックする。
APR_POOL_DEBUGにAPR_POOL_DEBUG_VERBOSE_ALLOCのビットがOnになっていると、
apr_pcalloc_debugの中で詳細なログを出力するようになる。


apr_thread_mutex_create()
apr_thread_mutex_create関数はパラメータで渡されたpoolを使用し、pthread_mutexを作成、初期化する。
APR_THREAD_MUTEX_NESTEDがflagsに指定された場合でpthreadがネストに対応していない場合は、APR_ENOTIMPLエラーを返す。
APR_THREAD_MUTEX_NESTEDがflagsに指定された場合でpthreadがネストに対応している場合は、
mutexattrをRECURSIVEに設定し、pthread_mutexを初期化する。
APR_THREAD_MUTEX_NESTEDがflagsに指定されていない場合は、
mutexattrは指定せずに、pthread_mutexを初期化する。



apr_pcalloc関数の方はcallocなだけに0クリアしているだけだし、
apr_thread_mutex_createの方は、pthreadを初期化しているだけ
な感じ。


うーむ。
まだ序章・・・、いや前書きかも。
.

[Apache][CodeReading] Apache2.2.8コードリーディング18日目(1)

今日もApache2.2.8コードリーディング。

どうでもいいことだが、
何も考えずにctagsでタグファイルを作ると、ジャンプできない関数がいっぱい。

だもんで、


$ ctags -R Apacheのソースディレクトリ \
--regex-c=/^APR_DECLARE\([a-zA-Z0-9_]+\)[ \t]*(ap[ru]_[a-zA-Z0-9_]+)\(.*$/\1/i
 

とやってます。

もっといい方法あるのかな???

--
これじゃだめだー。
APR_DECLARE_NONSTDとかも必要か。

--
doxygenがキーワードか???

--
doxygenがtagsファイル作ってくれると期待したけどだめっぽい。
とりあえず、doxygen.confの内容を参考に、

--regex-c=/^APR_[A-Z_]+\([a-zA-Z0-9_]+\)[ \t]*(ap[ru]_[a-zA-Z0-9_]+)\(.*$/\1/i
 

でやることに。。。

--追記:2008/2/24
APUシリーズもあるんで、

--regex-c=/^AP[RU]_[A-Z_]+\([a-zA-Z0-9_]+\)[ \t]*(ap[ru]_[a-zA-Z0-9_]+)\(.*$/\1/i
 

な感じか。

.

[Python][お勉強] Python入門(41) - モジュールに別名をつける

importステートメントやfromステートメントにはモジュールに別名をつけることができる。
その別名は、インポートしたそのファイルの中だけで有効。

importでの別名のつけ方は以下のとおり。


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dir1.hebo as hebohebo
hebo loading
hebo done
>>>
 

これでheboheboという名でdir1.heboモジュールにアクセスできる。

注意点としては、dir1.heboという名でアクセスできなくなっているということ。

>>> dir1.hebo.hebohebo('a')
Traceback (most recent call last):
File "", line 1, in ?
NameError: name 'dir1' is not defined
>>> hebohebo.hebohebo('a')
hebohebo call( a )
>>>
 


これは、

>>> import dir1.hebo
>>> hebohebo = dir1.hebo
>>> del dir1.hebo
>>>
 

というコードと同等のことが行われたことを示す。



fromステートメントでの別名のつけ方は、

>>> from dir1.hebo import hebohebo as shobo
hebo loading
hebo done
>>>
 

のように行う。
すると、dir1.hebo.hebohebo関数をshoboという名でアクセスできる。


>>> shobo('aaa')
hebohebo call( aaa )
>>>
 







おしまい。
.

[Python][お勉強] Python入門(40) - サーチパスをプログラムの中から変更する

プログラムの中からサーチパスを変更するには、
sysモジュールを使用する。

sysモジュールのpath属性の値を変更することでサーチパスを変えることができる。

ということで、やってみる。


>>> sys.path
['', '/usr/lib/python24.zip', '/usr/lib/python2.4', '/usr/lib/python2.4/plat-linux2',
'/usr/lib/python2.4/lib-tk', '/usr/lib/python2.4/lib-dynload',
'/usr/local/lib/python2.4/site-packages',
'/usr/lib/python2.4/site-packages',
'/var/lib/python-support/python2.4']
>>>
 


今、こんな感じ。
で変更してみる。

>>> sys.path = []
>>> sys.path
[]
>>>
 

何もない状態に変更。これで昨日作ったdir1.heboモジュールも探せない筈。


>>> import dir1.hebo
Traceback (most recent call last):
File "", line 1, in ?
ImportError: No module named dir1.hebo
>>>
 

よし、探せない。

今度は、dir1.heboモジュールをheboだけでインポートできるようにsys.pathを変更する。

>>> sys.path.append('./dir1')
>>> import hebo
hebo loading
hebo done
>>>
 

うむ。
インポートできた。



注意点
sys.pathの値の変更は、対話型セッションまたはプログラムが終了すれば無効になる。




おしまい。
.

[Python][お勉強] Python入門(39) - __name__属性

今日もPythonのお勉強。

今日は__name__属性から。

__name__属性は、あらゆるモジュールが必ず持っている属性。
トップレベルとして機能する場合は"__main__"という値になっている。
その他の場合には、モジュール名(インポートステートメントで使用されたもの)が値になっている。

ということで、早速見てみる。


$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> __name__
'__main__'
>>>
 

トップレベルでは__main__になっている。

次は昨日作ったheboモジュールをインポートして、そのモジュールの__name__属性の値を見てみる。

>>> import dir1.hebo
hebo loading
hebo done
>>> dir1.hebo.__name__
'dir1.hebo'
>>> dir1.__name__
'dir1'
>>>
 

ふむ。なるほど。



おしまい。
.

2008年2月17日日曜日

[Apache][CodeReading] Apache2.2.8コードリーディング17日目

今日も引き続きApache2.2.8をコードリーディング。

今日は昨日見つけた間違えを修正すべく、
apr_pollset_t構造体周りを読み直し。

今日作ったページは

  • APR_RING_HEADマクロ/Apache2.2.8
  • POLLSET_USES_SELECT定数/Apache2.2.8
  • POLLSET_USES_KQUEUE定数/Apache2.2.8
  • POLLSET_USES_EPOLL定数/Apache2.2.8
  • POLLSET_USES_POLL定数/Apache2.2.8
  • HAVE_EPOLL定数/Apache2.2.8
  • HAVE_PORT_CREATE定数/Apache2.2.8
  • HAVE_KQUEUE定数/Apache2.2.8
あたりだけ。全て定数・マクロなんでAPR_RING_HEAD以外は面白みなし。
APR_RING_HEADで定義される構造体を使っている部分を見ないとなんともいえないが、
ちょっとわくわくな感じか。それとも期待はずれか。。。


結局今日はあんまり腰をすえてじっくり読むことができなかった。。。
うーむ。残念。




.

[その他] MyMiniCity

わーい。

ちょっと大きめのビルが建った。
工場らしきものも4つになった。
ちなみに今1400位。


http://atkonn.myminicity.com/
http://atkonn.myminicity.com/ind
http://atkonn.myminicity.com/tra
http://atkonn.myminicity.com/sec

[mod_chxj][携帯] mod_chxj 0.8.5へ向けて

CentOS5.1では確認した。
あとは、

  • Debian-etch
  • Debian-sarge
  • Fedora-8
あたりをとりあえず確認したいところ。。


.

[Python][お勉強] Python入門(38) - パッケージ

今日はパッケージから。


パッケージとは
Pythonで言う、「パッケージ」とは、通常、sysモジュールのpath属性に記録されているサーチバスのディレクトリの__init__.pyファイルが置いてある「サブディレクトリ」のこと。

また、ディレクトリパスを指定してインポートすることを「パッケージインポート」と呼ぶ。



パッケージインポートしてみる。

パッケージインポートするには、モジュールの「パス」を指定する。
「パス」の指定には、ディレクトリセパレータに「.」(ドット)を使用する。

早速やってみる。
まず、カレントディレクトリに、dir1ディレクトリを作成。


$ mkdir dir1
$ ls
dir1/
 


で、dir1以下に行き、空の__init__.pyファイルを作成。

$ cd dir1
$ touch __init__.py
 


で、へぼモジュールを作成。中身はこんな感じ。

$ cat hebo.py
print "hebo loading"

def hebohebo(x):
print "hebohebo call(", x, ")"

print "hebo done"
 


そしたら、最初のディレクトリに戻って、

$ cd ..
 

pythonを起動しトップレベルを開く。でインポートしてみる。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dir1.hebo
hebo loading
hebo done
>>> dir1.hebo.hebohebo("hebo")
hebohebo call( hebo )
>>>
 


できた。

この場合、パッケージは「サブディレクトリ」であるdir1にあたる。


__init__.pyファイル
パッケージインポートする場合、「サブディレクトリ」には必ず__init__.pyファイルを置かなければならない。そうしないとインポートが行えない。

ということで、__init__.pyファイルを削除してインポートしてみる。

$ rm dir1/__init__.*
$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dir1.hebo
Traceback (most recent call last):
File "", line 1, in ?
ImportError: No module named dir1.hebo
>>>
 

怒られた。


__init__.pyファイルは普通のモジュールファイルで、Pythonのコードを中に書き込むことができる。
最低限、空でも良いので「サブディレクトリ」には__init__.pyファイルが存在しないとインポートできない。

__init__.pyファイルは通常パッケージインポートの際の初期化処理に利用される。つまり、__init__.pyファイルはパッケージインポートの際、中のコードが実行される。



パッケージの名前空間
パッケージインポートを行うと、指定されたディレクトリパスのディレクトリ毎に名前空間が作成される。

dir1.hebo
 

とあった場合には、dir1の名前空間と、heboモジュールの名前空間がネストされた状態で作成される。
dir1の名前空間には、ディレクトリdir1の__init__.pyで代入処理が行われた変数が全て属する。

ということで、またもややってみる。
__init__.pyの中で、Xという名の変数を用意。

$ cat dir1/__init__.py
X=100
 

で、インポートして変数Xにアクセスしてみる。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import dir1.hebo
hebo loading
hebo done
>>> dir1.X
100
>>>
 

ほんとだー。


__all__属性

from XXXX import *
 

という形でパッケージインポートされた際、どのパッケージをコピー対象とするかを__all__属性を使用して設定することができる。
__all__属性を使用しなかった場合は、インポートされるのは__init__.pyで作成された変数のみ。
サブディレクトリが自動的にインポートされるということはない。

これもまたやってみる。
まずは、__all__属性未指定。

$ cat dir1/__init__.py
X=100
 

で、fromステートメントの*版でインポート。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from dir1 import *
>>> import sys
>>> sys.modules.keys()
['dir1', 'copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'posixpath',
'encodings.codecs', 'os.path', '_codecs', 'encodings.exceptions', 'stat', 'zipimport',
'warnings', 'encodings.types', 'UserDict', 'encodings.utf_8', 'sys', 'codecs',
'readline', 'types', 'signal', 'linecache', 'posix', 'encodings.aliases', 'exceptions', 'os']
>>>
 

__all__属性未指定時はこんな感じになっている。
こんどは__all__属性を指定してみる。
__init__.pyはこんな感じ。

$ cat dir1/__init__.py
X=100
__all__ = ["hebo"]
 


早速インポート。

$ python
Python 2.4.4 (#2, Apr 5 2007, 20:11:18)
[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from dir1 import *
hebo loading
hebo done
>>> import sys
>>> sys.modules.keys()
['dir1', 'copy_reg', '__main__', 'site', '__builtin__', 'encodings', 'posixpath',
'encodings.codecs', 'os.path', '_codecs', 'encodings.exceptions', 'dir1.hebo',
'stat', 'zipimport', 'warnings', 'encodings.types', 'UserDict', 'encodings.utf_8',
'sys', 'codecs', 'readline', 'types', 'signal', 'linecache', 'posix', 'encodings.aliases',
'exceptions', 'os']
>>>
 

こんどはdir1.heboも入っている。



ふーん。

おしまい。
.