[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: patch for mmap and friends

From: Matt Wette
Subject: Re: patch for mmap and friends
Date: Sat, 14 Jan 2023 14:08:17 -0800
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2

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 <>.
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];


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.


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.

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


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)
      next = cur - 1;
 if (cur > 1)

  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_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);
    scm_misc_error ("mmap", "bad addr", addr);

  c_len = scm_to_size_t (len);

  if (SCM_UNBNDP (prot))
    c_prot = PROT_READ | PROT_WRITE;
    c_prot = scm_to_int (prot);

  if (SCM_UNBNDP (flags))
    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;
    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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]