nginx ソースコードリーディング 1-2

# 今回読むところ

- nginx-1.1.16 
- core/nginx.c:200 mainから呼ばれるos/unix/ngx_process_cycle.c:295 ngx_single_process_cycleの中身。

# その前に

GNU GLOBALを使おう。

```
$ brew install global
$ cd nginx-1.1.16
$ git init
$ gtags -v
$ cat .gitignore
GPATH
GRTAGS
GTAGS
Makefile
objs/
```

Emacsの例。

```Lisp:init-tags.el
(autoload 'gtags-mode "gtags" "" t)
(setq gtags-mode-hook
      '(lambda ()
         (local-set-key "\M-t" 'gtags-find-tag)
         (local-set-key "\M-r" 'gtags-find-rtag)
         (local-set-key "\M-s" 'gtags-find-symbol)
         (local-set-key "\C-t" 'gtags-pop-stack)))

(add-hook 'c-mode-common-hook
          '(lambda()
             (gtags-mode 1)
             (gtags-make-complete-list)))
```

# void ngx_single_process_cycle(ngx_cycle_t *cycle)

## cycleの定義

```C:ngx_core.h
typedef struct ngx_cycle_s       ngx_cycle_t;
```

```C:ngx_core.h
struct ngx_cycle_s {
    void                  ****conf_ctx;
    ngx_pool_t               *pool;

    ngx_log_t                *log;
    ngx_log_t                 new_log;

    ngx_connection_t        **files;
    ngx_connection_t         *free_connections;
    ngx_uint_t                free_connection_n;

    ngx_queue_t               reusable_connections_queue;

    ngx_array_t               listening;
    ngx_array_t               pathes;
    ngx_list_t                open_files;
    ngx_list_t                shared_memory;

    ngx_uint_t                connection_n;
    ngx_uint_t                files_n;

    ngx_connection_t         *connections;
    ngx_event_t              *read_events;
    ngx_event_t              *write_events;

    ngx_cycle_t              *old_cycle;

    ngx_str_t                 conf_file;
    ngx_str_t                 conf_param;
    ngx_str_t                 conf_prefix;
    ngx_str_t                 prefix;
    ngx_str_t                 lock_file;
    ngx_str_t                 hostname;
};
```

## 処理の流れ

1. モジュール初期化
2. メインループ突入
  1. イベント処理
  2. 終了条件チェック
  3. 再初期化チェック
  4. ログの再オープン

## イベント処理

```C:ngx_event.c
void ngx_process_events_and_timers(ngx_cycle_t *cycle)
```

1. タイムアウト設定
2. イベント監視
3. イベント処理

```C:ngx_event.c:246
(void) ngx_process_events(cycle, timer, flags);
```

ngx_process_eventsがなにやってるか。

```C:ngx_event.h
#define ngx_process_events   ngx_event_actions.process_events

// (snip)

typedef struct {
    ngx_int_t  (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    ngx_int_t  (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t  (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
    ngx_int_t  (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);

    ngx_int_t  (*add_conn)(ngx_connection_t *c);
    ngx_int_t  (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);

    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
    ngx_int_t  (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
                   ngx_uint_t flags);

    ngx_int_t  (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
    void       (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;

// (snip)

extern ngx_event_actions_t   ngx_event_actions;
```

この関数ポインタがつまったstruct(クラスっぽい感じのやつ)`ngx_event_actions`を、各event APIモジュールが実装している。

以下、select(2)の例。初期化時に、上記のメンバに実装を設定する:

```C:ngx_select_module.c:105
ngx_event_actions = ngx_select_module_ctx.actions;
```
んでもって、process_eventsの実装はこんな感じ:

```C:ngx_select_module.c:212
static ngx_int_t
ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
```

```
ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);

// (snip)

ngx_mutex_lock(ngx_posted_events_mutex);

nready = 0;

for (i = 0; i < nevents; i++) {
    ev = event_index[i];
    c = ev->data;
    found = 0;

    if (ev->write) {
        if (FD_ISSET(c->fd, &work_write_fd_set)) {
            found = 1;
            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "select write %d", c->fd);
        }

    } else {
        if (FD_ISSET(c->fd, &work_read_fd_set)) {
            found = 1;
            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "select read %d", c->fd);
        }
    }

    if (found) {
        ev->ready = 1;

        queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
                                               &ngx_posted_events);
        ngx_locked_post_event(ev, queue);

        nready++;
    }
}

ngx_mutex_unlock(ngx_posted_events_mutex);
// (snip)
```

以下略。