Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I’m building a cross platform xs module that creates a few C threads when the module is initialised. The lowest comment denominator is win32, pthreads and perl 5.6.1 (Activestate build 638).

The application is pretty much working, although I am getting a repeatable crash in one of my C threads when malloc is called.

After a lot of hunting and debugging I "solved" a lot of the problems by making sure the C and XS code use the same memory allocation calls (XSUB.h was refining malloc to PerlMem_malloc). Then I followed the various perl header files, and got very lost…:)

The end result is that I’m confused to what malloc functions I should be using in my C threads? I’ve searched the web and the manuals, but I just can’t see – what I assume is a simple solution?

Thanks.

  • Comment on General memory management for embedded/extended perl with C threads

Replies are listed 'Best First'.
Re: General memory management for embedded/extended perl with C threads
by beauregard (Monk) on Nov 14, 2004 at 20:37 UTC
    It's most likely not a problem with using the "right" or "wrong" malloc function. It sounds more like you're freeing memory outside of where it's being allocated. For example, something gets allocated with the libc malloc() but gets freed with the perl PerlMem_free(). This is an issue for more than just perl extensions... anytime you use a library that might have been linked with a debugging memory allocator you can encounter this. The rule of thumb is that you free memory in the same module you used to allocate it. That is, if you have a C library which exports a function like:
    char* my_crappy_strdup( const char* str ) { char* s = malloc(strlen(str)+1); memcpy( s, str, strlen(str)+1 ); return s; }
    Then you also need to provide, in the same source file:
    void my_crappy_free( char* str ) { free(s); }
    And make sure that the caller of my_crappy_strdup() knows that they need to call my_crappy_free() on whatever data is created. Then it doesn't matter if that C library is using perl's memory manager, ElectricFence, libc, or whatever. One of the interesting consequences of this, by the way, is that it's basically impossible to use libc's strdup() in perl extensions without some nasty #define magic because you'll never be able to get at the libc free() call... c.
      Thanks for the reply beauregard.

      You are right, this was one of the major sources of crashes - however, I'm still left with that crash on a malloc in the C thread.

      I've done a little more digging, and I'm wondering if it's because there is no Perl interpreter built in that C thread. If the standard Perl headers are used, then malloc gets redefined to use perl pointers associated with the thread - and since perl hasn't been set up: Boom! If this is the case, how do I get around that? I'm assuming it should be just a case of using the OS malloc/free for all memory management, then it shouldn't matter if a Perl interpreter has been built or not?

      Thanks.

Re: General memory management for embedded/extended perl with C threads
by osunderdog (Deacon) on Nov 15, 2004 at 02:38 UTC

    You may already know this but there is discussion of memory allocation in perldoc perlguts.

    It is suggested that you enable the version of malloc that is dis- tributed with Perl. It keeps pools of various sizes of unallocated memory in order to satisfy allocation requests more quickly. However, on some platforms, it may cause spurious malloc or free errors.
    I have found cases where perl's alloc doesn't play well in a threaded application. We had to revert to the OS alloc functions. Unfortunately if you use the OS alloc function, you will loose some very valuable debugging features. perldoc Devel::Peek.

    Mr. Rock, please meet Mr. Hard Spot.


    "Look, Shiny Things!" is not a better business strategy than compatibility and reuse.


    OSUnderdog
      Thanks for the reply osunderdog.

      How did you revert to using the OS's alloc functions?

        To see what you're using now:
        use Config qw|config_vars|; print "Using Perl Malloc? "; config_vars('usemymalloc'); print "\n";
        I just ran through the perl configure and here is the salient question:
        Do you wish to attempt to use the malloc that comes with perl5? [n]

        "Look, Shiny Things!" is not a better business strategy than compatibility and reuse.


        OSUnderdog
Re: General memory management for embedded/extended perl with C threads
by BrowserUk (Patriarch) on Nov 15, 2004 at 14:03 UTC

    With iThreads, under Win32, the memory for at least some of perl's internal datastructures is allocated from Thread Local Storage, and is so (at least notionally) only accessible from the thread in which it is created.

    There is also (under 5.8.x at least) a C++ class wrapped around an OS provided LocalMemAlloc() API.

    If either of these are the case with the version of Perl you are using, which is quite possible as iThreads evolved initially as a substitute for fork on Win32 in 5.6.1; and if you are allocating memory from the global heap in your C threads; and you are trying to share the two types of memory across both types of threads--this may explain (some) of your problems.

    There are a lot of 'ifs' in that, and it may be a complete red herring, but like you I have attempted to track through the memory allocation macros used by Perl (5.8.5 in my case) and they are incredibly deeply nested and very hard to follow.

    I think that your best source of advice would be the p5p list, and if your working on Win32 maybe the perl-win32 porters list also.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail        "Time is a poor substitute for thought"--theorbtwo
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
Re: General memory management for embedded/extended perl with C threads
by dave_the_m (Monsignor) on Nov 15, 2004 at 14:39 UTC
    The offical interface to malloc() from XS is New, Newz, Renew, Safefree. See the section "Memory Management" in perlapi.pod

    As an aside, note that you have to be very careful when creating multiple threads inside perl. Most of perl's data structures are private to each interpreter and are not designed to be shared by multiple threads. So for example if you have two threads accessing the same SV structure, madness will ensue. Make sure that only the original thread that called the XS code allocates/releases any further Perl data. If the other threads only do private stuff unrelated to perl then that's okay.

    Dave.

      Ok - I know what the problem is - I just don't know a proper solution:)

      Just creating and initialising a Perl interpreter when the C thread starts solves all the problems, even though this C thread has no interaction with Perl at all . It seems when malloc and co are redefined, they use pointers that are associated with the current thread. In other words, when you use the Perl header files (XSUB.h and I suspect some of the others) there HAS to be an Perl interpreter initialised on all threads if you use malloc and it's friends.

      Ideally, I don't want a Perl interpreter in each C thread:) There must be some way to build this module to use a global wide malloc?