ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
From: magaudet@ca.ibm.com
To: ruby-core@ruby-lang.org
Subject: [ruby-core:80800] [Ruby trunk Misc#13486] Using rb_thread_call_without_gvl{2}
Date: Wed, 19 Apr 2017 20:08:44 +0000	[thread overview]
Message-ID: <redmine.issue-13486.20170419200844.d0abbb8425136cdc@ruby-lang.org> (raw)
In-Reply-To: redmine.issue-13486.20170419200844@ruby-lang.org

Issue #13486 has been reported by magaudet (Matthew Gaudet).

----------------------------------------
Misc #13486: Using rb_thread_call_without_gvl{2}
https://bugs.ruby-lang.org/issues/13486

* Author: magaudet (Matthew Gaudet)
* Status: Open
* Priority: Normal
* Assignee: 
----------------------------------------
I'm currently working on adding asynchronous compilation to [Ruby+OMR][1], and I'm trying to use the existing Ruby thread API. However, given that compilation shouldn't happen while holding the GVL, I've been playing with `rb_thread_call_without_gvl{2}`. I've encountered something I don't entirely understand however. It appears that if the unblocking function for a thread is actually invoked, the interpreter hangs on shutdown. 

With some tracing code elided, it's a pretty simple bit of code: 

```
static int compilation_thread_started = 0;
void unblock_compilation_thread(void* arg) {                                                          
   *(int*)arg  = 0; // interrupt compilation thread.                                                  
}                                                                                                     
                                                                                                      
void* vm_compile_thread(void *vm) {                                                                   
   while (compilation_thread_started) { // compile until interupted.
         rb_thread_wait_for(rb_time_interval(DBL2NUM(0.01))); // pretend to compile by sleeping.
   }                                                                                                  
   return NULL;                                                                                       
}                                                                                                     

VALUE releaseGVLandStartCompilationThread(rb_vm_t* vm)                                                
   {                                                                                                  
   compilation_thread_started = 1;                                                                    
   rb_thread_call_without_gvl2(vm_compile_thread,             /* func */ 
                               (void*)vm,                     /* func arg */                          
                               unblock_compilation_thread,    /* unblock func */
                               &compilation_thread_started);  /* unblock arg */
      
   return Qnil; 
   }
   
void                                                                                                  
kickoff_thread(rb_vm_t* vm)                                                                           
{
   typedef VALUE (*thread_function)(ANYARGS);                                                         
   rb_thread_create((thread_function)(releaseGVLandStartCompilationThread),vm);                       
}
```

I've attached a patch with a very simple reproducing test case that should apply to trunk as of today. If you run it, what you'll notice is that the unblock function runs, the thread code exits and then the interpreter hangs; in an interpreter, what I see is the spawned thread that released the GVL is waiting to re-aquire, but it appears to be held. The main thread on the other hand, is waiting for the final non-main thread to shut down before proceeding with shutdown. 

I've marked this as Misc, because I'm not entirely sure this isn't user error, but I'd love some guidance on how to spawn a thread that's not holding the GVL, but also have it participate in cleanup actions like regular threads. 



[1]: https://github.com/rubyomr-preview/ruby/issues/30 

---Files--------------------------------
gvl_thread_error.patch (3.29 KB)


-- 
https://bugs.ruby-lang.org/

       reply	other threads:[~2017-04-19 19:28 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <redmine.issue-13486.20170419200844@ruby-lang.org>
2017-04-19 20:08 ` magaudet [this message]
2017-04-19 23:13 ` [ruby-core:80801] [Ruby trunk Misc#13486] Using rb_thread_call_without_gvl{2} ko1
2017-04-20 12:54 ` [ruby-core:80809] " magaudet
2017-04-21 15:27 ` [ruby-core:80818] " magaudet

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.ruby-lang.org/en/community/mailing-lists/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=redmine.issue-13486.20170419200844.d0abbb8425136cdc@ruby-lang.org \
    --to=ruby-core@ruby-lang.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).