ssize_t ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) { ngx_thread_task_t *task; ngx_thread_read_ctx_t *ctx; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "thread read: %d, %p, %uz, %O", file->fd, buf, size, offset); task = *taskp; if (task == NULL) { task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t)); if (task == NULL) { return NGX_ERROR; } task->handler = ngx_thread_read_handler; *taskp = task; } ctx = task->ctx; if (task->event.complete) { task->event.complete = 0; if (ctx->err) { ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, "pread() \"%s\" failed", file->name.data); return NGX_ERROR; } return ctx->read; } ctx->fd = file->fd; ctx->buf = buf; ctx->size = size; ctx->offset = offset; if (file->thread_handler(task, file) != NGX_OK) { return NGX_ERROR; } return NGX_AGAIN; }
static ngx_int_t ngx_linux_sendfile_thread(ngx_connection_t *c, ngx_buf_t *file, size_t size, size_t *sent) { ngx_uint_t flags; ngx_event_t *wev; ngx_thread_task_t *task; ngx_linux_sendfile_ctx_t *ctx; ngx_log_debug3(NGX_LOG_DEBUG_CORE, c->log, 0, "linux sendfile thread: %d, %uz, %O", file->file->fd, size, file->file_pos); task = c->sendfile_task; if (task == NULL) { task = ngx_thread_task_alloc(c->pool, sizeof(ngx_linux_sendfile_ctx_t)); if (task == NULL) { return NGX_ERROR; } task->handler = ngx_linux_sendfile_thread_handler; c->sendfile_task = task; } ctx = task->ctx; wev = c->write; if (task->event.complete) { task->event.complete = 0; if (ctx->err && ctx->err != NGX_EAGAIN) { wev->error = 1; ngx_connection_error(c, ctx->err, "sendfile() failed"); return NGX_ERROR; } *sent = ctx->sent; return (ctx->sent == ctx->size) ? NGX_DONE : NGX_AGAIN; } ctx->file = file; ctx->socket = c->fd; ctx->size = size; if (wev->active) { flags = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ? NGX_CLEAR_EVENT : NGX_LEVEL_EVENT; if (ngx_del_event(wev, NGX_WRITE_EVENT, flags) == NGX_ERROR) { return NGX_ERROR; } } if (file->file->thread_handler(task, file->file) != NGX_OK) { return NGX_ERROR; } *sent = 0; return NGX_OK; }
/* static void ngx_app_empty_handler(ngx_event_t *wev) { } */ static void ngx_app_wait_request_handler(ngx_event_t *ev) { ngx_connection_t *c; ngx_stream_session_t *s; ngx_stream_app_main_conf_t *cscf; ngx_stream_app_srv_conf_t *ascf; ngx_stream_app_ctx_t *s_ctx; ngx_app_task_t *t; ngx_buf_t *b; ngx_str_t log_buf; ssize_t n; size_t size; u_char *tmp; c = ev->data; s = c->data; if (ev->timedout) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); ngx_stream_close_connection(c); return; } if (c->close) { ngx_stream_close_connection(c); return; } cscf = ngx_stream_get_module_main_conf(s, ngx_stream_app_module); ascf = ngx_stream_get_module_srv_conf(s, ngx_stream_app_module); s_ctx = ngx_stream_get_module_ctx(s,ngx_stream_app_module); if(s_ctx == NULL){ s_ctx = ngx_palloc(c->pool, sizeof(ngx_stream_app_ctx_t)); if(s_ctx == NULL) return; s_ctx->header = 0; ngx_stream_set_ctx(s,s_ctx,ngx_stream_app_module); } b = c->buffer; if (b == NULL) { size = ascf->header_len; b = ngx_create_temp_buf(c->pool, size); if (b == NULL) { ngx_stream_close_connection(c); return; } c->buffer = b; } else if (b->start == NULL) { size = s_ctx->header == 0?ascf->header_len:s_ctx->body_len; b->start = ngx_palloc(c->pool, size); if (b->start == NULL) { ngx_stream_close_connection(c); return; } b->pos = b->start; b->last = b->start; b->end = b->last + size; } else { size = ascf->header_len + s_ctx->body_len - s->received; // size = b->end - b->last; } n = c->recv(c, b->last, size); if (n == NGX_AGAIN) { if (!c->read->timer_set) { ngx_add_timer(c->read, ascf->client_timeout); } if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } return; } if (n == NGX_ERROR) { ngx_stream_close_connection(c); return; } if (n == 0) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client closed connection"); ngx_stream_close_connection(c); return; } b->last += n; s->received +=n; c->log->action = "reading client request line"; log_buf.len = s->received; log_buf.data = b->start; ngx_log_error(NGX_LOG_ALERT, c->log, 0, "%d recved [%V],[%d:%d]",n,&log_buf,b->end,b->last); if(b->end != b->last){ if (ngx_handle_read_event(c->read, 0) != NGX_OK) { ngx_stream_close_connection(c); return; } } else { if(s_ctx->header == 0){ s_ctx->body_len = ngx_atoi(b->start,ascf->header_len); s_ctx->header = 1; if(s_ctx->body_len > 0 ){ tmp = ngx_pcalloc(c->pool, ascf->header_len + s_ctx->body_len); if (tmp == NULL) { ngx_stream_close_connection(c); return; } ngx_memcpy(tmp,b->start,ascf->header_len); ngx_pfree(c->pool, b->start); b->start = tmp; b->pos = b->start + ascf->header_len; b->last = b->pos; b->end = b->last + s_ctx->body_len; ngx_app_wait_request_handler(ev); } else{ ngx_log_error(NGX_LOG_INFO, c->log, 0, "empty request body"); ngx_stream_close_connection(c); return; } ngx_log_error(NGX_LOG_ALERT, c->log, 0, "recv header,len[%d]",s_ctx->body_len); } else{ // c->read->handler = ngx_app_empty_handler; t = (ngx_app_task_t *)ngx_thread_task_alloc(c->pool, sizeof(ngx_app_task_t) - sizeof(ngx_thread_task_t)); if(t == NULL){ ngx_log_error(NGX_LOG_ERR, c->log, 0, "create thread task failed"); ngx_stream_close_connection(c); } t->data = s; t->task.handler = ngx_stream_app_process; t->task.event.handler = ngx_stream_app_finalize; t->task.event.data= c; ngx_log_error(NGX_LOG_ALERT, c->log, 0, "t->data[%d]=[%d][%d]",t->data,t->task.ctx,t); if(ngx_thread_task_post(cscf->tp,(ngx_thread_task_t *)t) != NGX_OK){ ngx_log_error(NGX_LOG_ERR, c->log, 0, "post task to thread pool failed"); ngx_stream_close_connection(c); return; } ngx_log_error(NGX_LOG_ALERT, c->log, 0, "after post task"); } } return; }
//第一次进来的时候表示开始把读任务加入线程池中处理,表示正在开始读,第二次进来的时候表示数据已经通过notify_epoll通知读取完毕,可以处理了,第一次返回NAX_AGAIN //第二次放回线程池中的线程处理读任务读取到的字节数 ssize_t ngx_thread_read(ngx_thread_task_t **taskp, ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) { /* 该函数一般会进来两次,第一次是通过原始数据发送触发走到这里,这时候complete = 0,第二次是当线程池读取数据完成,则会通过 ngx_thread_pool_handler->ngx_http_copy_thread_event_handler->ngx_http_request_handler->ngx_http_writer在次走到这里 */ ngx_thread_task_t *task; ngx_thread_read_ctx_t *ctx; ngx_log_debug4(NGX_LOG_DEBUG_CORE, file->log, 0, "thread read: fd:%d, buf:%p, size:%uz, offset:%O", file->fd, buf, size, offset); task = *taskp; if (task == NULL) { task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_read_ctx_t)); if (task == NULL) { return NGX_ERROR; } task->handler = ngx_thread_read_handler; *taskp = task; } ctx = task->ctx; if (task->event.complete) { /* 该函数一般会进来两次,第一次是通过原始数据发送触发走到这里,这时候complete = 0,第二次是当线程池读取数据完成,则会通过 ngx_thread_pool_handler->ngx_http_copy_thread_event_handler->ngx_http_request_handler->ngx_http_writer在次走到这里,不过 这次complete已经在ngx_thread_pool_handler置1 */ task->event.complete = 0; if (ctx->err) { ngx_log_error(NGX_LOG_CRIT, file->log, ctx->err, "pread() \"%s\" failed", file->name.data); return NGX_ERROR; } return ctx->read; } ctx->fd = file->fd; ctx->buf = buf; ctx->size = size; ctx->offset = offset; //这里添加task->event信息到task中,当task->handler指向完后,通过nginx_notify可以继续通过epoll_wait返回执行task->event //客户端过来后如果有缓存存在,则ngx_http_file_cache_aio_read中赋值为ngx_http_cache_thread_handler; //如果是从后端获取的数据,然后发送给客户端,则ngx_output_chain_as_is中赋值未ngx_http_copy_thread_handler if (file->thread_handler(task, file) != NGX_OK) { return NGX_ERROR; } return NGX_AGAIN; }