2011-02-12 00:22:29 -05:00
|
|
|
#include "stdio_impl.h"
|
2012-11-08 16:39:41 -05:00
|
|
|
#include <sys/uio.h>
|
2012-02-02 00:11:29 -05:00
|
|
|
#include <pthread.h>
|
|
|
|
|
|
|
|
static void cleanup(void *p)
|
|
|
|
{
|
|
|
|
FILE *f = p;
|
|
|
|
if (!f->lockcount) __unlockfile(f);
|
|
|
|
}
|
2011-02-12 00:22:29 -05:00
|
|
|
|
|
|
|
size_t __stdio_write(FILE *f, const unsigned char *buf, size_t len)
|
|
|
|
{
|
major stdio overhaul, using readv/writev, plus other changes
the biggest change in this commit is that stdio now uses readv to fill
the caller's buffer and the FILE buffer with a single syscall, and
likewise writev to flush the FILE buffer and write out the caller's
buffer in a single syscall.
making this change required fundamental architectural changes to
stdio, so i also made a number of other improvements in the process:
- the implementation no longer assumes that further io will fail
following errors, and no longer blocks io when the error flag is set
(though the latter could easily be changed back if desired)
- unbuffered mode is no longer implemented as a one-byte buffer. as a
consequence, scanf unreading has to use ungetc, to the unget buffer
has been enlarged to hold at least 2 wide characters.
- the FILE structure has been rearranged to maintain the locations of
the fields that might be used in glibc getc/putc type macros, while
shrinking the structure to save some space.
- error cases for fflush, fseek, etc. should be more correct.
- library-internal macros are used for getc_unlocked and putc_unlocked
now, eliminating some ugly code duplication. __uflow and __overflow
are no longer used anywhere but these macros. switch to read or
write mode is also separated so the code can be better shared, e.g.
with ungetc.
- lots of other small things.
2011-03-28 01:14:44 -04:00
|
|
|
struct iovec iovs[2] = {
|
|
|
|
{ .iov_base = f->wbase, .iov_len = f->wpos-f->wbase },
|
|
|
|
{ .iov_base = (void *)buf, .iov_len = len }
|
|
|
|
};
|
|
|
|
struct iovec *iov = iovs;
|
|
|
|
size_t rem = iov[0].iov_len + iov[1].iov_len;
|
|
|
|
int iovcnt = 2;
|
|
|
|
ssize_t cnt;
|
|
|
|
for (;;) {
|
always initialize thread pointer at program start
this is the first step in an overhaul aimed at greatly simplifying and
optimizing everything dealing with thread-local state.
previously, the thread pointer was initialized lazily on first access,
or at program startup if stack protector was in use, or at certain
random places where inconsistent state could be reached if it were not
initialized early. while believed to be fully correct, the logic was
fragile and non-obvious.
in the first phase of the thread pointer overhaul, support is retained
(and in some cases improved) for systems/situation where loading the
thread pointer fails, e.g. old kernels.
some notes on specific changes:
- the confusing use of libc.main_thread as an indicator that the
thread pointer is initialized is eliminated in favor of an explicit
has_thread_pointer predicate.
- sigaction no longer needs to ensure that the thread pointer is
initialized before installing a signal handler (this was needed to
prevent a situation where the signal handler caused the thread
pointer to be initialized and the subsequent sigreturn cleared it
again) but it still needs to ensure that implementation-internal
thread-related signals are not blocked.
- pthread tsd initialization for the main thread is deferred in a new
manner to minimize bloat in the static-linked __init_tp code.
- pthread_setcancelstate no longer needs special handling for the
situation before the thread pointer is initialized. it simply fails
on systems that cannot support a thread pointer, which are
non-conforming anyway.
- pthread_cleanup_push/pop now check for missing thread pointer and
nop themselves out in this case, so stdio no longer needs to avoid
the cancellable path when the thread pointer is not available.
a number of cases remain where certain interfaces may crash if the
system does not support a thread pointer. at this point, these should
be limited to pthread interfaces, and the number of such cases should
be fewer than before.
2014-03-24 16:57:11 -04:00
|
|
|
pthread_cleanup_push(cleanup, f);
|
|
|
|
cnt = syscall_cp(SYS_writev, f->fd, iov, iovcnt);
|
|
|
|
pthread_cleanup_pop(0);
|
2012-02-02 00:11:29 -05:00
|
|
|
if (cnt == rem) {
|
2012-04-17 11:08:11 -04:00
|
|
|
f->wend = f->buf + f->buf_size;
|
2012-02-02 00:11:29 -05:00
|
|
|
f->wpos = f->wbase = f->buf;
|
|
|
|
return len;
|
|
|
|
}
|
major stdio overhaul, using readv/writev, plus other changes
the biggest change in this commit is that stdio now uses readv to fill
the caller's buffer and the FILE buffer with a single syscall, and
likewise writev to flush the FILE buffer and write out the caller's
buffer in a single syscall.
making this change required fundamental architectural changes to
stdio, so i also made a number of other improvements in the process:
- the implementation no longer assumes that further io will fail
following errors, and no longer blocks io when the error flag is set
(though the latter could easily be changed back if desired)
- unbuffered mode is no longer implemented as a one-byte buffer. as a
consequence, scanf unreading has to use ungetc, to the unget buffer
has been enlarged to hold at least 2 wide characters.
- the FILE structure has been rearranged to maintain the locations of
the fields that might be used in glibc getc/putc type macros, while
shrinking the structure to save some space.
- error cases for fflush, fseek, etc. should be more correct.
- library-internal macros are used for getc_unlocked and putc_unlocked
now, eliminating some ugly code duplication. __uflow and __overflow
are no longer used anywhere but these macros. switch to read or
write mode is also separated so the code can be better shared, e.g.
with ungetc.
- lots of other small things.
2011-03-28 01:14:44 -04:00
|
|
|
if (cnt < 0) {
|
|
|
|
f->wpos = f->wbase = f->wend = 0;
|
|
|
|
f->flags |= F_ERR;
|
|
|
|
return iovcnt == 2 ? 0 : len-iov[0].iov_len;
|
|
|
|
}
|
|
|
|
rem -= cnt;
|
|
|
|
if (cnt > iov[0].iov_len) {
|
2012-02-02 00:11:29 -05:00
|
|
|
f->wpos = f->wbase = f->buf;
|
major stdio overhaul, using readv/writev, plus other changes
the biggest change in this commit is that stdio now uses readv to fill
the caller's buffer and the FILE buffer with a single syscall, and
likewise writev to flush the FILE buffer and write out the caller's
buffer in a single syscall.
making this change required fundamental architectural changes to
stdio, so i also made a number of other improvements in the process:
- the implementation no longer assumes that further io will fail
following errors, and no longer blocks io when the error flag is set
(though the latter could easily be changed back if desired)
- unbuffered mode is no longer implemented as a one-byte buffer. as a
consequence, scanf unreading has to use ungetc, to the unget buffer
has been enlarged to hold at least 2 wide characters.
- the FILE structure has been rearranged to maintain the locations of
the fields that might be used in glibc getc/putc type macros, while
shrinking the structure to save some space.
- error cases for fflush, fseek, etc. should be more correct.
- library-internal macros are used for getc_unlocked and putc_unlocked
now, eliminating some ugly code duplication. __uflow and __overflow
are no longer used anywhere but these macros. switch to read or
write mode is also separated so the code can be better shared, e.g.
with ungetc.
- lots of other small things.
2011-03-28 01:14:44 -04:00
|
|
|
cnt -= iov[0].iov_len;
|
|
|
|
iov++; iovcnt--;
|
2012-02-02 00:11:29 -05:00
|
|
|
} else if (iovcnt == 2) {
|
|
|
|
f->wbase += cnt;
|
major stdio overhaul, using readv/writev, plus other changes
the biggest change in this commit is that stdio now uses readv to fill
the caller's buffer and the FILE buffer with a single syscall, and
likewise writev to flush the FILE buffer and write out the caller's
buffer in a single syscall.
making this change required fundamental architectural changes to
stdio, so i also made a number of other improvements in the process:
- the implementation no longer assumes that further io will fail
following errors, and no longer blocks io when the error flag is set
(though the latter could easily be changed back if desired)
- unbuffered mode is no longer implemented as a one-byte buffer. as a
consequence, scanf unreading has to use ungetc, to the unget buffer
has been enlarged to hold at least 2 wide characters.
- the FILE structure has been rearranged to maintain the locations of
the fields that might be used in glibc getc/putc type macros, while
shrinking the structure to save some space.
- error cases for fflush, fseek, etc. should be more correct.
- library-internal macros are used for getc_unlocked and putc_unlocked
now, eliminating some ugly code duplication. __uflow and __overflow
are no longer used anywhere but these macros. switch to read or
write mode is also separated so the code can be better shared, e.g.
with ungetc.
- lots of other small things.
2011-03-28 01:14:44 -04:00
|
|
|
}
|
|
|
|
iov[0].iov_base = (char *)iov[0].iov_base + cnt;
|
|
|
|
iov[0].iov_len -= cnt;
|
|
|
|
}
|
2011-02-12 00:22:29 -05:00
|
|
|
}
|