can you please explain in detail the need for the explicit close here?
I think it has to do with PerlIO in combination with an implementation peculiarity.
When you compare the straces of both variants, you'll see something like:
# with explicit close
close(1) = 0
open("/tmp/stdout.log", O_RDWR|O_CREAT|O_TRUNC, 0666) = 1
ioctl(1, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff2ba69a30) = -1 ENOTTY (I
+nappropriate ioctl for device)
lseek(1, 0, SEEK_CUR) = 0
fstat(1, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
fcntl(1, F_SETFD, 0) = 0
# without explicit close
open("/tmp/stdout.log", O_RDWR|O_CREAT|O_TRUNC, 0666) = 4
ioctl(4, SNDCTL_TMR_TIMEBASE or TCGETS, 0x7fff023c1390) = -1 ENOTTY (I
+nappropriate ioctl for device)
lseek(4, 0, SEEK_CUR) = 0
fstat(4, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
dup2(4, 1) = 1
close(4) = 0
fcntl(1, F_SETFD, 0) = 0
Now, the issue is (I think) that although the dup2 does
create a copy of fd 4 as fd 1 at the system level (and in fact
does also close the old fd 1), it does not copy the PerlIO part,
which is only being handled properly, when the filehandle is being
created directly using Perl's open. For this reason, the
filedescriptor is considered invalid from the PerlIO point of view (—> the "Bad file descriptor" message).
This is checked at the beginning of Perl's read using
PerlIOValid(f)1 (even before doing any read system call).
Don't ask (me), however, why the indirect dup2-technique is being
used in the first place instead of simply closing the filedescriptor
before the open... (Presumably, it did work before the the introduction of PerlIO, and might just not have been adapted appropriately since.)
___
1 see perlio.c:
#define Perl_PerlIO_or_Base(f, callback, base, failure, args) \
if (PerlIOValid(f)) { \
const PerlIO_funcs * const tab = PerlIOBase(f)->tab;\
if (tab && tab->callback) \
return (*tab->callback) args; \
else \
return PerlIOBase_ ## base args; \
} \
else \
SETERRNO(EBADF, SS_IVCHAN); \
return failure
...
SSize_t
Perl_PerlIO_read(pTHX_ PerlIO *f, void *vbuf, Size_t count)
{
Perl_PerlIO_or_Base(f, Read, read, -1, (aTHX_ f, vbuf, count));
}
|