Search code examples
posixrakunativecall

How to correctly use CPointer and CStruct in NativeCall interface


I am trying to get this example of NativeCall running:

use NativeCall;

class p_timespec is repr('CPointer') {
    has uint32 $.tv_sec;
    has long $.tv_nanosecs;
}

sub clock_gettime(uint32 $clock-id, p_timespec $tspec --> uint32) is native(Str) { * };

my p_timespec $this-time;

my $result = clock_gettime( 0, $this-time);

say "$result, $this-time";

It simply segfaults, which is what happens when you use pointers and you should not. In this case, it's probably due to the declaration of p_timespec; I have actually declared it as a CPointer, although the struct should be OK. However, from the segmentation fault I can't fathom what's really wrong. Can someone help?


Solution

  • There's two things wrong here.

    1. The CStruct representation should be used
    2. You need to make an instance of the structure for it to fill out with data, otherwise you're passing a null pointer

    This seems to work:

    use NativeCall;
    
    class p_timespec is repr('CStruct') {
        has uint32 $.tv_sec;
        has long $.tv_nanosecs;
    }
    
    sub clock_gettime(uint32 $clock-id, p_timespec $tspec --> uint32) is native(Str) { * };
    
    my p_timespec $this-time .= new;
    
    my $result = clock_gettime( 0, $this-time);
    
    say "$result, $this-time.tv_sec(), $this-time.tv_nanosecs()";
    

    As for debugging, Rakudo's installation process also installs a perl6-gdb-m and a perl6-valgrind-m; the latter, while slow, will tend to provide some useful information on memory errors.