前回はmainを読んだ。今回はevent.cのna_event_loopのから。
neoagentのロジックのほとんどはevent.cにあるといっても過言ではない。
void *na_event_loop (void *args)
{
struct ev_loop *loop;
na_env_t *env;
pthread_t th_support;
pthread_t *th_workers;
env = (na_env_t *)args;
前回出てきたenvの配列の一つがargsとして渡される。それをここではenvとしている。
開発者の方曰く、envにアクセスしているというのはグローバル変数にアクセスしていると思って構わないらしい。実際にはJSONでenvを複数個渡せるみたいだが、非推奨とのこと。
if (strlen(env->fssockpath) > 0) {
env->fsfd = na_front_server_unixsock_init(env->fssockpath, env->access_mask, env->conn_max);
} else {
env->fsfd = na_front_server_tcpsock_init(env->fsport, env->conn_max);
}
if (env->fsfd < 0) {
NA_DIE_WITH_ERROR(NA_ERROR_INVALID_FD);
}
指定されたunix domain socketのパスまたはtcpのポートでソケットを開く。
front_serverまはたfsというのはneoagentの用語で「接続してきたウェブアプリケーションのプロセス」のことを指すらしい。つまりfsfdはPHP等からのアクセスをlistenしているソケット(ファイルディスクリプタ)のこと。
na_connpool_init(env);
ClientPool = calloc(sizeof(na_client_t), env->client_pool_max);
memset(ClientPool, 0, sizeof(na_client_t) * env->client_pool_max);
for (int i=0;i<env->client_pool_max;++i) {
ClientPool[i].crbuf = (char *)malloc(env->request_bufsize + 1);
ClientPool[i].srbuf = (char *)malloc(env->response_bufsize + 1);
ClientPool[i].is_used = false;
pthread_mutex_init(&ClientPool[i].lock_use, NULL);
}
if (EventQueue == NULL) {
EventQueue = na_event_queue_create(env->conn_max);
}
コネクションプール、クライアントプール、イベントキューを初期化している。これについてはとりあえずそういうもんだと思って読み飛ばすことにする。
th_workers = calloc(sizeof(pthread_t), env->worker_max);
for (int i=0;i<env->worker_max;++i) {
pthread_create(&th_workers[i], NULL, na_event_observer, env);
}
worker_maxの数だけスレッドを起動している。workerスレッドで実行するのはna_event_observer。
if (strlen(env->stsockpath) > 0) {
env->stfd = na_stat_server_unixsock_init(env->stsockpath, env->access_mask);
} else {
env->stfd = na_stat_server_tcpsock_init(env->stport);
}
pthread_create(&th_support, NULL, na_support_loop, env);
同じくサポート用のスレッドを起動。これはneoagentの状態をモニタリングするために外部と通信するためのスレッドなので深くは触れない。
// for assign connection from connpool directional-ramdomly
srand(time(NULL));
pthread_mutex_lock(&env->lock_loop);
loop = na_event_loop_create(env->event_model);
pthread_mutex_unlock(&env->lock_loop);
env->fs_watcher.data = env;
ev_io_init(&env->fs_watcher, na_front_server_callback, env->fsfd, EV_READ);
ev_io_start(EV_A_ &env->fs_watcher);
ev_loop(EV_A_ 0);
ここでイベントループを作っている。libevのことを知らないと何やっているのが分からないが、fsfdのREADが走るとna_front_server_callbackという関数が実行されるという意味。
ev_loopは無限ループなので基本的にその下の処理に入ることはないと考えていい。
その下の処理。
for (int i=0;i<env->client_pool_max;++i) {
NA_FREE(ClientPool[i].crbuf);
NA_FREE(ClientPool[i].srbuf);
pthread_mutex_destroy(&ClientPool[i].lock_use);
}
NA_FREE(ClientPool);
na_event_queue_destroy(EventQueue);
return NULL;
}
解放処理だけ。
今回はここまで。
この処理がやっていた主なことは、na_observerを実行するスレッドを作ったことと、ウェブアプリケーションから入力があった時にna_front_server_callbackが呼ばれるようなイベントループを作ったこと。
次はna_front_server_callbackを見ていくつもり。