On 1/14/23 8:31 AM, Matt Wette wrote:
On 1/14/23 7:18 AM, Maxime Devos wrote:
\
Port objects should be accepted too, as previously asked on
<https://lists.gnu.org/archive/html/guile-user/2022-06/msg00060.html>.
As implied by later comments, using a raw fd causes problems with
'move->fdes'. For the remaining response, I'll assume that the
function accepts ports as well.
To avoid this problem, you can add
scm_remember_upto_here_1 (fd);
after the SCM_SYSCALL.
\
IIRC there is a C trick involving fields, arrays and types to check
this at compile-time instead. Maybe:
struct whatever {
/* if availability of zero-length arrays can be assumed */
int foo[sizeof(size_t) - sizeof(void*)];
/* alternatively, a weaker but portable check */
int foo[sizeof(size_t) - sizeof(void*) + 1];
};
Greetings,
Maxime.
Thanks for the feedback. I'm sorry I missed you comments on the
previous round.
I did respond to the ones I did catch. I'll work this and resubmit.
Matt
Here is another shot.
1) added port support
2) used dynwind to protect port/fd.
3) removed the assert: I don't know why I put it in there.
Notes:
1) four other guile headers needed: atomic-internal, foreign, finalizers
and ioext
2) had to copy/modify dynwind_acquire_port and release_port from ports.c
3) one maybe-kludge is if an fd is passed I use (car (fd->ports fd)) for
acquire_port
Matt
static void
mmap_finalizer (void *ptr, void *data)
{
SCM bvec;
void *c_addr;
size_t c_len;
int rv;
bvec = SCM_PACK_POINTER (ptr);
if (!SCM_BYTEVECTOR_P (bvec))
scm_misc_error ("mmap", "expecting bytevector", SCM_EOL);
c_addr = SCM_BYTEVECTOR_CONTENTS (bvec);
c_len = SCM_BYTEVECTOR_LENGTH (bvec);
SCM_SYSCALL (rv = munmap(c_addr, c_len));
if (rv != 0)
scm_misc_error ("mmap", "failed to munmap memory", SCM_EOL);
}
/* Code for scm_dynwind_acquire_port and release_port sourced from
ports.c. */
static void
release_port (SCM port)
{
scm_t_port *pt = SCM_PORT (port);
uint32_t cur = 1, next = 0;
while (!scm_atomic_compare_and_swap_uint32 (&pt->refcount, &cur, next))
{
if (cur == 0)
return;
next = cur - 1;
}
if (cur > 1)
return;
if (SCM_PORT_TYPE (port)->close)
SCM_PORT_TYPE (port)->close (port);
/* Skip encoding code from ports.c! */
}
static void
scm_dynwind_acquire_port (SCM port)
{
scm_t_port *pt = SCM_PORT (port);
uint32_t cur = 1, next = 2;
while (!scm_atomic_compare_and_swap_uint32 (&pt->refcount, &cur, next))
{
if (cur == 0)
scm_wrong_type_arg_msg (NULL, 0, port, "open port");
next = cur + 1;
}
scm_dynwind_unwind_handler_with_scm (release_port, port,
SCM_F_WIND_EXPLICITLY);
}
SCM_DEFINE (scm_mmap_search, "mmap/search", 2, 4, 0,
(SCM addr, SCM len, SCM prot, SCM flags, SCM file, SCM offset),
"Create a memory mapping, returning a bytevector.. @var{addr},\n"
"if non-zero, is the staring address; or, if zero, is assigned
by\n"
"the system. @var{prot}, if provided, assigns protection.\n"
"@var{file}, a port or fd, if provided associates the memory\n"
"region with a file starting at @var{offset}, if provided.\n"
"The region returned by mmap WILL be searched by the garbage\n"
"collector for pointers. See also mmap. Note that the\n"
"finalizer for the returned bytevector will call munmap.\n"
"Defaults for optional arguments are\n"
"@table @asis\n"
"@item prot\n(logior PROT_READ PROT_WRITE)\n"
"@item flags\n(logior MAP_ANONYMOUS MAP_PRIVATE)\n"
"@item fd\n-1\n"
"@item offset\n0\n"
"@end table")
#define FUNC_NAME s_scm_mmap_search
{
void *c_mem, *c_addr;
size_t c_len;
int c_prot, c_flags, c_fd;
scm_t_off c_offset;
SCM pointer, bvec;
if (SCM_POINTER_P (addr))
c_addr = SCM_POINTER_VALUE (addr);
else if (scm_is_integer (addr))
c_addr = (void*) scm_to_uintptr_t (addr);
else
scm_misc_error ("mmap", "bad addr", addr);
c_len = scm_to_size_t (len);
if (SCM_UNBNDP (prot))
c_prot = PROT_READ | PROT_WRITE;
else
c_prot = scm_to_int (prot);
if (SCM_UNBNDP (flags))
c_flags = MAP_ANONYMOUS | MAP_PRIVATE;
else
c_flags = scm_to_int (flags);
scm_dynwind_begin (0);
if (SCM_UNBNDP (file))
c_fd = -1;
else {
/* Use the fd under clobber protection from GC or another thread. */
if (SCM_PORTP (file))
c_fd = scm_to_int (scm_fileno (file));
else {
c_fd = scm_to_int (file);
file = SCM_CAR (scm_fdes_to_ports (file));
}
scm_dynwind_acquire_port (file);
}
if (SCM_UNBNDP (offset))
c_offset = 0;
else
c_offset = scm_to_off_t (offset);
if ((c_addr == NULL) && (c_flags & MAP_FIXED))
scm_misc_error ("mmap", "cannot have NULL addr w/ MAP_FIXED", SCM_EOL);
SCM_SYSCALL (c_mem = mmap(c_addr, c_len, c_prot, c_flags, c_fd,
c_offset));
if (c_mem == MAP_FAILED)
scm_syserror ("mmap"); /* errno set */
/* The fd is free to go now. */
scm_dynwind_end ();
pointer = scm_cell (scm_tc7_pointer, (scm_t_bits) c_mem);
bvec = scm_c_take_typed_bytevector((signed char *) c_mem + c_offset,
c_len,
SCM_ARRAY_ELEMENT_TYPE_VU8, pointer);
scm_i_set_finalizer (SCM2PTR (bvec), mmap_finalizer, (void*) c_len);
return bvec;
}
#undef FUNC_NAME