--- lib/multi.c.old	2006-02-06 18:47:28.000000000 +0800
+++ lib/multi.c	2006-02-06 19:02:33.000000000 +0800
@@ -105,6 +105,7 @@
   int msg_num; /* number of messages left in 'msg' to return */
 
   struct socketstate sockstate; /* for the socket API magic */
+  int nwaiting_sockets; /* how many sockets this handle is waiting */
 };
 
 
@@ -1043,6 +1044,8 @@
         /* socket is removed */
         action = CURL_POLL_REMOVE;
         s = easy->sockstate.socks[i]; /* this is the removed socket */
+	if (easy->nwaiting_sockets) 
+	  easy->nwaiting_sockets--;
       }
       else {
         if(easy->sockstate.socks[i] == s) {
@@ -1060,6 +1063,12 @@
           if(curr == prev)
             continue;
         }
+	else {
+	  /* if not the same socket, can we assert the prior socket must be
+	     CURL_SOCKET_BAD ? */
+	  curlassert(easy->sockstate.socks[i] == CURL_SOCKET_BAD);
+	  easy->nwaiting_sockets++;
+	}
 
         action = (current.action & GETSOCK_READSOCK(i)?CURL_POLL_IN:0) |
           (current.action & GETSOCK_WRITESOCK(i)?CURL_POLL_OUT:0);
@@ -1130,12 +1139,17 @@
 
       result = multi_runsingle(multi, data->set.one_easy, &running_handles);
 
-      if(result == CURLM_OK)
+      /* in my test, this forward statement should appear before singlesocket,
+         because the singlesocket may destroy the entry struct ? */
+      entry = entry->next;
+
+      /* we should ensure every event change, so disable the result test */      
+      /* if(result == CURLM_OK) */
         /* get the socket(s) and check if the state has been changed since
            last */
         singlesocket(multi, data->set.one_easy);
 
-      entry = entry->next;
+      /* entry = entry->next; */
 
     } while(entry);
 
@@ -1155,7 +1169,8 @@
     if(data) {
       result = multi_runsingle(multi, data->set.one_easy, &running_handles);
 
-      if(result == CURLM_OK)
+      /* we should ensure every event change, so disable the result test */
+      /* if(result == CURLM_OK) */
         /* get the socket(s) and check if the state has been changed since
            last */
         singlesocket(multi, data->set.one_easy);
@@ -1313,4 +1328,75 @@
 #endif
 }
 
+/* this routine traverse the multi stack's easy list and perform the
+   handles which can be perform non-blockly(probably!). at this step,
+   file descriptor events callback will also be triggered.
+   this routine will also check and perform all expire handles */
+CURLMcode curl_multi_perform_nonblock(CURLM *multi_handle, int *running_handles)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+  CURLMcode returncode=CURLM_OK;
+  struct Curl_tree *t;
+  CURLMcode result;
+  struct SessionHandle * data = NULL;
+
+  *running_handles = 0; /* bump this once for every living handle */
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  easy=multi->easy.next;;
+  while(easy) {
+    if(easy->nwaiting_sockets > 0) {
+      (*running_handles)++;
+      easy = easy->next;
+      continue;
+    }
+#if 1
+    printf("perform nonblock easy: %p\n", easy->easy_handle);
+#endif
+    result = multi_runsingle(multi, easy, running_handles);
+    if(result)
+      returncode = result;
+    singlesocket(multi, easy);	  
+
+    easy = easy->next; /* operate on next handle */
+  }
+
+  /*
+   * The loop following here will go on as long as there are expire-times left
+   * to process in the splay and 'data' will be re-assigned for every expired
+   * handle we deal with.
+   */
+  do {
+    int key;
+    struct timeval now;
+
+    /* the first loop lap 'data' can be NULL */
+    if(data) {
+      result = multi_runsingle(multi, data->set.one_easy, &running_handles);
+
+      /* we should ensure every event change, so disable the result test */
+      /* if(result == CURLM_OK) */
+        /* get the socket(s) and check if the state has been changed since
+           last */
+      singlesocket(multi, data->set.one_easy);
+    }
+
+    /* Check if there's one (more) expired timer to deal with! This function
+       extracts a matching node if there is one */
+
+    now = Curl_tvnow();
+    key = now.tv_sec; /* drop the usec part */
+
+    multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
+    if(t)
+      data = t->payload;
+
+  } while(t);
+
+  return returncode;    
+}
+
 #endif
--- include/curl/multi.h.old	2006-02-06 18:47:28.000000000 +0800
+++ include/curl/multi.h	2006-02-06 18:56:54.000000000 +0800
@@ -312,6 +312,8 @@
 CURLMcode curl_multi_setopt(CURLM *multi_handle,
                             CURLMoption option, ...);
 
+CURLMcode curl_multi_perform_nonblock(CURLM *multi_handle, int *running_handles);
+
 #ifdef __cplusplus
 } /* end of extern "C" */
 #endif

