※書き直しました。(2009/2/16)
http://mt.orz.at/archives/2009/02/tokyo-tyrantsol-2.html こちらの記事をどうぞ。
最初に断っておきますが、このやり方はとてもよろしくない方法で対応しています。
本来ならばEPOLL関連の関数に準ずる形でエミュレートするのが正しい方法だと思うのですが、力不足によりttutl.cの中に#ifdefでSolaris用に処理を追加するという暴挙に出てしまいました(´・д・`)
ですので、参考にしてはいけません。
言い訳をするとですね、waitの中でONESHOTフラグでない場合は再登録(port_assosiate)するという方法が動かなかったのです。後できちんと調べてmyconfの修正だけでいけるようにガンバリマス(*・ε・*)
・・・今書いてて思うのですが、ttの場合エミュレートしないといけないepoll系の関数は3つしかなくて、epoll_create()は最初の初期化、epoll_ctlは監視の登録/解除、epoll_waitは読み込み可能なFDを返す、という至極単純な動作なので自前である程度のフラグを管理すればどんな方法でも動くはずだと思いました。
というわけでソースを載せていきます。
対象としたソースは最新版ではなくて恐縮なのですが、1.1.11です。
まずはmyconf.hでSunOSの場合の定義を追加します。
94行目くらいを以下のように修正します。
#if !defined(_SYS_LINUX_) && !defined(_SYS_FREEBSD_) && !defined(_SYS_MACOSX_) && !defined(_SYS_SUNOS_) #error ======================================= #error Your platform is not supported. Sorry. #error ======================================= #endif
212行目くらいでSunOSの場合にマクロを新たに定義するようにします。なんとなく元ソースの流儀に従ってみましたが、単純にSunOSの場合はTTUSESOLEVENTPORTSを定義するだけで大丈夫なはずです。loadavgのヘッダファイルを読み込みます。
#if defined(_SYS_FREEBSD_) || defined(_SYS_MACOSX_) #define TTUSEKQUEUE 1 #define TTUSESOLEVENTPORTS 0 #elif defined(_SYS_SUNOS_) #include <sys/loadavg.h> #define TTUSEKQUEUE 0 #define TTUSESOLEVENTPORTS 1 #else #include <sys/epoll.h> #define TTUSEKQUEUE 0 #define TTUSESOLEVENTPORTS 0 #endif
258行目くらい(上記のコードを足しているので、当然ながらずれています) epoll emulationの所の最初の#ifの条件にTTUSESOLEVENTPORTSをORで追加します。EPOLLOUTはSolarisの場合は4だから定数値が異なってしまいますが、この値を直接使うわけではないので気にしない方向で。
#if TTUSEKQUEUE || TTUSESOLEVENTPORTS
次はmyconf.cを修正します。ソースの最後に以下のコードを追加します。無駄なコードが入っているので、後で削ります・・。あと、perrorではなくttservlogを使った方が良いと思います。
#if TTUSESOLEVENTPORTS
#include <port.h>
int _tt_epoll_create(int size) {
int port = port_create();
if (port < 0) {
perror("port_create failure");
return -1;
}
return port;
}
int _tt_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) {
if (op == EPOLL_CTL_ADD || op == EPOLL_CTL_MOD) {
if (event->events & EPOLLIN) {
int result = port_associate(epfd, PORT_SOURCE_FD, fd, POLLIN, NULL);
if (result == -1) {
perror("port_associate failure");
}
return result;
} else {
abort(); // dont support!!
}
} else if (op == EPOLL_CTL_DEL) {
int result = port_dissociate(epfd, PORT_SOURCE_FD, fd);
if (result == -1) {
perror("port_dissociate failure");
return -1;
}
return 0;
}
return -1;
}
int _tt_epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout) {
port_event_t list[maxevents];
div_t td = div(timeout, 1000);
struct timespec ts;
ts.tv_sec = td.quot;
ts.tv_nsec = td.rem * 1000000;
uint_t nget = maxevents;
if (port_getn(epfd, list, maxevents, &nget, &ts) == -1) {
// ここ後から修正しますた(2009/2/15)
if (errno == EINTR) {
return 0;
} else if (errno != ETIME) {
perror("port_getn failure");
return -1;
}
}
for (int i = 0; i < nget; i++) {
events[i].data.fd = list[i].portev_object;
events[i].events = list[i].portev_events;
}
return nget;
}
#endif
↑のコードのETIMEの扱いが間違っていたので修正しました(2009/2/15)
さらに追記。この方法だと遅いので最初にactiveなFD数を取得してから処理しないとダメです。 (2009/2/15)
本当は、port_associateの最後の引数に好きな値を設定しておくことが出来るので、ここにNULLではなくONESHOTフラグかどうかを登録します。そしてwait関数のforの中でlist[i].portev_userが非ONESHOTフラグの場合は、再登録をするという方法をとりたかったのです。普通に実装したら、READできる状態ではないのにport_getnで帰ってきたりしたので、Σ(´Д`lll)エエ!!と思いました。
あ・・・もう1回port_getして読み込み可能でなければそれを返さなければいいのかな・・。
で、↑が上手く実装できなかったので苦肉の策として以下のようなダメダメコードを書いてしまいました・・。
ttutil.cの905行目辺りです。ttacceptsockunixかttacceptsockを発行した直後の部分です。
#if TTUSESOLEVENTPORTS
do {
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = lfd;
if (epoll_ctl(epfd, EPOLL_CTL_MOD, lfd, &ev) != 0) {
cfd = -1;
}
} while (false);
#endif
あとはconfigureのc99をgnu99に変更して、できたMakefileはsonameを使わない書き方に変更すればビルドが通ります。
きちんとエミュレーションするコードをがんばって書きます(´Д⊂グスン
何度も書きますが参考にしないでね。