Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Forks.pm dilemma

by liz (Monsignor)
on Aug 07, 2003 at 15:38 UTC ( [id://281932]=perlmeditation: print w/replies, xml ) Need Help??

I was checking forks.pm to make sure it will run under 5.8.1 (it will) and finally looked at the problem of running it under 5.6.x (it doesn't).

This is basically the problem:

share( $variable );
The share subroutine is actually an XS routine that has this special prototype:
PROTOTYPE: \[$@%]
This prototype was introduced somewhere in the 5.7 track. So in 5.6.x I can't use that (I verified this on p5p). Simply removing the prototype and then having to specify a reference when calling share(), works:
share( \$variable );
Of course, it doesn't work in 5.8.x then, but I think that's fixable. But then the user's source code becomes incompatible with the real threads module.

So before I start doing that, I figure I put the dilemma to the Monks. I see the following options:

  • Forget about supporting pre 5.8.x
    This is sad, because one of the reasons for me to develop forks.pm was to allow people to try out threaded programming in 5.6.x without having to upgrade. The only advantage to this proposal would be that you do not need a threaded 5.8.x perl to be able to run (as opposed to threads.pm, which needs perl with threads enabled).

  • Support 5.6.x, forces references everywhere
    This would make the user's source incompatible with current threads and forks users. So if you would want to migrate to "true" threads, you would need to change your code with every call to share(), lock(), cond_wait(), etc. But it would allow you to migrate from 5.6.x to 5.8.x without any problem.

  • Support 5.6.X, force references in 5.6.x, force direct otherwise
    This would mean that when code using forks is migrated from 5.6.x to 5.8.x or higher, it stops working because you need to remove the reference from each call to share(), lock() etc.
Any suggestions with regards to this dilemma are deeply appreciated.

Liz

Update
It seems possible to use a source filter for 5.6.x. I think I'll give that a try. Thanks everyone for their feedback!

Update 2

The URL

    http://www.liz.nl/CPAN/forks-0.04.tar.gz

has entered CPAN as

  file: $CPAN/authors/id/E/EL/ELIZABETH/forks-0.04.tar.gz
  size: 27883 bytes
   md5: 5855b7f32f260d5ed04b3a34671f1866

No action is required on your part
Request entered by: ELIZABETH (Elizabeth Mattijsen)
Request entered on: Mon, 11 Aug 2003 00:37:06 GMT
Request completed:  Mon, 11 Aug 2003 00:45:48 GMT

Replies are listed 'Best First'.
Re: Forks.pm dilemma
by dragonchild (Archbishop) on Aug 07, 2003 at 16:01 UTC
    Option 4 - have share() be a Perl subroutine that determines if the version of Perl is 5.6 or 5.8. If it's 5.6, takes the reference. Then, passes whatever to the XS routine. When building the XS routine, determine the Perl version and build with or without the prototype.

    In other words, make your stuff smart so the user can be dumb. :-)

    ------
    We are the carpenters and bricklayers of the Information Age.

    The idea is a little like C++ templates, except not quite so brain-meltingly complicated. -- TheDamian, Exegesis 6

    Please remember that I'm crufty and crochety. All opinions are purely mine and all code is untested, unless otherwise specified.

      ...In other words, make your stuff smart so the user can be dumb. :-)

      Unfortunately, apart from the technical difficulties (I would appreciate it if someone could tell me how to make the PROTOTYPE: conditional in the XS code, depending on the perl version), this does not address the source incompatibility issue with the real threads module. It's not just about share(), it's also about lock(), cond_wait(), cond_signal() and cond_broadcast().

      I don't see forks.pm as a substitute for the real threads module, just as a teaching and prototyping tool. I would like people to be able to try threaded programming by just downloading a CPAN module, rather than having to upgrade/rebuild perl. I would like the source incompatibility issue to be as small as possible.

      That's why I'm considering the last option as the most favorable: if you want to try out threads programming in 5.6.x, then you know you will have to change your code when you upgrade to 5.8.x and/or real threads. If you want to try out threads programming in (unthreaded) 5.8.x, then you won't need to change anything when you upgrade. So, 5.6.x support is for really toying around, higher perls support a real upgrade path.

      Liz

        As I understand this problem, dragonchild actually proposed a solution that actually solves your problem, but you somehow overlooked that.

        Consider: you'll define functions in XS with some changed name (use some prefix for example), without PROTOTYPE keyword and then provide prototype in forks.pm, and those wrapper functions will call proper XS function.
        Why this will not work in your case?

        I did same thing for Tcl perl module, where I solved another problem this way: it was too complicated for me to do logic in XS, so I decided to move it to Perl side.

        I'm not knowledgable enough to say you how to do a PROTOTYPE in perl-5.6.x

        Courage, the Cowardly Dog

Re: Forks.pm dilemma
by Juerd (Abbot) on Aug 07, 2003 at 17:42 UTC

    Or use a source filter ;)

    There is a fourth option. You could choose to step away from the threads API and invent your own sub. A sub that takes a reference but has a different name. I don't know of a good name, but let's call it refshare for now. This can be combined with supporting share with the new prototype on newer perls. On older perls you could croak 'Old perl needs refshare(\$foo) instead of share($foo)'.

    This has one froblem: s/use forks;/use threads;/ no longer magically makes the program use real threads. But a third module (threads::forks?) could implement a refshare that calls the real share to solve that problem.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      ...Or use a source filter ;)

      Can you do source filters in 5.6.x? That would be a solution, simply only apply a source filter for source < 5.8.0 that replaces:

      share( $x );
      with:
      share( \$x );
      under the hood as it were. But I seem to remember source filters were introduced somewhere in the 5.7.x track?

      And no, I don't want to invent my own API. Perl needs a good threads implementation. I'm just trying to make it easier to learn and prototype with it.

      Liz

        Can you do source filters in 5.6.x?

        http://search.cpan.org/src/PMQS/Filter-1.29/README says:

        Before you can build the Source Filters you need to have the following
        installed on your system:
        
            * Perl 5.004 or better. 5.6.0 or better is recommended for Win32.
        

        The source filter can be as simple as (untested)

        package Filter::share; use Filter::Simple; FILTER_ONLY code => sub { s/( \b share \b \s* \(? )(?= \s* [\@\$%] )/$ +1\\/gxe };
        but IIRC, source filters don't work on eval()ed code. OTOH, why would anyone eval a share call... :)

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: Forks.pm dilemma
by Kageneko (Scribe) on Aug 07, 2003 at 16:58 UTC
    Perhaps you could determine the version of perl during the makefile building process, set a proper variable, and then run the XS code through some kind of preprocessor? I'm not sure how ExtUtils::MM does things, so I can't comment on the difficulty. Considering all the work that DBD::Oracle does when you do perl Makefile.PL, it must be possible.
    PERL_VER = `perl -e 'print $['` preprocess: @cpp -DPERL_VAR=${PERL_VAR} forks.xs forks.i @mv forks.i forks.xs
    In forks.xs, use happy fun #ifdefs to partition the code. What do you think?
      PERL_VER = `perl -e 'print $['`

      I assume you mean:

      PERL_VER = `$^X -e 'print $]'`
      as you cannot be sure the Makefile.PL is called by "perl". And note it should be $] rather than $[

      Actually, if I would have to resort to that, it would probably be easier to not define a macro for 5.6.x, and define a macro with the the PROTOTYPE: string for all other versions.

      Liz

      Update:
      While investigating something about $[, I realized there was an error in this node. So I changed $[ to $] where appropriate and added a comment.

        That's exactly what I meant ;) I wonder if the xsubpp maintainer (is there one?) can be convinced to allow a pre-processing option, similar to 'perl -P'.
Re: Forks.pm dilemma
by BrowserUk (Patriarch) on Aug 07, 2003 at 17:07 UTC

    I'll admit to not having thought this through very far, and I know naff all about XS, but...

    Couldn't you declare the share routine as a perl sub conditionally upon the basis of version. > 5.7 use the new prototype, < 5.7 omit the prototype and test&cast the parameter using ref then call the XS code that does the real work?


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller
    If I understand your problem, I can solve it! Of course, the same can be said for you.

Re: Forks.pm dilemma
by simonflk (Pilgrim) on Aug 11, 2003 at 13:54 UTC

    Maybe I'm missing something, but won't something like this work:

    /* --- PerlVersionDemo.xs --- */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include <stdio.h> void print_hello_561 (void) { printf("hello world from perl 5.6.1\n"); } void print_hello_58 (void) { printf("hello world from perl 5.8 or higher\n"); } MODULE = PerlVersionDemo PACKAGE = PerlVersionDemo #if (PERL_REVISION == 5) && (PERL_VERSION == 6) && (PERL_SUBVERSION == + 1) void print_hello() CODE: print_hello_561(); #else # if (PERL_REVISION == 5) && (PERL_VERSION >=8) void print_hello() CODE: print_hello_58(); # endif #endif

    Just stick your PROTOTYPE in the perl 5.8.x bit and it will be ignored on earlier perls.

    Update: So, your share_561() would accept a regular variable and pass a reference to the actual share()

    -- simonflk

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://281932]
Front-paged by broquaint
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (5)
As of 2024-03-19 03:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found