Dear gvfs developers, it's some times I have noticed an unwanted behaviour of gvfsd-http. That is, sockets used to retrieve files over the network stay in the CLOSE_WAIT state for ages... and thus the number of FDs is growing and growing. I have a long-running program I wrote (and I know also for Rhythmbox this was an issue), which soon runs out of file descriptors, leading to a failure. To help better seeing the problem, I have written a small program using Gtkmm, which exhibits the issue. It is attached here. To see it run out of file descriptors, increase the amount of fetches to 1001. I tried digging into GDaemonFile's source, which I think is the client counterpart to gvfsd-http, and I *think* the problem is at least that, upon destruction of the GFile it subtypes, gvfsd-http does not get notified to close the socket. In alternative, closing the socket upon a call to g_file_read_finish(), inside GIO, might be the correct think to do. I would like to know if this is a bug in gvfs, gio, or my program, and in the former cases if I should submit it to Bugzilla. Thanks for your help! Matteo % ---------------- %< ----------------------- %< ---------------------
// Please compile with:
// g++ -std=c++11 `pkg-config --cflags --libs glibmm-2.4 giomm-2.4`test.cc
// Then kill gvfsd-http before running, and monitor with:
// lsof -p $(pidof gvfsd-http)
#include <glibmm.h>
#include <giomm.h>
#include <iostream>
namespace {
static const char *URL = "http://www.google.com/images/srpr/logo11w.png";
}
using Glib::ustring;
using Glib::RefPtr;
static RefPtr<Glib::MainLoop> main_loop = Glib::MainLoop::create ();
class RemoteLoader
{
public:
RemoteLoader (const Glib::ustring& url)
: m_cancellable (Gio::Cancellable::create ())
{
std::cout << "Requesting " << url << std::endl;
auto file = Gio::File::create_for_uri (url);
auto callback = sigc::ptr_fun (&RemoteLoader::on_load);
file->load_contents_async (callback, m_cancellable);
}
~RemoteLoader ()
{
auto cancellable = m_cancellable;
if (!cancellable) return;
Glib::Thread *joinable = Glib::Thread::create ([cancellable] ()
{
cancellable->cancel ();
// No direct support for detached threads, so...
Glib::Thread *self = Glib::Thread::self ();
g_thread_unref (self->gobj ());
});
}
static void on_load (const RefPtr<Gio::AsyncResult>& result)
{
char *buf = nullptr;
gsize length = 0;
const auto file = RefPtr<Gio::File>::cast_dynamic (result->get_source_object_base ());
if (!file) return;
try
{
bool success = file->load_contents_finish (result, buf, length);
if (!success)
{
std::cerr << "Not successful (" << file->get_uri () << ")" << std::endl;
}
else
{
std::cout << "Successful load (" << file->get_uri () << ")" << std::endl;
}
}
catch (const Glib::Error& e)
{
std::cerr << "Exception: " << e.what () << " when trying to load "
<< file->get_uri () << std::endl;
}
g_free (buf);
}
private:
RefPtr<Gio::Cancellable> m_cancellable;
};
static bool
load_another ()
{
static int how_many = 0;
if (how_many > 9)
{
std::cout << "Exiting in 5 seconds... " << std::endl;
Glib::signal_timeout ().connect_seconds_once ([] { main_loop->quit (); }, 5);
return false;
}
for (int i = how_many*5; i < (how_many+1)*5; ++i)
{
std::ostringstream oss;
oss << URL << "?nocache=" << i;
auto loader = new RemoteLoader (oss.str ());
Glib::signal_timeout ().connect_seconds_once ([loader] { delete loader; }, 5);
}
++how_many;
return true;
}
int
main ()
{
std::cout << " === Killing gvfsd-http === " << std::endl;
system ("killall gvfsd-http");
Gio::init ();
Glib::signal_timeout ().connect_seconds (sigc::ptr_fun (&load_another), 1);
main_loop->run ();
std::string cmd = "bash -c 'pidof gvfsd-http | xargs lsof -p'";
std::cout << "\n\n\t === Running " << cmd << " === \n" << std::endl;
return system (cmd.c_str ());
}
Attachment:
pgpr_aPIc22iE.pgp
Description: PGP signature