From kde-bindings Fri Feb 05 19:37:16 2010 From: Uriel Date: Fri, 05 Feb 2010 19:37:16 +0000 To: kde-bindings Subject: Re: [Kde-bindings] Using threads with QtRuby Message-Id: <4B6C736C.2080900 () inbox ! ru> X-MARC-Message: https://marc.info/?l=kde-bindings&m=126539868507573 > But you only get a log of vitual method callbacks if you want them. > The are > various levels and types of debug output and it is quite easy to > customize. > Maybe it is a bit over complicated but you will only get virtual method > callbacks logged if one of the things you pass to > Qt::Internal.setDebug() is > QTDB_VIRTUAL. Yes, I know about different debug levels, thank you. But sometimes I become paranoid and explicitly set level to QTDB_ALL complicating all the thing around myself. :) So, may be it's not a really big deal. Here is the small patch for qtruby4.rb in trunk with comments. I've tested it on different amount of threads and everything seems to be ok. --- qtruby4.rb 2010-02-06 00:20:35.056527428 +0500 +++ qtruby4.rb 2010-02-06 00:31:59.293534007 +0500 @@ -43,6 +43,17 @@ @@debug_level end + # We're causing main thread to sleep for some really small amount of time time to force Ruby VM do the scheduling + @@ruby_thread_sleep_time = 1e-9 + + def Qt.ruby_thread_sleep_time + @@ruby_thread_sleep_time + end + + def Qt.ruby_thread_sleep_time=(time) + @@ruby_thread_sleep_time = time + end + module Internal # # From the enum MethodFlags in qt-copy/src/tools/moc/generator.cpp @@ -454,6 +465,26 @@ end class Application < Qt::Base + private + def enable_ruby_threads + # Start timer if only it hasn't been started yet + return unless @ruby_threads_timer_id == -1 + + @ruby_threads_timer_id = startTimer 0 + end + + def disable_ruby_threads + # Stop timer only if we have main thread and just one custom which will be stopped right after this call + return unless Thread.list.count == 2 + + killTimer @ruby_threads_timer_id + @ruby_threads_timer_id = -1 + end + protected + def timerEvent(ev) + sleep Qt::ruby_thread_sleep_time + end + public def initialize(*args) if args.length == 1 && args[0].kind_of?(Array) super(args.length + 1, [$0] + args[0]) @@ -466,6 +497,8 @@ # Otherwise, rb_gc_call_finalizer_at_exit() can delete # stuff that Qt::Application still needs for its cleanup. def exec + @ruby_threads_timer_id = -1 + method_missing(:exec) self.dispose Qt::Internal.application_terminated = true @@ -3149,4 +3182,32 @@ end end +# We're doing some trick here by redefining all the methods for new thread creation. +# Then we adding custom function call to the user's block passed to one of these functions. +class Thread + class << self + alias :__oldNew :new + alias :__oldStart :start + alias :__oldFork :fork + end + + def self.decorate_thread(old_method, *args, &block) + Qt::Application.instance.send :enable_ruby_threads + send old_method, *args, &proc{ block.call; Qt::Application.instance.send :disable_ruby_threads } + end + private_class_method(:decorate_thread) + + def self.new(*args, &block) + decorate_thread :__oldNew, *args, &block + end + + def self.start(*args, &block) + decorate_thread :__oldStart, *args, &block + end + + def self.fork(*args, &block) + decorate_thread :__oldFork, *args, &block + end +end + # kate: space-indent false; _______________________________________________ Kde-bindings mailing list Kde-bindings@kde.org https://mail.kde.org/mailman/listinfo/kde-bindings