RT-Thread RTOS 1.2.0
An open source embedded real-time operating system
载入中...
搜索中...
未找到
dfs_seq_file.c
浏览该文件的文档.
1/*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 */
9
10#include <dfs_seq_file.h>
11#include <dfs_dentry.h>
12
13#define DBG_TAG "DFS.seq"
14#define DBG_LVL DBG_WARNING
15#include <rtdbg.h>
16
17#ifndef PAGE_SIZE
18#define PAGE_SIZE 4096
19#endif
20
21static void dfs_seq_overflow(struct dfs_seq_file *seq)
22{
23 seq->count = seq->size;
24}
25
26static void *dfs_seq_alloc(unsigned long size)
27{
28 return rt_calloc(1, size);
29}
30
31int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops)
32{
33 struct dfs_seq_file *seq;
34
35 if (!ops)
36 {
37 LOG_E("dfs_seq_open: ops = null, pathname: %s\n", file->dentry->pathname);
38 return -EINVAL;
39 }
40
41 if (file->data)
42 {
43 LOG_W("dfs_seq_open: file->data != null\n");
44 }
45
46 seq = rt_calloc(1, sizeof(struct dfs_seq_file));
47 if (!seq)
48 return -ENOMEM;
49
50 file->data = seq;
51
52 rt_mutex_init(&seq->lock, "dfs_seq", RT_IPC_FLAG_PRIO);
53
54 seq->ops = ops;
55 seq->file = file;
56
57 return 0;
58}
59
60static int dfs_seq_traverse(struct dfs_seq_file *seq, off_t offset)
61{
62 off_t pos = 0;
63 int error = 0;
64 void *p;
65
66 seq->index = 0;
67 seq->count = seq->from = 0;
68 if (!offset)
69 return 0;
70
71 if (!seq->buf)
72 {
73 seq->buf = dfs_seq_alloc(seq->size = PAGE_SIZE);
74 if (!seq->buf)
75 return -ENOMEM;
76 }
77 p = seq->ops->start(seq, &seq->index);
78 while (p)
79 {
80 error = seq->ops->show(seq, p);
81 if (error < 0)
82 break;
83 if (error)
84 {
85 error = 0;
86 seq->count = 0;
87 }
88 if (dfs_seq_is_full(seq))
89 goto Eoverflow;
90
91 p = seq->ops->next(seq, p, &seq->index);
92 if (pos + seq->count > offset)
93 {
94 seq->from = offset - pos;
95 seq->count -= seq->from;
96 break;
97 }
98 pos += seq->count;
99 seq->count = 0;
100 if (pos == offset)
101 break;
102 }
103 seq->ops->stop(seq, p);
104 return error;
105
106Eoverflow:
107 seq->ops->stop(seq, p);
108 rt_free(seq->buf);
109 seq->count = 0;
110 seq->buf = dfs_seq_alloc(seq->size <<= 1);
111 return !seq->buf ? -ENOMEM : -EAGAIN;
112}
113
114ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos)
115{
116 struct dfs_seq_file *seq = file->data;
117 size_t copied = 0;
118 size_t n;
119 void *p;
120 int err = 0;
121
122 if (!size)
123 return 0;
124
126
127 /*
128 * if request is to read from zero offset, reset iterator to first
129 * record as it might have been already advanced by previous requests
130 */
131 if (*pos == 0)
132 {
133 seq->index = 0;
134 seq->count = 0;
135 }
136
137 /* Don't assume ki_pos is where we left it */
138 if (*pos != seq->read_pos)
139 {
140 while ((err = dfs_seq_traverse(seq, *pos)) == -EAGAIN)
141 ;
142 if (err)
143 {
144 /* With prejudice... */
145 seq->read_pos = 0;
146 seq->index = 0;
147 seq->count = 0;
148 goto Done;
149 }
150 else
151 {
152 seq->read_pos = *pos;
153 }
154 }
155
156 /* grab buffer if we didn't have one */
157 if (!seq->buf)
158 {
159 seq->buf = dfs_seq_alloc(seq->size = PAGE_SIZE);
160 if (!seq->buf)
161 goto Enomem;
162 }
163 // something left in the buffer - copy it out first
164 if (seq->count)
165 {
166 n = seq->count > size ? size : seq->count;
167 rt_memcpy((char *)buf + copied, seq->buf + seq->from, n);
168 size -= n;
169 seq->count -= n;
170 seq->from += n;
171 copied += n;
172 if (seq->count) // hadn't managed to copy everything
173 goto Done;
174 }
175 // get a non-empty record in the buffer
176 seq->from = 0;
177 p = seq->ops->start(seq, &seq->index);
178 while (p)
179 {
180 err = seq->ops->show(seq, p);
181 if (err < 0) // hard error
182 break;
183 if (err) // ->show() says "skip it"
184 seq->count = 0;
185 if (!seq->count)
186 { // empty record
187 p = seq->ops->next(seq, p, &seq->index);
188 continue;
189 }
190 if (!dfs_seq_is_full(seq)) // got it
191 goto Fill;
192 // need a bigger buffer
193 seq->ops->stop(seq, p);
194 rt_free(seq->buf);
195 seq->count = 0;
196 seq->buf = dfs_seq_alloc(seq->size <<= 1);
197 if (!seq->buf)
198 goto Enomem;
199 p = seq->ops->start(seq, &seq->index);
200 }
201 // EOF or an error
202 seq->ops->stop(seq, p);
203 seq->count = 0;
204 goto Done;
205Fill:
206 // one non-empty record is in the buffer; if they want more,
207 // try to fit more in, but in any case we need to advance
208 // the iterator once for every record shown.
209 while (1)
210 {
211 size_t offs = seq->count;
212 off_t pos = seq->index;
213
214 p = seq->ops->next(seq, p, &seq->index);
215 if (pos == seq->index)
216 {
217 LOG_W(".next function %p did not update position index\n", seq->ops->next);
218 seq->index++;
219 }
220 if (!p) // no next record for us
221 break;
222 if (seq->count >= size)
223 break;
224 err = seq->ops->show(seq, p);
225 if (err > 0)
226 { // ->show() says "skip it"
227 seq->count = offs;
228 }
229 else if (err || dfs_seq_is_full(seq))
230 {
231 seq->count = offs;
232 break;
233 }
234 }
235 seq->ops->stop(seq, p);
236 n = seq->count > size ? size : seq->count;
237 rt_memcpy((char *)buf + copied, seq->buf, n);
238 size -= n;
239 copied += n;
240 seq->count -= n;
241 seq->from = n;
242Done:
243 if (!copied)
244 {
245 copied = seq->count ? -EFAULT : err;
246 }
247 else
248 {
249 *pos += copied;
250 seq->read_pos += copied;
251 }
252 rt_mutex_release(&seq->lock);
253 return copied;
254Enomem:
255 err = -ENOMEM;
256 goto Done;
257}
258
259off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
260{
261 struct dfs_seq_file *seq = file->data;
262 off_t retval = -EINVAL;
263
265
266 switch (whence)
267 {
268 case SEEK_CUR:
269 offset += file->fpos;
270 case SEEK_SET:
271 if (offset < 0)
272 break;
273 retval = offset;
274 if (offset != seq->read_pos)
275 {
276 while ((retval = dfs_seq_traverse(seq, offset)) == -EAGAIN);
277 if (retval)
278 {
279 /* with extreme prejudice... */
280 retval = 0;
281 seq->read_pos = 0;
282 seq->index = 0;
283 seq->count = 0;
284 }
285 else
286 {
287 seq->read_pos = offset;
288 retval = offset;
289 }
290 }
291 }
292
293 rt_mutex_release(&seq->lock);
294
295 return retval;
296}
297
299{
300 struct dfs_seq_file *seq = file->data;
301
302 if (seq)
303 {
304 rt_mutex_detach(&seq->lock);
305 if (seq->buf)
306 {
307 rt_free(seq->buf);
308 }
309 rt_free(seq);
310 }
311
312 return 0;
313}
314
315void dfs_seq_vprintf(struct dfs_seq_file *seq, const char *f, va_list args)
316{
317 int len;
318
319 if (seq->count < seq->size)
320 {
321 len = vsnprintf(seq->buf + seq->count, seq->size - seq->count, f, args);
322 if (seq->count + len < seq->size)
323 {
324 seq->count += len;
325 return;
326 }
327 }
328 dfs_seq_overflow(seq);
329}
330
331void dfs_seq_printf(struct dfs_seq_file *seq, const char *f, ...)
332{
333 va_list args;
334
335 va_start(args, f);
336 dfs_seq_vprintf(seq, f, args);
337 va_end(args);
338}
339
343void dfs_seq_putc(struct dfs_seq_file *seq, char c)
344{
345 if (seq->count < seq->size)
346 {
347 seq->buf[seq->count++] = c;
348 }
349}
350
354void dfs_seq_puts(struct dfs_seq_file *seq, const char *s)
355{
356 int len = strlen(s);
357
358 if (seq->count + len >= seq->size)
359 {
360 dfs_seq_overflow(seq);
361 return;
362 }
363 rt_memcpy(seq->buf + seq->count, s, len);
364 seq->count += len;
365}
366
370int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len)
371{
372 if (seq->count + len < seq->size)
373 {
374 rt_memcpy(seq->buf + seq->count, data, len);
375 seq->count += len;
376 return 0;
377 }
378 dfs_seq_overflow(seq);
379 return -1;
380}
381
385void dfs_seq_pad(struct dfs_seq_file *seq, char c)
386{
387 int size = seq->pad_until - seq->count;
388
389 if (size > 0)
390 {
391 if (size + seq->count > seq->size)
392 {
393 dfs_seq_overflow(seq);
394 return;
395 }
396 rt_memset(seq->buf + seq->count, ' ', size);
397 seq->count += size;
398 }
399
400 if (c)
401 {
402 dfs_seq_putc(seq, c);
403 }
404}
int dfs_seq_release(struct dfs_file *file)
off_t dfs_seq_lseek(struct dfs_file *file, off_t offset, int whence)
void dfs_seq_pad(struct dfs_seq_file *seq, char c)
void dfs_seq_putc(struct dfs_seq_file *seq, char c)
#define PAGE_SIZE
void dfs_seq_puts(struct dfs_seq_file *seq, const char *s)
void dfs_seq_vprintf(struct dfs_seq_file *seq, const char *f, va_list args)
ssize_t dfs_seq_read(struct dfs_file *file, void *buf, size_t size, off_t *pos)
int dfs_seq_open(struct dfs_file *file, const struct dfs_seq_ops *ops)
int dfs_seq_write(struct dfs_seq_file *seq, const void *data, size_t len)
void dfs_seq_printf(struct dfs_seq_file *seq, const char *f,...)
#define RT_IPC_FLAG_PRIO
#define RT_WAITING_FOREVER
rt_weak void * rt_calloc(rt_size_t count, rt_size_t size)
This function will contiguously allocate enough space for count objects that are size bytes of memory...
rt_weak void rt_free(void *ptr)
This function will release the previously allocated memory block by rt_malloc. The released memory bl...
rt_err_t rt_mutex_take(rt_mutex_t mutex, rt_int32_t time)
定义 ipc.c:1537
rt_err_t rt_mutex_detach(rt_mutex_t mutex)
This function will detach a static mutex object.
定义 ipc.c:1054
rt_err_t rt_mutex_init(rt_mutex_t mutex, const char *name, rt_uint8_t flag)
Initialize a static mutex object.
定义 ipc.c:1007
rt_err_t rt_mutex_release(rt_mutex_t mutex)
This function will release a mutex. If there is thread suspended on the mutex, the thread will be res...
定义 ipc.c:1589
#define LOG_W(...)
#define LOG_E(fmt,...)
struct dfs_dentry * dentry
struct rt_mutex lock
const struct dfs_file * file
const struct dfs_seq_ops * ops
int(* show)(struct dfs_seq_file *seq, void *data)
void *(* next)(struct dfs_seq_file *seq, void *data, off_t *index)
void(* stop)(struct dfs_seq_file *seq, void *data)
void *(* start)(struct dfs_seq_file *seq, off_t *index)