genode/repos/libports/src/lib/libc/fd_alloc.cc
Norman Feske cd92b32622 libc: close all open FDs on exit
This is important to issue sync requests for written-to files.

As the closing must be performed by an atexit handler, it happens at a
time _after_ libc plugins are destructed. Consequently an FD allocated
by such a plugin results in a close error, which in turn, does not
destruct the FD. We ultimatedly end up in an infinte loop of
re-attempting the close. For this reason, the patch changes 'close' to
be robust against this special case.

This is generally not a problem because libc plugins are phased out.
However, at present, the libc_noux plugin is still important. With the
changed 'close' in place, there occurred an error message "Error: close:
close not implemented" at the exit of each noux program. This patch
removes the error printing from the libc plugin mechansim to avoid this
noise. The error messages are not important anyway because the
deprecation of the libc plugin interface.

Issue #3578
2019-12-19 17:00:48 +01:00

200 lines
4.0 KiB
C++

/*
* \brief File-descriptor allocator implementation
* \author Christian Prochaska
* \author Norman Feske
* \date 2010-01-21
*/
/*
* Copyright (C) 2010-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <util/construct_at.h>
#include <base/env.h>
#include <base/log.h>
/* Genode-internal includes */
#include <base/internal/unmanaged_singleton.h>
/* libc plugin interface */
#include <libc-plugin/fd_alloc.h>
/* libc includes */
#include <fcntl.h>
#include <unistd.h>
/* libc-internal includes */
#include <internal/init.h>
using namespace Libc;
static Allocator *_alloc_ptr;
void Libc::init_fd_alloc(Allocator &alloc) { _alloc_ptr = &alloc; }
File_descriptor_allocator *Libc::file_descriptor_allocator()
{
if (_alloc_ptr)
return unmanaged_singleton<File_descriptor_allocator>(*_alloc_ptr);
error("missing call of 'init_fd_alloc'");
return nullptr;
}
File_descriptor_allocator::File_descriptor_allocator(Allocator &alloc)
: _alloc(alloc)
{ }
File_descriptor *File_descriptor_allocator::alloc(Plugin *plugin,
Plugin_context *context,
int libc_fd)
{
Lock::Guard guard(_lock);
bool const any_fd = (libc_fd < 0);
Id_space::Id id {(unsigned)libc_fd};
if (any_fd) {
id.value = _id_allocator.alloc();
} else {
_id_allocator.alloc_addr(addr_t(libc_fd));
}
return new (_alloc) File_descriptor(_id_space, *plugin, *context, id);
}
void File_descriptor_allocator::free(File_descriptor *fdo)
{
Lock::Guard guard(_lock);
if (fdo->fd_path)
_alloc.free((void *)fdo->fd_path, ::strlen(fdo->fd_path) + 1);
_id_allocator.free(fdo->libc_fd);
destroy(_alloc, fdo);
}
void File_descriptor_allocator::preserve(int fd)
{
if (!find_by_libc_fd(fd))
alloc(nullptr, nullptr, fd);
}
File_descriptor *File_descriptor_allocator::find_by_libc_fd(int libc_fd)
{
Lock::Guard guard(_lock);
if (libc_fd < 0)
return nullptr;
File_descriptor *result = nullptr;
try {
Id_space::Id const id {(unsigned)libc_fd};
_id_space.apply<File_descriptor>(id, [&] (File_descriptor &fd) {
result = &fd; });
} catch (Id_space::Unknown_id) { }
return result;
}
File_descriptor *File_descriptor_allocator::any_cloexec_libc_fd()
{
Lock::Guard guard(_lock);
File_descriptor *result = nullptr;
_id_space.for_each<File_descriptor>([&] (File_descriptor &fd) {
if (!result && fd.cloexec)
result = &fd; });
return result;
}
int File_descriptor_allocator::any_open_fd()
{
Lock::Guard guard(_lock);
int result = -1;
_id_space.apply_any<File_descriptor>([&] (File_descriptor &fd) {
result = fd.libc_fd; });
return result;
}
void File_descriptor_allocator::generate_info(Xml_generator &xml)
{
Lock::Guard guard(_lock);
_id_space.for_each<File_descriptor>([&] (File_descriptor &fd) {
xml.node("fd", [&] () {
xml.attribute("id", fd.libc_fd);
if (fd.fd_path)
xml.attribute("path", fd.fd_path);
if (fd.cloexec)
xml.attribute("cloexec", "yes");
if (((fd.flags & O_ACCMODE) != O_WRONLY))
xml.attribute("readable", "yes");
if (((fd.flags & O_ACCMODE) != O_RDONLY))
xml.attribute("writeable", "yes");
if (fd.plugin) {
::off_t const seek = fd.plugin->lseek(&fd, 0, SEEK_CUR);
if (seek)
xml.attribute("seek", seek);
}
});
});
}
void File_descriptor::path(char const *newpath)
{
if (fd_path)
warning("may leak former FD path memory");
if (!_alloc_ptr) {
error("missing call of 'init_fd_alloc'");
return;
}
if (newpath) {
size_t const path_size = ::strlen(newpath) + 1;
char *buf = (char*)_alloc_ptr->alloc(path_size);
if (!buf) {
error("could not allocate path buffer for libc_fd ", libc_fd);
return;
}
::memcpy(buf, newpath, path_size);
fd_path = buf;
} else
fd_path = 0;
}
/********************
** Libc functions **
********************/
extern "C" int __attribute__((weak)) getdtablesize(void) { return MAX_NUM_FDS; }