Re: cvs: php4 /ext/standard file.c
| From: | Michael Widenius | Date: | Sat, 23 Dec 2000 19:49:52 +0000 |
| Subject: | Re: cvs: php4 /ext/standard file.c | ||
| References: | 1 2 | Groups: | php.cvs |
| Request: | Send a blank email to php-cvs+get-3285@lists.php.net to get a copy of this message | ||
Hi!
>>>>> "Sascha" == Sascha Schumann <sascha@schumann.cx> writes:
Sascha> Hi,
>> The above is not really right; If you check the code of my_write(),
>> it only uses errno if write() returns 0 or -1, in which case
>> errno should contain the right error code.
>>
>> (I know that we do a check of ENOSCP for all cases, but as this error
>> is not very likely and the only action we take is to sleep for a short
>> time and then continue, this is not really fatal).
Sascha> Right, that is the only case. The point here is that
Sascha> my_write retries the write(), possibly generating SIGXFSZ.
>> my_write() also does a retry until all bytes are written or until
>> write() returns -1, so it's not likely that it should miss to write
>> anything.
>>
>> Can you give us a scenario when my_write() can fail?
Sascha> There are a couple of system calls which might set errno to
Sascha> ENOSPC:
Sascha> open()
Sascha> link()
Sascha> mkdir()
Sascha> mkfifo()
Sascha> rename()
Sascha> write()
Sascha> sem_init()
Sascha> sem_open()
Sascha> mq_open()
Sascha> rf_create()
Sascha> If such a system call fails and sets errno to ENOSPC and if
Sascha> errno is not set afterwards, and if my_write() is invoked and
Sascha> if there is less room than necessary to write the data to the
Sascha> filesystem, SIGXFSZ will be delivered to the thread of
Sascha> execution during the write() retry.
MySQL doesn't catch the SIGXFSZ signal. In this case write() is
supposed to return -1 and set errno accordingly. In other words, this
should not be a problem.
Sascha> Unless I'm missing something, there is no way to distinguish
Sascha> these cases: First, the thread was interrupted by a signal
Sascha> and some data was already written. A retry is perfectly
Sascha> acceptable. Second, some data was written and the disk has
Sascha> no more space. Retrying the write() causes SIGXFSZ. This
Sascha> ambiguity is caused by write() not setting errno and simply
Sascha> returning the number of bytes written.
But this is not a problem with the current code(); If ENOSCP is set,
then we only loose a sleep(), which is not perfect but will not crash
anything (I already sent a mail with a single line fix to fix that).
>> The only thing that 'may' conflict with the above in the my_write()
>> code is that we check errno if write() returns 0. This isn't covered
>> by your cases, but this is something I have seen happening with
>> threads on some systems (in which case errno was always set to EINTR).
Sascha> Do you remember on which systems that happened? I've walked
Sascha> through the man pages of HPUX 10.20/11.0, FreeBSD 5.0, SunOS
Sascha> 4.1.3/5.8, Ultrix 4.2, AIX 4.2, and OpenServer 5.0.6. The
Sascha> only thing I could dig up were some references to returning
Sascha> 0, if non-blocking I/O is used. The only irregularity I
Sascha> found is on AIX which optionally returns -1 in the EINTR
Sascha> case, although some data was already written.
I am pretty sure that this happened on Solaris or SunOS; Even then it
wasn't something that was documented but something that just happened!
(Note that we also use my_write() for non-blocking IO, so we have to
handle this case too)
>> Anyway, I can't quickly see any scenario when my_write() would fail without
>> having a correct my_errno/errno set. Sasha, if you could give us
>> a scenario that proves me the current code wrong, then we will of
>> course change it!
Sascha> As I said before, this is a very unlikely case and applies to
Sascha> regular files only. A quick grep through the MySQL sources
Sascha> reveals that there is no apparent handling of SIGXFSZ, so it
Sascha> is possible that, depending on the circumstances outlined
Sascha> above, MySQL might get terminated during my_write (or are you
Sascha> ignoring most signals by default?).
We are ignoring most signals by default; We have often got a full disk
with MySQL while testing and we know from practice that my_write()
works perfectly even in this case
The problem with signals and threads is that the standard is pretty
broken regarding this; Many signals (like sigpipe) are delivered to
'any' thread, not the thread that had a problem; This makes it very
hard to use signals and most threaded programs fixes this by having
one thread that handles all signals and all other threads ignores most
of the signals (MySQL works this way).
Regards,
Monty