diff options
Diffstat (limited to 'src/nxt_job_file.c')
-rw-r--r-- | src/nxt_job_file.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/src/nxt_job_file.c b/src/nxt_job_file.c new file mode 100644 index 00000000..bbebdee6 --- /dev/null +++ b/src/nxt_job_file.c @@ -0,0 +1,303 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + + +#include <nxt_main.h> + + +static void nxt_job_file_open_and_read(nxt_thread_t *thr, void *obj, + void *data); +static nxt_int_t nxt_job_file_open(nxt_job_file_t *jbf); +static nxt_int_t nxt_job_file_info(nxt_job_file_t *jbf); +static nxt_int_t nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size); +static nxt_int_t nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size); +static nxt_int_t nxt_job_file_read_required(nxt_job_file_t *jbf); + + +nxt_job_file_t * +nxt_job_file_create(nxt_mem_pool_t *mp) +{ + nxt_job_file_t *jbf; + + jbf = nxt_job_create(mp, sizeof(nxt_job_file_t)); + + if (nxt_fast_path(jbf != NULL)) { + jbf->file.fd = NXT_FILE_INVALID; + jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO; + jbf->read_required = nxt_job_file_read_required; + } + + return jbf; +} + + +void +nxt_job_file_init(nxt_job_file_t *jbf) +{ + nxt_job_init(&jbf->job, sizeof(nxt_job_file_t)); + + jbf->file.fd = NXT_FILE_INVALID; + jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO; + jbf->read_required = nxt_job_file_read_required; +} + + +/* + * Must be a function but not a macro, because + * it can be used as function pointer. + */ + +void +nxt_job_file_read(nxt_thread_t *thr, nxt_job_t *job) +{ + nxt_job_start(thr, job, nxt_job_file_open_and_read); +} + + +static void +nxt_job_file_open_and_read(nxt_thread_t *thr, void *obj, void *data) +{ + size_t size; + nxt_int_t n; + nxt_bool_t read_ahead; + nxt_file_t *file; + nxt_job_file_t *jbf; + nxt_work_handler_t handler; + + jbf = obj; + file = &jbf->file; + + nxt_log_debug(thr->log, "file job read: \"%FN\"", file->name); + + if (file->fd != NXT_FILE_INVALID && jbf->close_before_open) { + nxt_file_close(file); + file->fd = NXT_FILE_INVALID; + } + + if (file->fd == NXT_FILE_INVALID) { + + switch (nxt_job_file_open(jbf)) { + + case NXT_OK: + break; + + case NXT_DECLINED: + handler = jbf->ready_handler; + goto done; + + default: /* NXT_ERROR */ + handler = jbf->error_handler; + goto done; + } + } + + if (file->size > 0) { + + if (jbf->buffer != NULL) { + size = nxt_buf_mem_size(&jbf->buffer->mem); + size = nxt_min(file->size, (nxt_off_t) size); + read_ahead = nxt_buf_is_mmap(jbf->buffer); + + } else { + size = nxt_min(file->size, 1024 * 1024); + read_ahead = jbf->read_ahead; + } + + if (read_ahead) { + nxt_file_read_ahead(&jbf->file, jbf->offset, size); + } + + if (jbf->buffer != NULL) { + + if (nxt_buf_is_mmap(jbf->buffer)) { + n = nxt_job_file_mmap(jbf, size); + + } else { + n = nxt_job_file_read_data(jbf, size); + } + + if (nxt_slow_path(n != NXT_OK)) { + handler = jbf->error_handler; + goto done; + } + } + } + + if (jbf->offset == file->size) { + jbf->complete = 1; + + if (jbf->close) { + nxt_file_close(file); + file->fd = NXT_FILE_INVALID; + } + } + + nxt_job_return(thr, &jbf->job, jbf->ready_handler); + return; + +done: + + if (file->fd != NXT_FILE_INVALID) { + nxt_file_close(file); + file->fd = NXT_FILE_INVALID; + } + + nxt_job_return(thr, &jbf->job, handler); +} + + +static nxt_int_t +nxt_job_file_open(nxt_job_file_t *jbf) +{ + nxt_int_t n; + + if (jbf->test_before_open) { + n = nxt_job_file_info(jbf); + + if (n != NXT_OK) { + goto test_directory; + } + + if (jbf->file.type == NXT_FILE_DIRECTORY) { + return NXT_DECLINED; + } + + if (jbf->read_required(jbf) != NXT_OK) { + return NXT_DECLINED; + } + } + + n = nxt_file_open(&jbf->file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0); + + if (n == NXT_OK) { + n = nxt_job_file_info(jbf); + + if (nxt_fast_path(n == NXT_OK)) { + + if (jbf->file.type == NXT_FILE_DIRECTORY) { + return NXT_DECLINED; + } + + return jbf->read_required(jbf); + } + + return n; + } + +test_directory: + + if (jbf->directory_end != 0 + && jbf->file.error != NXT_ENOTDIR + && jbf->file.error != NXT_ENAMETOOLONG + && jbf->file.error != NXT_EACCES) + { + jbf->file.name[jbf->directory_end] = '\0'; + + return nxt_job_file_info(jbf); + } + + return n; +} + + +static nxt_int_t +nxt_job_file_info(nxt_job_file_t *jbf) +{ + nxt_int_t n; + nxt_file_t *file; + nxt_file_info_t fi; + + file = &jbf->file; + + n = nxt_file_info(file, &fi); + + if (n != NXT_OK) { + return NXT_ERROR; + } + + if (nxt_is_file(&fi)) { + file->type = NXT_FILE_REGULAR; + file->size = nxt_file_size(&fi); + file->mtime = nxt_file_mtime(&fi); + + } else if (nxt_is_dir(&fi)) { + file->type = NXT_FILE_DIRECTORY; + file->size = nxt_file_size(&fi); + file->mtime = nxt_file_mtime(&fi); + } + + return NXT_OK; +} + + +static nxt_int_t +nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size) +{ + u_char *p, *end; + static nxt_uint_t n; + + p = nxt_mem_map(NULL, &jbf->buffer->mmap, size, NXT_MEM_MAP_READ, + (NXT_MEM_MAP_FILE | NXT_MEM_MAP_PREFAULT), + jbf->file.fd, jbf->offset); + + if (nxt_fast_path(p != NXT_MEM_MAP_FAILED)) { + + end = p + size; + + jbf->buffer->mem.pos = p; + jbf->buffer->mem.free = end; + jbf->buffer->mem.start = p; + jbf->buffer->mem.end = end; + jbf->buffer->file_end += size; + jbf->offset += size; + + /* + * The mapped pages should be already preloaded in the kernel page + * cache by nxt_file_read_ahead(). Touching them should wire the pages + * in user land memory if mmap() did not do this. Adding to the static + * variable "n" disables the loop elimination during optimization. + */ + n += *p; + + for (p = nxt_align_ptr(p, nxt_pagesize); p < end; p += nxt_pagesize) { + n += *p; + } + + return NXT_OK; + } + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size) +{ + ssize_t n; + + n = nxt_file_read(&jbf->file, jbf->buffer->mem.pos, size, jbf->offset); + + if (nxt_fast_path(n > 0)) { + + jbf->buffer->mem.free += n; + jbf->offset += n; + + if (nxt_buf_is_file(jbf->buffer)) { + jbf->buffer->file_end += n; + } + + return NXT_OK; + } + + return NXT_ERROR; +} + + +static nxt_int_t +nxt_job_file_read_required(nxt_job_file_t *jbf) +{ + return NXT_OK; +} |