Previous: , Up: posix fd device   [Index]


4.13.8.2 Close–on–exec mode

On POSIX platforms, right after a fork call: the parent and child will share all the input/output file descriptors that are open at the time of the fork call. This is problematic.

Let’s see what happens with the following program in which we open a file, fork the process then close the file in both the parent and child:

#!vicare
(import (vicare)
  (prefix (vicare posix) px.))

(define (parent-proc child-pid)
  (px.waitpid child-pid 0)
  (close-output-port port)
  (exit 0))

(define (child-thunk)
  (close-output-port port)
  (exit 0))

(define port
  (parametrise ((output-file-buffer-size 8))
    (open-file-output-port "demo.txt"
			   (file-options no-fail)
			   (buffer-mode block)
			   (native-transcoder))))

(put-string port "0123456789ABCDEF")

(px.fork parent-proc child-thunk)

the output port has a buffer of 8 characters and the string written to it is 16 characters long; the call to put-string immediately flushes the first 8 characters and leaves the rest in the output buffer. The fork call causes the output buffer and its contents to be duplicated, so, when we close the port, the two buffers are flushed to the same file. The resulting file contents are:

0123456789ABCDEF89ABCDEF

which is not what we want.

POSIX has a partial solution for this problem: to configure file descriptors as close–on–exec; Vicare extends this to propose a partial solution: to configure ports as close–on–exec. Notice that it is close–on–exec, not close–on–fork. So we can try to address this problem by:

  1. Registering ports to be in close–on–exec mode.
  2. Before calling fork: flush the ports in close–on–exec mode.
  3. In the child process: close the ports in close–on–exec mode, to free allocated file descriptors.

Here is the example above modified to do so:

#!vicare
(import (vicare)
  (prefix (vicare posix) px.))

(define (parent-proc child-pid)
  (px.waitpid child-pid 0)
  (close-output-port port)
  (exit 0))

(define (child-thunk)
  (px.close-ports-in-close-on-exec-mode)
  (exit 0))

(define port
  (parametrise ((output-file-buffer-size 8))
    (open-file-output-port "demo.txt"
                           (file-options no-fail)
                           (buffer-mode block)
                           (native-transcoder))))

(px.port-set-close-on-exec-mode! port)

(put-string port "0123456789ABCDEF")

(px.flush-ports-in-close-on-exec-mode)
(px.fork parent-proc child-thunk)

File descriptors in close–on–exec mode

Function: fd-set-close-on-exec-mode! fd
Function: fd-unset-close-on-exec-mode! fd

Special interface to the C function fcntl(), (libc)fcntl. Configure the file descriptor fd in “close on exec” mode or “do not close on exec” mode; if successful return unspecified values, else raise an exception.

Function: fd-in-close-on-exec-mode? fd

Special interface to the C function fcntl(), (libc)fcntl. Query the file descriptor fd for its “close on exec” mode; if successful: return #t if fd is in “close on exec” mode, #f otherwise. If an error occurs: raise an exception.

Ports in close–on–exec mode

Function: port-set-close-on-exec-mode! port

Register a Scheme port to be closed if the current process uses one of the exec functions. If successful: return unspecified values, else raise an exception.

port can be any port: it is not required for it to have a file descriptor as underlying device. If the underlying device is a file descriptor: this descriptor is configured in close–on–exec mode.

Function: port-unset-close-on-exec-mode! port

Unregister a Scheme port so that it is not closed if the current process uses one of the exec functions. If successful: return unspecified values, else raise an exception.

If the underlying device is a file descriptor: this descriptor is configured not to be in close–on–exec mode.

Function: port-in-close-on-exec-mode? port

Return a boolean: true if port is in close–on–exec mode, false otherwise.

Function: close-ports-in-close-on-exec-mode
Function: close-ports-in-close-on-exec-mode error-handler

Close all the ports registered to be in close–on–exec mode. Each port is closed by applying close-port to it.

Function: flush-ports-in-close-on-exec-mode
Function: flush-ports-in-close-on-exec-mode error-handler

Flush the output buffer of all the output ports registered to be in close–on–exec mode. Each port is processed by applying flush-output-port to it.


Previous: , Up: posix fd device   [Index]