9

I seem to be doing something wrong in this attempt to expose the localtime functionality in Perl 6:

use NativeCall;
my class TimeStruct is repr<CStruct> {
    has int32 $!tm_sec;
    has int32 $!tm_min;
    has int32 $!tm_hour;
    has int32 $!tm_mday;
    has int32 $!tm_mon;
    has int32 $!tm_year;
    has int32 $!tm_wday;
    has int32 $!tm_yday;
    has int32 $!tm_isdst;
    has Str   $!tm_zone;
    has long  $!tm_gmtoff;
}

sub localtime(uint32 $epoch --> TimeStruct) is native {*}
dd localtime(time);  # segfault

Running under perl6-lldb-m, I get:

Process 82758 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x5ae5dda1)
    frame #0: 0x00007fffe852efb4 libsystem_c.dylib`_st_localsub + 13
libsystem_c.dylib`_st_localsub:
->  0x7fffe852efb4 <+13>: movq   (%rdi), %rax
    0x7fffe852efb7 <+16>: movq   %rax, -0x20(%rbp)
    0x7fffe852efbb <+20>: movq   0x8e71d3e(%rip), %rbx     ; lclptr
    0x7fffe852efc2 <+27>: testq  %rbx, %rbx
Target 0: (moar) stopped.

Any obvious things I'm doing wrong here?

UPDATE: the final working solution:

class TimeStruct is repr<CStruct> {
    has int32 $.tm_sec;    # *must* be public attributes
    has int32 $.tm_min;
    has int32 $.tm_hour;
    has int32 $.tm_mday;
    has int32 $.tm_mon;
    has int32 $.tm_year;
    has int32 $.tm_wday;
    has int32 $.tm_yday;
    has int32 $.tm_isdst;
    has long  $.tm_gmtoff; # these two were
    has Str   $.time_zone; # in the wrong order
}

sub localtime(int64 $epoch is rw --> TimeStruct) is native {*}

my int64 $epoch = time;  # needs a separate definition somehow
dd localtime($epoch);
Pat
  • 36,282
  • 18
  • 72
  • 87
Elizabeth Mattijsen
  • 25,654
  • 3
  • 75
  • 105
  • I am checking several things, and all segfault; I have the impression that the number returned by Perl 6 `time` is simply too big to be held in an `uint32`. Have you tried to use also the native `time`? – jjmerelo Apr 29 '18 at 16:21

1 Answers1

8

localtime() expects a pointer of type time_t* as argument. Assuming time_t and uint32_t are compatible types on your particular platform,

sub localtime(uint32 $epoch is rw --> TimeStruct) is native {*}
my uint32 $t = time;
dd localtime($t);

should do it (though you won't get to see anything unless you make your attributes public).

I'm a bit surprised that your time_t isn't a 64-bit type, and having just googled apple time.h, I also suspect the last two attributes in your struct declaration are in the wrong order...

Christoph
  • 164,997
  • 36
  • 182
  • 240
  • I get an error with this solution, and I don't really see how it solves the problem, except that the `is rw` seems to fix the segmentation fault. This yields the error `Native call expected argument that references a native integer, but got P6int in method CALL-ME at /home/jmerelo/.rakudobrew/moar-2018.04/install/share/perl6/sources/24DD121B5B4774C04A7084827BFAD92199756E03 (NativeCall) line 581 in block at localtime-native.p6 line 23 ` – jjmerelo Apr 29 '18 at 16:14
  • 1
    @jjmerelo: for some reason, using an anonymous inline variable doesn't work; if you add a separate declaration, it works over here... – Christoph Apr 29 '18 at 16:26
  • it does not segfault, but just prints " TimeStruct.new ". Also, `atomicint` can be used instead of `uint32`, with the same result. – jjmerelo Apr 29 '18 at 16:37
  • 1
    @jjmerelo: that's because liz has declared all her attribute private... – Christoph Apr 29 '18 at 16:45
  • 2
    @jjmerelo: cf my suspicion that the last two attributes are switched, ie `$!tm_zone` won't contain a valid address; you could try the opposite order, or just make only the first couple of attributes public so you can check that at least those will contain the expected values... – Christoph Apr 29 '18 at 17:19
  • 2
    It appears the MacOS `man localtime` documentation does not match reality. Christoph++ for pointing out the sore spots. – Elizabeth Mattijsen Apr 29 '18 at 19:45