1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7
8 #include <nxt_main.h>
9
10
11 static void nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data);
12 static nxt_int_t nxt_job_file_open(nxt_job_file_t *jbf);
13 static nxt_int_t nxt_job_file_info(nxt_job_file_t *jbf);
14 static nxt_int_t nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size);
15 static nxt_int_t nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size);
16 static nxt_int_t nxt_job_file_read_required(nxt_job_file_t *jbf);
17
18
19 nxt_job_file_t *
nxt_job_file_create(nxt_mp_t * mp)20 nxt_job_file_create(nxt_mp_t *mp)
21 {
22 nxt_job_file_t *jbf;
23
24 jbf = nxt_job_create(mp, sizeof(nxt_job_file_t));
25
26 if (nxt_fast_path(jbf != NULL)) {
27 jbf->file.fd = NXT_FILE_INVALID;
28 jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
29 jbf->read_required = nxt_job_file_read_required;
30 }
31
32 return jbf;
33 }
34
35
36 void
nxt_job_file_init(nxt_job_file_t * jbf)37 nxt_job_file_init(nxt_job_file_t *jbf)
38 {
39 nxt_job_init(&jbf->job, sizeof(nxt_job_file_t));
40
41 jbf->file.fd = NXT_FILE_INVALID;
42 jbf->file.accessed = NXT_FILE_ACCESSED_LONG_AGO;
43 jbf->read_required = nxt_job_file_read_required;
44 }
45
46
47 /*
48 * Must be a function but not a macro, because
49 * it can be used as function pointer.
50 */
51
52 void
nxt_job_file_read(nxt_task_t * task,nxt_job_t * job)53 nxt_job_file_read(nxt_task_t *task, nxt_job_t *job)
54 {
55 nxt_job_start(task, job, nxt_job_file_open_and_read);
56 }
57
58
59 static void
nxt_job_file_open_and_read(nxt_task_t * task,void * obj,void * data)60 nxt_job_file_open_and_read(nxt_task_t *task, void *obj, void *data)
61 {
62 size_t size;
63 nxt_int_t n;
64 nxt_bool_t read_ahead;
65 nxt_file_t *file;
66 nxt_job_file_t *jbf;
67 nxt_work_handler_t handler;
68
69 jbf = obj;
70 file = &jbf->file;
71
72 nxt_debug(task, "file job read: \"%FN\"", file->name);
73
74 if (file->fd != NXT_FILE_INVALID && jbf->close_before_open) {
75 nxt_file_close(file);
76 file->fd = NXT_FILE_INVALID;
77 }
78
79 if (file->fd == NXT_FILE_INVALID) {
80
81 switch (nxt_job_file_open(jbf)) {
82
83 case NXT_OK:
84 break;
85
86 case NXT_DECLINED:
87 handler = jbf->ready_handler;
88 goto done;
89
90 default: /* NXT_ERROR */
91 handler = jbf->error_handler;
92 goto done;
93 }
94 }
95
96 if (file->size > 0) {
97
98 if (jbf->buffer != NULL) {
99 size = nxt_buf_mem_size(&jbf->buffer->mem);
100 size = nxt_min(file->size, (nxt_off_t) size);
101 read_ahead = nxt_buf_is_mmap(jbf->buffer);
102
103 } else {
104 size = nxt_min(file->size, 1024 * 1024);
105 read_ahead = jbf->read_ahead;
106 }
107
108 if (read_ahead) {
109 nxt_file_read_ahead(&jbf->file, jbf->offset, size);
110 }
111
112 if (jbf->buffer != NULL) {
113
114 if (nxt_buf_is_mmap(jbf->buffer)) {
115 n = nxt_job_file_mmap(jbf, size);
116
117 } else {
118 n = nxt_job_file_read_data(jbf, size);
119 }
120
121 if (nxt_slow_path(n != NXT_OK)) {
122 handler = jbf->error_handler;
123 goto done;
124 }
125 }
126 }
127
128 if (jbf->offset == file->size) {
129 jbf->complete = 1;
130
131 if (jbf->close) {
132 nxt_file_close(file);
133 file->fd = NXT_FILE_INVALID;
134 }
135 }
136
137 nxt_job_return(task, &jbf->job, jbf->ready_handler);
138 return;
139
140 done:
141
142 if (file->fd != NXT_FILE_INVALID) {
143 nxt_file_close(file);
144 file->fd = NXT_FILE_INVALID;
145 }
146
147 nxt_job_return(task, &jbf->job, handler);
148 }
149
150
151 static nxt_int_t
nxt_job_file_open(nxt_job_file_t * jbf)152 nxt_job_file_open(nxt_job_file_t *jbf)
153 {
154 nxt_int_t n;
155
156 if (jbf->test_before_open) {
157 n = nxt_job_file_info(jbf);
158
159 if (n != NXT_OK) {
160 goto test_directory;
161 }
162
163 if (jbf->file.type == NXT_FILE_DIRECTORY) {
164 return NXT_DECLINED;
165 }
166
167 if (jbf->read_required(jbf) != NXT_OK) {
168 return NXT_DECLINED;
169 }
170 }
171
172 n = nxt_file_open(&jbf->file, NXT_FILE_RDONLY, NXT_FILE_OPEN, 0);
173
174 if (n == NXT_OK) {
175 n = nxt_job_file_info(jbf);
176
177 if (nxt_fast_path(n == NXT_OK)) {
178
179 if (jbf->file.type == NXT_FILE_DIRECTORY) {
180 return NXT_DECLINED;
181 }
182
183 return jbf->read_required(jbf);
184 }
185
186 return n;
187 }
188
189 test_directory:
190
191 if (jbf->directory_end != 0
192 && jbf->file.error != NXT_ENOTDIR
193 && jbf->file.error != NXT_ENAMETOOLONG
194 && jbf->file.error != NXT_EACCES)
195 {
196 jbf->file.name[jbf->directory_end] = '\0';
197
198 return nxt_job_file_info(jbf);
199 }
200
201 return n;
202 }
203
204
205 static nxt_int_t
nxt_job_file_info(nxt_job_file_t * jbf)206 nxt_job_file_info(nxt_job_file_t *jbf)
207 {
208 nxt_int_t n;
209 nxt_file_t *file;
210 nxt_file_info_t fi;
211
212 file = &jbf->file;
213
214 n = nxt_file_info(file, &fi);
215
216 if (n != NXT_OK) {
217 return NXT_ERROR;
218 }
219
220 if (nxt_is_file(&fi)) {
221 file->type = NXT_FILE_REGULAR;
222 file->size = nxt_file_size(&fi);
223 file->mtime = nxt_file_mtime(&fi);
224
225 } else if (nxt_is_dir(&fi)) {
226 file->type = NXT_FILE_DIRECTORY;
227 file->size = nxt_file_size(&fi);
228 file->mtime = nxt_file_mtime(&fi);
229 }
230
231 return NXT_OK;
232 }
233
234
235 static nxt_int_t
nxt_job_file_mmap(nxt_job_file_t * jbf,size_t size)236 nxt_job_file_mmap(nxt_job_file_t *jbf, size_t size)
237 {
238 u_char *p, *end;
239 static nxt_uint_t n;
240
241 p = nxt_mem_map(NULL, &jbf->buffer->mmap, size, NXT_MEM_MAP_READ,
242 (NXT_MEM_MAP_FILE | NXT_MEM_MAP_PREFAULT),
243 jbf->file.fd, jbf->offset);
244
245 if (nxt_fast_path(p != NXT_MEM_MAP_FAILED)) {
246
247 end = p + size;
248
249 jbf->buffer->mem.pos = p;
250 jbf->buffer->mem.free = end;
251 jbf->buffer->mem.start = p;
252 jbf->buffer->mem.end = end;
253 jbf->buffer->file_end += size;
254 jbf->offset += size;
255
256 /*
257 * The mapped pages should be already preloaded in the kernel page
258 * cache by nxt_file_read_ahead(). Touching them should wire the pages
259 * in user land memory if mmap() did not do this. Adding to the static
260 * variable "n" disables the loop elimination during optimization.
261 */
262 n += *p;
263
264 for (p = nxt_align_ptr(p, nxt_pagesize); p < end; p += nxt_pagesize) {
265 n += *p;
266 }
267
268 return NXT_OK;
269 }
270
271 return NXT_ERROR;
272 }
273
274
275 static nxt_int_t
nxt_job_file_read_data(nxt_job_file_t * jbf,size_t size)276 nxt_job_file_read_data(nxt_job_file_t *jbf, size_t size)
277 {
278 ssize_t n;
279
280 n = nxt_file_read(&jbf->file, jbf->buffer->mem.free, size, jbf->offset);
281
282 if (nxt_fast_path(n > 0)) {
283
284 jbf->buffer->mem.free += n;
285 jbf->offset += n;
286
287 if (nxt_buf_is_file(jbf->buffer)) {
288 jbf->buffer->file_end += n;
289 }
290
291 return NXT_OK;
292 }
293
294 return NXT_ERROR;
295 }
296
297
298 static nxt_int_t
nxt_job_file_read_required(nxt_job_file_t * jbf)299 nxt_job_file_read_required(nxt_job_file_t *jbf)
300 {
301 return NXT_OK;
302 }
303