未验证 提交 1f60b5be 编写于 作者: O openharmony_ci 提交者: Gitee

!939 Optimize fopen function

Merge pull request !939 from Wang Yaofeng/fopen_optimization
......@@ -2175,6 +2175,13 @@ musl_src_porting_file = [
"src/stdio/fmemopen.c",
"src/stdio/freopen.c",
"src/stdio/stdin.c",
"src/stdio/__fmodeflags.c",
"src/stdio/fopen.c",
"src/stdio/ofl.c",
"src/stdio/fclose.c",
"src/stdio/__toread.c",
"src/stdio/__towrite.c",
"src/stdio/stderr.c",
"src/internal/stdio_impl.h",
"src/internal/vdso.c",
"src/time/clock_gettime.c",
......
......@@ -17,6 +17,7 @@
#define F_ERR 32
#define F_SVB 64
#define F_APP 128
#define F_NOBUF 256
struct _IO_FILE {
unsigned flags;
......@@ -31,6 +32,14 @@ struct _IO_FILE {
off_t (*seek)(FILE *, off_t, int);
unsigned char *buf;
size_t buf_size;
/* when allocating buffer dynamically, base == buf - UNGET,
* free base when calling fclose.
* otherwise, base == NULL, cases:
* 1. in stdout, stdin, stdout, base is static array.
* 2. call setvbuf to set buffer or non-buffer.
* 3. call fmemopen, base == NULL && buf_size != 0.
*/
unsigned char *base;
FILE *prev, *next;
int fd;
int pipe_pid;
......@@ -67,6 +76,7 @@ hidden ssize_t __flush_buffer(FILE *f);
hidden int __toread(FILE *);
hidden int __towrite(FILE *);
hidden int __falloc_buf(FILE *);
hidden void __stdio_exit(void);
hidden void __stdio_exit_needed(void);
......@@ -84,11 +94,14 @@ hidden size_t __fwritex(const unsigned char *, size_t, FILE *);
hidden int __putc_unlocked(int, FILE *);
hidden FILE *__fdopen(int, const char *);
hidden int __fmodeflags(const char *);
hidden FILE *__fdopenx(int, int);
hidden int __fmodeflags(const char *, int *);
hidden FILE *__ofl_add(FILE *f);
hidden FILE **__ofl_lock(void);
hidden void __ofl_unlock(void);
hidden void __ofl_free(FILE *f);
hidden FILE *__ofl_alloc();
struct __pthread;
hidden void __register_locked_file(FILE *, struct __pthread *);
......
......@@ -21,7 +21,7 @@
#include <string.h>
#include "libc.h"
static size_t get_bufsize(int fd)
static size_t __get_bufsize(int fd)
{
struct stat st;
size_t buf_size = 0;
......@@ -37,50 +37,79 @@ static size_t get_bufsize(int fd)
return buf_size;
}
FILE *__fdopen(int fd, const char *mode)
int __falloc_buf(FILE *f)
{
FILE *f;
struct winsize wsz;
size_t buf_size = 0;
/* Check for valid initial mode character */
if (!strchr("rwa", *mode)) {
errno = EINVAL;
/* return if already allocated, or F_NOBUF set */
if (f->buf != NULL || f->buf_size != 0 || f->flags & F_NOBUF) {
return 0;
}
/* Default, base and buf are NULL,and buf_size = 0 */
size_t buf_size = 0;
/* get buffer size via file stat */
buf_size = get_bufsize(fd);
buf_size = __get_bufsize(f->fd);
/* Allocate FILE+buffer or fail */
if (!(f = malloc(sizeof *f + UNGET + buf_size))) {
return 0;
/* alloc R/W buffer */
f->base = (unsigned char *)malloc(UNGET + buf_size * sizeof(unsigned char));
if (!f->base) {
errno = -ENOMEM;
return errno;
}
/* Zero-fill only the struct, not the buffer */
memset(f, 0, sizeof *f);
/* reserve UNGET buffer */
f->buf = f->base + UNGET;
f->buf_size = buf_size;
return 0;
}
/* Impose mode restrictions */
if (!strchr(mode, '+')) {
f->flags = (*mode == 'r') ? F_NOWR : F_NORD;
FILE *__fdopen(int fd, const char *mode)
{
FILE *f = NULL;
int file_flags = 0;
int mode_flags = 0;
/* Compute the flags to pass to open() */
mode_flags = __fmodeflags(mode, &file_flags);
if (mode_flags < 0) {
return NULL;
}
/* Apply close-on-exec flag */
if (strchr(mode, 'e')) {
if (mode_flags & O_CLOEXEC) {
__syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
}
/* Set append mode on fd if opened for append */
if (*mode == 'a') {
if (mode_flags & O_APPEND) {
int flags = __syscall(SYS_fcntl, fd, F_GETFL);
if (!(flags & O_APPEND))
__syscall(SYS_fcntl, fd, F_SETFL, flags | O_APPEND);
f->flags |= F_APP;
}
f = __fdopenx(fd, file_flags);
if (f) {
return f;
}
return NULL;
}
weak_alias(__fdopen, fdopen);
FILE *__fdopenx(int fd, int flags)
{
FILE *f = 0;
struct winsize wsz;
/* Allocate FILE or fail */
if (!(f = __ofl_alloc())) {
return NULL;
}
/* Zero-fill only the struct, not the buffer */
memset(f, 0, sizeof *f);
f->flags = flags;
f->fd = fd;
f->buf = (unsigned char *)f + sizeof *f + UNGET;
f->buf_size = buf_size;
/* Activate line buffered mode for terminals */
f->lbf = EOF;
......@@ -103,4 +132,3 @@ FILE *__fdopen(int fd, const char *mode)
return __ofl_add(f);
}
weak_alias(__fdopen, fdopen);
#include "stdio_impl.h"
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int __fmodeflags(const char *mode, int *flags)
{
int mode_flags = 0;
int options = 0;
switch (*mode) {
case 'r':
mode_flags = O_RDONLY;
*flags = F_NOWR;
break;
case 'w':
mode_flags = O_WRONLY;
options = O_TRUNC | O_CREAT;
*flags = F_NORD;
break;
case 'a':
mode_flags = O_WRONLY;
options = O_APPEND | O_CREAT;
*flags = F_NORD | F_APP;
break;
default:
errno = EINVAL;
return -EINVAL;
}
mode++;
while (*mode != '\0') {
switch (*mode) {
case '+':
mode_flags = O_RDWR;
*flags &= ~(F_NORD | F_NOWR);
break;
case 'x':
/* need O_CREAT check */
options |= O_EXCL;
break;
case 'e':
options |= O_CLOEXEC;
break;
case 'b':
break;
default:
/* only accept "+xeb" */
break;
}
mode++;
}
return mode_flags | options;
}
#include <stdio_impl.h>
int __toread(FILE *f)
{
f->mode |= f->mode-1;
if (f->wpos != f->wbase) f->write(f, 0, 0);
f->wpos = f->wbase = f->wend = 0;
if (f->flags & F_NORD) {
f->flags |= F_ERR;
return EOF;
}
/* Alloc file buffer if needed */
if (__falloc_buf(f) < 0) {
f->flags |= F_ERR;
return EOF;
}
f->rpos = f->rend = f->buf + f->buf_size;
return (f->flags & F_EOF) ? EOF : 0;
}
hidden void __toread_needs_stdio_exit()
{
__stdio_exit_needed();
}
#include "stdio_impl.h"
int __towrite(FILE *f)
{
f->mode |= f->mode-1;
if (f->flags & F_NOWR) {
f->flags |= F_ERR;
return EOF;
}
/* Clear read buffer (easier than summoning nasal demons) */
f->rpos = f->rend = 0;
/* Alloc file buffer if needed */
if (__falloc_buf(f) < 0) {
f->flags |= F_ERR;
return EOF;
}
/* Activate write through the buffer. */
f->wpos = f->wbase = f->buf;
f->wend = f->buf + f->buf_size;
return 0;
}
hidden void __towrite_needs_stdio_exit()
{
__stdio_exit_needed();
}
#include "stdio_impl.h"
#include <stdlib.h>
static void dummy(FILE *f) { }
weak_alias(dummy, __unlist_locked_file);
int fclose(FILE *f)
{
int r;
FLOCK(f);
r = fflush(f);
r |= f->close(f);
FUNLOCK(f);
/* Past this point, f is closed and any further explict access
* to it is undefined. However, it still exists as an entry in
* the open file list and possibly in the thread's locked files
* list, if it was closed while explicitly locked. Functions
* which process these lists must tolerate dead FILE objects
* (which necessarily have inactive buffer pointers) without
* producing any side effects. */
if (f->flags & F_PERM) return r;
__unlist_locked_file(f);
free(f->getln_buf);
/* release base instead of buf which may be modified by setvbuf
* or iniitalize by local variable */
free(f->base);
__ofl_free(f);
return r;
}
#include "stdio_impl.h"
#include <fcntl.h>
#include <string.h>
#include <errno.h>
FILE *fopen(const char *restrict filename, const char *restrict mode)
{
FILE *f = NULL;
int fd = -1;
int file_flags = 0;
int mode_flags = 0;
/* Compute the flags to pass to open() */
mode_flags = __fmodeflags(mode, &file_flags);
if (mode_flags < 0) {
return NULL;
}
fd = sys_open(filename, mode_flags, 0666);
if (fd < 0) return 0;
if (mode_flags & O_CLOEXEC)
__syscall(SYS_fcntl, fd, F_SETFD, FD_CLOEXEC);
f = __fdopenx(fd, file_flags);
if (f) {
return f;
}
__syscall(SYS_close, fd);
return 0;
}
weak_alias(fopen, fopen64);
......@@ -9,6 +9,7 @@ int __fill_buffer(FILE *f)
if (r != 0) {
return r;
}
int k = f->readx(f, f->buf, f->buf_size);
if (k <= 0) {
f->flags |= (k == 0) ? F_EOF : F_ERR;
......@@ -32,6 +33,12 @@ size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
FLOCK(f);
/* allocate file buffer if needed */
if (__falloc_buf(f) < 0) {
f->flags |= F_ERR;
goto exit;
}
f->mode |= f->mode-1;
while (l > 0) {
......@@ -47,7 +54,9 @@ size_t fread(void *restrict destv, size_t size, size_t nmemb, FILE *restrict f)
if (l == 0) {
goto exit;
}
/* if user buffer is longer than file buffer, read directly */
/* if user buffer is longer than file buffer,
* maybe buffer size is 0, non-buffer mode,
* read directly */
if (l > f->buf_size) {
break;
}
......
......@@ -12,7 +12,8 @@
FILE *freopen(const char *restrict filename, const char *restrict mode, FILE *restrict f)
{
int fl = __fmodeflags(mode);
int file_flags = 0;
int fl = __fmodeflags(mode, &file_flags);
FILE *f2;
FLOCK(f);
......
#include "stdio_impl.h"
#include "lock.h"
#include "fork_impl.h"
#include <stdlib.h>
#define DEFAULT_ALLOC_FILE (8)
static FILE *ofl_head = NULL;
static FILE *ofl_free = NULL;
static volatile int ofl_lock[1];
volatile int *const __stdio_ofl_lockptr = ofl_lock;
FILE **__ofl_lock()
{
LOCK(ofl_lock);
return &ofl_head;
}
void __ofl_unlock()
{
UNLOCK(ofl_lock);
}
FILE *__ofl_alloc()
{
unsigned char *fsb = NULL;
size_t cnt = 0;
FILE *f = NULL;
LOCK(ofl_lock);
if (ofl_free) {
f = ofl_free;
ofl_free = ofl_free->next;
UNLOCK(ofl_lock);
return f;
}
UNLOCK(ofl_lock);
/* alloc new FILEs(8) */
fsb = (unsigned char *)malloc(DEFAULT_ALLOC_FILE * sizeof(FILE));
if (!fsb) {
return NULL;
}
LOCK(ofl_lock);
ofl_free = (FILE*)fsb;
ofl_free->prev = NULL;
f = ofl_free;
for (cnt = 1; cnt < DEFAULT_ALLOC_FILE; cnt++) {
FILE *tmp = (FILE*)(fsb + cnt * sizeof(FILE));
tmp->next = NULL;
f->next = tmp;
tmp->prev = f;
f = f->next;
}
/* reset and move to next free FILE */
f = ofl_free;
ofl_free = ofl_free->next;
if (ofl_free) {
ofl_free->prev = NULL;
}
UNLOCK(ofl_lock);
return f;
}
void __ofl_free(FILE *f)
{
LOCK(ofl_lock);
if (!f) {
return;
}
/* remove from head list */
if (f->prev) {
f->prev->next = f->next;
}
if (f->next) {
f->next->prev = f->prev;
}
if (f == ofl_head) {
ofl_head = f->next;
}
/* push to free list */
f->next = ofl_free;
if (ofl_free) {
ofl_free->prev = f;
}
ofl_free = f;
UNLOCK(ofl_lock);
}
#include "stdio_impl.h"
/* The behavior of this function is undefined except when it is the first
* operation on the stream, so the presence or absence of locking is not
* observable in a program whose behavior is defined. Thus no locking is
* performed here. No allocation of buffers is performed, but a buffer
* provided by the caller is used as long as it is suitably sized. */
int setvbuf(FILE *restrict f, char *restrict buf, int type, size_t size)
{
f->lbf = EOF;
if (type == _IONBF) {
f->buf_size = 0;
f->flags |= F_NOBUF;
} else if (type == _IOLBF || type == _IOFBF) {
if (buf && size >= UNGET) {
f->buf = (void *)(buf + UNGET);
f->buf_size = size - UNGET;
}
if (type == _IOLBF && f->buf_size)
f->lbf = '\n';
f->flags &= ~F_NOBUF;
} else {
return -1;
}
f->flags |= F_SVB;
return 0;
}
#include "stdio_impl.h"
#undef stderr
static unsigned char buf[UNGET];
hidden FILE __stderr_FILE = {
.buf = buf+UNGET,
.buf_size = 0,
.fd = 2,
.flags = F_PERM | F_NORD | F_NOBUF,
.lbf = -1,
.write = __stdio_write,
.seek = __stdio_seek,
.close = __stdio_close,
.lock = -1,
};
FILE *const stderr = &__stderr_FILE;
FILE *volatile __stderr_used = &__stderr_FILE;
......@@ -674,6 +674,13 @@ int vfprintf(FILE *restrict f, const char *restrict fmt, va_list ap)
FLOCK(f);
olderr = f->flags & F_ERR;
if (f->mode < 1) f->flags &= ~F_ERR;
/* allocate file buffer if need */
if (__falloc_buf(f) < 0) {
f->flags |= F_ERR;
ret = -1;
}
if (!f->buf_size) {
saved_buf = f->buf;
f->buf = internal_buf;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册