random...@fastmail.us: > On Wed, Jun 3, 2015, at 10:43, Marko Rauhamaa wrote: >> However, the child process needs to be prepared for os.close() to >> block indefinitely because of an NFS problem or because SO_LINGER has >> been specified by the parent, for example. Setting the close-on-exec >> flag doesn't help there. > > Out of curiosity, does exec block in this situation?
I didn't try it, but it is apparent in the source code: ======================================================================== void do_close_on_exec(struct files_struct *files) { unsigned i; struct fdtable *fdt; /* exec unshares first */ spin_lock(&files->file_lock); for (i = 0; ; i++) { unsigned long set; unsigned fd = i * BITS_PER_LONG; fdt = files_fdtable(files); if (fd >= fdt->max_fds) break; set = fdt->close_on_exec[i]; if (!set) continue; fdt->close_on_exec[i] = 0; for ( ; set ; fd++, set >>= 1) { struct file *file; if (!(set & 1)) continue; file = fdt->fd[fd]; if (!file) continue; rcu_assign_pointer(fdt->fd[fd], NULL); __put_unused_fd(files, fd); spin_unlock(&files->file_lock); filp_close(file, files); cond_resched(); spin_lock(&files->file_lock); } } spin_unlock(&files->file_lock); } int filp_close(struct file *filp, fl_owner_t id) { int retval = 0; if (!file_count(filp)) { printk(KERN_ERR "VFS: Close: file count is 0\n"); return 0; } if (filp->f_op->flush) retval = filp->f_op->flush(filp, id); if (likely(!(filp->f_mode & FMODE_PATH))) { dnotify_flush(filp, id); locks_remove_posix(filp, id); } fput(filp); return retval; } ======================================================================== Now, the kernel NFS code specifies a flush() method, which can block and even fail. Sockets don't have a flush() method. So closing a socket cannot fail. However, fput(), which decrements the reference count, may block if lingering has been specified for the socket. So I wasn't all that wrong earlier after all: whoever closes a socket last will linger. Thus, the parent (who wanted to linger) might zip through closing a socket while the unwitting child process will suffer the lingering delay before it gets to exec. However, there's this comment in inet_release(): /* [...] * If the close is due to the process exiting, we never * linger.. */ Marko -- https://mail.python.org/mailman/listinfo/python-list