10Sigor@sysoev.ru
20Sigor@sysoev.ru /*
30Sigor@sysoev.ru * Copyright (C) Igor Sysoev
40Sigor@sysoev.ru * Copyright (C) NGINX, Inc.
50Sigor@sysoev.ru */
60Sigor@sysoev.ru
70Sigor@sysoev.ru #include <nxt_main.h>
80Sigor@sysoev.ru
90Sigor@sysoev.ru
100Sigor@sysoev.ru typedef struct {
110Sigor@sysoev.ru nxt_job_t job;
120Sigor@sysoev.ru nxt_buf_t *out;
130Sigor@sysoev.ru size_t sent;
140Sigor@sysoev.ru size_t limit;
150Sigor@sysoev.ru nxt_work_handler_t ready_handler;
160Sigor@sysoev.ru } nxt_job_sendfile_t;
170Sigor@sysoev.ru
180Sigor@sysoev.ru
191Sigor@sysoev.ru static void nxt_event_conn_job_sendfile_start(nxt_task_t *task, void *obj,
200Sigor@sysoev.ru void *data);
211Sigor@sysoev.ru static void nxt_event_conn_job_sendfile_handler(nxt_task_t *task, void *obj,
220Sigor@sysoev.ru void *data);
231Sigor@sysoev.ru static void nxt_event_conn_job_sendfile_return(nxt_task_t *task, void *obj,
240Sigor@sysoev.ru void *data);
251Sigor@sysoev.ru static nxt_buf_t *nxt_event_conn_job_sendfile_completion(nxt_task_t *task,
2662Sigor@sysoev.ru nxt_conn_t *c, nxt_buf_t *b);
270Sigor@sysoev.ru
280Sigor@sysoev.ru
290Sigor@sysoev.ru void
nxt_event_conn_job_sendfile(nxt_task_t * task,nxt_conn_t * c)3062Sigor@sysoev.ru nxt_event_conn_job_sendfile(nxt_task_t *task, nxt_conn_t *c)
310Sigor@sysoev.ru {
3212Sigor@sysoev.ru nxt_fd_event_disable(task->thread->engine, &c->socket);
330Sigor@sysoev.ru
340Sigor@sysoev.ru /* A work item data is not used in nxt_event_conn_job_sendfile_start(). */
351Sigor@sysoev.ru nxt_event_conn_job_sendfile_start(task, c, NULL);
360Sigor@sysoev.ru }
370Sigor@sysoev.ru
380Sigor@sysoev.ru
390Sigor@sysoev.ru static void
nxt_event_conn_job_sendfile_start(nxt_task_t * task,void * obj,void * data)401Sigor@sysoev.ru nxt_event_conn_job_sendfile_start(nxt_task_t *task, void *obj, void *data)
410Sigor@sysoev.ru {
4262Sigor@sysoev.ru nxt_conn_t *c;
430Sigor@sysoev.ru nxt_iobuf_t b;
440Sigor@sysoev.ru nxt_job_sendfile_t *jbs;
450Sigor@sysoev.ru nxt_sendbuf_coalesce_t sb;
460Sigor@sysoev.ru
470Sigor@sysoev.ru c = obj;
480Sigor@sysoev.ru
491Sigor@sysoev.ru nxt_debug(task, "event conn sendfile fd:%d", c->socket.fd);
500Sigor@sysoev.ru
510Sigor@sysoev.ru jbs = nxt_job_create(c->mem_pool, sizeof(nxt_job_sendfile_t));
520Sigor@sysoev.ru
530Sigor@sysoev.ru if (nxt_slow_path(jbs == NULL)) {
541Sigor@sysoev.ru c->write_state->error_handler(task, c, NULL);
550Sigor@sysoev.ru return;
560Sigor@sysoev.ru }
570Sigor@sysoev.ru
580Sigor@sysoev.ru c->socket.write_handler = nxt_event_conn_job_sendfile_start;
590Sigor@sysoev.ru c->socket.error_handler = c->write_state->error_handler;
600Sigor@sysoev.ru
610Sigor@sysoev.ru jbs->job.data = c;
620Sigor@sysoev.ru nxt_job_set_name(&jbs->job, "job sendfile");
630Sigor@sysoev.ru
640Sigor@sysoev.ru jbs->limit = nxt_event_conn_write_limit(c);
650Sigor@sysoev.ru
660Sigor@sysoev.ru if (jbs->limit != 0) {
670Sigor@sysoev.ru
680Sigor@sysoev.ru sb.buf = c->write;
690Sigor@sysoev.ru sb.iobuf = &b;
700Sigor@sysoev.ru sb.nmax = 1;
710Sigor@sysoev.ru sb.sync = 0;
720Sigor@sysoev.ru sb.size = 0;
730Sigor@sysoev.ru sb.limit = jbs->limit;
740Sigor@sysoev.ru
751Sigor@sysoev.ru if (nxt_sendbuf_mem_coalesce(c->socket.task, &sb) != 0 || !sb.sync) {
760Sigor@sysoev.ru
770Sigor@sysoev.ru jbs->job.thread_pool = c->u.thread_pool;
780Sigor@sysoev.ru jbs->job.log = c->socket.log;
790Sigor@sysoev.ru jbs->out = c->write;
800Sigor@sysoev.ru c->write = NULL;
810Sigor@sysoev.ru jbs->ready_handler = nxt_event_conn_job_sendfile_return;
820Sigor@sysoev.ru
83*979Sigor@sysoev.ru c->block_read = 1;
84*979Sigor@sysoev.ru c->block_write = 1;
850Sigor@sysoev.ru
861Sigor@sysoev.ru nxt_job_start(task, &jbs->job, nxt_event_conn_job_sendfile_handler);
870Sigor@sysoev.ru return;
880Sigor@sysoev.ru }
890Sigor@sysoev.ru }
900Sigor@sysoev.ru
911Sigor@sysoev.ru nxt_event_conn_job_sendfile_return(task, jbs, c);
920Sigor@sysoev.ru }
930Sigor@sysoev.ru
940Sigor@sysoev.ru
950Sigor@sysoev.ru static void
nxt_event_conn_job_sendfile_handler(nxt_task_t * task,void * obj,void * data)961Sigor@sysoev.ru nxt_event_conn_job_sendfile_handler(nxt_task_t *task, void *obj, void *data)
970Sigor@sysoev.ru {
980Sigor@sysoev.ru ssize_t ret;
990Sigor@sysoev.ru nxt_buf_t *b;
1000Sigor@sysoev.ru nxt_bool_t first;
10162Sigor@sysoev.ru nxt_conn_t *c;
1020Sigor@sysoev.ru nxt_job_sendfile_t *jbs;
1030Sigor@sysoev.ru
1040Sigor@sysoev.ru jbs = obj;
1050Sigor@sysoev.ru c = data;
1060Sigor@sysoev.ru
1071Sigor@sysoev.ru nxt_debug(task, "event conn job sendfile fd:%d", c->socket.fd);
1080Sigor@sysoev.ru
1090Sigor@sysoev.ru first = c->socket.write_ready;
1100Sigor@sysoev.ru b = jbs->out;
1110Sigor@sysoev.ru
1120Sigor@sysoev.ru do {
113771Sigor@sysoev.ru ret = c->io->old_sendbuf(c, b, jbs->limit);
1140Sigor@sysoev.ru
1150Sigor@sysoev.ru if (ret == NXT_AGAIN) {
1160Sigor@sysoev.ru break;
1170Sigor@sysoev.ru }
1180Sigor@sysoev.ru
1190Sigor@sysoev.ru if (nxt_slow_path(ret == NXT_ERROR)) {
1200Sigor@sysoev.ru goto done;
1210Sigor@sysoev.ru }
1220Sigor@sysoev.ru
1230Sigor@sysoev.ru jbs->sent += ret;
1240Sigor@sysoev.ru jbs->limit -= ret;
1250Sigor@sysoev.ru
1260Sigor@sysoev.ru b = nxt_sendbuf_update(b, ret);
1270Sigor@sysoev.ru
1280Sigor@sysoev.ru if (b == NULL) {
1290Sigor@sysoev.ru goto done;
1300Sigor@sysoev.ru }
1310Sigor@sysoev.ru
1320Sigor@sysoev.ru if (jbs->limit == 0) {
1330Sigor@sysoev.ru
1340Sigor@sysoev.ru if (c->rate == NULL) {
1350Sigor@sysoev.ru jbs->limit = c->max_chunk;
1360Sigor@sysoev.ru goto fast;
1370Sigor@sysoev.ru }
1380Sigor@sysoev.ru
1390Sigor@sysoev.ru goto done;
1400Sigor@sysoev.ru }
1410Sigor@sysoev.ru
1420Sigor@sysoev.ru } while (c->socket.write_ready);
1430Sigor@sysoev.ru
1441Sigor@sysoev.ru if (first && task->thread->thread_pool->work_queue.head != NULL) {
1450Sigor@sysoev.ru goto fast;
1460Sigor@sysoev.ru }
1470Sigor@sysoev.ru
1480Sigor@sysoev.ru done:
1490Sigor@sysoev.ru
1501Sigor@sysoev.ru nxt_job_return(task, &jbs->job, jbs->ready_handler);
1510Sigor@sysoev.ru return;
1520Sigor@sysoev.ru
1530Sigor@sysoev.ru fast:
1540Sigor@sysoev.ru
1554Sigor@sysoev.ru nxt_work_set(&jbs->job.work, nxt_event_conn_job_sendfile_handler,
1564Sigor@sysoev.ru jbs->job.task, jbs, c);
1574Sigor@sysoev.ru
1584Sigor@sysoev.ru nxt_thread_pool_post(task->thread->thread_pool, &jbs->job.work);
1590Sigor@sysoev.ru }
1600Sigor@sysoev.ru
1610Sigor@sysoev.ru
1620Sigor@sysoev.ru static void
nxt_event_conn_job_sendfile_return(nxt_task_t * task,void * obj,void * data)1631Sigor@sysoev.ru nxt_event_conn_job_sendfile_return(nxt_task_t *task, void *obj, void *data)
1640Sigor@sysoev.ru {
1650Sigor@sysoev.ru size_t sent;
1660Sigor@sysoev.ru nxt_buf_t *b;
1670Sigor@sysoev.ru nxt_bool_t done;
16862Sigor@sysoev.ru nxt_conn_t *c;
1690Sigor@sysoev.ru nxt_job_sendfile_t *jbs;
1700Sigor@sysoev.ru
1710Sigor@sysoev.ru jbs = obj;
1720Sigor@sysoev.ru c = data;
1730Sigor@sysoev.ru
174*979Sigor@sysoev.ru c->block_read = 0;
175*979Sigor@sysoev.ru c->block_write = 0;
1760Sigor@sysoev.ru
1770Sigor@sysoev.ru sent = jbs->sent;
1780Sigor@sysoev.ru c->sent += sent;
1790Sigor@sysoev.ru
1801Sigor@sysoev.ru nxt_debug(task, "event conn sendfile sent:%z", sent);
1810Sigor@sysoev.ru
1820Sigor@sysoev.ru b = jbs->out;
1830Sigor@sysoev.ru
1840Sigor@sysoev.ru /* The job must be destroyed before connection error handler. */
18520Sigor@sysoev.ru nxt_job_destroy(task, jbs);
1860Sigor@sysoev.ru
18756Sigor@sysoev.ru if (0 /* STUB: c->write_state->process_buffers */) {
1881Sigor@sysoev.ru b = nxt_event_conn_job_sendfile_completion(task, c, b);
1890Sigor@sysoev.ru
1900Sigor@sysoev.ru done = (b == NULL);
1910Sigor@sysoev.ru
1920Sigor@sysoev.ru /* Add data which might be added after sendfile job has started. */
1930Sigor@sysoev.ru nxt_buf_chain_add(&b, c->write);
1940Sigor@sysoev.ru c->write = b;
1950Sigor@sysoev.ru
1960Sigor@sysoev.ru if (done) {
1970Sigor@sysoev.ru /* All data has been sent. */
1980Sigor@sysoev.ru
1990Sigor@sysoev.ru if (b != NULL) {
2000Sigor@sysoev.ru /* But new data has been added. */
2011Sigor@sysoev.ru nxt_event_conn_job_sendfile_start(task, c, NULL);
2020Sigor@sysoev.ru }
2030Sigor@sysoev.ru
2040Sigor@sysoev.ru return;
2050Sigor@sysoev.ru }
2060Sigor@sysoev.ru }
2070Sigor@sysoev.ru
20856Sigor@sysoev.ru if (sent != 0 && c->write_state->timer_autoreset) {
2097Sigor@sysoev.ru nxt_timer_disable(task->thread->engine, &c->write_timer);
2100Sigor@sysoev.ru }
2110Sigor@sysoev.ru
2120Sigor@sysoev.ru if (c->socket.error == 0
2131Sigor@sysoev.ru && !nxt_event_conn_write_delayed(task->thread->engine, c, sent))
2140Sigor@sysoev.ru {
21562Sigor@sysoev.ru nxt_conn_timer(task->thread->engine, c, c->write_state,
21662Sigor@sysoev.ru &c->write_timer);
2170Sigor@sysoev.ru
21812Sigor@sysoev.ru nxt_fd_event_oneshot_write(task->thread->engine, &c->socket);
2190Sigor@sysoev.ru }
2200Sigor@sysoev.ru
2210Sigor@sysoev.ru if (sent != 0) {
22213Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, c->write_state->ready_handler,
22313Sigor@sysoev.ru task, c, c->socket.data);
2240Sigor@sysoev.ru /*
2250Sigor@sysoev.ru * Fall through if first operations were
2260Sigor@sysoev.ru * successful but the last one failed.
2270Sigor@sysoev.ru */
2280Sigor@sysoev.ru }
2290Sigor@sysoev.ru
2300Sigor@sysoev.ru if (nxt_slow_path(c->socket.error != 0)) {
23113Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue, c->write_state->error_handler,
23213Sigor@sysoev.ru task, c, c->socket.data);
2330Sigor@sysoev.ru }
2340Sigor@sysoev.ru }
2350Sigor@sysoev.ru
2360Sigor@sysoev.ru
2370Sigor@sysoev.ru static nxt_buf_t *
nxt_event_conn_job_sendfile_completion(nxt_task_t * task,nxt_conn_t * c,nxt_buf_t * b)23862Sigor@sysoev.ru nxt_event_conn_job_sendfile_completion(nxt_task_t *task, nxt_conn_t *c,
2390Sigor@sysoev.ru nxt_buf_t *b)
2400Sigor@sysoev.ru {
2410Sigor@sysoev.ru while (b != NULL) {
2420Sigor@sysoev.ru
2430Sigor@sysoev.ru nxt_prefetch(b->next);
2440Sigor@sysoev.ru
2450Sigor@sysoev.ru if (nxt_buf_is_mem(b) && b->mem.pos != b->mem.free) {
2460Sigor@sysoev.ru break;
2470Sigor@sysoev.ru
2480Sigor@sysoev.ru } else if (nxt_buf_is_file(b) && b->file_pos != b->file_end) {
2490Sigor@sysoev.ru break;
2500Sigor@sysoev.ru }
2510Sigor@sysoev.ru
2524Sigor@sysoev.ru nxt_work_queue_add(c->write_work_queue,
2534Sigor@sysoev.ru b->completion_handler, task, b, b->parent);
2540Sigor@sysoev.ru
2550Sigor@sysoev.ru b = b->next;
2560Sigor@sysoev.ru }
2570Sigor@sysoev.ru
2580Sigor@sysoev.ru return b;
2590Sigor@sysoev.ru }
260