GNOME Bugzilla – Bug 705367
kqueue file monitor consumes file descriptors
Last modified: 2014-03-10 21:28:16 UTC
Created attachment 250732 [details] Screenshot of the error box I am doing a repetitive work which involves the following: 1) Get the result I want on some other application's window 2) Take a screenshot with The GIMP 3) Crop the screenshot 4) Export as JPEG 5) Close the screenshot on The GIMP Repeat, repeat, repeat. After I have done this a few dozen times (I suspect, 75 times), Export to JPEG fails with a message box that reads: *** Unable to run plug-in "file-jpeg" (/Applications/GIMP.app/Contents/Resources/lib/gimp/2.0/plug-ins/file-jpeg) pipe() failed: Too many open files *** Note that *I* don't keep any files open that I know of--clearly The GIMP is not closing files properly. I say it's 75 files because when this happens, the window title is "screenshot.png-75.0". So, after this happens I get a "Too many open files" with any disk operation I try. If I try saving the file again, I get "Too many open files". If I try opening a file, The GIMP won't read the directory but will tell me "Too many open files". I'm sorry but I cannot provide you with a test file. I am attaching a screenshot :-) (taken with another application) of The GIMP's error message. MY FIX: Simple--close The GIMP, and reopen. It works again, for another 75 times. Not knowing anything about The GIMP's code, if I were looking for the bug I would first look at the "file-jpeg" code. I hope that helps.
I get a leak of 3 file descriptors whenever I open the export dialog, they are references to whichever directory the dialog displays. The leak appears to be related to _kh_add_sub in gio/kqueue/kqueue-helper.c in glib. This is in gimp-master built against glib 2.36.3.
CCing the author of the kqueue stuff
Hi. I am not the gio-kqueue developer but I am the one who integrated Dmitry's work indeed. Anyway what you are seeing is "normal" in the sense that this is an inherent problem with kqueue as it uses file descriptors to monitor files and directories -- other BSDs suffer from the same limitation. I don't know much about Mac OS but after a quick look at a friend's MacBook Pro it seems the openfiles limit is very low on OS X (256 by default according to 'ulimit -a'). With The GIMP is seems you are able to reach this limit pretty fast so you need to bump the openfiles/maxfiles limit. Here how to do it: * for shell (Terminal) applications, it works the same as with other UNICES, e.g.: ulimit -n 1024 -> this will bump your maximum number of openfiles from 256 to 1024 * but according to online docs for better OS X integration, you should run this instead: launchctl limit maxfiles 1024 To make the change permanent, you need to create the '/etc/launchd.conf' file that contains: limit maxfiles 1024 1024 Of course, adapt 1024 to your needs. I hope this helped and fixed your issue.
Thanks for the hints! But I'm wondering: does it really not leak the file descriptors? Because each time the dialog is opened, a few more are used. Why are they never closed?
More info: If I do the same on linux, the FDs I see in "strace -e open" are the same no matter how often I open the file chooser, and they are never over 50. Thus I conclude that the code leaks FDs on OSX.
(In reply to comment #5) > More info: If I do the same on linux, the FDs I see in "strace -e open" > are the same no matter how often I open the file chooser, and they > are never over 50. Thus I conclude that the code leaks FDs on OSX. Linux does not use kqueue but inotify which does not work at all in the same way. I will try and have a look at the chooser thing to see whether that behavior is expected or not.
Ah, that must be why I have never seen kqueue before in any stack stace or elsewhere :) Thank you, a loser look is really appreciated, this is kindof a showstopper for any app that runs for a longer time.
Hello, My name is Dmitry, I am the author of that stuff. Julio, could you please tell which exact Glib & GIMP versions do you use so I could try to reproduce it on an as-close-as-possible setup? I do not have a Mac, but Antoine already confirmed me that the issue reproduces on OpenBSD too. Thanks, Dmitry
> Julio, could you please tell which exact Glib & GIMP versions do you use so I > could try to reproduce it on an as-close-as-possible setup? Hi Dmitry. As mentioned it is: gimp-master built against glib 2.36.3. But it is not really relevant because it is not specific to any version, I believe it's been here since the gio-kqueue integration. > I do not have a Mac, but Antoine already confirmed me that the issue reproduces > on OpenBSD too. FWIW I can indeed reproduce it on OpenBSD -current with glib2-2.38.2 and gimp-2.8.4 - so if that helps you reproduce the issue, you can quickly install OpenBSD and 'pkg_add gimp'. I am not sure it is a leak, maybe some files/dirs are added to the monitor queue while they already being monitored, that would explain why the number of FDs grows everytime you open the gtk-chooser... (just thinking out loud).
My GIMP version: 2.8.4 How do I find out which glibc I am using? I have no /lib and I can't make any (Linux) sense of /Library or ~/Library … Thanks for looking into this, people! :)
To find out the GLib version your GIMP is build with: 1. Go to Applications/Utilities, then Terminal. 2. Enter /Applications/GIMP.app/Contents/MacOS/GIMP -v GIMP will then print out a few lines and quit (without the graphical user interface). Please note, that glibc and GLib are not the same: glibc is a free implementation of the C standard library. GLib (without trailing c) is a C library mainly for the GTK+ project.
Created attachment 263056 [details] Sample minimal app to reproduce the problem Warning! I use LD_LIBRARY_PATH=(path to my patched Glib build) and link the app with my version of Glib manually (by setting CFLAGS/LDFLAGS paths manually).
Reproduced on NetBSD with the recent Glib (from git) with a minimal sample app (attached). When selecting directories in a dialog with a mouse, the file descriptors are managed (opened/closed) properly. When typing a directory path in the Dialog's "Location" field, the leak occurs. After closing a dialog, the file descriptors aren't closed (I assume because the GFileMonitors used there haven't cancelled the subscriptions).
Comment on attachment 263056 [details] Sample minimal app to reproduce the problem #include <gtk/gtk.h> static void on_button_click(GtkButton *button, gpointer udata) { GtkWidget *dialog; dialog = gtk_file_chooser_dialog_new ("A dialog", NULL, (GtkFileChooserAction) udata, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_hide (dialog); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); GtkWidget *window, *btnOpen, *btnSave, *vbox; window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Sample"); btnOpen = gtk_button_new_with_label ("Open a file..."); btnSave = gtk_button_new_with_label ("Save a file..."); vbox = gtk_vbox_new (TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), btnOpen, TRUE, TRUE, 0); gtk_box_pack_start (GTK_BOX (vbox), btnSave, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); g_signal_connect (btnOpen, "clicked", G_CALLBACK (on_button_click), GTK_FILE_CHOOSER_ACTION_OPEN); g_signal_connect (btnSave, "clicked", G_CALLBACK (on_button_click), GTK_FILE_CHOOSER_ACTION_SAVE); gtk_widget_show_all (window); gtk_main(); return 0; }
Created attachment 263206 [details] [review] Proposed fix Hi, Sorry for a delay, I had some problems with making a debug build of G* stuff on my NetBSD box. Actually, the bug is in GTK+. A new GtkFolder object is created every time the user types in the "Location" dialog entry (a GtkFileChooserEntry). Here is the code flow: (GtkFileChooserEntry) refresh_current_folder_and_file_part (GtkFileChooserEntry) : reload_current_folder (GtkFileChooserEntry) : start_loading_current_folder (GtkFileSystem) : _gtk_file_system_get_folder (GtkFileSystem) : g_file_enumerate_children_async (GLib/GIO) : : (GLib/GIO) : V (GtkFileSystem) : .--- enumerate_children_callback : / * creates a new GtkFolder object and attaches the directory content to it :/ * GtkFolder internally creates a directory monitor for the directory V * passes the GtkFolder object to the callback (see below) (GtkFileChooserEntry) load_directory_get_folder_callback * increases the passed GtkFolder object reference count (*End*) I've skipped a part of the call stack, but hope that it still illustrates the issue well. Every time user types a character in the GtkFileChooserEntry, it tries to update its file name completion list. The is a list of async calls that starts with refresh_current_folder_and_file_part() (gtkfilechooserentry.c) and reaches its depth in enumerate_children_callback() (gtkfilesystem.c). This callback creates a GtkFolder object (which internally contains a monitor) and passes it back to the callbacks. Then finally this GtkFolder object is caught in GtkFileChooserEntry's load_directory_get_folder_callback(), where it is copied to the GtkFileChooserEntry's member variable using g_object_ref(). However, the GtkFolder object passed to this function isn't unreferenced anywhere, so it continues to live even when the GtkFileChooserEntry switches to another directory and discard_current_folder() is called (I assume it decreases the GtkFolder's reference count to 1, so it is still alive). I've attached a simple patch that fixes the problem (at least, for me). According to my understanding, _gtk_file_system_get_folder() assumes that its user will clear the passed GtkFolder when needed, and does not unreference the created GtkFolder after calling its callback. My work is based on GTK+ 2.24(.22?). With best regards, Dmitry
Thanks for tracking this down ! I think it would be nicer to add the unref in enumerate_children_callback
Hmm, yes. I think it would be more correct. Actually, it already clears an "async data" [1] after invoking a callback. And that data already contains a GtkFolder (but the field isn't set to the created object in this case). Probably, the created GtkFolder should be saved to that member variable. I do not know about the real design decisions :) ----- [1]: https://git.gnome.org/browse/gtk+/tree/gtk/gtkfilesystem.c?id=2.24.22#n868
*** Bug 722075 has been marked as a duplicate of this bug. ***
*** Bug 726065 has been marked as a duplicate of this bug. ***