Skip to content

GIL is not released when calling blocking IO functions from C #37

@jjmason

Description

@jjmason

C functions like ldap_open block until a connection is opened. If an upstream LDAP is bogged down, or someone attempts to connect to a server that doesn't support LDAP and lets the connection time out, all other ruby threads are blocked until the ldap_open call returns. Here is some code to demonstrate this:

#!/usr/bin/env ruby
require 'ldap'

# Start a thread that prints 'beep!' every second.
beeper = Thread.new do 
  loop do
    puts "beep!"
    sleep 1
  end
end

# sleep the main thread so the beeper can get a few messages out
sleep 3

# Google.com hangs for a rather long time when we try to open
# a connection on port 389.

puts "about to connect to google.com:389..."

conn = LDAP::Conn.open 'google.com', 389

puts "connected???" # looks like we've hacked google!

Expected result: The beeper thread will continue to print "beep!" every second while the ldap connection is being opened.
Actual result: The beeper thread stops until the call to LDAP::Conn.open finishes.

I encountered this issue on a project for work where users can perform certain LDAP actions through a web user interface. Because the project uses a threaded webserver (Puma), a connection attempt that takes a while will block all other requests to the server from being processed. While switching to a multi-process webserver is an obvious solution, it would be better for this library to perform the IO with the GIL released so that other threads can make progress, which is the behavior of other blocking native IO in ruby.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions