On 14-01-2023 23:08, Matt Wette wrote: > 2) had to copy/modify dynwind_acquire_port and release_port from ports.c Is it because of the 'static' qualifier? If so, you could use the 'SCM_INTERNAL [...] scm_i_[...]' pattern, e.g. see 'scm_i_is_mutable_bitvector' in libguile/bitvectors.h and libguile/bitvectors.c. > 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); > } You need to acquire the port _before_ taking its file descriptor! Otherwise, it is protected too late. I.e., scm_dynwind_acquire_port needs to be moved before the 'scm_fileno'. On the second branch, in particular 'c_fd = scm_to_int (file);': IIUC, the idea is to, when a raw fd is passed, look up the corresponding port to lock it, right? If so, I think it's too late for that -- another thread might change things between 'c_fd = ...' and 'file = SCM_CAR (scm_fdes_to_ports (file))'. More generally, when a raw fd is passed, I think it's impossible to solve the 'other thread/GC interfering' problem. As such, to simplify things, I propose to only do the 'scm_dynwind_acquire_port' when a port is passed, instead of failing to solve the interference problems (if the user passed a raw fd, then only they can make sure there are no problems, e.g. by changing their code to use ports or by not using move->fdes stuff).: Proposed code (untested): { 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 if (scm_is_integer (file)) c_fd = scm_to_int (file); else { /* Use the fd of the port under clobber protection from concurrency. As scm_dynwind_acquire_port assumes that FILE is a port, check that first. */ SCM_VALIDATE_PORT (SCM_ARG5, file); scm_dynwind_acquire_port (file); c_fd = scm_fileno (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