<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -8,6 +8,7 @@
 #include &quot;curb_errors.h&quot;
 #include &quot;curb_postfield.h&quot;
 
+#include &lt;errno.h&gt;
 #include &lt;string.h&gt;
 
 extern VALUE mCurl;
@@ -1352,13 +1353,87 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce, VALUE bodybuf, V
  */
 static VALUE handle_perform(VALUE self, ruby_curl_easy *rbce) {  
 
+  int msgs;
+  int still_running = 1;
   CURLcode result = -1;
+  CURLMcode mcode = -1;
+  CURLM *multi_handle = curl_multi_init();
   struct curl_slist *headers = NULL;
   VALUE bodybuf = Qnil, headerbuf = Qnil;
 
   ruby_curl_easy_setup(rbce, &amp;bodybuf, &amp;headerbuf, &amp;headers);
 
-  result = curl_easy_perform(rbce-&gt;curl);
+  /* NOTE:
+   * We create an Curl multi handle here and use rb_thread_select allowing other ruby threads to 
+   * perform actions... ideally we'd have just 1 shared multi handle per all curl easy handles globally
+   */
+  mcode = curl_multi_add_handle(multi_handle, rbce-&gt;curl);
+  if (mcode != CURLM_CALL_MULTI_PERFORM &amp;&amp; mcode != CURLM_OK) {
+    raise_curl_multi_error_exception(mcode);
+  }
+
+  while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &amp;still_running)) ) ;
+
+  if (mcode != CURLM_CALL_MULTI_PERFORM &amp;&amp; mcode != CURLM_OK) {
+    raise_curl_multi_error_exception(mcode);
+  }
+
+  while(still_running) {
+    struct timeval timeout;
+    int rc; /* select() return code */
+    int maxfd;
+
+    fd_set fdread;
+    fd_set fdwrite;
+    fd_set fdexcep;
+
+    FD_ZERO(&amp;fdread);
+    FD_ZERO(&amp;fdwrite);
+    FD_ZERO(&amp;fdexcep);
+
+    /* set a suitable timeout to play around with */
+    timeout.tv_sec = 1;
+    timeout.tv_usec = 0;
+    /* get file descriptors from the transfers */
+    mcode = curl_multi_fdset(multi_handle, &amp;fdread, &amp;fdwrite, &amp;fdexcep, &amp;maxfd);
+    if (mcode != CURLM_CALL_MULTI_PERFORM &amp;&amp; mcode != CURLM_OK) {
+      raise_curl_multi_error_exception(mcode);
+    }
+
+    rc = rb_thread_select(maxfd+1, &amp;fdread, &amp;fdwrite, &amp;fdexcep, &amp;timeout);
+    if (rc &lt; 0) {
+      rb_raise(rb_eRuntimeError, &quot;select(): %s&quot;, strerror(errno));
+    }
+ 
+    switch(rc) {
+    case 0: /* timeout */
+    default:
+      /* timeout or readable/writable sockets */
+      while(CURLM_CALL_MULTI_PERFORM == (mcode=curl_multi_perform(multi_handle, &amp;still_running)) );
+    break;
+    }
+ 
+    if (mcode != CURLM_CALL_MULTI_PERFORM &amp;&amp; mcode != CURLM_OK) {
+      raise_curl_multi_error_exception(mcode);
+    }
+
+  }
+  
+  /* check for errors */
+  CURLMsg *msg = curl_multi_info_read(multi_handle, &amp;msgs);
+  if (msg) {
+    result = msg-&gt;data.result;
+  }
+  else {
+    long val;
+    curl_easy_getinfo( rbce-&gt;curl, CURLINFO_OS_ERRNO, &amp;val );
+    result = val;
+  }
+
+  curl_multi_remove_handle(multi_handle, rbce-&gt;curl);
+  curl_multi_cleanup(multi_handle);
+
+  //result = curl_easy_perform(rbce-&gt;curl);
 
   ruby_curl_easy_cleanup(self, rbce, bodybuf, headerbuf, headers);
 </diff>
      <filename>ext/curb_easy.c</filename>
    </modified>
    <modified>
      <diff>@@ -269,7 +269,7 @@ static VALUE ruby_curl_multi_perform(VALUE self) {
     tv.tv_sec = timeout / 1000;
     tv.tv_usec = (timeout * 1000) % 1000000;
 
-    rc = select(maxfd+1, &amp;fdread, &amp;fdwrite, &amp;fdexcep, &amp;tv);
+    rc = rb_thread_select(maxfd+1, &amp;fdread, &amp;fdwrite, &amp;fdexcep, &amp;tv);
     if (rc &lt; 0) {
       rb_raise(rb_eRuntimeError, &quot;select(): %s&quot;, strerror(errno));
     }</diff>
      <filename>ext/curb_multi.c</filename>
    </modified>
    <modified>
      <diff>@@ -86,7 +86,7 @@ class TestCurbCurlEasy &lt; Test::Unit::TestCase
 
   def test_get_01   
     c = Curl::Easy.new($TEST_URL)    
-    assert_equal true, c.http_get    
+    assert_equal true, c.http_get
     assert_match(/^# DO NOT REMOVE THIS COMMENT/, c.body_str)
     assert_equal &quot;&quot;, c.header_str
   end    </diff>
      <filename>tests/tc_curl_easy.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>350157aca0b1395a5a30229cfa5d824e79a3fb1e</id>
    </parent>
  </parents>
  <author>
    <name>Todd A. Fisher</name>
    <login></login>
    <email>taf2@web3.anerian.com</email>
  </author>
  <url>http://github.com/taf2/curb/commit/8f46873c2018d29287846986aec14425385587b1</url>
  <id>8f46873c2018d29287846986aec14425385587b1</id>
  <committed-date>2008-08-04T19:13:48-07:00</committed-date>
  <authored-date>2008-08-04T19:13:48-07:00</authored-date>
  <message>use rb_thread_select, instead of native select, this allows ruby threads to schedule while curl is idle on network transfers</message>
  <tree>d5db0998a471a391667bbafbb1b5c013d2b400c3</tree>
  <committer>
    <name>Todd A. Fisher</name>
    <login></login>
    <email>taf2@web3.anerian.com</email>
  </committer>
</commit>
