I'm trying to wrap the read
function from unistd.h
, but can't get it to work.
Here's what I have: (in file: read.raku
)
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf is rw, size_t $count --> ssize_t) is native is symbol('read') { * }
my $buf = Buf[byte].new(0 xx 5);
my $pbuf = nativecast(Pointer, $buf);
say c_read(3, $pbuf, 5);
say '---------------------';
say $buf;
I test it like this, from the command line (bash):
$ (exec 3< <(echo hello world); raku ./read.raku)
But I get:
5
---------------------
Buf[byte]:0x<00 00 00 00 00>
So it looks like the bytes read from FD 3 are not written to the Buf
.
I also tried this instead:
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf is rw, size_t $count --> ssize_t) is native is symbol('read') { * }
sub c_malloc(size_t $size --> Pointer) is native is symbol('malloc') { * }
my $pbuf = nativecast(Pointer[byte], c_malloc(5));
say c_read(3, $pbuf, 5);
say '---------------------';
say $pbuf[^5];
But I get a segmentation fault, I guess due to dereferencing into unauthorized memory location with $pbuf[^5]
. But even just $pbuf.deref
doesn't give the first byte read.
So I must have done something wrong or completely misunderstood how to work with native calls.
UPDATE:
After playing around with it more, it looks like the problem with the second snippet above is with the is rw
bit. This seems to work:
use NativeCall;
use NativeHelpers::Blob;
sub c_read(int32 $fd, Pointer $buf, size_t $count --> ssize_t) is native is symbol('read') { * }
sub c_malloc(size_t $size --> Pointer) is native is symbol('malloc') { * }
my $pbuf := nativecast(Pointer[byte], c_malloc(5));
say c_read(3, $pbuf, 5);
say '---------------------';
say $pbuf[^5]; # (104 101 108 108 111)
The following method accepts an Windows::Storage::Streams::IBuffer and returns a raw pointer to the underlying byte array. To call the function, pass in a WriteableBitmap::PixelBuffer property.
Obtaining pointers to data buffers (C++/CX) In the Windows Runtime the Windows::Storage::Streams::IBuffer interface provides a language-neutral, stream-based means to access data buffers. In C++ you can get a raw pointer to the underlying byte array by using the Windows Runtime Library IBufferByteAccess interface that is defined in robuffer.h.
Passing pointers to functions in C. C programming allows passing a pointer to a function. To do so, simply declare the function parameter as a pointer type.
OK, so the problem is with the rw
trait given to the Pointer $buf
. I guess that results in the read
function incrementing the pointer as it writes, and thus gives the wrong address when I use it later.
Here's the working code for both cases:
use NativeCall;
# ssize_t read(int fd, void *buf, size_t count);
sub c_read(int32 $fd, Pointer $buf, size_t $count --> ssize_t) is native is symbol('read') { * }
# Passing a pointer to a Buf directly:
{
my $buf = Buf[byte].new(0 xx 5);
my $pbuf = nativecast(Pointer[byte], $buf);
say c_read(3, $pbuf, 5);
say '---------------------';
say $buf;
}
# Using malloc also works:
{
sub c_malloc(size_t $size --> Pointer) is native is symbol('malloc') { * }
my $pbuf = nativecast(Pointer[byte], c_malloc(5));
say c_read(3, $pbuf, 5);
say '---------------------';
say $pbuf[^5];
}
Tested it like this:
$ (exec 3< <(echo hello world); perl6 ./read.raku)
5
---------------------
Buf[byte]:0x<68 65 6C 6C 6F>
5
---------------------
(32 119 111 114 108)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With