fcntl/ $$ oddity

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
This text is supposed to document an oddity in the perl fcntl
implementation which cropped up in a program I wrote as part of my job
that puzzled me for a while.

The mini perl script included below is supposed to tell the kernel
that the current process is supposed to receive asynchronous I/O
notification signals for the file descriptor belonging to the created

use Fcntl;
use Socket;

socket($sk, AF_UNIX, SOCK_STREAM, 0) or die("$!");
print STDERR ("$$\n");
fcntl($sk, F_SETOWN, $$) or die("$!");

When trying to execute this on Debian 6.0.1/ perl 5.10.1, the
fcntl-call aborts with the following error message:

[rw@sapphire]/tmp $perl a.pl
Modification of a read-only value attempted at a.pl line 6.

The reason for this is that the print which preceded the fcntl caused
the value of $$ to be stringified, meaning, it is now SvPOK. The error
is actually caused (AFAIK) by the following code in pp_sys.c:



    if (SvPOK(argsv) || !SvNIOK(argsv)) {
        STRLEN len;
        STRLEN need;
        s = SvPV_force(argsv, len);
        need = IOCPARM_LEN(func);
        if (len < need) {
            s = Sv_Grow(argsv, need + 1);
            SvCUR_set(argsv, need);

        s[SvCUR(argsv)] = 17;   /* a little sanity check here */

A workaround is to add 0 to $$ which causes a new sv to be
created that has just an integer value. One could argue that
the SvPOK(argsv) || !SvNIOK(argsv) should rather be
!SvNIOK(argsv) only.

Re: fcntl/ $$ oddity


Quoted text here. Click to load it

Fcntl is not implemented (I have ActiveState for windows installed) but
I can duplicate your processing problem.

The docs for ioctl() state the SCALAR param, if a string state uses the address
to pass to fcntl(2). Otherwise it passes by value.

This may be independent of fnctl, more a Perl variable thing.

While this fails,
   print STDERR ("$$\n");
   fcntl($sk, LOCK_EX, $$) or die("$!");
with a "Modification of a read-only value attempted"

These all work:

  print STDERR ("$$\n");
  fcntl($sk, LOCK_EX, $$+0) or die("$!");

  print STDERR ("$$\n");
  fcntl($sk, LOCK_EX, $$) or die("$!");

  print STDERR $$,"\n";
  fcntl($sk, LOCK_EX, $$) or die("$!");

Actually, the docs state if its a number, better to add a 0 to it to put
the variable into a numeric state.

The whole thing smells Perlish to me.


Site Timeline