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
80Sigor@sysoev.ru #include <nxt_main.h>
90Sigor@sysoev.ru
100Sigor@sysoev.ru
111Sigor@sysoev.ru static void nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data);
120Sigor@sysoev.ru static nxt_int_t nxt_job_file_open(nxt_job_file_t *jbf);
130Sigor@sysoev.ru static nxt_int_t nxt_job_file_info(nxt_job_file_t *jbf);
140Sigor@sysoev.ru static nxt_int_t nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size);
150Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size);
160Sigor@sysoev.ru static nxt_int_t nxt_job_file_read_required(nxt_job_file_t *jbf);
170Sigor@sysoev.ru
180Sigor@sysoev.ru
190Sigor@sysoev.ru nxt_job_file_t *
nxt_job_file_create(nxt_mp_t * mp)2065Sigor@sysoev.ru nxt_job_file_create(nxt_mp_t *mp)
210Sigor@sysoev.ru {
220Sigor@sysoev.ru nxt_job_file_t *jbf;
230Sigor@sysoev.ru
240Sigor@sysoev.ru jbf = nxt_job_create(mp, sizeof(nxt_job_file_t));
250Sigor@sysoev.ru
260Sigor@sysoev.ru if (nxt_fast_path(jbf != NULL)) {
270Sigor@sysoev.ru jbf->file.fd = NXT_FILE_INVALID;
280Sigor@sysoev.ru jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
290Sigor@sysoev.ru jbf->read_required = nxt_job_file_read_required;
300Sigor@sysoev.ru }
310Sigor@sysoev.ru
320Sigor@sysoev.ru return jbf;
330Sigor@sysoev.ru }
340Sigor@sysoev.ru
350Sigor@sysoev.ru
360Sigor@sysoev.ru void
nxt_job_file_init(nxt_job_file_t * jbf)370Sigor@sysoev.ru nxt_job_file_init(nxt_job_file_t *jbf)
380Sigor@sysoev.ru {
390Sigor@sysoev.ru nxt_job_init(&jbf->job, sizeof(nxt_job_file_t));
400Sigor@sysoev.ru
410Sigor@sysoev.ru jbf->file.fd = NXT_FILE_INVALID;
420Sigor@sysoev.ru jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
430Sigor@sysoev.ru jbf->read_required = nxt_job_file_read_required;
440Sigor@sysoev.ru }
450Sigor@sysoev.ru
460Sigor@sysoev.ru
470Sigor@sysoev.ru /*
480Sigor@sysoev.ru * Must be a function but not a macro, because
490Sigor@sysoev.ru * it can be used as function pointer.
500Sigor@sysoev.ru */
510Sigor@sysoev.ru
520Sigor@sysoev.ru void
nxt_job_file_read(nxt_task_t * task,nxt_job_t * job)531Sigor@sysoev.ru nxt_job_file_read(nxt_task_t *task, nxt_job_t *job)
540Sigor@sysoev.ru {
551Sigor@sysoev.ru nxt_job_start(task, job, nxt_job_file_open_and_read);
560Sigor@sysoev.ru }
570Sigor@sysoev.ru
580Sigor@sysoev.ru
590Sigor@sysoev.ru static void
nxt_job_file_open_and_read(nxt_task_t * task,void * obj,void * data)601Sigor@sysoev.ru nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data)
610Sigor@sysoev.ru {
620Sigor@sysoev.ru size_t size;
630Sigor@sysoev.ru nxt_int_t n;
640Sigor@sysoev.ru nxt_bool_t read_ahead;
650Sigor@sysoev.ru nxt_file_t *file;
660Sigor@sysoev.ru nxt_job_file_t *jbf;
670Sigor@sysoev.ru nxt_work_handler_t handler;
680Sigor@sysoev.ru
690Sigor@sysoev.ru jbf = obj;
700Sigor@sysoev.ru file = &jbf->file;
710Sigor@sysoev.ru
721Sigor@sysoev.ru nxt_debug(task, "file job read: \"%FN\"", file->name);
730Sigor@sysoev.ru
740Sigor@sysoev.ru if (file->fd != NXT_FILE_INVALID && jbf->close_before_open) {
750Sigor@sysoev.ru nxt_file_close(file);
760Sigor@sysoev.ru file->fd = NXT_FILE_INVALID;
770Sigor@sysoev.ru }
780Sigor@sysoev.ru
790Sigor@sysoev.ru if (file->fd == NXT_FILE_INVALID) {
800Sigor@sysoev.ru
810Sigor@sysoev.ru switch (nxt_job_file_open(jbf)) {
820Sigor@sysoev.ru
830Sigor@sysoev.ru case NXT_OK:
840Sigor@sysoev.ru break;
850Sigor@sysoev.ru
860Sigor@sysoev.ru case NXT_DECLINED:
870Sigor@sysoev.ru handler = jbf->ready_handler;
880Sigor@sysoev.ru goto done;
890Sigor@sysoev.ru
900Sigor@sysoev.ru default: /* NXT_ERROR */
910Sigor@sysoev.ru handler = jbf->error_handler;
920Sigor@sysoev.ru goto done;
930Sigor@sysoev.ru }
940Sigor@sysoev.ru }
950Sigor@sysoev.ru
960Sigor@sysoev.ru if (file->size > 0) {
970Sigor@sysoev.ru
980Sigor@sysoev.ru if (jbf->buffer != NULL) {
990Sigor@sysoev.ru size = nxt_buf_mem_size(&jbf->buffer->mem);
1000Sigor@sysoev.ru size = nxt_min(file->size, (nxt_off_t) size);
1010Sigor@sysoev.ru read_ahead = nxt_buf_is_mmap(jbf->buffer);
1020Sigor@sysoev.ru
1030Sigor@sysoev.ru } else {
1040Sigor@sysoev.ru size = nxt_min(file->size, 1024 * 1024);
1050Sigor@sysoev.ru read_ahead = jbf->read_ahead;
1060Sigor@sysoev.ru }
1070Sigor@sysoev.ru
1080Sigor@sysoev.ru if (read_ahead) {
1090Sigor@sysoev.ru nxt_file_read_ahead(&jbf->file, jbf->offset, size);
1100Sigor@sysoev.ru }
1110Sigor@sysoev.ru
1120Sigor@sysoev.ru if (jbf->buffer != NULL) {
1130Sigor@sysoev.ru
1140Sigor@sysoev.ru if (nxt_buf_is_mmap(jbf->buffer)) {
1150Sigor@sysoev.ru n = nxt_job_file_mmap(jbf, size);
1160Sigor@sysoev.ru
1170Sigor@sysoev.ru } else {
1180Sigor@sysoev.ru n = nxt_job_file_read_data(jbf, size);
1190Sigor@sysoev.ru }
1200Sigor@sysoev.ru
1210Sigor@sysoev.ru if (nxt_slow_path(n != NXT_OK)) {
1220Sigor@sysoev.ru handler = jbf->error_handler;
1230Sigor@sysoev.ru goto done;
1240Sigor@sysoev.ru }
1250Sigor@sysoev.ru }
1260Sigor@sysoev.ru }
1270Sigor@sysoev.ru
1280Sigor@sysoev.ru if (jbf->offset == file->size) {
1290Sigor@sysoev.ru jbf->complete = 1;
1300Sigor@sysoev.ru
1310Sigor@sysoev.ru if (jbf->close) {
1320Sigor@sysoev.ru nxt_file_close(file);
1330Sigor@sysoev.ru file->fd = NXT_FILE_INVALID;
1340Sigor@sysoev.ru }
1350Sigor@sysoev.ru }
1360Sigor@sysoev.ru
1371Sigor@sysoev.ru nxt_job_return(task, &jbf->job, jbf->ready_handler);
1380Sigor@sysoev.ru return;
1390Sigor@sysoev.ru
1400Sigor@sysoev.ru done:
1410Sigor@sysoev.ru
1420Sigor@sysoev.ru if (file->fd != NXT_FILE_INVALID) {
1430Sigor@sysoev.ru nxt_file_close(file);
1440Sigor@sysoev.ru file->fd = NXT_FILE_INVALID;
1450Sigor@sysoev.ru }
1460Sigor@sysoev.ru
1471Sigor@sysoev.ru nxt_job_return(task, &jbf->job, handler);
1480Sigor@sysoev.ru }
1490Sigor@sysoev.ru
1500Sigor@sysoev.ru
1510Sigor@sysoev.ru static nxt_int_t
nxt_job_file_open(nxt_job_file_t * jbf)1520Sigor@sysoev.ru nxt_job_file_open(nxt_job_file_t *jbf)
1530Sigor@sysoev.ru {
1540Sigor@sysoev.ru nxt_int_t n;
1550Sigor@sysoev.ru
1560Sigor@sysoev.ru if (jbf->test_before_open) {
1570Sigor@sysoev.ru n = nxt_job_file_info(jbf);
1580Sigor@sysoev.ru
1590Sigor@sysoev.ru if (n != NXT_OK) {
1600Sigor@sysoev.ru goto test_directory;
1610Sigor@sysoev.ru }
1620Sigor@sysoev.ru
1630Sigor@sysoev.ru if (jbf->file.type == NXT_FILE_DIRECTORY) {
1640Sigor@sysoev.ru return NXT_DECLINED;
1650Sigor@sysoev.ru }
1660Sigor@sysoev.ru
1670Sigor@sysoev.ru if (jbf->read_required(jbf) != NXT_OK) {
1680Sigor@sysoev.ru return NXT_DECLINED;
1690Sigor@sysoev.ru }
1700Sigor@sysoev.ru }
1710Sigor@sysoev.ru
1720Sigor@sysoev.ru n = nxt_file_open(&jbf->file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
1730Sigor@sysoev.ru
1740Sigor@sysoev.ru if (n == NXT_OK) {
1750Sigor@sysoev.ru n = nxt_job_file_info(jbf);
1760Sigor@sysoev.ru
1770Sigor@sysoev.ru if (nxt_fast_path(n == NXT_OK)) {
1780Sigor@sysoev.ru
1790Sigor@sysoev.ru if (jbf->file.type == NXT_FILE_DIRECTORY) {
1800Sigor@sysoev.ru return NXT_DECLINED;
1810Sigor@sysoev.ru }
1820Sigor@sysoev.ru
1830Sigor@sysoev.ru return jbf->read_required(jbf);
1840Sigor@sysoev.ru }
1850Sigor@sysoev.ru
1860Sigor@sysoev.ru return n;
1870Sigor@sysoev.ru }
1880Sigor@sysoev.ru
1890Sigor@sysoev.ru test_directory:
1900Sigor@sysoev.ru
1910Sigor@sysoev.ru if (jbf->directory_end != 0
1920Sigor@sysoev.ru && jbf->file.error != NXT_ENOTDIR
1930Sigor@sysoev.ru && jbf->file.error != NXT_ENAMETOOLONG
1940Sigor@sysoev.ru && jbf->file.error != NXT_EACCES)
1950Sigor@sysoev.ru {
1960Sigor@sysoev.ru jbf->file.name[jbf->directory_end] = '\0';
1970Sigor@sysoev.ru
1980Sigor@sysoev.ru return nxt_job_file_info(jbf);
1990Sigor@sysoev.ru }
2000Sigor@sysoev.ru
2010Sigor@sysoev.ru return n;
2020Sigor@sysoev.ru }
2030Sigor@sysoev.ru
2040Sigor@sysoev.ru
2050Sigor@sysoev.ru static nxt_int_t
nxt_job_file_info(nxt_job_file_t * jbf)2060Sigor@sysoev.ru nxt_job_file_info(nxt_job_file_t *jbf)
2070Sigor@sysoev.ru {
2080Sigor@sysoev.ru nxt_int_t n;
2090Sigor@sysoev.ru nxt_file_t *file;
2100Sigor@sysoev.ru nxt_file_info_t fi;
2110Sigor@sysoev.ru
2120Sigor@sysoev.ru file = &jbf->file;
2130Sigor@sysoev.ru
2140Sigor@sysoev.ru n = nxt_file_info(file, &fi);
2150Sigor@sysoev.ru
2160Sigor@sysoev.ru if (n != NXT_OK) {
2170Sigor@sysoev.ru return NXT_ERROR;
2180Sigor@sysoev.ru }
2190Sigor@sysoev.ru
2200Sigor@sysoev.ru if (nxt_is_file(&fi)) {
2210Sigor@sysoev.ru file->type = NXT_FILE_REGULAR;
2220Sigor@sysoev.ru file->size = nxt_file_size(&fi);
2230Sigor@sysoev.ru file->mtime = nxt_file_mtime(&fi);
2240Sigor@sysoev.ru
2250Sigor@sysoev.ru } else if (nxt_is_dir(&fi)) {
2260Sigor@sysoev.ru file->type = NXT_FILE_DIRECTORY;
2270Sigor@sysoev.ru file->size = nxt_file_size(&fi);
2280Sigor@sysoev.ru file->mtime = nxt_file_mtime(&fi);
2290Sigor@sysoev.ru }
2300Sigor@sysoev.ru
2310Sigor@sysoev.ru return NXT_OK;
2320Sigor@sysoev.ru }
2330Sigor@sysoev.ru
2340Sigor@sysoev.ru
2350Sigor@sysoev.ru static nxt_int_t
nxt_job_file_mmap(nxt_job_file_t * jbf,size_t size)2360Sigor@sysoev.ru nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size)
2370Sigor@sysoev.ru {
2380Sigor@sysoev.ru u_char *p, *end;
2390Sigor@sysoev.ru static nxt_uint_t n;
2400Sigor@sysoev.ru
2410Sigor@sysoev.ru p = nxt_mem_map(NULL, &jbf->buffer->mmap, size, NXT_MEM_MAP_READ,
2420Sigor@sysoev.ru (NXT_MEM_MAP_FILE | NXT_MEM_MAP_PREFAULT),
2430Sigor@sysoev.ru jbf->file.fd, jbf->offset);
2440Sigor@sysoev.ru
2450Sigor@sysoev.ru if (nxt_fast_path(p != NXT_MEM_MAP_FAILED)) {
2460Sigor@sysoev.ru
2470Sigor@sysoev.ru end = p + size;
2480Sigor@sysoev.ru
2490Sigor@sysoev.ru jbf->buffer->mem.pos = p;
2500Sigor@sysoev.ru jbf->buffer->mem.free = end;
2510Sigor@sysoev.ru jbf->buffer->mem.start = p;
2520Sigor@sysoev.ru jbf->buffer->mem.end = end;
2530Sigor@sysoev.ru jbf->buffer->file_end += size;
2540Sigor@sysoev.ru jbf->offset += size;
2550Sigor@sysoev.ru
2560Sigor@sysoev.ru /*
2570Sigor@sysoev.ru * The mapped pages should be already preloaded in the kernel page
2580Sigor@sysoev.ru * cache by nxt_file_read_ahead(). Touching them should wire the pages
2590Sigor@sysoev.ru * in user land memory if mmap() did not do this. Adding to the static
2600Sigor@sysoev.ru * variable "n" disables the loop elimination during optimization.
2610Sigor@sysoev.ru */
2620Sigor@sysoev.ru n += *p;
2630Sigor@sysoev.ru
2640Sigor@sysoev.ru for (p = nxt_align_ptr(p, nxt_pagesize); p < end; p += nxt_pagesize) {
2650Sigor@sysoev.ru n += *p;
2660Sigor@sysoev.ru }
2670Sigor@sysoev.ru
2680Sigor@sysoev.ru return NXT_OK;
2690Sigor@sysoev.ru }
2700Sigor@sysoev.ru
2710Sigor@sysoev.ru return NXT_ERROR;
2720Sigor@sysoev.ru }
2730Sigor@sysoev.ru
2740Sigor@sysoev.ru
2750Sigor@sysoev.ru static nxt_int_t
nxt_job_file_read_data(nxt_job_file_t * jbf,size_t size)2760Sigor@sysoev.ru nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size)
2770Sigor@sysoev.ru {
2780Sigor@sysoev.ru ssize_t n;
2790Sigor@sysoev.ru
280*237Svbart@nginx.com n = nxt_file_read(&jbf->file, jbf->buffer->mem.free, size, jbf->offset);
2810Sigor@sysoev.ru
2820Sigor@sysoev.ru if (nxt_fast_path(n > 0)) {
2830Sigor@sysoev.ru
2840Sigor@sysoev.ru jbf->buffer->mem.free += n;
2850Sigor@sysoev.ru jbf->offset += n;
2860Sigor@sysoev.ru
2870Sigor@sysoev.ru if (nxt_buf_is_file(jbf->buffer)) {
2880Sigor@sysoev.ru jbf->buffer->file_end += n;
2890Sigor@sysoev.ru }
2900Sigor@sysoev.ru
2910Sigor@sysoev.ru return NXT_OK;
2920Sigor@sysoev.ru }
2930Sigor@sysoev.ru
2940Sigor@sysoev.ru return NXT_ERROR;
2950Sigor@sysoev.ru }
2960Sigor@sysoev.ru
2970Sigor@sysoev.ru
2980Sigor@sysoev.ru static nxt_int_t
nxt_job_file_read_required(nxt_job_file_t * jbf)2990Sigor@sysoev.ru nxt_job_file_read_required(nxt_job_file_t *jbf)
3000Sigor@sysoev.ru {
3010Sigor@sysoev.ru return NXT_OK;
3020Sigor@sysoev.ru }
303