[4/6] testbot/testagentd: Add a wait() RPC that takes a timeout as a parameter.

Francois Gouget fgouget at codeweavers.com
Mon Feb 25 10:34:18 CST 2013


This is a new RPC which preserves compatibility with old clients.
---

See patch 3/6 for the backward and forward compatibility aspects.

 testbot/src/testagentd/platform.h         |    6 ++---
 testbot/src/testagentd/platform_unix.c    |   25 ++++++++++++++++---
 testbot/src/testagentd/platform_windows.c |    7 ++++--
 testbot/src/testagentd/testagentd.c       |   38 +++++++++++++++++++++++++++--
 4 files changed, 66 insertions(+), 10 deletions(-)

diff --git a/testbot/src/testagentd/platform.h b/testbot/src/testagentd/platform.h
index 3c25271..d2a3934 100644
--- a/testbot/src/testagentd/platform.h
+++ b/testbot/src/testagentd/platform.h
@@ -68,12 +68,12 @@ enum run_flags_t {
 uint64_t platform_run(char** argv, uint32_t flags, char** redirects);
 
 /* If a command was started in the background, waits until either that command
- * terminates or the client disconnects (typically because it got tired of
- * waiting).
+ * terminates, the specified timeout (in seconds) expires, or the client
+ * disconnects (typically because it got tired of waiting).
  * If no command was started in the background, then reports an error
  * immediately.
  */
-int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus);
+int platform_wait(SOCKET client, uint64_t pid, uint32_t timeout, uint32_t *childstatus);
 
 /* Returns a string describing the last socket-related error */
 int sockeintr(void);
diff --git a/testbot/src/testagentd/platform_unix.c b/testbot/src/testagentd/platform_unix.c
index d7d8f54..797a3d2 100644
--- a/testbot/src/testagentd/platform_unix.c
+++ b/testbot/src/testagentd/platform_unix.c
@@ -28,6 +28,7 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 #include <signal.h>
+#include <time.h>
 
 #include "platform.h"
 #include "list.h"
@@ -125,9 +126,10 @@ uint64_t platform_run(char** argv, uint32_t flags, char** redirects)
     return pid;
 }
 
-int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus)
+int platform_wait(SOCKET client, uint64_t pid, uint32_t timeout, uint32_t *childstatus)
 {
     struct child_t* child;
+    time_t deadline;
 
     LIST_FOR_EACH_ENTRY(child, &children, struct child_t, entry)
     {
@@ -140,10 +142,14 @@ int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus)
         return 0;
     }
 
+    if (timeout)
+        deadline = time(NULL) + timeout;
     while (!child->reaped)
     {
         fd_set rfds;
         char buffer;
+        struct timeval tv;
+        int ready;
 
         /* select() blocks until either the client disconnects or until, or
          * the SIGCHLD signal indicates the child has exited. The recv() call
@@ -152,8 +158,21 @@ int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus)
         debug("Waiting for " U64FMT "\n", pid);
         FD_ZERO(&rfds);
         FD_SET(client, &rfds);
-        if (select(client+1, &rfds, NULL, NULL, NULL) == 1 &&
-            FD_ISSET(client, &rfds) &&
+        if (timeout)
+        {
+            tv.tv_sec = deadline - time(NULL);
+            if (tv.tv_sec < 0)
+                tv.tv_sec = 0;
+            tv.tv_usec = 0;
+        }
+        ready = select(client+1, &rfds, NULL, NULL, timeout ? &tv : NULL);
+        if (ready == 0)
+        {
+            /* This is the timeout */
+            set_status(ST_ERROR, "timed out waiting for the child process");
+            return 0;
+        }
+        if (ready == 1 && FD_ISSET(client, &rfds) &&
             recv(client, &buffer, 1, MSG_PEEK | MSG_DONTWAIT) <= 0)
         {
             set_status(ST_FATAL, "connection closed");
diff --git a/testbot/src/testagentd/platform_windows.c b/testbot/src/testagentd/platform_windows.c
index ab4bf7b..55ed51d 100644
--- a/testbot/src/testagentd/platform_windows.c
+++ b/testbot/src/testagentd/platform_windows.c
@@ -136,7 +136,7 @@ uint64_t platform_run(char** argv, uint32_t flags, char** redirects)
     return pi.dwProcessId;
 }
 
-int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus)
+int platform_wait(SOCKET client, uint64_t pid, uint32_t timeout, uint32_t *childstatus)
 {
     struct child_t *child;
     HANDLE handles[2];
@@ -160,7 +160,7 @@ int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus)
     handles[0] = WSACreateEvent();
     WSAEventSelect(client, handles[0], FD_CLOSE);
     handles[1] = child->handle;
-    r = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+    r = WaitForMultipleObjects(2, handles, FALSE, timeout * 1000);
 
     success = 0;
     switch (r)
@@ -179,6 +179,9 @@ int platform_wait(SOCKET client, uint64_t pid, uint32_t *childstatus)
         else
             debug("GetExitCodeProcess() failed (%lu). Giving up!\n", GetLastError());
         break;
+    case WAIT_TIMEOUT:
+        set_status(ST_ERROR, "timed out waiting for the child process");
+        return 0;
     default:
         debug("WaitForMultipleObjects() returned %lu (le=%lu). Giving up!\n", r, GetLastError());
         break;
diff --git a/testbot/src/testagentd/testagentd.c b/testbot/src/testagentd/testagentd.c
index 3de9a3c..26e2a9b 100644
--- a/testbot/src/testagentd/testagentd.c
+++ b/testbot/src/testagentd/testagentd.c
@@ -29,7 +29,13 @@
 
 #include "platform.h"
 
-#define PROTOCOL_VERSION "testagentd 1.0"
+/* Increase the major version number when making backward-incompatible changes.
+ * Otherwise increase the minor version number:
+ * 1.0:  Initial release.
+ * 1.1:  Added the wait2 RPC.
+ */
+#define PROTOCOL_VERSION "testagentd 1.1"
+
 #define BLOCK_SIZE       4096
 
 const char *name0;
@@ -73,6 +79,7 @@ enum rpc_ids_t
     RPCID_RUN,
     RPCID_WAIT,
     RPCID_RM,
+    RPCID_WAIT2,
 };
 
 /* This is the RPC currently being processed */
@@ -89,6 +96,7 @@ static const char* rpc_name(uint32_t id)
         "run",
         "wait",
         "rm",
+        "wait2",
     };
 
     if (id < sizeof(names) / sizeof(*names))
@@ -761,7 +769,30 @@ static void do_wait(SOCKET client)
         return;
     }
 
-    if (platform_wait(client, pid, &childstatus))
+    if (platform_wait(client, pid, 0, &childstatus))
+    {
+        send_list_size(client, 1);
+        send_uint32(client, childstatus);
+    }
+    else
+        send_error(client);
+}
+
+static void do_wait2(SOCKET client)
+{
+    uint64_t pid;
+    uint32_t timeout;
+    uint32_t childstatus;
+
+    if (!expect_list_size(client, 2) ||
+        !recv_uint64(client, &pid) ||
+        !recv_uint32(client, &timeout))
+    {
+        send_error(client);
+        return;
+    }
+
+    if (platform_wait(client, pid, timeout, &childstatus))
     {
         send_list_size(client, 1);
         send_uint32(client, childstatus);
@@ -906,6 +937,9 @@ static void process_rpc(SOCKET client)
     case RPCID_WAIT:
         do_wait(client);
         break;
+    case RPCID_WAIT2:
+        do_wait2(client);
+        break;
     case RPCID_RM:
         do_rm(client);
         break;
-- 
1.7.10.4




More information about the wine-patches mailing list