summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_job_file.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/nxt_job_file.c303
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;
+}