Browse Source

P3D_check_request(timeout)

David Rose 16 years ago
parent
commit
a4fcdbe5b9

+ 14 - 5
direct/src/p3d/panda3d.pdef

@@ -44,12 +44,21 @@ class panda3d(package):
     # automatically be included as well, and we end up with a pretty
     # complete list that way.
     module('direct.directbase.DirectStart',
+           'direct.actor.*',
+           'direct.controls.*',
+           'direct.directdevices.*',
+           'direct.directnotify.*',
+           'direct.directtools.*',
+           'direct.directutil.*',
+           'direct.distributed.*',
+           'direct.fsm.*',
+           'direct.gui.*',
+           'direct.interval.*',
+           'direct.particles.*',
            'direct.showbase.*',
-           'direct.actor.Actor',
-           'direct.fsm.FSM',
-           'direct.interval.IntervalGlobal',
-           'direct.particles.ParticleEffect',
-           'direct.directutil.Mopath')
+           'direct.showutil.*',
+           'direct.stdpy.*')          
+
 
     # Exclude these GUI toolkits; they're big, and many applications don't
     # use them.  We define them as separate, optional packages, below.

+ 55 - 3
direct/src/plugin/p3dInstanceManager.cxx

@@ -404,7 +404,8 @@ check_request() {
 //     Function: P3DInstanceManager::wait_request
 //       Access: Public
 //  Description: Does not return until a request is pending on some
-//               instance, or until no instances remain.  Use
+//               instance, or until no instances remain, or until the
+//               indicated time in seconds has elapsed.  Use
 //               check_request to retrieve the pending request.  Due
 //               to the possibility of race conditions, it is possible
 //               for this function to return when there is in fact no
@@ -412,9 +413,60 @@ check_request() {
 //               the request first).
 ////////////////////////////////////////////////////////////////////
 void P3DInstanceManager::
-wait_request() {
+wait_request(double timeout) {
+#ifdef _WIN32
+  int stop_tick = int(GetTickCount() + timeout * 1000.0);
+#else
+  struct timeval stop_time;
+  gettimeofday(&stop_time, NULL);
+
+  int seconds = (int)floor(timeout);
+  stop_time.tv_sec += seconds;
+  stop_time.tv_usec += (int)((timeout - seconds) * 1000.0);
+  if (stop_time.tv_usec > 1000) {
+    stop_time.tv_usec -= 1000;
+    ++stop_time.tv_sec;
+  }
+#endif
+
   _request_ready.acquire();
+  if (check_request() != (P3DInstance *)NULL) {
+    _request_ready.release();
+    return;
+  }
+  if (_instances.empty()) {
+    _request_ready.release();
+    return;
+  }
+  
+  // No pending requests; go to sleep.
+  _request_ready.wait(timeout);
+
   while (true) {
+#ifdef _WIN32
+    int remaining_ticks = stop_tick - GetTickCount();
+    if (remaining_ticks <= 0) {
+      break;
+    }
+    timeout = remaining_ticks * 0.001;
+#else
+    struct timeval now;
+    gettimeofday(&now, NULL);
+
+    struct timeval remaining;
+    remaining.tv_sec = stop_time.tv_sec - now.tv_sec;
+    remaining.tv_usec = stop_time.tv_usec - now.tv_usec;
+
+    if (remaining.tv_usec < 0) {
+      remaining.tv_usec += 1000;
+      --remaining.tv_sec;
+    }
+    if (remaining.tv_sec < 0) {
+      break;
+    }
+    timeout = remaining.tv_sec + remaining.tv_usec * 0.001;
+#endif
+
     if (check_request() != (P3DInstance *)NULL) {
       _request_ready.release();
       return;
@@ -425,7 +477,7 @@ wait_request() {
     }
     
     // No pending requests; go to sleep.
-    _request_ready.wait();
+    _request_ready.wait(timeout);
   }
   _request_ready.release();
 }

+ 1 - 1
direct/src/plugin/p3dInstanceManager.h

@@ -73,7 +73,7 @@ public:
   P3DInstance *validate_instance(P3D_instance *instance);
 
   P3DInstance *check_request();
-  void wait_request();
+  void wait_request(double timeout);
 
   P3DHost *get_host(const string &host_url);
 

+ 49 - 4
direct/src/plugin/p3d_plugin.cxx

@@ -25,6 +25,7 @@
 #include "p3dStringObject.h"
 
 #include <assert.h>
+#include <math.h>
 
 // Use a simple lock to protect the C-style API functions in this
 // module from parallel access by multiple threads in the host.
@@ -405,21 +406,65 @@ P3D_instance_get_request(P3D_instance *instance) {
 }
 
 P3D_instance *
-P3D_check_request(bool wait) {
+P3D_check_request(double timeout) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
   P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
   P3D_instance *inst = inst_mgr->check_request();
 
-  if (inst != NULL || !wait) {
+  if (inst != NULL || timeout <= 0.0) {
     RELEASE_LOCK(_api_lock);
     return inst;
   }
-  
+
+#ifdef _WIN32
+  int stop_tick = int(GetTickCount() + timeout * 1000.0);
+#else
+  struct timeval stop_time;
+  gettimeofday(&stop_time, NULL);
+
+  int seconds = (int)floor(timeout);
+  stop_time.tv_sec += seconds;
+  stop_time.tv_usec += (int)((timeout - seconds) * 1000.0);
+  if (stop_time.tv_usec > 1000) {
+    stop_time.tv_usec -= 1000;
+    ++stop_time.tv_sec;
+  }
+#endif
+
   // Now we have to block until a request is available.
+  RELEASE_LOCK(_api_lock);
+  inst_mgr->wait_request(timeout);
+  ACQUIRE_LOCK(_api_lock);
+  inst = inst_mgr->check_request();
+
   while (inst == NULL && inst_mgr->get_num_instances() != 0) {
+#ifdef _WIN32
+    int remaining_ticks = stop_tick - GetTickCount();
+    if (remaining_ticks <= 0) {
+      break;
+    }
+    timeout = remaining_ticks * 0.001;
+#else
+    struct timeval now;
+    gettimeofday(&now, NULL);
+
+    struct timeval remaining;
+    remaining.tv_sec = stop_time.tv_sec - now.tv_sec;
+    remaining.tv_usec = stop_time.tv_usec - now.tv_usec;
+
+    if (remaining.tv_usec < 0) {
+      remaining.tv_usec += 1000;
+      --remaining.tv_sec;
+    }
+    if (remaining.tv_sec < 0) {
+      break;
+    }
+    timeout = remaining.tv_sec + remaining.tv_usec * 0.001;
+#endif
+
     RELEASE_LOCK(_api_lock);
-    inst_mgr->wait_request();
+    inst_mgr->wait_request(timeout);
     ACQUIRE_LOCK(_api_lock);
     inst = inst_mgr->check_request();
   }

+ 4 - 5
direct/src/plugin/p3d_plugin.h

@@ -738,10 +738,9 @@ P3D_instance_get_request_func(P3D_instance *instance);
    If any open instance has a pending request, this function will
    return a pointer to one of them (which you may then pass to
    P3D_instance_get_request_func).  If no instances have a pending
-   request, this function will return NULL.  If wait is true, this
-   function will never return NULL unless there are no instances open;
-   instead, it will wait indefinitely until there is a request
-   available.
+   request, this function will return NULL.  This function will not
+   return until at least timeout seconds have elapsed, or a request is
+   available, whichever comes first.
 
    Note that, due to race conditions, it is possible for this function
    to return a P3D_instance that does not in fact have any requests
@@ -749,7 +748,7 @@ P3D_instance_get_request_func(P3D_instance *instance);
    should always verify that the return value of
    P3D_instance_get_request() is not NULL. */
 typedef P3D_instance *
-P3D_check_request_func(bool wait);
+P3D_check_request_func(double timeout);
 
 /* A request retrieved by P3D_instance_get_request() should eventually
    be passed here, after it has been handled, to deallocate its

+ 53 - 12
direct/src/plugin_standalone/panda3d.cxx

@@ -36,6 +36,9 @@
 #endif
 
 
+// The amount of time in seconds to wait for new messages.
+static const double wait_cycle = 0.2;
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3D::Constructor
 //       Access: Public
@@ -61,7 +64,7 @@ run(int argc, char *argv[]) {
   // We prefix a "+" sign to tell gnu getopt not to parse options
   // following the first not-option parameter.  (These will be passed
   // into the sub-process.)
-  const char *optstr = "+mu:p:ft:s:o:l:h";
+  const char *optstr = "+mu:p:fw:t:s:o:l:h";
 
   bool allow_multiple = false;
   string download_url = PANDA_PACKAGE_HOST_URL;
@@ -92,7 +95,7 @@ run(int argc, char *argv[]) {
       verify_contents = true;
       break;
 
-    case 't':
+    case 'w':
       if (strcmp(optarg, "toplevel") == 0) {
         window_type = P3D_WT_toplevel;
       } else if (strcmp(optarg, "embedded") == 0) {
@@ -102,7 +105,14 @@ run(int argc, char *argv[]) {
       } else if (strcmp(optarg, "hidden") == 0) {
         window_type = P3D_WT_hidden;
       } else {
-        cerr << "Invalid value for -t: " << optarg << "\n";
+        cerr << "Invalid value for -w: " << optarg << "\n";
+        return 1;
+      }
+      break;
+
+    case 't':
+      if (!parse_token(optarg)) {
+        cerr << "Web tokens (-t) must be of the form token=value: " << optarg << "\n";
         return 1;
       }
       break;
@@ -248,13 +258,13 @@ run(int argc, char *argv[]) {
       DispatchMessage(&msg);
 
       // Check for new requests from the Panda3D plugin.
-      P3D_instance *inst = P3D_check_request(false);
+      P3D_instance *inst = P3D_check_request(wait_cycle);
       while (inst != (P3D_instance *)NULL) {
         P3D_request *request = P3D_instance_get_request(inst);
         if (request != (P3D_request *)NULL) {
           handle_request(request);
         }
-        inst = P3D_check_request(false);
+        inst = P3D_check_request(wait_cycle);
       }
 
       while (!_url_getters.empty() && 
@@ -276,7 +286,7 @@ run(int argc, char *argv[]) {
     // Not an embedded window, so we don't have our own window to
     // generate Windows events.  Instead, just wait for requests.
     while (!_instances.empty()) {
-      P3D_instance *inst = P3D_check_request(false);
+      P3D_instance *inst = P3D_check_request(wait_cycle);
       if (inst != (P3D_instance *)NULL) {
         P3D_request *request = P3D_instance_get_request(inst);
         if (request != (P3D_request *)NULL) {
@@ -294,7 +304,7 @@ run(int argc, char *argv[]) {
   EventLoopRef main_loop = GetMainEventLoop();
   EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback);
   EventLoopTimerRef timer;
-  EventTimerInterval interval = 200 * kEventDurationMillisecond;
+  EventTimerInterval interval = wait_cycle * kEventDurationSecond;
   InstallEventLoopTimer(main_loop, interval, interval,
                         timer_upp, this, &timer);
   RunApplicationEventLoop();
@@ -310,7 +320,7 @@ run(int argc, char *argv[]) {
 
   // Now wait while we process pending requests.
   while (!_instances.empty()) {
-    P3D_instance *inst = P3D_check_request(false);
+    P3D_instance *inst = P3D_check_request(wait_cycle);
     if (inst != (P3D_instance *)NULL) {
       P3D_request *request = P3D_instance_get_request(inst);
       if (request != (P3D_request *)NULL) {
@@ -647,7 +657,7 @@ create_instance(const string &p3d, P3D_window_type window_type,
   } 
 
   // Build up the token list.
-  pvector<P3D_token> tokens;
+  Tokens tokens = _tokens;
   P3D_token token;
 
   string log_basename;
@@ -745,7 +755,11 @@ usage() {
     << "    time, but additional arguments may not be passed to any of the\n"
     << "    applictions.\n\n"
 
-    << "  -t [toplevel|embedded|fullscreen|hidden]\n"
+    << "  -t token=value\n"
+    << "    Defines a web token or parameter to pass to the application(s).\n"
+    << "    This simulates a <param> entry in an <object> tag.\n\n"
+
+    << "  -w [toplevel|embedded|fullscreen|hidden]\n"
     << "    Specify the type of graphic window to create.  If you specify\n"
     << "    \"embedded\", a new window is created to be the parent.\n\n"
 
@@ -775,6 +789,33 @@ usage() {
     << DTOOL_PLATFORM << "\" .\n\n";
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Panda3D::parse_token
+//       Access: Private
+//  Description: Parses a web token of the form token=value, and
+//               stores it in _tokens.  Returns true on success, false
+//               on failure.
+////////////////////////////////////////////////////////////////////
+bool Panda3D::
+parse_token(char *arg) {
+  char *equals = strchr(arg, '=');
+  if (equals == NULL) {
+    return false;
+  }
+
+  // Directly munge the C string to truncate it at the equals sign.
+  // Classic C tricks.
+  *equals = '\0';
+  P3D_token token;
+  token._keyword = strdup(arg);
+  token._value = strdup(equals + 1);
+  *equals = '=';
+
+  _tokens.push_back(token);
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Panda3D::parse_int_pair
 //       Access: Private
@@ -857,13 +898,13 @@ st_timer_callback(EventLoopTimerRef timer, void *user_data) {
 void Panda3D::
 timer_callback(EventLoopTimerRef timer) {
   // Check for new requests from the Panda3D plugin.
-  P3D_instance *inst = P3D_check_request(false);
+  P3D_instance *inst = P3D_check_request(0.0);
   while (inst != (P3D_instance *)NULL) {
     P3D_request *request = P3D_instance_get_request(inst);
     if (request != (P3D_request *)NULL) {
       handle_request(request);
     }
-    inst = P3D_check_request(false);
+    inst = P3D_check_request(0.0);
   }
   
   // Check the download tasks.

+ 4 - 0
direct/src/plugin_standalone/panda3d.h

@@ -63,6 +63,7 @@ private:
   void delete_instance(P3D_instance *instance);
 
   void usage();
+  bool parse_token(char *arg);
   bool parse_int_pair(char *arg, int &x, int &y);
 
   void report_downloading_package(P3D_instance *instance);
@@ -83,6 +84,9 @@ private:
   typedef pset<P3D_instance *> Instances;
   Instances _instances;
 
+  typedef pvector<P3D_token> Tokens;
+  Tokens _tokens;
+
   // This nested class keeps track of active URL requests.
   class URLGetter {
   public: