Skip to content

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

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions