After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 579406 - pygtk_main_watch_prepare leaks file descriptors, causing crashes if the main loop is run repeatedly
pygtk_main_watch_prepare leaks file descriptors, causing crashes if the main ...
Status: RESOLVED FIXED
Product: pygtk
Classification: Bindings
Component: gtk
2.14.x
Other Linux
: Normal normal
: ---
Assigned To: Nobody's working on this now (help wanted and appreciated)
Python bindings maintainers
Depends on:
Blocks:
 
 
Reported: 2009-04-18 12:22 UTC by Glyph Lefkowitz
Modified: 2009-10-29 19:31 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
fix (1.87 KB, patch)
2009-05-02 14:10 UTC, Paul Pogonyshev
committed Details | Review
fix for the second bug (742 bytes, patch)
2009-09-23 18:30 UTC, Paul Pogonyshev
none Details | Review

Description Glyph Lefkowitz 2009-04-18 12:22:02 UTC
I've already filed this issue on the Launchpad bug tracker: details are here: 

https://bugs.launchpad.net/ubuntu/+source/gtk+2.0/+bug/363245

Here's a script which reproduces the problem:

from gtk import main, main_quit
from gobject import threads_init, timeout_add, source_remove
import sys

def test(iterations, use_threads):
    if use_threads:
        threads_init()
    tick = 0
    while tick < iterations:
        tick += 1
        if (tick % 1000) == 0:
            print 'Tick', tick
        lasttag = timeout_add(1, main_quit)
        main()
        source_remove(lasttag)

if __name__ == "__main__":
    if sys.argv[1:] == ['no-threads']:
        threads = False
    else:
        threads = True
    print 'Using threads:', threads
    test(10000, threads)
    print 'Done.'
Comment 1 Paul Pogonyshev 2009-05-02 14:10:47 UTC
Created attachment 133805 [details] [review]
fix

The change that really fixes the bug is the g_source_unref() call.
Comment 2 Nicola 2009-09-22 07:33:16 UTC
I can reproduce the same error using gobject only without gtk import so I think this fix don't really solve the problem:

# -*- coding: utf-8 -*-
from gobject import threads_init, timeout_add, source_remove
import gobject
import sys

def test(iterations, use_threads):
    if use_threads:
        threads_init()
    tick = 0
    while tick < iterations:
        loop=gobject.MainLoop()
        tick += 1
        if (tick % 1000) == 0:
            print 'Tick', tick
        lasttag = timeout_add(1, loop.quit)
        loop.run()
        source_remove(lasttag)

if __name__ == "__main__":
    if sys.argv[1:] == ['no-threads']:
        threads = False
    else:
        threads = True
    print 'Using threads:', threads
    test(10000, threads)
    print 'Done.'

Using threads: True

** ERROR **: Cannot create main loop pipe: Too many open files

aborting...
Aborted
Comment 3 Paul Pogonyshev 2009-09-22 19:11:22 UTC
(In reply to comment #2)
> I can reproduce the same error using gobject only without gtk import so I think
> this fix don't really solve the problem:

It does, just there is another piece of code (in PyGObject) with the same problem.  I fixed that too, you can test in the repository.  Don't know if it will make it to the current stable release branch though.
Comment 4 Nicola 2009-09-23 11:47:35 UTC
Thanks, it is possible to have a diffs for python-gobject 2.16.1 and 2.18 so I can apply the patch to jaunty and karmic?

Nicola
Comment 5 Paul Pogonyshev 2009-09-23 18:30:39 UTC
Created attachment 143819 [details] [review]
fix for the second bug

You could extract it from git yourself ;)
Comment 6 Nicola 2009-10-29 09:23:59 UTC
Paul, seems there are yet issues with gobject and threads, look at this simple test case:

# -*- coding: utf-8 -*-
import gobject
import time
import threading

gobject.threads_init()

def test():
    loop=gobject.MainLoop()
    loop.run()
    time.sleep(1)
    loop.quit()

def testlaucher(iterations):
    for i in range(iterations):
      print 'Iteration:', i+1
      t=threading.Thread(target=test)
      t.start()

if __name__ == "__main__":
    testlaucher(10000)
    print 'Done.'

here is the output:

....
....
Iteration: 559
Iteration: 560

** ERROR **: Cannot create main loop pipe: Too many open files

aborting...
Abortito

seems two fd are created when loop=gobject.MainLoop() is called and are never given back when the thread exit, 

maybe a better solution would be:

1) allocate the fd on "loop.run()"
2) release the fd on "loop.quit()"

regards
Nicola
Comment 7 Nicola 2009-10-29 09:30:56 UTC
same issue even if you remove the line time.sleep(1)

Nicola
Comment 8 Paul Pogonyshev 2009-10-29 19:31:16 UTC
This is not valid.  After you call 'loop.run()', the thread is stuck and 'loop.quit()' is never executed.  So, you create hundreds of threads each with its own stuck loop --- of course you run out of files.